2 Nix evaluation tests for various lib functions.
4 Since these tests are implemented with Nix evaluation, error checking is limited to what `builtins.tryEval` can detect, which is `throw`'s and `abort`'s, without error messages.
5 If you need to test error messages or more complex evaluations, see ./modules.sh, ./sources.sh or ./filesystem.sh as examples.
9 [nixpkgs]$ nix-instantiate --eval --strict lib/tests/misc.nix
11 If the resulting list is empty, all tests passed.
12 Alternatively, to run all `lib` tests:
14 [nixpkgs]$ nix-build lib/tests/release.nix
16 with import ../default.nix;
19 testingThrow = expr: {
20 expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
21 expected = { success = false; value = false; };
24 expr = (builtins.tryEval expr).success;
27 testingDeepThrow = expr: testingThrow (builtins.deepSeq expr expr);
29 testSanitizeDerivationName = { name, expected }:
32 name = strings.sanitizeDerivationName name;
37 # Evaluate the derivation so an invalid name would be caught
38 expr = builtins.seq drv.drvPath drv.name;
48 testFunctionArgsMakeOverridable = {
49 expr = functionArgs (makeOverridable ({ a, b, c ? null}: {}));
50 expected = { a = false; b = false; c = true; };
53 testFunctionArgsMakeOverridableOverride = {
54 expr = functionArgs (makeOverridable ({ a, b, c ? null }: {}) { a = 1; b = 2; }).override;
55 expected = { a = false; b = false; c = true; };
72 (x: x + 2) # 2 + 2 = 4
73 (x: x * 2) # 4 * 2 = 8
103 expr = and true false;
108 expr = fix (x: {a = if x ? a then "a" else "b";});
109 expected = {a = "a";};
112 testComposeExtensions = {
113 expr = let obj = makeExtensible (self: { foo = self.bar; });
114 f = self: super: { bar = false; baz = true; };
115 g = self: super: { bar = super.baz or false; };
116 f_o_g = composeExtensions f g;
117 composed = obj.extend f_o_g;
122 testComposeManyExtensions0 = {
123 expr = let obj = makeExtensible (self: { foo = true; });
124 emptyComposition = composeManyExtensions [];
125 composed = obj.extend emptyComposition;
130 testComposeManyExtensions =
131 let f = self: super: { bar = false; baz = true; };
132 g = self: super: { bar = super.baz or false; };
133 h = self: super: { qux = super.bar or false; };
134 obj = makeExtensible (self: { foo = self.qux; });
136 expr = let composition = composeManyExtensions [f g h];
137 composed = obj.extend composition;
139 expected = (obj.extend (composeExtensions f (composeExtensions g h))).foo;
143 expr = (bitAnd 3 10);
153 expr = (bitXor 3 10);
158 expr = toHexString 250;
163 expr = toBaseDigits 2 6;
164 expected = [ 1 1 0 ];
167 testFunctionArgsFunctor = {
168 expr = functionArgs { __functor = self: { a, b }: null; };
169 expected = { a = false; b = false; };
172 testFunctionArgsSetFunctionArgs = {
173 expr = functionArgs (setFunctionArgs (args: args.x) { x = false; });
174 expected = { x = false; };
179 testConcatMapStrings = {
180 expr = concatMapStrings (x: x + ";") ["a" "b" "c"];
184 testConcatStringsSep = {
185 expr = concatStringsSep "," ["a" "b" "c"];
190 expr = concatLines ["a" "b" "c"];
191 expected = "a\nb\nc\n";
194 testReplicateString = {
195 expr = strings.replicate 5 "hello";
196 expected = "hellohellohellohellohello";
199 testSplitStringsSimple = {
200 expr = strings.splitString "." "a.b.c.d";
201 expected = [ "a" "b" "c" "d" ];
204 testSplitStringsEmpty = {
205 expr = strings.splitString "." "a..b";
206 expected = [ "a" "" "b" ];
209 testSplitStringsOne = {
210 expr = strings.splitString ":" "a.b";
211 expected = [ "a.b" ];
214 testSplitStringsNone = {
215 expr = strings.splitString "." "";
219 testSplitStringsFirstEmpty = {
220 expr = strings.splitString "/" "/a/b/c";
221 expected = [ "" "a" "b" "c" ];
224 testSplitStringsLastEmpty = {
225 expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:";
226 expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ];
229 testSplitStringsRegex = {
230 expr = strings.splitString "\\[{}]()^$?*+|." "A\\[{}]()^$?*+|.B";
231 expected = [ "A" "B" ];
234 testSplitStringsDerivation = {
235 expr = take 3 (strings.splitString "/" (derivation {
240 expected = ["" "nix" "store"];
243 testSplitVersionSingle = {
244 expr = versions.splitVersion "1";
248 testSplitVersionDouble = {
249 expr = versions.splitVersion "1.2";
250 expected = [ "1" "2" ];
253 testSplitVersionTriple = {
254 expr = versions.splitVersion "1.2.3";
255 expected = [ "1" "2" "3" ];
258 testPadVersionLess = {
259 expr = versions.pad 3 "1.2";
263 testPadVersionLessExtra = {
264 expr = versions.pad 3 "1.3-rc1";
265 expected = "1.3.0-rc1";
268 testPadVersionMore = {
269 expr = versions.pad 3 "1.2.3.4";
276 "${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11";
278 storePath = isStorePath goodPath;
279 storePathDerivation = isStorePath (import ../.. { system = "x86_64-linux"; }).hello;
280 storePathAppendix = isStorePath
281 "${goodPath}/bin/python";
282 nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath)));
283 asPath = isStorePath (/. + goodPath);
284 otherPath = isStorePath "/something/else";
286 attrset = isStorePath {};
287 list = isStorePath [];
288 int = isStorePath 42;
293 storePathDerivation = true;
294 storePathAppendix = false;
307 expr = escapeXML ''"test" 'test' < & >'';
308 expected = ""test" 'test' < & >";
314 STRing01 = "just a 'string'";
315 _array_ = [ "with" "more strings" ];
316 assoc."with some" = ''
322 foo = "ignored attribute";
326 __toString = _: "hello toString";
327 bar = "ignored attribute";
332 STRing01='just a '\'''string'\''''
333 declare -a _array_=('with' 'more strings')
334 declare -A assoc=(['with some']='strings
339 stringable='hello toString'
343 testHasInfixFalse = {
344 expr = hasInfix "c" "abde";
349 expr = hasInfix "c" "abcde";
353 testHasInfixDerivation = {
354 expr = hasInfix "hello" (import ../.. { system = "x86_64-linux"; }).hello;
359 expr = hasInfix "tests" ./.;
363 testHasInfixPathStoreDir = {
364 expr = hasInfix builtins.storeDir ./.;
368 testHasInfixToString = {
369 expr = hasInfix "a" { __toString = _: "a"; };
373 testRemovePrefixExample1 = {
374 expr = removePrefix "foo." "foo.bar.baz";
375 expected = "bar.baz";
377 testRemovePrefixExample2 = {
378 expr = removePrefix "xxx" "foo.bar.baz";
379 expected = "foo.bar.baz";
381 testRemovePrefixEmptyPrefix = {
382 expr = removePrefix "" "foo";
385 testRemovePrefixEmptyString = {
386 expr = removePrefix "foo" "";
389 testRemovePrefixEmptyBoth = {
390 expr = removePrefix "" "";
394 testNormalizePath = {
395 expr = strings.normalizePath "//a/b//c////d/";
396 expected = "/a/b/c/d/";
400 expr = strings.charToInt "A";
405 expr = strings.escapeC [ " " ] "Hello World";
406 expected = "Hello\\x20World";
409 testEscapeURL = testAllTrue [
410 ("" == strings.escapeURL "")
411 ("Hello" == strings.escapeURL "Hello")
412 ("Hello%20World" == strings.escapeURL "Hello World")
413 ("Hello%2FWorld" == strings.escapeURL "Hello/World")
414 ("42%25" == strings.escapeURL "42%")
415 ("%20%3F%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%09%3A%2F%40%24%27%28%29%2A%2C%3B" == strings.escapeURL " ?&=#+%!<>#\"{}|\\^[]`\t:/@$'()*,;")
418 testToInt = testAllTrue [
423 (123 == toInt " 123")
424 (123 == toInt "123 ")
425 (123 == toInt " 123 ")
426 (123 == toInt " 123 ")
434 testToIntFails = testAllTrue [
435 ( builtins.tryEval (toInt "") == { success = false; value = false; } )
436 ( builtins.tryEval (toInt "123 123") == { success = false; value = false; } )
437 ( builtins.tryEval (toInt "0 123") == { success = false; value = false; } )
438 ( builtins.tryEval (toInt " 0d ") == { success = false; value = false; } )
439 ( builtins.tryEval (toInt " 1d ") == { success = false; value = false; } )
440 ( builtins.tryEval (toInt " d0 ") == { success = false; value = false; } )
441 ( builtins.tryEval (toInt "00") == { success = false; value = false; } )
442 ( builtins.tryEval (toInt "01") == { success = false; value = false; } )
443 ( builtins.tryEval (toInt "002") == { success = false; value = false; } )
444 ( builtins.tryEval (toInt " 002 ") == { success = false; value = false; } )
445 ( builtins.tryEval (toInt " foo ") == { success = false; value = false; } )
446 ( builtins.tryEval (toInt " foo 123 ") == { success = false; value = false; } )
447 ( builtins.tryEval (toInt " foo123 ") == { success = false; value = false; } )
450 testToIntBase10 = testAllTrue [
452 (123 == toIntBase10 "123")
453 (0 == toIntBase10 "0")
455 (123 == toIntBase10 " 123")
456 (123 == toIntBase10 "123 ")
457 (123 == toIntBase10 " 123 ")
458 (123 == toIntBase10 " 123 ")
459 (0 == toIntBase10 " 0")
460 (0 == toIntBase10 "0 ")
461 (0 == toIntBase10 " 0 ")
463 (123 == toIntBase10 "0123")
464 (123 == toIntBase10 "0000123")
465 (0 == toIntBase10 "000000")
466 # Whitespace and Zero Padding
467 (123 == toIntBase10 " 0123")
468 (123 == toIntBase10 "0123 ")
469 (123 == toIntBase10 " 0123 ")
470 (123 == toIntBase10 " 0000123")
471 (123 == toIntBase10 "0000123 ")
472 (123 == toIntBase10 " 0000123 ")
473 (0 == toIntBase10 " 000000")
474 (0 == toIntBase10 "000000 ")
475 (0 == toIntBase10 " 000000 ")
476 (-1 == toIntBase10 "-1")
477 (-1 == toIntBase10 " -1 ")
480 testToIntBase10Fails = testAllTrue [
481 ( builtins.tryEval (toIntBase10 "") == { success = false; value = false; } )
482 ( builtins.tryEval (toIntBase10 "123 123") == { success = false; value = false; } )
483 ( builtins.tryEval (toIntBase10 "0 123") == { success = false; value = false; } )
484 ( builtins.tryEval (toIntBase10 " 0d ") == { success = false; value = false; } )
485 ( builtins.tryEval (toIntBase10 " 1d ") == { success = false; value = false; } )
486 ( builtins.tryEval (toIntBase10 " d0 ") == { success = false; value = false; } )
487 ( builtins.tryEval (toIntBase10 " foo ") == { success = false; value = false; } )
488 ( builtins.tryEval (toIntBase10 " foo 123 ") == { success = false; value = false; } )
489 ( builtins.tryEval (toIntBase10 " foo 00123 ") == { success = false; value = false; } )
490 ( builtins.tryEval (toIntBase10 " foo00123 ") == { success = false; value = false; } )
496 expr = filter (x: x != "a") ["a" "b" "c" "a"];
497 expected = ["b" "c"];
502 f = op: fold: fold op 0 (range 0 100);
503 # fold with associative operator
504 assoc = f builtins.add;
505 # fold with non-associative operator
506 nonAssoc = f builtins.sub;
509 assocRight = assoc foldr;
510 # right fold with assoc operator is same as left fold
511 assocRightIsLeft = assoc foldr == assoc foldl;
512 nonAssocRight = nonAssoc foldr;
513 nonAssocLeft = nonAssoc foldl;
514 # with non-assoc operator the fold results are not the same
515 nonAssocRightIsNotLeft = nonAssoc foldl != nonAssoc foldr;
516 # fold is an alias for foldr
517 foldIsRight = nonAssoc fold == nonAssoc foldr;
521 assocRightIsLeft = true;
523 nonAssocLeft = (-5050);
524 nonAssocRightIsNotLeft = true;
530 expr = foldl' (acc: el: abort "operation not called") 0 [ ];
534 testFoldl'IntegerAdding = {
535 expr = foldl' (acc: el: acc + el) 0 [ 1 2 3 ];
539 # The accumulator isn't forced deeply
540 testFoldl'NonDeep = {
541 expr = take 3 (foldl'
542 (acc: el: [ el ] ++ acc)
543 [ (abort "unevaluated list entry") ]
545 expected = [ 3 2 1 ];
548 # Compared to builtins.foldl', lib.foldl' evaluates the first accumulator strictly too
549 testFoldl'StrictInitial = {
550 expr = (builtins.tryEval (foldl' (acc: el: el) (throw "hello") [])).success;
554 # Make sure we don't get a stack overflow for large lists
555 # This number of elements would notably cause a stack overflow if it was implemented without the `foldl'` builtin
557 expr = foldl' (acc: el: acc + el) 0 (range 0 100000);
558 expected = 5000050000;
561 testTake = testAllTrue [
562 ([] == (take 0 [ 1 2 3 ]))
563 ([1] == (take 1 [ 1 2 3 ]))
564 ([ 1 2 ] == (take 2 [ 1 2 3 ]))
565 ([ 1 2 3 ] == (take 3 [ 1 2 3 ]))
566 ([ 1 2 3 ] == (take 4 [ 1 2 3 ]))
569 testListHasPrefixExample1 = {
570 expr = lists.hasPrefix [ 1 2 ] [ 1 2 3 4 ];
573 testListHasPrefixExample2 = {
574 expr = lists.hasPrefix [ 0 1 ] [ 1 2 3 4 ];
577 testListHasPrefixLazy = {
578 expr = lists.hasPrefix [ 1 ] [ 1 (abort "lib.lists.hasPrefix is not lazy") ];
581 testListHasPrefixEmptyPrefix = {
582 expr = lists.hasPrefix [ ] [ 1 2 ];
585 testListHasPrefixEmptyList = {
586 expr = lists.hasPrefix [ 1 2 ] [ ];
590 testListRemovePrefixExample1 = {
591 expr = lists.removePrefix [ 1 2 ] [ 1 2 3 4 ];
594 testListRemovePrefixExample2 = {
595 expr = (builtins.tryEval (lists.removePrefix [ 0 1 ] [ 1 2 3 4 ])).success;
598 testListRemovePrefixEmptyPrefix = {
599 expr = lists.removePrefix [ ] [ 1 2 ];
602 testListRemovePrefixEmptyList = {
603 expr = (builtins.tryEval (lists.removePrefix [ 1 2 ] [ ])).success;
608 expr = foldAttrs (n: a: [n] ++ a) [] [
612 expected = { a = [ 2 3 ]; b = [7]; c = [8];};
615 testListCommonPrefixExample1 = {
616 expr = lists.commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ];
619 testListCommonPrefixExample2 = {
620 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ];
621 expected = [ 1 2 3 ];
623 testListCommonPrefixExample3 = {
624 expr = lists.commonPrefix [ 1 2 3 ] [ 4 5 6 ];
627 testListCommonPrefixEmpty = {
628 expr = lists.commonPrefix [ ] [ 1 2 3 ];
631 testListCommonPrefixSame = {
632 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 ];
633 expected = [ 1 2 3 ];
635 testListCommonPrefixLazy = {
636 expr = lists.commonPrefix [ 1 ] [ 1 (abort "lib.lists.commonPrefix shouldn't evaluate this")];
639 # This would stack overflow if `commonPrefix` were implemented using recursion
640 testListCommonPrefixLong =
642 longList = genList (n: n) 100000;
644 expr = lists.commonPrefix longList longList;
649 expr = sort builtins.lessThan [ 40 2 30 42 ];
650 expected = [2 30 40 42];
654 expr = sortOn stringLength [ "aa" "b" "cccc" ];
655 expected = [ "b" "aa" "cccc" ];
659 expr = sortOn (throw "nope") [ ];
663 testSortOnIncomparable = {
668 { ok = 1; f = x: x; }
669 { ok = 3; f = x: x + 3; }
670 { ok = 2; f = x: x; }
672 expected = [ 1 2 6 ];
676 expr = replicate 3 "a";
677 expected = ["a" "a" "a"];
680 testToIntShouldConvertStringToInt = {
685 testToIntShouldThrowErrorIfItCouldNotConvertToInt = {
686 expr = builtins.tryEval (toInt "\"foo\"");
687 expected = { success = false; value = false; };
690 testHasAttrByPathTrue = {
691 expr = hasAttrByPath ["a" "b"] { a = { b = "yey"; }; };
695 testHasAttrByPathFalse = {
696 expr = hasAttrByPath ["a" "b"] { a = { c = "yey"; }; };
700 testFindFirstIndexExample1 = {
701 expr = lists.findFirstIndex (x: x > 3) (abort "index found, so a default must not be evaluated") [ 1 6 4 ];
705 testFindFirstIndexExample2 = {
706 expr = lists.findFirstIndex (x: x > 9) "a very specific default" [ 1 6 4 ];
707 expected = "a very specific default";
710 testFindFirstIndexEmpty = {
711 expr = lists.findFirstIndex (abort "when the list is empty, the predicate is not needed") null [];
715 testFindFirstIndexSingleMatch = {
716 expr = lists.findFirstIndex (x: x == 5) null [ 5 ];
720 testFindFirstIndexSingleDefault = {
721 expr = lists.findFirstIndex (x: false) null [ (abort "if the predicate doesn't access the value, it must not be evaluated") ];
725 testFindFirstIndexNone = {
726 expr = builtins.tryEval (lists.findFirstIndex (x: x == 2) null [ 1 (throw "the last element must be evaluated when there's no match") ]);
727 expected = { success = false; value = false; };
730 # Makes sure that the implementation doesn't cause a stack overflow
731 testFindFirstIndexBig = {
732 expr = lists.findFirstIndex (x: x == 1000000) null (range 0 1000000);
736 testFindFirstIndexLazy = {
737 expr = lists.findFirstIndex (x: x == 1) null [ 1 (abort "list elements after the match must not be evaluated") ];
741 testFindFirstExample1 = {
742 expr = lists.findFirst (x: x > 3) 7 [ 1 6 4 ];
746 testFindFirstExample2 = {
747 expr = lists.findFirst (x: x > 9) 7 [ 1 6 4 ];
751 testAllUnique_true = {
752 expr = allUnique [ 3 2 4 1 ];
755 testAllUnique_false = {
756 expr = allUnique [ 3 2 3 4 ];
762 testConcatMapAttrs = {
763 expr = concatMapAttrs
766 ${name + value} = value;
784 sum = acc.sum + value;
785 names = acc.names ++ [ name ];
787 { sum = 0; names = [ ]; }
792 # should just return the initial value
793 emptySet = foldlAttrs (throw "function not needed") 123 { };
794 # should just evaluate to the last value
795 valuesNotNeeded = foldlAttrs (acc: _name: _v: acc) 3 { z = throw "value z not needed"; a = throw "value a not needed"; };
796 # the accumulator doesnt have to be an attrset it can be as trivial as being just a number or string
797 trivialAcc = foldlAttrs (acc: _name: v: acc * 10 + v) 1 { z = 1; a = 2; };
802 names = [ "bar" "foo" ];
811 testMergeAttrsListExample1 = {
812 expr = attrsets.mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ];
813 expected = { a = 0; b = 1; c = 2; d = 3; };
815 testMergeAttrsListExample2 = {
816 expr = attrsets.mergeAttrsList [ { a = 0; } { a = 1; } ];
817 expected = { a = 1; };
819 testMergeAttrsListExampleMany =
822 listToAttrs (genList (m:
824 # Integer divide n by two to create duplicate attributes
825 str = "halfn${toString (n / 2)}m${toString m}";
827 nameValuePair str str
831 expr = attrsets.mergeAttrsList list;
832 expected = foldl' mergeAttrs { } list;
835 # code from the example
836 testRecursiveUpdateUntil = {
837 expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) {
838 # first attribute set
843 #second attribute set
849 foo.bar = 1; # 'foo.*' from the second set
851 bar = 3; # 'bar' from the first set
852 baz = 4; # 'baz' from the second set
856 testMatchAttrsMatchingExact = {
857 expr = matchAttrs { cpu = { bits = 64; }; } { cpu = { bits = 64; }; };
861 testMatchAttrsMismatch = {
862 expr = matchAttrs { cpu = { bits = 128; }; } { cpu = { bits = 64; }; };
866 testMatchAttrsMatchingImplicit = {
867 expr = matchAttrs { cpu = { }; } { cpu = { bits = 64; }; };
871 testMatchAttrsMissingAttrs = {
872 expr = matchAttrs { cpu = {}; } { };
876 testOverrideExistingEmpty = {
877 expr = overrideExisting {} { a = 1; };
881 testOverrideExistingDisjoint = {
882 expr = overrideExisting { b = 2; } { a = 1; };
883 expected = { b = 2; };
886 testOverrideExistingOverride = {
887 expr = overrideExisting { a = 3; b = 2; } { a = 1; };
888 expected = { a = 1; b = 2; };
891 testListAttrsReverse = let
892 exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;};
893 exampleSingletonList = [{name="foo"; value=1;}];
896 isReverseToListToAttrs = builtins.listToAttrs (attrsToList exampleAttrs) == exampleAttrs;
897 isReverseToAttrsToList = attrsToList (builtins.listToAttrs exampleSingletonList) == exampleSingletonList;
898 testDuplicatePruningBehaviour = attrsToList (builtins.listToAttrs [{name="a"; value=2;} {name="a"; value=1;}]);
901 isReverseToAttrsToList = true;
902 isReverseToListToAttrs = true;
903 testDuplicatePruningBehaviour = [{name="a"; value=2;}];
907 testAttrsToListsCanDealWithFunctions = testingEval (
908 attrsToList { someFunc= a: a + 1;}
912 # these tests assume attributes are converted to lists
913 # in alphabetical order
915 testMkKeyValueDefault = {
916 expr = generators.mkKeyValueDefault {} ":" "f:oo" "bar";
917 expected = ''f\:oo:bar'';
920 testMkValueString = {
928 # float = 42.23; # floats are strange
931 (const (generators.mkValueStringDefault {}))
939 # float = "42.23" true false [ "bar" ] ]'';
944 expr = generators.toKeyValue {} {
955 expr = generators.toINI {} {};
959 testToINIEmptySection = {
960 expr = generators.toINI {} { foo = {}; bar = {}; };
968 testToINIDuplicateKeys = {
969 expr = generators.toINI { listsAsDuplicateKeys = true; } { foo.bar = true; baz.qux = [ 1 false ]; };
980 testToINIDefaultEscapes = {
981 expr = generators.toINI {} {
982 "no [ and ] allowed unescaped" = {
983 "and also no = in keys" = 42;
987 [no \[ and \] allowed unescaped]
988 and also no \= in keys=42
992 testToINIDefaultFull = {
993 expr = generators.toINI {} {
996 x = "Me-se JarJar Binx";
997 # booleans are converted verbatim by default
1001 "he\\h=he" = "this is okay";
1006 he\h\=he=this is okay
1015 testToINIWithGlobalSectionEmpty = {
1016 expr = generators.toINIWithGlobalSection {} {
1026 testToINIWithGlobalSectionGlobalEmptyIsTheSameAsToINI =
1031 x = "Me-se JarJar Binx";
1034 "he\\h=he" = "this is okay";
1039 generators.toINIWithGlobalSection {} {
1041 sections = sections;
1043 expected = generators.toINI {} sections;
1046 testToINIWithGlobalSectionFull = {
1047 expr = generators.toINIWithGlobalSection {} {
1055 x = "Me-se JarJar Binx";
1058 "he\\h=he" = "this is okay";
1067 he\h\=he=this is okay
1076 expr = generators.toGitINI {
1078 email = "user@example.org";
1080 signingKey = "00112233445566778899AABBCCDDEEFF";
1082 gpg.program = "path-to-gpg";
1084 include.path = "~/path/to/config.inc";
1085 includeIf."gitdif:~/src/dir".path = "~/path/to/conditional.inc";
1090 subsection.value = "test";
1094 ${"\t"}boolean = true
1096 ${"\t"}name = "value"
1098 [extra "subsection"]
1099 ${"\t"}value = "test"
1102 ${"\t"}program = "path-to-gpg"
1105 ${"\t"}path = "~/path/to/config.inc"
1107 [includeIf "gitdif:~/src/dir"]
1108 ${"\t"}path = "~/path/to/conditional.inc"
1111 ${"\t"}gpgSign = true
1114 ${"\t"}email = "user@example.org"
1115 ${"\t"}name = "John Doe"
1116 ${"\t"}signingKey = "00112233445566778899AABBCCDDEEFF"
1120 /* right now only invocation check */
1123 foobar = [ "baz" 1 2 3 ];
1126 expr = generators.toJSON {} val;
1127 # trivial implementation
1128 expected = builtins.toJSON val;
1131 /* right now only invocation check */
1134 list = [ { one = 1; } { two = 2; } ];
1138 expr = generators.toYAML {} val;
1139 # trivial implementation
1140 expected = builtins.toJSON val;
1145 deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
1147 expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec {
1152 string = "fn\${o}\"r\\d";
1153 newlinestring = "\n";
1157 functionArgs = { arg ? 4, foo }: arg;
1158 list = [ 3 4 function [ false ] ];
1160 attrs = { foo = null; "foo b/ar" = "baz"; };
1168 emptystring = ''""'';
1169 string = ''"fn\''${o}\"r\\d"'';
1170 newlinestring = "\"\\n\"";
1173 function = "<function>";
1174 functionArgs = "<function, args: {arg?, foo}>";
1175 list = "[ 3 4 ${function} [ false ] ]";
1177 attrs = "{ foo = null; \"foo b/ar\" = \"baz\"; }";
1179 drv = "<derivation ${deriv.name}>";
1188 expr = generators.toPretty { } (generators.withRecursion { throwOnDepthLimit = false; depthLimit = 2; } a);
1189 expected = "{\n b = 1;\n c = {\n b = \"<unevaluated>\";\n c = {\n b = \"<unevaluated>\";\n c = \"<unevaluated>\";\n };\n };\n}";
1192 testToPrettyLimitThrow =
1197 expr = (builtins.tryEval
1198 (generators.toPretty { } (generators.withRecursion { depthLimit = 2; } a))).success;
1202 testWithRecursionDealsWithFunctors =
1205 __functor = self: { a, b, }: null;
1213 expr = generators.toPretty { } (generators.withRecursion { depthLimit = 1; throwOnDepthLimit = false; } a);
1214 expected = "{\n b = <function, args: {a, b}>;\n c = {\n d = \"<unevaluated>\";\n };\n value = \"<unevaluated>\";\n}";
1217 testToPrettyMultiline = {
1218 expr = mapAttrs (const (generators.toPretty { })) rec {
1219 list = [ 3 4 [ false ] ];
1220 attrs = { foo = null; bar.foo = "baz"; };
1221 newlinestring = "\n";
1222 multilinestring = ''
1227 multilinestring' = ''
1248 newlinestring = "''\n \n''";
1249 multilinestring = ''
1255 multilinestring' = ''
1264 testToPrettyAllowPrettyValues = {
1265 expr = generators.toPretty { allowPrettyValues = true; }
1266 { __pretty = v: "«" + v + "»"; val = "foo"; };
1267 expected = "«foo»";
1272 deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
1274 expr = mapAttrs (const (generators.toPlist { })) {
1276 nested.values = rec {
1281 string = "fn\${o}\"r\\d";
1282 newlinestring = "\n";
1285 list = [ 3 4 "test" ];
1287 attrs = { foo = null; "foo b/ar" = "baz"; };
1292 expected = { value = builtins.readFile ./test-to-plist-expected.plist; };
1295 testToLuaEmptyAttrSet = {
1296 expr = generators.toLua {} {};
1300 testToLuaEmptyList = {
1301 expr = generators.toLua {} [];
1305 testToLuaListOfVariousTypes = {
1306 expr = generators.toLua {} [ null 43 3.14159 true ];
1317 expr = generators.toLua {} ''double-quote (") and single quotes (')'';
1318 expected = ''"double-quote (\") and single quotes (')"'';
1321 testToLuaAttrsetWithLuaInline = {
1322 expr = generators.toLua {} { x = generators.mkLuaInline ''"abc" .. "def"''; };
1325 ["x"] = ("abc" .. "def")
1329 testToLuaAttrsetWithSpaceInKey = {
1330 expr = generators.toLua {} { "some space and double-quote (\")" = 42; };
1333 ["some space and double-quote (\")"] = 42
1337 testToLuaWithoutMultiline = {
1338 expr = generators.toLua { multiline = false; } [ 41 43 ];
1339 expected = ''{ 41, 43 }'';
1342 testToLuaEmptyBindings = {
1343 expr = generators.toLua { asBindings = true; } {};
1347 testToLuaBindings = {
1348 expr = generators.toLua { asBindings = true; } { x1 = 41; _y = { a = 43; }; };
1357 testToLuaPartialTableBindings = {
1358 expr = generators.toLua { asBindings = true; } { "x.y" = 42; };
1364 testToLuaIndentedBindings = {
1365 expr = generators.toLua { asBindings = true; indent = " "; } { x = { y = 42; }; };
1366 expected = " x = {\n [\"y\"] = 42\n }\n";
1369 testToLuaBindingsWithSpace = testingThrow (
1370 generators.toLua { asBindings = true; } { "with space" = 42; }
1373 testToLuaBindingsWithLeadingDigit = testingThrow (
1374 generators.toLua { asBindings = true; } { "11eleven" = 42; }
1377 testToLuaBasicExample = {
1378 expr = generators.toLua {} {
1379 cmd = [ "typescript-language-server" "--stdio" ];
1380 settings.workspace.library = generators.mkLuaInline ''vim.api.nvim_get_runtime_file("", true)'';
1385 "typescript-language-server",
1390 ["library"] = (vim.api.nvim_get_runtime_file("", true))
1398 testToGNUCommandLine = {
1399 expr = cli.toGNUCommandLine {} {
1400 data = builtins.toJSON { id = 0; };
1404 url = [ "https://example.com/foo" "https://example.com/bar" ];
1411 "--data" "{\"id\":0}"
1413 "--url" "https://example.com/foo"
1414 "--url" "https://example.com/bar"
1419 testToGNUCommandLineShell = {
1420 expr = cli.toGNUCommandLineShell {} {
1421 data = builtins.toJSON { id = 0; };
1425 url = [ "https://example.com/foo" "https://example.com/bar" ];
1430 expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
1433 testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName {
1438 testSanitizeDerivationNameUnicode = testSanitizeDerivationName {
1443 testSanitizeDerivationNameAscii = testSanitizeDerivationName {
1444 name = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
1445 expected = "-+--.-0123456789-=-?-ABCDEFGHIJKLMNOPQRSTUVWXYZ-_-abcdefghijklmnopqrstuvwxyz-";
1448 testSanitizeDerivationNameTooLong = testSanitizeDerivationName {
1449 name = "This string is loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1450 expected = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1453 testSanitizeDerivationNameTooLongWithInvalid = testSanitizeDerivationName {
1454 name = "Hello there aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&&&&&&&";
1455 expected = "there-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-";
1458 testSanitizeDerivationNameEmpty = testSanitizeDerivationName {
1460 expected = "unknown";
1463 testFreeformOptions = {
1466 submodule = { lib, ... }: {
1467 freeformType = lib.types.attrsOf (lib.types.submodule {
1468 options.bar = lib.mkOption {};
1470 options.bar = lib.mkOption {};
1473 module = { lib, ... }: {
1474 options.foo = lib.mkOption {
1475 type = lib.types.submodule submodule;
1479 options = (evalModules {
1480 modules = [ module ];
1483 locs = filter (o: ! o.internal) (optionAttrSetToDocList options);
1484 in map (o: o.loc) locs;
1485 expected = [ [ "_module" "args" ] [ "foo" ] [ "foo" "<name>" "bar" ] [ "foo" "bar" ] ];
1488 testCartesianProductOfEmptySet = {
1489 expr = cartesianProductOfSets {};
1493 testCartesianProductOfOneSet = {
1494 expr = cartesianProductOfSets { a = [ 1 2 3 ]; };
1495 expected = [ { a = 1; } { a = 2; } { a = 3; } ];
1498 testCartesianProductOfTwoSets = {
1499 expr = cartesianProductOfSets { a = [ 1 ]; b = [ 10 20 ]; };
1506 testCartesianProductOfTwoSetsWithOneEmpty = {
1507 expr = cartesianProductOfSets { a = [ ]; b = [ 10 20 ]; };
1511 testCartesianProductOfThreeSets = {
1512 expr = cartesianProductOfSets {
1515 c = [ 100 200 300 ];
1518 { a = 1; b = 10; c = 100; }
1519 { a = 1; b = 10; c = 200; }
1520 { a = 1; b = 10; c = 300; }
1522 { a = 1; b = 20; c = 100; }
1523 { a = 1; b = 20; c = 200; }
1524 { a = 1; b = 20; c = 300; }
1526 { a = 1; b = 30; c = 100; }
1527 { a = 1; b = 30; c = 200; }
1528 { a = 1; b = 30; c = 300; }
1530 { a = 2; b = 10; c = 100; }
1531 { a = 2; b = 10; c = 200; }
1532 { a = 2; b = 10; c = 300; }
1534 { a = 2; b = 20; c = 100; }
1535 { a = 2; b = 20; c = 200; }
1536 { a = 2; b = 20; c = 300; }
1538 { a = 2; b = 30; c = 100; }
1539 { a = 2; b = 30; c = 200; }
1540 { a = 2; b = 30; c = 300; }
1542 { a = 3; b = 10; c = 100; }
1543 { a = 3; b = 10; c = 200; }
1544 { a = 3; b = 10; c = 300; }
1546 { a = 3; b = 20; c = 100; }
1547 { a = 3; b = 20; c = 200; }
1548 { a = 3; b = 20; c = 300; }
1550 { a = 3; b = 30; c = 100; }
1551 { a = 3; b = 30; c = 200; }
1552 { a = 3; b = 30; c = 300; }
1556 # The example from the showAttrPath documentation
1557 testShowAttrPathExample = {
1558 expr = showAttrPath [ "foo" "10" "bar" ];
1559 expected = "foo.\"10\".bar";
1562 testShowAttrPathEmpty = {
1563 expr = showAttrPath [];
1564 expected = "<root attribute path>";
1567 testShowAttrPathVarious = {
1568 expr = showAttrPath [
1575 expected = ''".".foo."2".a2-b._bc'de'';
1579 expr = groupBy (n: toString (mod n 5)) (range 0 16);
1581 "0" = [ 0 5 10 15 ];
1582 "1" = [ 1 6 11 16 ];
1590 expr = groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ];
1591 expected = { false = 3; true = 12; };
1594 # The example from the updateManyAttrsByPath documentation
1595 testUpdateManyAttrsByPathExample = {
1596 expr = updateManyAttrsByPath [
1599 update = old: { d = old.c; };
1602 path = [ "a" "b" "c" ];
1603 update = old: old + 1;
1610 expected = { a = { b = { d = 1; }; }; x = { y = "xy"; }; };
1613 # If there are no updates, the value is passed through
1614 testUpdateManyAttrsByPathNone = {
1615 expr = updateManyAttrsByPath [] "something";
1616 expected = "something";
1619 # A single update to the root path is just like applying the function directly
1620 testUpdateManyAttrsByPathSingleIncrement = {
1621 expr = updateManyAttrsByPath [
1624 update = old: old + 1;
1630 # Multiple updates can be applied are done in order
1631 testUpdateManyAttrsByPathMultipleIncrements = {
1632 expr = updateManyAttrsByPath [
1635 update = old: old + "a";
1639 update = old: old + "b";
1643 update = old: old + "c";
1649 # If an update doesn't use the value, all previous updates are not evaluated
1650 testUpdateManyAttrsByPathLazy = {
1651 expr = updateManyAttrsByPath [
1654 update = old: old + throw "nope";
1658 update = old: "untainted";
1661 expected = "untainted";
1664 # Deeply nested attributes can be updated without affecting others
1665 testUpdateManyAttrsByPathDeep = {
1666 expr = updateManyAttrsByPath [
1668 path = [ "a" "b" "c" ];
1669 update = old: old + 1;
1687 # Nested attributes are updated first
1688 testUpdateManyAttrsByPathNestedBeforehand = {
1689 expr = updateManyAttrsByPath [
1692 update = old: old // { x = old.b; };
1696 update = old: old + 1;
1707 ## Levenshtein distance functions and co.
1708 testCommonPrefixLengthEmpty = {
1709 expr = strings.commonPrefixLength "" "hello";
1713 testCommonPrefixLengthSame = {
1714 expr = strings.commonPrefixLength "hello" "hello";
1718 testCommonPrefixLengthDiffering = {
1719 expr = strings.commonPrefixLength "hello" "hey";
1723 testCommonSuffixLengthEmpty = {
1724 expr = strings.commonSuffixLength "" "hello";
1728 testCommonSuffixLengthSame = {
1729 expr = strings.commonSuffixLength "hello" "hello";
1733 testCommonSuffixLengthDiffering = {
1734 expr = strings.commonSuffixLength "test" "rest";
1738 testLevenshteinEmpty = {
1739 expr = strings.levenshtein "" "";
1743 testLevenshteinOnlyAdd = {
1744 expr = strings.levenshtein "" "hello there";
1748 testLevenshteinOnlyRemove = {
1749 expr = strings.levenshtein "hello there" "";
1753 testLevenshteinOnlyTransform = {
1754 expr = strings.levenshtein "abcdef" "ghijkl";
1758 testLevenshteinMixed = {
1759 expr = strings.levenshtein "kitchen" "sitting";
1763 testLevenshteinAtMostZeroFalse = {
1764 expr = strings.levenshteinAtMost 0 "foo" "boo";
1768 testLevenshteinAtMostZeroTrue = {
1769 expr = strings.levenshteinAtMost 0 "foo" "foo";
1773 testLevenshteinAtMostOneFalse = {
1774 expr = strings.levenshteinAtMost 1 "car" "ct";
1778 testLevenshteinAtMostOneTrue = {
1779 expr = strings.levenshteinAtMost 1 "car" "cr";
1783 # We test levenshteinAtMost 2 particularly well because it uses a complicated
1785 testLevenshteinAtMostTwoIsEmpty = {
1786 expr = strings.levenshteinAtMost 2 "" "";
1790 testLevenshteinAtMostTwoIsZero = {
1791 expr = strings.levenshteinAtMost 2 "abcdef" "abcdef";
1795 testLevenshteinAtMostTwoIsOne = {
1796 expr = strings.levenshteinAtMost 2 "abcdef" "abddef";
1800 testLevenshteinAtMostTwoDiff0False = {
1801 expr = strings.levenshteinAtMost 2 "abcdef" "aczyef";
1805 testLevenshteinAtMostTwoDiff0Outer = {
1806 expr = strings.levenshteinAtMost 2 "abcdef" "zbcdez";
1810 testLevenshteinAtMostTwoDiff0DelLeft = {
1811 expr = strings.levenshteinAtMost 2 "abcdef" "bcdefz";
1815 testLevenshteinAtMostTwoDiff0DelRight = {
1816 expr = strings.levenshteinAtMost 2 "abcdef" "zabcde";
1820 testLevenshteinAtMostTwoDiff1False = {
1821 expr = strings.levenshteinAtMost 2 "abcdef" "bddez";
1825 testLevenshteinAtMostTwoDiff1DelLeft = {
1826 expr = strings.levenshteinAtMost 2 "abcdef" "bcdez";
1830 testLevenshteinAtMostTwoDiff1DelRight = {
1831 expr = strings.levenshteinAtMost 2 "abcdef" "zbcde";
1835 testLevenshteinAtMostTwoDiff2False = {
1836 expr = strings.levenshteinAtMost 2 "hello" "hxo";
1840 testLevenshteinAtMostTwoDiff2True = {
1841 expr = strings.levenshteinAtMost 2 "hello" "heo";
1845 testLevenshteinAtMostTwoDiff3 = {
1846 expr = strings.levenshteinAtMost 2 "hello" "ho";
1850 testLevenshteinAtMostThreeFalse = {
1851 expr = strings.levenshteinAtMost 3 "hello" "Holla!";
1855 testLevenshteinAtMostThreeTrue = {
1856 expr = strings.levenshteinAtMost 3 "hello" "Holla";
1862 testLazyDerivationIsLazyInDerivationForAttrNames = {
1863 expr = attrNames (lazyDerivation {
1864 derivation = throw "not lazy enough";
1866 # It's ok to add attribute names here when lazyDerivation is improved
1867 # in accordance with its inline comments.
1868 expected = [ "drvPath" "meta" "name" "out" "outPath" "outputName" "outputs" "system" "type" ];
1871 testLazyDerivationIsLazyInDerivationForPassthruAttr = {
1872 expr = (lazyDerivation {
1873 derivation = throw "not lazy enough";
1874 passthru.tests = "whatever is in tests";
1876 expected = "whatever is in tests";
1879 testLazyDerivationIsLazyInDerivationForPassthruAttr2 = {
1880 # passthru.tests is not a special case. It works for any attr.
1881 expr = (lazyDerivation {
1882 derivation = throw "not lazy enough";
1883 passthru.foo = "whatever is in foo";
1885 expected = "whatever is in foo";
1888 testLazyDerivationIsLazyInDerivationForMeta = {
1889 expr = (lazyDerivation {
1890 derivation = throw "not lazy enough";
1891 meta = "whatever is in meta";
1893 expected = "whatever is in meta";
1896 testLazyDerivationReturnsDerivationAttrs = let
1898 type = "derivation";
1901 outPath = "test outPath";
1903 drvPath = "test drvPath";
1905 system = "test system";
1909 expr = lazyDerivation { inherit derivation; };
1910 expected = derivation;
1913 testTypeDescriptionInt = {
1914 expr = (with types; int).description;
1915 expected = "signed integer";
1917 testTypeDescriptionListOfInt = {
1918 expr = (with types; listOf int).description;
1919 expected = "list of signed integer";
1921 testTypeDescriptionListOfListOfInt = {
1922 expr = (with types; listOf (listOf int)).description;
1923 expected = "list of list of signed integer";
1925 testTypeDescriptionListOfEitherStrOrBool = {
1926 expr = (with types; listOf (either str bool)).description;
1927 expected = "list of (string or boolean)";
1929 testTypeDescriptionEitherListOfStrOrBool = {
1930 expr = (with types; either (listOf bool) str).description;
1931 expected = "(list of boolean) or string";
1933 testTypeDescriptionEitherStrOrListOfBool = {
1934 expr = (with types; either str (listOf bool)).description;
1935 expected = "string or list of boolean";
1937 testTypeDescriptionOneOfListOfStrOrBool = {
1938 expr = (with types; oneOf [ (listOf bool) str ]).description;
1939 expected = "(list of boolean) or string";
1941 testTypeDescriptionOneOfListOfStrOrBoolOrNumber = {
1942 expr = (with types; oneOf [ (listOf bool) str number ]).description;
1943 expected = "(list of boolean) or string or signed integer or floating point number";
1945 testTypeDescriptionEitherListOfBoolOrEitherStringOrNumber = {
1946 expr = (with types; either (listOf bool) (either str number)).description;
1947 expected = "(list of boolean) or string or signed integer or floating point number";
1949 testTypeDescriptionEitherEitherListOfBoolOrStringOrNumber = {
1950 expr = (with types; either (either (listOf bool) str) number).description;
1951 expected = "(list of boolean) or string or signed integer or floating point number";
1953 testTypeDescriptionEitherNullOrBoolOrString = {
1954 expr = (with types; either (nullOr bool) str).description;
1955 expected = "null or boolean or string";
1957 testTypeDescriptionEitherListOfEitherBoolOrStrOrInt = {
1958 expr = (with types; either (listOf (either bool str)) int).description;
1959 expected = "(list of (boolean or string)) or signed integer";
1961 testTypeDescriptionEitherIntOrListOrEitherBoolOrStr = {
1962 expr = (with types; either int (listOf (either bool str))).description;
1963 expected = "signed integer or list of (boolean or string)";
1967 testGetExe'Output = {
1969 type = "derivation";
1970 out = "somelonghash";
1971 bin = "somelonghash";
1973 expected = "somelonghash/bin/executable";
1976 testGetExeOutput = {
1978 type = "derivation";
1979 out = "somelonghash";
1980 bin = "somelonghash";
1981 meta.mainProgram = "mainProgram";
1983 expected = "somelonghash/bin/mainProgram";
1986 testGetExe'FailureFirstArg = testingThrow (
1987 getExe' "not a derivation" "executable"
1990 testGetExe'FailureSecondArg = testingThrow (
1991 getExe' { type = "derivation"; } "dir/executable"
1994 testPlatformMatch = {
1995 expr = meta.platformMatch { system = "x86_64-linux"; } "x86_64-linux";
1999 testPlatformMatchAttrs = {
2000 expr = meta.platformMatch (systems.elaborate "x86_64-linux") (systems.elaborate "x86_64-linux").parsed;
2004 testPlatformMatchNoMatch = {
2005 expr = meta.platformMatch { system = "x86_64-darwin"; } "x86_64-linux";
2009 testPlatformMatchMissingSystem = {
2010 expr = meta.platformMatch { } "x86_64-linux";