1# to run these tests:
2# nix-instantiate --eval --strict nixpkgs/lib/tests/misc.nix
3# if the resulting list is empty, all tests passed
4with import ../default.nix;
5
6runTests {
7
8
9# TRIVIAL
10
11 testId = {
12 expr = id 1;
13 expected = 1;
14 };
15
16 testConst = {
17 expr = const 2 3;
18 expected = 2;
19 };
20
21 /*
22 testOr = {
23 expr = or true false;
24 expected = true;
25 };
26 */
27
28 testAnd = {
29 expr = and true false;
30 expected = false;
31 };
32
33 testFix = {
34 expr = fix (x: {a = if x ? a then "a" else "b";});
35 expected = {a = "a";};
36 };
37
38 testComposeExtensions = {
39 expr = let obj = makeExtensible (self: { foo = self.bar; });
40 f = self: super: { bar = false; baz = true; };
41 g = self: super: { bar = super.baz or false; };
42 f_o_g = composeExtensions f g;
43 composed = obj.extend f_o_g;
44 in composed.foo;
45 expected = true;
46 };
47
48# STRINGS
49
50 testConcatMapStrings = {
51 expr = concatMapStrings (x: x + ";") ["a" "b" "c"];
52 expected = "a;b;c;";
53 };
54
55 testConcatStringsSep = {
56 expr = concatStringsSep "," ["a" "b" "c"];
57 expected = "a,b,c";
58 };
59
60 testSplitStringsSimple = {
61 expr = strings.splitString "." "a.b.c.d";
62 expected = [ "a" "b" "c" "d" ];
63 };
64
65 testSplitStringsEmpty = {
66 expr = strings.splitString "." "a..b";
67 expected = [ "a" "" "b" ];
68 };
69
70 testSplitStringsOne = {
71 expr = strings.splitString ":" "a.b";
72 expected = [ "a.b" ];
73 };
74
75 testSplitStringsNone = {
76 expr = strings.splitString "." "";
77 expected = [ "" ];
78 };
79
80 testSplitStringsFirstEmpty = {
81 expr = strings.splitString "/" "/a/b/c";
82 expected = [ "" "a" "b" "c" ];
83 };
84
85 testSplitStringsLastEmpty = {
86 expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:";
87 expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ];
88 };
89
90 testIsStorePath = {
91 expr =
92 let goodPath =
93 "${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11";
94 in {
95 storePath = isStorePath goodPath;
96 storePathAppendix = isStorePath
97 "${goodPath}/bin/python";
98 nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath)));
99 asPath = isStorePath (builtins.toPath goodPath);
100 otherPath = isStorePath "/something/else";
101 otherVals = {
102 attrset = isStorePath {};
103 list = isStorePath [];
104 int = isStorePath 42;
105 };
106 };
107 expected = {
108 storePath = true;
109 storePathAppendix = false;
110 nonAbsolute = false;
111 asPath = true;
112 otherPath = false;
113 otherVals = {
114 attrset = false;
115 list = false;
116 int = false;
117 };
118 };
119 };
120
121# LISTS
122
123 testFilter = {
124 expr = filter (x: x != "a") ["a" "b" "c" "a"];
125 expected = ["b" "c"];
126 };
127
128 testFold =
129 let
130 f = op: fold: fold op 0 (range 0 100);
131 # fold with associative operator
132 assoc = f builtins.add;
133 # fold with non-associative operator
134 nonAssoc = f builtins.sub;
135 in {
136 expr = {
137 assocRight = assoc foldr;
138 # right fold with assoc operator is same as left fold
139 assocRightIsLeft = assoc foldr == assoc foldl;
140 nonAssocRight = nonAssoc foldr;
141 nonAssocLeft = nonAssoc foldl;
142 # with non-assoc operator the fold results are not the same
143 nonAssocRightIsNotLeft = nonAssoc foldl != nonAssoc foldr;
144 # fold is an alias for foldr
145 foldIsRight = nonAssoc fold == nonAssoc foldr;
146 };
147 expected = {
148 assocRight = 5050;
149 assocRightIsLeft = true;
150 nonAssocRight = 50;
151 nonAssocLeft = (-5050);
152 nonAssocRightIsNotLeft = true;
153 foldIsRight = true;
154 };
155 };
156
157 testTake = testAllTrue [
158 ([] == (take 0 [ 1 2 3 ]))
159 ([1] == (take 1 [ 1 2 3 ]))
160 ([ 1 2 ] == (take 2 [ 1 2 3 ]))
161 ([ 1 2 3 ] == (take 3 [ 1 2 3 ]))
162 ([ 1 2 3 ] == (take 4 [ 1 2 3 ]))
163 ];
164
165 testFoldAttrs = {
166 expr = foldAttrs (n: a: [n] ++ a) [] [
167 { a = 2; b = 7; }
168 { a = 3; c = 8; }
169 ];
170 expected = { a = [ 2 3 ]; b = [7]; c = [8];};
171 };
172
173 testSort = {
174 expr = sort builtins.lessThan [ 40 2 30 42 ];
175 expected = [2 30 40 42];
176 };
177
178 testToIntShouldConvertStringToInt = {
179 expr = toInt "27";
180 expected = 27;
181 };
182
183 testToIntShouldThrowErrorIfItCouldNotConvertToInt = {
184 expr = builtins.tryEval (toInt "\"foo\"");
185 expected = { success = false; value = false; };
186 };
187
188 testHasAttrByPathTrue = {
189 expr = hasAttrByPath ["a" "b"] { a = { b = "yey"; }; };
190 expected = true;
191 };
192
193 testHasAttrByPathFalse = {
194 expr = hasAttrByPath ["a" "b"] { a = { c = "yey"; }; };
195 expected = false;
196 };
197
198
199# GENERATORS
200# these tests assume attributes are converted to lists
201# in alphabetical order
202
203 testMkKeyValueDefault = {
204 expr = generators.mkKeyValueDefault {} ":" "f:oo" "bar";
205 expected = ''f\:oo:bar'';
206 };
207
208 testToKeyValue = {
209 expr = generators.toKeyValue {} {
210 key = "value";
211 "other=key" = "baz";
212 };
213 expected = ''
214 key=value
215 other\=key=baz
216 '';
217 };
218
219 testToINIEmpty = {
220 expr = generators.toINI {} {};
221 expected = "";
222 };
223
224 testToINIEmptySection = {
225 expr = generators.toINI {} { foo = {}; bar = {}; };
226 expected = ''
227 [bar]
228
229 [foo]
230 '';
231 };
232
233 testToINIDefaultEscapes = {
234 expr = generators.toINI {} {
235 "no [ and ] allowed unescaped" = {
236 "and also no = in keys" = 42;
237 };
238 };
239 expected = ''
240 [no \[ and \] allowed unescaped]
241 and also no \= in keys=42
242 '';
243 };
244
245 testToINIDefaultFull = {
246 expr = generators.toINI {} {
247 "section 1" = {
248 attribute1 = 5;
249 x = "Me-se JarJar Binx";
250 };
251 "foo[]" = {
252 "he\\h=he" = "this is okay";
253 };
254 };
255 expected = ''
256 [foo\[\]]
257 he\h\=he=this is okay
258
259 [section 1]
260 attribute1=5
261 x=Me-se JarJar Binx
262 '';
263 };
264
265 /* right now only invocation check */
266 testToJSONSimple =
267 let val = {
268 foobar = [ "baz" 1 2 3 ];
269 };
270 in {
271 expr = generators.toJSON {} val;
272 # trivial implementation
273 expected = builtins.toJSON val;
274 };
275
276 /* right now only invocation check */
277 testToYAMLSimple =
278 let val = {
279 list = [ { one = 1; } { two = 2; } ];
280 all = 42;
281 };
282 in {
283 expr = generators.toYAML {} val;
284 # trivial implementation
285 expected = builtins.toJSON val;
286 };
287
288 testToPretty = {
289 expr = mapAttrs (const (generators.toPretty {})) rec {
290 int = 42;
291 bool = true;
292 string = "fnord";
293 null_ = null;
294 function = x: x;
295 functionArgs = { arg ? 4, foo }: arg;
296 list = [ 3 4 function [ false ] ];
297 attrs = { foo = null; "foo bar" = "baz"; };
298 drv = derivation { name = "test"; system = builtins.currentSystem; };
299 };
300 expected = rec {
301 int = "42";
302 bool = "true";
303 string = "\"fnord\"";
304 null_ = "null";
305 function = "<λ>";
306 functionArgs = "<λ:{(arg),foo}>";
307 list = "[ 3 4 ${function} [ false ] ]";
308 attrs = "{ \"foo\" = null; \"foo bar\" = \"baz\"; }";
309 drv = "<δ>";
310 };
311 };
312
313 testToPrettyAllowPrettyValues = {
314 expr = generators.toPretty { allowPrettyValues = true; }
315 { __pretty = v: "«" + v + "»"; val = "foo"; };
316 expected = "«foo»";
317 };
318
319
320# MISC
321
322 testOverridableDelayableArgsTest = {
323 expr =
324 let res1 = defaultOverridableDelayableArgs id {};
325 res2 = defaultOverridableDelayableArgs id { a = 7; };
326 res3 = let x = defaultOverridableDelayableArgs id { a = 7; };
327 in (x.merge) { b = 10; };
328 res4 = let x = defaultOverridableDelayableArgs id { a = 7; };
329 in (x.merge) ( x: { b = 10; });
330 res5 = let x = defaultOverridableDelayableArgs id { a = 7; };
331 in (x.merge) ( x: { a = builtins.add x.a 3; });
332 res6 = let x = defaultOverridableDelayableArgs id { a = 7; mergeAttrBy = { a = builtins.add; }; };
333 y = x.merge {};
334 in (y.merge) { a = 10; };
335
336 resRem7 = res6.replace (a: removeAttrs a ["a"]);
337
338 resReplace6 = let x = defaultOverridableDelayableArgs id { a = 7; mergeAttrBy = { a = builtins.add; }; };
339 x2 = x.merge { a = 20; }; # now we have 27
340 in (x2.replace) { a = 10; }; # and override the value by 10
341
342 # fixed tests (delayed args): (when using them add some comments, please)
343 resFixed1 =
344 let x = defaultOverridableDelayableArgs id ( x: { a = 7; c = x.fixed.b; });
345 y = x.merge (x: { name = "name-${builtins.toString x.fixed.c}"; });
346 in (y.merge) { b = 10; };
347 strip = attrs: removeAttrs attrs ["merge" "replace"];
348 in all id
349 [ ((strip res1) == { })
350 ((strip res2) == { a = 7; })
351 ((strip res3) == { a = 7; b = 10; })
352 ((strip res4) == { a = 7; b = 10; })
353 ((strip res5) == { a = 10; })
354 ((strip res6) == { a = 17; })
355 ((strip resRem7) == {})
356 ((strip resFixed1) == { a = 7; b = 10; c =10; name = "name-10"; })
357 ];
358 expected = true;
359 };
360
361}