2 Nix evaluation tests for various lib functions.
4 Since these tests are implemented with Nix evaluation,
5 error checking is limited to what `builtins.tryEval` can detect,
6 which is `throw`'s and `abort`'s, without error messages.
8 If you need to test error messages or more complex evaluations, see
9 `lib/tests/modules.sh`, `lib/tests/sources.sh` or `lib/tests/filesystem.sh` as examples.
13 [nixpkgs]$ nix-instantiate --eval --strict lib/tests/misc.nix
15 If the resulting list is empty, all tests passed.
16 Alternatively, to run all `lib` tests:
18 [nixpkgs]$ nix-build lib/tests/release.nix
22 lib = import ../default.nix;
62 getLicenseFromSpdxIdOr
85 optionAttrSetToDocList
87 packagesFromDirectoryRecursive
113 updateManyAttrsByPath
118 testingThrow = expr: {
119 expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
120 expected = { success = false; value = false; };
122 testingEval = expr: {
123 expr = (builtins.tryEval expr).success;
127 testSanitizeDerivationName = { name, expected }:
130 name = strings.sanitizeDerivationName name;
135 # Evaluate the derivation so an invalid name would be caught
136 expr = builtins.seq drv.drvPath drv.name;
146 testFunctionArgsMakeOverridable = {
147 expr = functionArgs (makeOverridable ({ a, b, c ? null}: {}));
148 expected = { a = false; b = false; c = true; };
151 testFunctionArgsMakeOverridableOverride = {
152 expr = functionArgs (makeOverridable ({ a, b, c ? null }: {}) { a = 1; b = 2; }).override;
153 expected = { a = false; b = false; c = true; };
156 testCallPackageWithOverridePreservesArguments =
158 f = { a ? 0, b }: {};
159 f' = callPackageWith { a = 1; b = 2; } f {};
161 expr = functionArgs f'.override;
162 expected = functionArgs f;
165 testCallPackagesWithOverridePreservesArguments =
167 f = { a ? 0, b }: { nested = {}; };
168 f' = callPackagesWith { a = 1; b = 2; } f {};
170 expr = functionArgs f'.nested.override;
171 expected = functionArgs f;
188 (x: x + 2) # 2 + 2 = 4
189 (x: x * 2) # 4 * 2 = 8
200 expr = pipe [ 3 4 ] [
213 expr = or true false;
219 expr = and true false;
238 testComposeExtensions = {
239 expr = let obj = makeExtensible (self: { foo = self.bar; });
240 f = self: super: { bar = false; baz = true; };
241 g = self: super: { bar = super.baz or false; };
242 f_o_g = composeExtensions f g;
243 composed = obj.extend f_o_g;
248 testComposeManyExtensions0 = {
249 expr = let obj = makeExtensible (self: { foo = true; });
250 emptyComposition = composeManyExtensions [];
251 composed = obj.extend emptyComposition;
256 testComposeManyExtensions =
257 let f = self: super: { bar = false; baz = true; };
258 g = self: super: { bar = super.baz or false; };
259 h = self: super: { qux = super.bar or false; };
260 obj = makeExtensible (self: { foo = self.qux; });
262 expr = let composition = composeManyExtensions [f g h];
263 composed = obj.extend composition;
265 expected = (obj.extend (composeExtensions f (composeExtensions g h))).foo;
269 expr = (bitAnd 3 10);
279 expr = (bitXor 3 10);
284 expr = toHexString 250;
288 testFromHexStringFirstExample = {
289 expr = fromHexString "FF";
293 testFromHexStringSecondExample = {
294 expr = fromHexString (builtins.hashString "sha256" "test");
295 expected = 9223372036854775807;
298 testFromHexStringWithPrefix = {
299 expr = fromHexString "0Xf";
304 expr = toBaseDigits 2 6;
305 expected = [ 1 1 0 ];
308 testFunctionArgsFunctor = {
309 expr = functionArgs { __functor = self: { a, b }: null; };
310 expected = { a = false; b = false; };
313 testFunctionArgsSetFunctionArgs = {
314 expr = functionArgs (setFunctionArgs (args: args.x) { x = false; });
315 expected = { x = false; };
320 testConcatMapStrings = {
321 expr = concatMapStrings (x: x + ";") ["a" "b" "c"];
325 testConcatStringsSep = {
326 expr = concatStringsSep "," ["a" "b" "c"];
331 expr = concatLines ["a" "b" "c"];
332 expected = "a\nb\nc\n";
335 testMakeIncludePathWithPkgs = {
336 expr = (makeIncludePath [
337 # makeIncludePath preferably selects the "dev" output
338 { dev.outPath = "/dev"; out.outPath = "/out"; outPath = "/default"; }
339 # "out" is used if "dev" is not found
340 { out.outPath = "/out"; outPath = "/default"; }
341 # And it returns the derivation directly if there's no "out" either
342 { outPath = "/default"; }
343 # Same if the output is specified explicitly, even if there's a "dev"
344 { dev.outPath = "/dev"; outPath = "/default"; outputSpecified = true; }
346 expected = "/dev/include:/out/include:/default/include:/default/include";
349 testMakeIncludePathWithEmptyList = {
350 expr = (makeIncludePath [ ]);
354 testMakeIncludePathWithOneString = {
355 expr = (makeIncludePath [ "/usr" ]);
356 expected = "/usr/include";
359 testMakeIncludePathWithManyString = {
360 expr = (makeIncludePath [ "/usr" "/usr/local" ]);
361 expected = "/usr/include:/usr/local/include";
364 testReplicateString = {
365 expr = strings.replicate 5 "hello";
366 expected = "hellohellohellohellohello";
369 # Test various strings are trimmed correctly
373 testValues = f: mapAttrs (_: f) {
379 leading = " Hello, world";
380 trailing = "Hello, world ";
381 mixed = " Hello, world ";
382 mixed-tabs = " \t\tHello, world \t \t ";
383 multiline = " Hello,\n world! ";
384 multiline-crlf = " Hello,\r\n world! ";
388 leading = testValues (strings.trimWith { start = true; });
389 trailing = testValues (strings.trimWith { end = true; });
390 both = testValues strings.trim;
399 leading = "Hello, world";
400 trailing = "Hello, world ";
401 mixed = "Hello, world ";
402 mixed-tabs = "Hello, world \t \t ";
403 multiline = "Hello,\n world! ";
404 multiline-crlf = "Hello,\r\n world! ";
412 leading = " Hello, world";
413 trailing = "Hello, world";
414 mixed = " Hello, world";
415 mixed-tabs = " \t\tHello, world";
416 multiline = " Hello,\n world!";
417 multiline-crlf = " Hello,\r\n world!";
425 leading = "Hello, world";
426 trailing = "Hello, world";
427 mixed = "Hello, world";
428 mixed-tabs = "Hello, world";
429 multiline = "Hello,\n world!";
430 multiline-crlf = "Hello,\r\n world!";
435 testSplitStringsSimple = {
436 expr = strings.splitString "." "a.b.c.d";
437 expected = [ "a" "b" "c" "d" ];
440 testSplitStringsEmpty = {
441 expr = strings.splitString "." "a..b";
442 expected = [ "a" "" "b" ];
445 testSplitStringsOne = {
446 expr = strings.splitString ":" "a.b";
447 expected = [ "a.b" ];
450 testSplitStringsNone = {
451 expr = strings.splitString "." "";
455 testSplitStringsFirstEmpty = {
456 expr = strings.splitString "/" "/a/b/c";
457 expected = [ "" "a" "b" "c" ];
460 testSplitStringsLastEmpty = {
461 expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:";
462 expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ];
465 testSplitStringsRegex = {
466 expr = strings.splitString "\\[{}]()^$?*+|." "A\\[{}]()^$?*+|.B";
467 expected = [ "A" "B" ];
470 testEscapeShellArg = {
471 expr = strings.escapeShellArg "esc'ape\nme";
472 expected = "'esc'\\''ape\nme'";
475 testEscapeShellArgEmpty = {
476 expr = strings.escapeShellArg "";
480 testEscapeShellArgs = {
481 expr = strings.escapeShellArgs ["one" "two three" "four'five"];
482 expected = "one 'two three' 'four'\\''five'";
485 testEscapeShellArgsUnicode = {
486 expr = strings.escapeShellArg "á";
490 testSplitStringsDerivation = {
491 expr = take 3 (strings.splitString "/" (derivation {
496 expected = ["" "nix" "store"];
499 testSplitVersionSingle = {
500 expr = versions.splitVersion "1";
504 testSplitVersionDouble = {
505 expr = versions.splitVersion "1.2";
506 expected = [ "1" "2" ];
509 testSplitVersionTriple = {
510 expr = versions.splitVersion "1.2.3";
511 expected = [ "1" "2" "3" ];
514 testPadVersionLess = {
515 expr = versions.pad 3 "1.2";
519 testPadVersionLessExtra = {
520 expr = versions.pad 3 "1.3-rc1";
521 expected = "1.3.0-rc1";
524 testPadVersionMore = {
525 expr = versions.pad 3 "1.2.3.4";
532 "${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11";
534 storePath = isStorePath goodPath;
535 storePathDerivation = isStorePath (import ../.. { system = "x86_64-linux"; }).hello;
536 storePathAppendix = isStorePath
537 "${goodPath}/bin/python";
538 nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath)));
539 asPath = isStorePath (/. + goodPath);
540 otherPath = isStorePath "/something/else";
542 attrset = isStorePath {};
543 list = isStorePath [];
544 int = isStorePath 42;
549 storePathDerivation = true;
550 storePathAppendix = false;
563 expr = escapeXML ''"test" 'test' < & >'';
564 expected = ""test" 'test' < & >";
570 STRing01 = "just a 'string'";
571 _array_ = [ "with" "more strings" ];
572 assoc."with some" = ''
578 foo = "ignored attribute";
582 __toString = _: "hello toString";
583 bar = "ignored attribute";
588 STRing01='just a '\'''string'\''''
589 declare -a _array_=(with 'more strings')
590 declare -A assoc=(['with some']='strings
595 stringable='hello toString'
599 testHasInfixFalse = {
600 expr = hasInfix "c" "abde";
605 expr = hasInfix "c" "abcde";
609 testHasInfixDerivation = {
610 expr = hasInfix "hello" (import ../.. { system = "x86_64-linux"; }).hello;
615 expr = hasInfix "tests" ./.;
619 testHasInfixPathStoreDir = {
620 expr = hasInfix builtins.storeDir ./.;
624 testHasInfixToString = {
625 expr = hasInfix "a" { __toString = _: "a"; };
629 testRemovePrefixExample1 = {
630 expr = removePrefix "foo." "foo.bar.baz";
631 expected = "bar.baz";
633 testRemovePrefixExample2 = {
634 expr = removePrefix "xxx" "foo.bar.baz";
635 expected = "foo.bar.baz";
637 testRemovePrefixEmptyPrefix = {
638 expr = removePrefix "" "foo";
641 testRemovePrefixEmptyString = {
642 expr = removePrefix "foo" "";
645 testRemovePrefixEmptyBoth = {
646 expr = removePrefix "" "";
650 testNormalizePath = {
651 expr = strings.normalizePath "//a/b//c////d/";
652 expected = "/a/b/c/d/";
656 expr = strings.charToInt "A";
661 expr = strings.escapeC [ " " ] "Hello World";
662 expected = "Hello\\x20World";
665 testEscapeURL = testAllTrue [
666 ("" == strings.escapeURL "")
667 ("Hello" == strings.escapeURL "Hello")
668 ("Hello%20World" == strings.escapeURL "Hello World")
669 ("Hello%2FWorld" == strings.escapeURL "Hello/World")
670 ("42%25" == strings.escapeURL "42%")
671 ("%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:/@$'()*,;")
674 testToInt = testAllTrue [
679 (123 == toInt " 123")
680 (123 == toInt "123 ")
681 (123 == toInt " 123 ")
682 (123 == toInt " 123 ")
690 testToIntFails = testAllTrue [
691 ( builtins.tryEval (toInt "") == { success = false; value = false; } )
692 ( builtins.tryEval (toInt "123 123") == { success = false; value = false; } )
693 ( builtins.tryEval (toInt "0 123") == { success = false; value = false; } )
694 ( builtins.tryEval (toInt " 0d ") == { success = false; value = false; } )
695 ( builtins.tryEval (toInt " 1d ") == { success = false; value = false; } )
696 ( builtins.tryEval (toInt " d0 ") == { success = false; value = false; } )
697 ( builtins.tryEval (toInt "00") == { success = false; value = false; } )
698 ( builtins.tryEval (toInt "01") == { success = false; value = false; } )
699 ( builtins.tryEval (toInt "002") == { success = false; value = false; } )
700 ( builtins.tryEval (toInt " 002 ") == { success = false; value = false; } )
701 ( builtins.tryEval (toInt " foo ") == { success = false; value = false; } )
702 ( builtins.tryEval (toInt " foo 123 ") == { success = false; value = false; } )
703 ( builtins.tryEval (toInt " foo123 ") == { success = false; value = false; } )
706 testToIntBase10 = testAllTrue [
708 (123 == toIntBase10 "123")
709 (0 == toIntBase10 "0")
711 (123 == toIntBase10 " 123")
712 (123 == toIntBase10 "123 ")
713 (123 == toIntBase10 " 123 ")
714 (123 == toIntBase10 " 123 ")
715 (0 == toIntBase10 " 0")
716 (0 == toIntBase10 "0 ")
717 (0 == toIntBase10 " 0 ")
719 (123 == toIntBase10 "0123")
720 (123 == toIntBase10 "0000123")
721 (0 == toIntBase10 "000000")
722 # Whitespace and Zero Padding
723 (123 == toIntBase10 " 0123")
724 (123 == toIntBase10 "0123 ")
725 (123 == toIntBase10 " 0123 ")
726 (123 == toIntBase10 " 0000123")
727 (123 == toIntBase10 "0000123 ")
728 (123 == toIntBase10 " 0000123 ")
729 (0 == toIntBase10 " 000000")
730 (0 == toIntBase10 "000000 ")
731 (0 == toIntBase10 " 000000 ")
732 (-1 == toIntBase10 "-1")
733 (-1 == toIntBase10 " -1 ")
736 testToIntBase10Fails = testAllTrue [
737 ( builtins.tryEval (toIntBase10 "") == { success = false; value = false; } )
738 ( builtins.tryEval (toIntBase10 "123 123") == { success = false; value = false; } )
739 ( builtins.tryEval (toIntBase10 "0 123") == { success = false; value = false; } )
740 ( builtins.tryEval (toIntBase10 " 0d ") == { success = false; value = false; } )
741 ( builtins.tryEval (toIntBase10 " 1d ") == { success = false; value = false; } )
742 ( builtins.tryEval (toIntBase10 " d0 ") == { success = false; value = false; } )
743 ( builtins.tryEval (toIntBase10 " foo ") == { success = false; value = false; } )
744 ( builtins.tryEval (toIntBase10 " foo 123 ") == { success = false; value = false; } )
745 ( builtins.tryEval (toIntBase10 " foo 00123 ") == { success = false; value = false; } )
746 ( builtins.tryEval (toIntBase10 " foo00123 ") == { success = false; value = false; } )
752 expr = filter (x: x != "a") ["a" "b" "c" "a"];
753 expected = ["b" "c"];
756 testIfilter0Example = {
757 expr = ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ];
760 testIfilter0Empty = {
761 expr = ifilter0 (i: v: abort "shouldn't be evaluated!") [ ];
764 testIfilter0IndexOnly = {
765 expr = length (ifilter0 (i: v: mod i 2 == 0) [ (throw "0") (throw "1") (throw "2") (throw "3")]);
769 expr = ifilter0 (i: v: true) [ 10 11 12 13 14 15 ];
770 expected = [ 10 11 12 13 14 15 ];
772 testIfilter0First = {
773 expr = ifilter0 (i: v: i == 0) [ 10 11 12 13 14 15 ];
777 expr = ifilter0 (i: v: i == 5) [ 10 11 12 13 14 15 ];
783 f = op: fold: fold op 0 (range 0 100);
784 # fold with associative operator
785 assoc = f builtins.add;
786 # fold with non-associative operator
787 nonAssoc = f builtins.sub;
790 assocRight = assoc foldr;
791 # right fold with assoc operator is same as left fold
792 assocRightIsLeft = assoc foldr == assoc foldl;
793 nonAssocRight = nonAssoc foldr;
794 nonAssocLeft = nonAssoc foldl;
795 # with non-assoc operator the fold results are not the same
796 nonAssocRightIsNotLeft = nonAssoc foldl != nonAssoc foldr;
797 # fold is an alias for foldr
798 foldIsRight = nonAssoc fold == nonAssoc foldr;
802 assocRightIsLeft = true;
804 nonAssocLeft = (-5050);
805 nonAssocRightIsNotLeft = true;
811 expr = foldl' (acc: el: abort "operation not called") 0 [ ];
815 testFoldl'IntegerAdding = {
816 expr = foldl' (acc: el: acc + el) 0 [ 1 2 3 ];
820 # The accumulator isn't forced deeply
821 testFoldl'NonDeep = {
822 expr = take 3 (foldl'
823 (acc: el: [ el ] ++ acc)
824 [ (abort "unevaluated list entry") ]
826 expected = [ 3 2 1 ];
829 # Compared to builtins.foldl', lib.foldl' evaluates the first accumulator strictly too
830 testFoldl'StrictInitial = {
831 expr = (builtins.tryEval (foldl' (acc: el: el) (throw "hello") [])).success;
835 # Make sure we don't get a stack overflow for large lists
836 # This number of elements would notably cause a stack overflow if it was implemented without the `foldl'` builtin
838 expr = foldl' (acc: el: acc + el) 0 (range 0 100000);
839 expected = 5000050000;
842 testTake = testAllTrue [
843 ([] == (take 0 [ 1 2 3 ]))
844 ([1] == (take 1 [ 1 2 3 ]))
845 ([ 1 2 ] == (take 2 [ 1 2 3 ]))
846 ([ 1 2 3 ] == (take 3 [ 1 2 3 ]))
847 ([ 1 2 3 ] == (take 4 [ 1 2 3 ]))
850 testListHasPrefixExample1 = {
851 expr = lists.hasPrefix [ 1 2 ] [ 1 2 3 4 ];
854 testListHasPrefixExample2 = {
855 expr = lists.hasPrefix [ 0 1 ] [ 1 2 3 4 ];
858 testListHasPrefixLazy = {
859 expr = lists.hasPrefix [ 1 ] [ 1 (abort "lib.lists.hasPrefix is not lazy") ];
862 testListHasPrefixEmptyPrefix = {
863 expr = lists.hasPrefix [ ] [ 1 2 ];
866 testListHasPrefixEmptyList = {
867 expr = lists.hasPrefix [ 1 2 ] [ ];
871 testListRemovePrefixExample1 = {
872 expr = lists.removePrefix [ 1 2 ] [ 1 2 3 4 ];
875 testListRemovePrefixExample2 = {
876 expr = (builtins.tryEval (lists.removePrefix [ 0 1 ] [ 1 2 3 4 ])).success;
879 testListRemovePrefixEmptyPrefix = {
880 expr = lists.removePrefix [ ] [ 1 2 ];
883 testListRemovePrefixEmptyList = {
884 expr = (builtins.tryEval (lists.removePrefix [ 1 2 ] [ ])).success;
889 expr = foldAttrs (n: a: [n] ++ a) [] [
893 expected = { a = [ 2 3 ]; b = [7]; c = [8];};
896 testListCommonPrefixExample1 = {
897 expr = lists.commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ];
900 testListCommonPrefixExample2 = {
901 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ];
902 expected = [ 1 2 3 ];
904 testListCommonPrefixExample3 = {
905 expr = lists.commonPrefix [ 1 2 3 ] [ 4 5 6 ];
908 testListCommonPrefixEmpty = {
909 expr = lists.commonPrefix [ ] [ 1 2 3 ];
912 testListCommonPrefixSame = {
913 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 ];
914 expected = [ 1 2 3 ];
916 testListCommonPrefixLazy = {
917 expr = lists.commonPrefix [ 1 ] [ 1 (abort "lib.lists.commonPrefix shouldn't evaluate this")];
920 # This would stack overflow if `commonPrefix` were implemented using recursion
921 testListCommonPrefixLong =
923 longList = genList (n: n) 100000;
925 expr = lists.commonPrefix longList longList;
930 expr = sort builtins.lessThan [ 40 2 30 42 ];
931 expected = [2 30 40 42];
935 expr = sortOn stringLength [ "aa" "b" "cccc" ];
936 expected = [ "b" "aa" "cccc" ];
940 expr = sortOn (throw "nope") [ ];
944 testSortOnIncomparable = {
949 { ok = 1; f = x: x; }
950 { ok = 3; f = x: x + 3; }
951 { ok = 2; f = x: x; }
953 expected = [ 1 2 6 ];
957 expr = replicate 3 "a";
958 expected = ["a" "a" "a"];
961 testToIntShouldConvertStringToInt = {
966 testToIntShouldThrowErrorIfItCouldNotConvertToInt = {
967 expr = builtins.tryEval (toInt "\"foo\"");
968 expected = { success = false; value = false; };
971 testHasAttrByPathTrue = {
972 expr = hasAttrByPath ["a" "b"] { a = { b = "yey"; }; };
976 testHasAttrByPathFalse = {
977 expr = hasAttrByPath ["a" "b"] { a = { c = "yey"; }; };
981 testHasAttrByPathNonStrict = {
982 expr = hasAttrByPath [] (throw "do not use");
986 testLongestValidPathPrefix_empty_empty = {
987 expr = attrsets.longestValidPathPrefix [ ] { };
991 testLongestValidPathPrefix_empty_nonStrict = {
992 expr = attrsets.longestValidPathPrefix [ ] (throw "do not use");
996 testLongestValidPathPrefix_zero = {
997 expr = attrsets.longestValidPathPrefix [ "a" (throw "do not use") ] { d = null; };
1001 testLongestValidPathPrefix_zero_b = {
1002 expr = attrsets.longestValidPathPrefix [ "z" "z" ] "remarkably harmonious";
1006 testLongestValidPathPrefix_one = {
1007 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a = null; };
1011 testLongestValidPathPrefix_two = {
1012 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b = null; };
1013 expected = [ "a" "b" ];
1016 testLongestValidPathPrefix_three = {
1017 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c = null; };
1018 expected = [ "a" "b" "c" ];
1021 testLongestValidPathPrefix_three_extra = {
1022 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c.d = throw "nope"; };
1023 expected = [ "a" "b" "c" ];
1026 testFindFirstIndexExample1 = {
1027 expr = lists.findFirstIndex (x: x > 3) (abort "index found, so a default must not be evaluated") [ 1 6 4 ];
1031 testFindFirstIndexExample2 = {
1032 expr = lists.findFirstIndex (x: x > 9) "a very specific default" [ 1 6 4 ];
1033 expected = "a very specific default";
1036 testFindFirstIndexEmpty = {
1037 expr = lists.findFirstIndex (abort "when the list is empty, the predicate is not needed") null [];
1041 testFindFirstIndexSingleMatch = {
1042 expr = lists.findFirstIndex (x: x == 5) null [ 5 ];
1046 testFindFirstIndexSingleDefault = {
1047 expr = lists.findFirstIndex (x: false) null [ (abort "if the predicate doesn't access the value, it must not be evaluated") ];
1051 testFindFirstIndexNone = {
1052 expr = builtins.tryEval (lists.findFirstIndex (x: x == 2) null [ 1 (throw "the last element must be evaluated when there's no match") ]);
1053 expected = { success = false; value = false; };
1056 # Makes sure that the implementation doesn't cause a stack overflow
1057 testFindFirstIndexBig = {
1058 expr = lists.findFirstIndex (x: x == 1000000) null (range 0 1000000);
1062 testFindFirstIndexLazy = {
1063 expr = lists.findFirstIndex (x: x == 1) null [ 1 (abort "list elements after the match must not be evaluated") ];
1067 testFindFirstExample1 = {
1068 expr = lists.findFirst (x: x > 3) 7 [ 1 6 4 ];
1072 testFindFirstExample2 = {
1073 expr = lists.findFirst (x: x > 9) 7 [ 1 6 4 ];
1077 testAllUnique_true = {
1078 expr = allUnique [ 3 2 4 1 ];
1081 testAllUnique_false = {
1082 expr = allUnique [ 3 2 3 4 ];
1088 testConcatMapAttrs = {
1089 expr = concatMapAttrs
1092 ${name + value} = value;
1108 example = foldlAttrs
1109 (acc: name: value: {
1110 sum = acc.sum + value;
1111 names = acc.names ++ [ name ];
1113 { sum = 0; names = [ ]; }
1118 # should just return the initial value
1119 emptySet = foldlAttrs (throw "function not needed") 123 { };
1120 # should just evaluate to the last value
1121 valuesNotNeeded = foldlAttrs (acc: _name: _v: acc) 3 { z = throw "value z not needed"; a = throw "value a not needed"; };
1122 # the accumulator doesnt have to be an attrset it can be as trivial as being just a number or string
1123 trivialAcc = foldlAttrs (acc: _name: v: acc * 10 + v) 1 { z = 1; a = 2; };
1128 names = [ "bar" "foo" ];
1131 valuesNotNeeded = 3;
1137 testMergeAttrsListExample1 = {
1138 expr = attrsets.mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ];
1139 expected = { a = 0; b = 1; c = 2; d = 3; };
1141 testMergeAttrsListExample2 = {
1142 expr = attrsets.mergeAttrsList [ { a = 0; } { a = 1; } ];
1143 expected = { a = 1; };
1145 testMergeAttrsListExampleMany =
1148 listToAttrs (genList (m:
1150 # Integer divide n by two to create duplicate attributes
1151 str = "halfn${toString (n / 2)}m${toString m}";
1153 nameValuePair str str
1157 expr = attrsets.mergeAttrsList list;
1158 expected = foldl' mergeAttrs { } list;
1161 # code from the example
1162 testRecursiveUpdateUntil = {
1163 expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) {
1164 # first attribute set
1169 #second attribute set
1175 foo.bar = 1; # 'foo.*' from the second set
1177 bar = 3; # 'bar' from the first set
1178 baz = 4; # 'baz' from the second set
1182 testMatchAttrsMatchingExact = {
1183 expr = matchAttrs { cpu = { bits = 64; }; } { cpu = { bits = 64; }; };
1187 testMatchAttrsMismatch = {
1188 expr = matchAttrs { cpu = { bits = 128; }; } { cpu = { bits = 64; }; };
1192 testMatchAttrsMatchingImplicit = {
1193 expr = matchAttrs { cpu = { }; } { cpu = { bits = 64; }; };
1197 testMatchAttrsMissingAttrs = {
1198 expr = matchAttrs { cpu = {}; } { };
1202 testOverrideExistingEmpty = {
1203 expr = overrideExisting {} { a = 1; };
1207 testOverrideExistingDisjoint = {
1208 expr = overrideExisting { b = 2; } { a = 1; };
1209 expected = { b = 2; };
1212 testOverrideExistingOverride = {
1213 expr = overrideExisting { a = 3; b = 2; } { a = 1; };
1214 expected = { a = 1; b = 2; };
1217 testListAttrsReverse = let
1218 exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;};
1219 exampleSingletonList = [{name="foo"; value=1;}];
1222 isReverseToListToAttrs = builtins.listToAttrs (attrsToList exampleAttrs) == exampleAttrs;
1223 isReverseToAttrsToList = attrsToList (builtins.listToAttrs exampleSingletonList) == exampleSingletonList;
1224 testDuplicatePruningBehaviour = attrsToList (builtins.listToAttrs [{name="a"; value=2;} {name="a"; value=1;}]);
1227 isReverseToAttrsToList = true;
1228 isReverseToListToAttrs = true;
1229 testDuplicatePruningBehaviour = [{name="a"; value=2;}];
1233 testAttrsToListsCanDealWithFunctions = testingEval (
1234 attrsToList { someFunc= a: a + 1;}
1240 expr = fix (x: {a = if x ? a then "a" else "b";});
1241 expected = {a = "a";};
1246 (fix (final: { a = 0; c = final.a; }))
1247 (fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; })))
1248 (fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; })))
1249 (fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1; })) (final: { a = 0; c = final.a; })))
1253 { a = 1; b = 2; c = 1; }
1254 { a = 1; b = 0; c = 1; }
1255 { a = 1; b = 0; c = 2; }
1260 # these tests assume attributes are converted to lists
1261 # in alphabetical order
1263 testMkKeyValueDefault = {
1264 expr = generators.mkKeyValueDefault {} ":" "f:oo" "bar";
1265 expected = ''f\:oo:bar'';
1268 testMkValueString = {
1276 # float = 42.23; # floats are strange
1279 (const (generators.mkValueStringDefault {}))
1287 # float = "42.23" true false [ "bar" ] ]'';
1292 expr = generators.toKeyValue {} {
1294 "other=key" = "baz";
1303 expr = generators.toINI {} {};
1307 testToINIEmptySection = {
1308 expr = generators.toINI {} { foo = {}; bar = {}; };
1316 testToINIDuplicateKeys = {
1317 expr = generators.toINI { listsAsDuplicateKeys = true; } { foo.bar = true; baz.qux = [ 1 false ]; };
1328 testToINIDefaultEscapes = {
1329 expr = generators.toINI {} {
1330 "no [ and ] allowed unescaped" = {
1331 "and also no = in keys" = 42;
1335 [no \[ and \] allowed unescaped]
1336 and also no \= in keys=42
1340 testToINIDefaultFull = {
1341 expr = generators.toINI {} {
1344 x = "Me-se JarJar Binx";
1345 # booleans are converted verbatim by default
1349 "he\\h=he" = "this is okay";
1354 he\h\=he=this is okay
1363 testToINIWithGlobalSectionEmpty = {
1364 expr = generators.toINIWithGlobalSection {} {
1374 testToINIWithGlobalSectionGlobalEmptyIsTheSameAsToINI =
1379 x = "Me-se JarJar Binx";
1382 "he\\h=he" = "this is okay";
1387 generators.toINIWithGlobalSection {} {
1389 sections = sections;
1391 expected = generators.toINI {} sections;
1394 testToINIWithGlobalSectionFull = {
1395 expr = generators.toINIWithGlobalSection {} {
1403 x = "Me-se JarJar Binx";
1406 "he\\h=he" = "this is okay";
1415 he\h\=he=this is okay
1424 expr = generators.toGitINI {
1426 email = "user@example.org";
1428 signingKey = "00112233445566778899AABBCCDDEEFF";
1430 gpg.program = "path-to-gpg";
1432 include.path = "~/path/to/config.inc";
1433 includeIf."gitdif:~/src/dir".path = "~/path/to/conditional.inc";
1438 subsection.value = "test";
1442 ${"\t"}boolean = true
1444 ${"\t"}name = "value"
1446 [extra "subsection"]
1447 ${"\t"}value = "test"
1450 ${"\t"}program = "path-to-gpg"
1453 ${"\t"}path = "~/path/to/config.inc"
1455 [includeIf "gitdif:~/src/dir"]
1456 ${"\t"}path = "~/path/to/conditional.inc"
1459 ${"\t"}gpgSign = true
1462 ${"\t"}email = "user@example.org"
1463 ${"\t"}name = "John Doe"
1464 ${"\t"}signingKey = "00112233445566778899AABBCCDDEEFF"
1468 # right now only invocation check
1471 foobar = [ "baz" 1 2 3 ];
1474 expr = generators.toJSON {} val;
1475 # trivial implementation
1476 expected = builtins.toJSON val;
1479 # right now only invocation check
1482 list = [ { one = 1; } { two = 2; } ];
1486 expr = generators.toYAML {} val;
1487 # trivial implementation
1488 expected = builtins.toJSON val;
1493 deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
1495 expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec {
1500 string = "fn\${o}\"r\\d";
1501 newlinestring = "\n";
1505 functionArgs = { arg ? 4, foo }: arg;
1506 list = [ 3 4 function [ false ] ];
1508 attrs = { foo = null; "foo b/ar" = "baz"; };
1516 emptystring = ''""'';
1517 string = ''"fn\''${o}\"r\\d"'';
1518 newlinestring = "\"\\n\"";
1521 function = "<function>";
1522 functionArgs = "<function, args: {arg?, foo}>";
1523 list = "[ 3 4 ${function} [ false ] ]";
1525 attrs = "{ foo = null; \"foo b/ar\" = \"baz\"; }";
1527 drv = "<derivation ${deriv.name}>";
1536 expr = generators.toPretty { } (generators.withRecursion { throwOnDepthLimit = false; depthLimit = 2; } a);
1537 expected = "{\n b = 1;\n c = {\n b = \"<unevaluated>\";\n c = {\n b = \"<unevaluated>\";\n c = \"<unevaluated>\";\n };\n };\n}";
1540 testToPrettyLimitThrow =
1545 expr = (builtins.tryEval
1546 (generators.toPretty { } (generators.withRecursion { depthLimit = 2; } a))).success;
1550 testWithRecursionDealsWithFunctors =
1553 __functor = self: { a, b, }: null;
1561 expr = generators.toPretty { } (generators.withRecursion { depthLimit = 1; throwOnDepthLimit = false; } a);
1562 expected = "{\n b = <function, args: {a, b}>;\n c = {\n d = \"<unevaluated>\";\n };\n value = \"<unevaluated>\";\n}";
1565 testToPrettyMultiline = {
1566 expr = mapAttrs (const (generators.toPretty { })) {
1567 list = [ 3 4 [ false ] ];
1568 attrs = { foo = null; bar.foo = "baz"; };
1569 newlinestring = "\n";
1570 multilinestring = ''
1575 multilinestring' = ''
1596 newlinestring = "''\n \n''";
1597 multilinestring = ''
1603 multilinestring' = ''
1612 testToPrettyAllowPrettyValues = {
1613 expr = generators.toPretty { allowPrettyValues = true; }
1614 { __pretty = v: "«" + v + "»"; val = "foo"; };
1615 expected = "«foo»";
1619 expr = mapAttrs (const (generators.toPlist { })) {
1626 string = "fn\${o}\"r\\d";
1627 newlinestring = "\n";
1630 list = [ 3 4 "test" ];
1632 attrs = { foo = null; "foo b/ar" = "baz"; };
1637 expected = { value = builtins.readFile ./test-to-plist-expected.plist; };
1640 testToLuaEmptyAttrSet = {
1641 expr = generators.toLua {} {};
1645 testToLuaEmptyList = {
1646 expr = generators.toLua {} [];
1650 testToLuaListOfVariousTypes = {
1651 expr = generators.toLua {} [ null 43 3.14159 true ];
1662 expr = generators.toLua {} ''double-quote (") and single quotes (')'';
1663 expected = ''"double-quote (\") and single quotes (')"'';
1666 testToLuaAttrsetWithLuaInline = {
1667 expr = generators.toLua {} { x = generators.mkLuaInline ''"abc" .. "def"''; };
1670 ["x"] = ("abc" .. "def")
1674 testToLuaAttrsetWithSpaceInKey = {
1675 expr = generators.toLua {} { "some space and double-quote (\")" = 42; };
1678 ["some space and double-quote (\")"] = 42
1682 testToLuaWithoutMultiline = {
1683 expr = generators.toLua { multiline = false; } [ 41 43 ];
1684 expected = ''{ 41, 43 }'';
1687 testToLuaEmptyBindings = {
1688 expr = generators.toLua { asBindings = true; } {};
1692 testToLuaBindings = {
1693 expr = generators.toLua { asBindings = true; } { x1 = 41; _y = { a = 43; }; };
1702 testToLuaPartialTableBindings = {
1703 expr = generators.toLua { asBindings = true; } { "x.y" = 42; };
1709 testToLuaIndentedBindings = {
1710 expr = generators.toLua { asBindings = true; indent = " "; } { x = { y = 42; }; };
1711 expected = " x = {\n [\"y\"] = 42\n }\n";
1714 testToLuaBindingsWithSpace = testingThrow (
1715 generators.toLua { asBindings = true; } { "with space" = 42; }
1718 testToLuaBindingsWithLeadingDigit = testingThrow (
1719 generators.toLua { asBindings = true; } { "11eleven" = 42; }
1722 testToLuaBasicExample = {
1723 expr = generators.toLua {} {
1724 cmd = [ "typescript-language-server" "--stdio" ];
1725 settings.workspace.library = generators.mkLuaInline ''vim.api.nvim_get_runtime_file("", true)'';
1730 "typescript-language-server",
1735 ["library"] = (vim.api.nvim_get_runtime_file("", true))
1743 testToGNUCommandLine = {
1744 expr = cli.toGNUCommandLine {} {
1745 data = builtins.toJSON { id = 0; };
1749 url = [ "https://example.com/foo" "https://example.com/bar" ];
1756 "--data" "{\"id\":0}"
1758 "--url" "https://example.com/foo"
1759 "--url" "https://example.com/bar"
1764 testToGNUCommandLineSeparator = {
1765 expr = cli.toGNUCommandLine { optionValueSeparator = "="; } {
1766 data = builtins.toJSON { id = 0; };
1770 url = [ "https://example.com/foo" "https://example.com/bar" ];
1779 "--url=https://example.com/foo"
1780 "--url=https://example.com/bar"
1785 testToGNUCommandLineShell = {
1786 expr = cli.toGNUCommandLineShell {} {
1787 data = builtins.toJSON { id = 0; };
1791 url = [ "https://example.com/foo" "https://example.com/bar" ];
1796 expected = "-X PUT --data '{\"id\":0}' --retry 3 --url https://example.com/foo --url https://example.com/bar --verbose";
1799 testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName {
1804 testSanitizeDerivationNameUnicode = testSanitizeDerivationName {
1809 testSanitizeDerivationNameAscii = testSanitizeDerivationName {
1810 name = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
1811 expected = "-+--.-0123456789-=-?-ABCDEFGHIJKLMNOPQRSTUVWXYZ-_-abcdefghijklmnopqrstuvwxyz-";
1814 testSanitizeDerivationNameTooLong = testSanitizeDerivationName {
1815 name = "This string is loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1816 expected = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1819 testSanitizeDerivationNameTooLongWithInvalid = testSanitizeDerivationName {
1820 name = "Hello there aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&&&&&&&";
1821 expected = "there-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-";
1824 testSanitizeDerivationNameEmpty = testSanitizeDerivationName {
1826 expected = "unknown";
1829 testFreeformOptions = {
1832 submodule = { lib, ... }: {
1833 freeformType = lib.types.attrsOf (lib.types.submodule {
1834 options.bar = lib.mkOption {};
1836 options.bar = lib.mkOption {};
1839 module = { lib, ... }: {
1840 options.foo = lib.mkOption {
1841 type = lib.types.submodule submodule;
1845 options = (evalModules {
1846 modules = [ module ];
1849 locs = filter (o: ! o.internal) (optionAttrSetToDocList options);
1850 in map (o: o.loc) locs;
1851 expected = [ [ "_module" "args" ] [ "foo" ] [ "foo" "<name>" "bar" ] [ "foo" "bar" ] ];
1854 testCartesianProductOfEmptySet = {
1855 expr = cartesianProduct {};
1859 testCartesianProductOfOneSet = {
1860 expr = cartesianProduct { a = [ 1 2 3 ]; };
1861 expected = [ { a = 1; } { a = 2; } { a = 3; } ];
1864 testCartesianProductOfTwoSets = {
1865 expr = cartesianProduct { a = [ 1 ]; b = [ 10 20 ]; };
1872 testCartesianProductOfTwoSetsWithOneEmpty = {
1873 expr = cartesianProduct { a = [ ]; b = [ 10 20 ]; };
1877 testCartesianProductOfThreeSets = {
1878 expr = cartesianProduct {
1881 c = [ 100 200 300 ];
1884 { a = 1; b = 10; c = 100; }
1885 { a = 1; b = 10; c = 200; }
1886 { a = 1; b = 10; c = 300; }
1888 { a = 1; b = 20; c = 100; }
1889 { a = 1; b = 20; c = 200; }
1890 { a = 1; b = 20; c = 300; }
1892 { a = 1; b = 30; c = 100; }
1893 { a = 1; b = 30; c = 200; }
1894 { a = 1; b = 30; c = 300; }
1896 { a = 2; b = 10; c = 100; }
1897 { a = 2; b = 10; c = 200; }
1898 { a = 2; b = 10; c = 300; }
1900 { a = 2; b = 20; c = 100; }
1901 { a = 2; b = 20; c = 200; }
1902 { a = 2; b = 20; c = 300; }
1904 { a = 2; b = 30; c = 100; }
1905 { a = 2; b = 30; c = 200; }
1906 { a = 2; b = 30; c = 300; }
1908 { a = 3; b = 10; c = 100; }
1909 { a = 3; b = 10; c = 200; }
1910 { a = 3; b = 10; c = 300; }
1912 { a = 3; b = 20; c = 100; }
1913 { a = 3; b = 20; c = 200; }
1914 { a = 3; b = 20; c = 300; }
1916 { a = 3; b = 30; c = 100; }
1917 { a = 3; b = 30; c = 200; }
1918 { a = 3; b = 30; c = 300; }
1922 testMapCartesianProductOfOneSet = {
1923 expr = mapCartesianProduct ({a}: a * 2) { a = [ 1 2 3 ]; };
1924 expected = [ 2 4 6 ];
1927 testMapCartesianProductOfTwoSets = {
1928 expr = mapCartesianProduct ({a,b}: a + b) { a = [ 1 ]; b = [ 10 20 ]; };
1929 expected = [ 11 21 ];
1932 testMapCartesianProcutOfTwoSetsWithOneEmpty = {
1933 expr = mapCartesianProduct (x: x.a + x.b) { a = [ ]; b = [ 10 20 ]; };
1937 testMapCartesianProductOfThreeSets = {
1938 expr = mapCartesianProduct ({a,b,c}: a + b + c) {
1941 c = [ 100 200 300 ];
1943 expected = [ 111 211 311 121 221 321 131 231 331 112 212 312 122 222 322 132 232 332 113 213 313 123 223 323 133 233 333 ];
1946 # The example from the showAttrPath documentation
1947 testShowAttrPathExample = {
1948 expr = showAttrPath [ "foo" "10" "bar" ];
1949 expected = "foo.\"10\".bar";
1952 testShowAttrPathEmpty = {
1953 expr = showAttrPath [];
1954 expected = "<root attribute path>";
1957 testShowAttrPathVarious = {
1958 expr = showAttrPath [
1965 expected = ''".".foo."2".a2-b._bc'de'';
1969 expr = groupBy (n: toString (mod n 5)) (range 0 16);
1971 "0" = [ 0 5 10 15 ];
1972 "1" = [ 1 6 11 16 ];
1980 expr = groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ];
1981 expected = { false = 3; true = 12; };
1984 # The example from the updateManyAttrsByPath documentation
1985 testUpdateManyAttrsByPathExample = {
1986 expr = updateManyAttrsByPath [
1989 update = old: { d = old.c; };
1992 path = [ "a" "b" "c" ];
1993 update = old: old + 1;
2000 expected = { a = { b = { d = 1; }; }; x = { y = "xy"; }; };
2003 # If there are no updates, the value is passed through
2004 testUpdateManyAttrsByPathNone = {
2005 expr = updateManyAttrsByPath [] "something";
2006 expected = "something";
2009 # A single update to the root path is just like applying the function directly
2010 testUpdateManyAttrsByPathSingleIncrement = {
2011 expr = updateManyAttrsByPath [
2014 update = old: old + 1;
2020 # Multiple updates can be applied are done in order
2021 testUpdateManyAttrsByPathMultipleIncrements = {
2022 expr = updateManyAttrsByPath [
2025 update = old: old + "a";
2029 update = old: old + "b";
2033 update = old: old + "c";
2039 # If an update doesn't use the value, all previous updates are not evaluated
2040 testUpdateManyAttrsByPathLazy = {
2041 expr = updateManyAttrsByPath [
2044 update = old: old + throw "nope";
2048 update = old: "untainted";
2051 expected = "untainted";
2054 # Deeply nested attributes can be updated without affecting others
2055 testUpdateManyAttrsByPathDeep = {
2056 expr = updateManyAttrsByPath [
2058 path = [ "a" "b" "c" ];
2059 update = old: old + 1;
2077 # Nested attributes are updated first
2078 testUpdateManyAttrsByPathNestedBeforehand = {
2079 expr = updateManyAttrsByPath [
2082 update = old: old // { x = old.b; };
2086 update = old: old + 1;
2097 ## Levenshtein distance functions and co.
2098 testCommonPrefixLengthEmpty = {
2099 expr = strings.commonPrefixLength "" "hello";
2103 testCommonPrefixLengthSame = {
2104 expr = strings.commonPrefixLength "hello" "hello";
2108 testCommonPrefixLengthDiffering = {
2109 expr = strings.commonPrefixLength "hello" "hey";
2113 testCommonSuffixLengthEmpty = {
2114 expr = strings.commonSuffixLength "" "hello";
2118 testCommonSuffixLengthSame = {
2119 expr = strings.commonSuffixLength "hello" "hello";
2123 testCommonSuffixLengthDiffering = {
2124 expr = strings.commonSuffixLength "test" "rest";
2128 testLevenshteinEmpty = {
2129 expr = strings.levenshtein "" "";
2133 testLevenshteinOnlyAdd = {
2134 expr = strings.levenshtein "" "hello there";
2138 testLevenshteinOnlyRemove = {
2139 expr = strings.levenshtein "hello there" "";
2143 testLevenshteinOnlyTransform = {
2144 expr = strings.levenshtein "abcdef" "ghijkl";
2148 testLevenshteinMixed = {
2149 expr = strings.levenshtein "kitchen" "sitting";
2153 testLevenshteinAtMostZeroFalse = {
2154 expr = strings.levenshteinAtMost 0 "foo" "boo";
2158 testLevenshteinAtMostZeroTrue = {
2159 expr = strings.levenshteinAtMost 0 "foo" "foo";
2163 testLevenshteinAtMostOneFalse = {
2164 expr = strings.levenshteinAtMost 1 "car" "ct";
2168 testLevenshteinAtMostOneTrue = {
2169 expr = strings.levenshteinAtMost 1 "car" "cr";
2173 # We test levenshteinAtMost 2 particularly well because it uses a complicated
2175 testLevenshteinAtMostTwoIsEmpty = {
2176 expr = strings.levenshteinAtMost 2 "" "";
2180 testLevenshteinAtMostTwoIsZero = {
2181 expr = strings.levenshteinAtMost 2 "abcdef" "abcdef";
2185 testLevenshteinAtMostTwoIsOne = {
2186 expr = strings.levenshteinAtMost 2 "abcdef" "abddef";
2190 testLevenshteinAtMostTwoDiff0False = {
2191 expr = strings.levenshteinAtMost 2 "abcdef" "aczyef";
2195 testLevenshteinAtMostTwoDiff0Outer = {
2196 expr = strings.levenshteinAtMost 2 "abcdef" "zbcdez";
2200 testLevenshteinAtMostTwoDiff0DelLeft = {
2201 expr = strings.levenshteinAtMost 2 "abcdef" "bcdefz";
2205 testLevenshteinAtMostTwoDiff0DelRight = {
2206 expr = strings.levenshteinAtMost 2 "abcdef" "zabcde";
2210 testLevenshteinAtMostTwoDiff1False = {
2211 expr = strings.levenshteinAtMost 2 "abcdef" "bddez";
2215 testLevenshteinAtMostTwoDiff1DelLeft = {
2216 expr = strings.levenshteinAtMost 2 "abcdef" "bcdez";
2220 testLevenshteinAtMostTwoDiff1DelRight = {
2221 expr = strings.levenshteinAtMost 2 "abcdef" "zbcde";
2225 testLevenshteinAtMostTwoDiff2False = {
2226 expr = strings.levenshteinAtMost 2 "hello" "hxo";
2230 testLevenshteinAtMostTwoDiff2True = {
2231 expr = strings.levenshteinAtMost 2 "hello" "heo";
2235 testLevenshteinAtMostTwoDiff3 = {
2236 expr = strings.levenshteinAtMost 2 "hello" "ho";
2240 testLevenshteinAtMostThreeFalse = {
2241 expr = strings.levenshteinAtMost 3 "hello" "Holla!";
2245 testLevenshteinAtMostThreeTrue = {
2246 expr = strings.levenshteinAtMost 3 "hello" "Holla";
2252 testLazyDerivationIsLazyInDerivationForAttrNames = {
2253 expr = attrNames (lazyDerivation {
2254 derivation = throw "not lazy enough";
2256 # It's ok to add attribute names here when lazyDerivation is improved
2257 # in accordance with its inline comments.
2258 expected = [ "drvPath" "meta" "name" "out" "outPath" "outputName" "outputs" "system" "type" ];
2261 testLazyDerivationIsLazyInDerivationForPassthruAttr = {
2262 expr = (lazyDerivation {
2263 derivation = throw "not lazy enough";
2264 passthru.tests = "whatever is in tests";
2266 expected = "whatever is in tests";
2269 testLazyDerivationIsLazyInDerivationForPassthruAttr2 = {
2270 # passthru.tests is not a special case. It works for any attr.
2271 expr = (lazyDerivation {
2272 derivation = throw "not lazy enough";
2273 passthru.foo = "whatever is in foo";
2275 expected = "whatever is in foo";
2278 testLazyDerivationIsLazyInDerivationForMeta = {
2279 expr = (lazyDerivation {
2280 derivation = throw "not lazy enough";
2281 meta = "whatever is in meta";
2283 expected = "whatever is in meta";
2286 testLazyDerivationReturnsDerivationAttrs = let
2288 type = "derivation";
2291 outPath = "test outPath";
2293 drvPath = "test drvPath";
2295 system = "test system";
2299 expr = lazyDerivation { inherit derivation; };
2300 expected = derivation;
2303 testOptionalDrvAttr = let
2304 mkDerivation = args: derivation (args // {
2305 builder = "builder";
2307 __ignoreNulls = true;
2310 expr = (mkDerivation {
2312 x = optionalDrvAttr true 1;
2313 y = optionalDrvAttr false 1;
2315 expected = (mkDerivation {
2321 testLazyDerivationMultiOutputReturnsDerivationAttrs = let
2323 type = "derivation";
2324 outputs = ["out" "dev"];
2327 outPath = "test outPath";
2329 drvPath = "test drvPath";
2331 system = "test system";
2332 meta.position = "/hi:23";
2335 expr = lazyDerivation { inherit derivation; outputs = ["out" "dev"]; passthru.meta.position = "/hi:23"; };
2336 expected = derivation;
2339 testTypeDescriptionInt = {
2340 expr = (with types; int).description;
2341 expected = "signed integer";
2343 testTypeDescriptionIntsPositive = {
2344 expr = (with types; ints.positive).description;
2345 expected = "positive integer, meaning >0";
2347 testTypeDescriptionIntsPositiveOrEnumAuto = {
2348 expr = (with types; either ints.positive (enum ["auto"])).description;
2349 expected = ''positive integer, meaning >0, or value "auto" (singular enum)'';
2351 testTypeDescriptionListOfPositive = {
2352 expr = (with types; listOf ints.positive).description;
2353 expected = "list of (positive integer, meaning >0)";
2355 testTypeDescriptionListOfInt = {
2356 expr = (with types; listOf int).description;
2357 expected = "list of signed integer";
2359 testTypeDescriptionListOfListOfInt = {
2360 expr = (with types; listOf (listOf int)).description;
2361 expected = "list of list of signed integer";
2363 testTypeDescriptionListOfEitherStrOrBool = {
2364 expr = (with types; listOf (either str bool)).description;
2365 expected = "list of (string or boolean)";
2367 testTypeDescriptionEitherListOfStrOrBool = {
2368 expr = (with types; either (listOf bool) str).description;
2369 expected = "(list of boolean) or string";
2371 testTypeDescriptionEitherStrOrListOfBool = {
2372 expr = (with types; either str (listOf bool)).description;
2373 expected = "string or list of boolean";
2375 testTypeDescriptionOneOfListOfStrOrBool = {
2376 expr = (with types; oneOf [ (listOf bool) str ]).description;
2377 expected = "(list of boolean) or string";
2379 testTypeDescriptionOneOfListOfStrOrBoolOrNumber = {
2380 expr = (with types; oneOf [ (listOf bool) str number ]).description;
2381 expected = "(list of boolean) or string or signed integer or floating point number";
2383 testTypeDescriptionEitherListOfBoolOrEitherStringOrNumber = {
2384 expr = (with types; either (listOf bool) (either str number)).description;
2385 expected = "(list of boolean) or string or signed integer or floating point number";
2387 testTypeDescriptionEitherEitherListOfBoolOrStringOrNumber = {
2388 expr = (with types; either (either (listOf bool) str) number).description;
2389 expected = "(list of boolean) or string or signed integer or floating point number";
2391 testTypeDescriptionEitherNullOrBoolOrString = {
2392 expr = (with types; either (nullOr bool) str).description;
2393 expected = "null or boolean or string";
2395 testTypeDescriptionEitherListOfEitherBoolOrStrOrInt = {
2396 expr = (with types; either (listOf (either bool str)) int).description;
2397 expected = "(list of (boolean or string)) or signed integer";
2399 testTypeDescriptionEitherIntOrListOrEitherBoolOrStr = {
2400 expr = (with types; either int (listOf (either bool str))).description;
2401 expected = "signed integer or list of (boolean or string)";
2405 testGetExe'Output = {
2407 type = "derivation";
2408 out = "somelonghash";
2409 bin = "somelonghash";
2411 expected = "somelonghash/bin/executable";
2414 testGetExeOutput = {
2416 type = "derivation";
2417 out = "somelonghash";
2418 bin = "somelonghash";
2419 meta.mainProgram = "mainProgram";
2421 expected = "somelonghash/bin/mainProgram";
2424 testGetExe'FailureFirstArg = testingThrow (
2425 getExe' "not a derivation" "executable"
2428 testGetExe'FailureSecondArg = testingThrow (
2429 getExe' { type = "derivation"; } "dir/executable"
2432 testGetLicenseFromSpdxIdOrExamples = {
2434 (getLicenseFromSpdxIdOr "MIT" null)
2435 (getLicenseFromSpdxIdOr "mIt" null)
2436 (getLicenseFromSpdxIdOr "MY LICENSE" lib.licenses.free)
2437 (getLicenseFromSpdxIdOr "MY LICENSE" null)
2447 testGetLicenseFromSpdxIdOrThrow = testingThrow (
2448 getLicenseFromSpdxIdOr "MY LICENSE" (throw "No SPDX ID matches MY LICENSE")
2451 testPlatformMatch = {
2452 expr = meta.platformMatch { system = "x86_64-linux"; } "x86_64-linux";
2456 testPlatformMatchAttrs = {
2457 expr = meta.platformMatch (systems.elaborate "x86_64-linux") (systems.elaborate "x86_64-linux").parsed;
2461 testPlatformMatchNoMatch = {
2462 expr = meta.platformMatch { system = "x86_64-darwin"; } "x86_64-linux";
2466 testPlatformMatchMissingSystem = {
2467 expr = meta.platformMatch { } "x86_64-linux";
2471 testPackagesFromDirectoryRecursive = {
2472 expr = packagesFromDirectoryRecursive {
2473 callPackage = path: overrides: import path overrides;
2474 directory = ./packages-from-directory;
2479 # Note: Other files/directories in `./test-data/c/` are ignored and can be
2480 # used by `package.nix`.
2486 my-sub-namespace = {
2494 # Check that `packagesFromDirectoryRecursive` can process a directory with a
2495 # top-level `package.nix` file into a single package.
2496 testPackagesFromDirectoryRecursiveTopLevelPackageNix = {
2497 expr = packagesFromDirectoryRecursive {
2498 callPackage = path: overrides: import path overrides;
2499 directory = ./packages-from-directory/c;