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;
63 getLicenseFromSpdxIdOr
86 optionAttrSetToDocList
88 packagesFromDirectoryRecursive
114 updateManyAttrsByPath
119 testingThrow = expr: {
120 expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
121 expected = { success = false; value = false; };
123 testingEval = expr: {
124 expr = (builtins.tryEval expr).success;
128 testSanitizeDerivationName = { name, expected }:
131 name = strings.sanitizeDerivationName name;
136 # Evaluate the derivation so an invalid name would be caught
137 expr = builtins.seq drv.drvPath drv.name;
147 testFunctionArgsMakeOverridable = {
148 expr = functionArgs (makeOverridable ({ a, b, c ? null}: {}));
149 expected = { a = false; b = false; c = true; };
152 testFunctionArgsMakeOverridableOverride = {
153 expr = functionArgs (makeOverridable ({ a, b, c ? null }: {}) { a = 1; b = 2; }).override;
154 expected = { a = false; b = false; c = true; };
157 testCallPackageWithOverridePreservesArguments =
159 f = { a ? 0, b }: {};
160 f' = callPackageWith { a = 1; b = 2; } f {};
162 expr = functionArgs f'.override;
163 expected = functionArgs f;
166 testCallPackagesWithOverridePreservesArguments =
168 f = { a ? 0, b }: { nested = {}; };
169 f' = callPackagesWith { a = 1; b = 2; } f {};
171 expr = functionArgs f'.nested.override;
172 expected = functionArgs f;
189 (x: x + 2) # 2 + 2 = 4
190 (x: x * 2) # 4 * 2 = 8
201 expr = pipe [ 3 4 ] [
214 expr = or true false;
220 expr = and true false;
239 testComposeExtensions = {
240 expr = let obj = makeExtensible (self: { foo = self.bar; });
241 f = self: super: { bar = false; baz = true; };
242 g = self: super: { bar = super.baz or false; };
243 f_o_g = composeExtensions f g;
244 composed = obj.extend f_o_g;
249 testComposeManyExtensions0 = {
250 expr = let obj = makeExtensible (self: { foo = true; });
251 emptyComposition = composeManyExtensions [];
252 composed = obj.extend emptyComposition;
257 testComposeManyExtensions =
258 let f = self: super: { bar = false; baz = true; };
259 g = self: super: { bar = super.baz or false; };
260 h = self: super: { qux = super.bar or false; };
261 obj = makeExtensible (self: { foo = self.qux; });
263 expr = let composition = composeManyExtensions [f g h];
264 composed = obj.extend composition;
266 expected = (obj.extend (composeExtensions f (composeExtensions g h))).foo;
270 expr = (bitAnd 3 10);
280 expr = (bitXor 3 10);
285 expr = toHexString 250;
289 testFromHexStringFirstExample = {
290 expr = fromHexString "FF";
294 testFromHexStringSecondExample = {
295 expr = fromHexString (builtins.hashString "sha256" "test");
296 expected = 9223372036854775807;
299 testFromHexStringWithPrefix = {
300 expr = fromHexString "0Xf";
305 expr = toBaseDigits 2 6;
306 expected = [ 1 1 0 ];
309 testFunctionArgsFunctor = {
310 expr = functionArgs { __functor = self: { a, b }: null; };
311 expected = { a = false; b = false; };
314 testFunctionArgsSetFunctionArgs = {
315 expr = functionArgs (setFunctionArgs (args: args.x) { x = false; });
316 expected = { x = false; };
321 testConcatMapStrings = {
322 expr = concatMapStrings (x: x + ";") ["a" "b" "c"];
326 testConcatStringsSep = {
327 expr = concatStringsSep "," ["a" "b" "c"];
332 expr = concatLines ["a" "b" "c"];
333 expected = "a\nb\nc\n";
336 testMakeIncludePathWithPkgs = {
337 expr = (makeIncludePath [
338 # makeIncludePath preferably selects the "dev" output
339 { dev.outPath = "/dev"; out.outPath = "/out"; outPath = "/default"; }
340 # "out" is used if "dev" is not found
341 { out.outPath = "/out"; outPath = "/default"; }
342 # And it returns the derivation directly if there's no "out" either
343 { outPath = "/default"; }
344 # Same if the output is specified explicitly, even if there's a "dev"
345 { dev.outPath = "/dev"; outPath = "/default"; outputSpecified = true; }
347 expected = "/dev/include:/out/include:/default/include:/default/include";
350 testMakeIncludePathWithEmptyList = {
351 expr = (makeIncludePath [ ]);
355 testMakeIncludePathWithOneString = {
356 expr = (makeIncludePath [ "/usr" ]);
357 expected = "/usr/include";
360 testMakeIncludePathWithManyString = {
361 expr = (makeIncludePath [ "/usr" "/usr/local" ]);
362 expected = "/usr/include:/usr/local/include";
365 testReplicateString = {
366 expr = strings.replicate 5 "hello";
367 expected = "hellohellohellohellohello";
370 # Test various strings are trimmed correctly
374 testValues = f: mapAttrs (_: f) {
380 leading = " Hello, world";
381 trailing = "Hello, world ";
382 mixed = " Hello, world ";
383 mixed-tabs = " \t\tHello, world \t \t ";
384 multiline = " Hello,\n world! ";
385 multiline-crlf = " Hello,\r\n world! ";
389 leading = testValues (strings.trimWith { start = true; });
390 trailing = testValues (strings.trimWith { end = true; });
391 both = testValues strings.trim;
400 leading = "Hello, world";
401 trailing = "Hello, world ";
402 mixed = "Hello, world ";
403 mixed-tabs = "Hello, world \t \t ";
404 multiline = "Hello,\n world! ";
405 multiline-crlf = "Hello,\r\n world! ";
413 leading = " Hello, world";
414 trailing = "Hello, world";
415 mixed = " Hello, world";
416 mixed-tabs = " \t\tHello, world";
417 multiline = " Hello,\n world!";
418 multiline-crlf = " Hello,\r\n world!";
426 leading = "Hello, world";
427 trailing = "Hello, world";
428 mixed = "Hello, world";
429 mixed-tabs = "Hello, world";
430 multiline = "Hello,\n world!";
431 multiline-crlf = "Hello,\r\n world!";
436 testSplitStringsSimple = {
437 expr = strings.splitString "." "a.b.c.d";
438 expected = [ "a" "b" "c" "d" ];
441 testSplitStringsEmpty = {
442 expr = strings.splitString "." "a..b";
443 expected = [ "a" "" "b" ];
446 testSplitStringsOne = {
447 expr = strings.splitString ":" "a.b";
448 expected = [ "a.b" ];
451 testSplitStringsNone = {
452 expr = strings.splitString "." "";
456 testSplitStringsFirstEmpty = {
457 expr = strings.splitString "/" "/a/b/c";
458 expected = [ "" "a" "b" "c" ];
461 testSplitStringsLastEmpty = {
462 expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:";
463 expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ];
466 testSplitStringsRegex = {
467 expr = strings.splitString "\\[{}]()^$?*+|." "A\\[{}]()^$?*+|.B";
468 expected = [ "A" "B" ];
471 testEscapeShellArg = {
472 expr = strings.escapeShellArg "esc'ape\nme";
473 expected = "'esc'\\''ape\nme'";
476 testEscapeShellArgEmpty = {
477 expr = strings.escapeShellArg "";
481 testEscapeShellArgs = {
482 expr = strings.escapeShellArgs ["one" "two three" "four'five"];
483 expected = "one 'two three' 'four'\\''five'";
486 testEscapeShellArgsUnicode = {
487 expr = strings.escapeShellArg "á";
491 testSplitStringsDerivation = {
492 expr = take 3 (strings.splitString "/" (derivation {
497 expected = ["" "nix" "store"];
500 testSplitVersionSingle = {
501 expr = versions.splitVersion "1";
505 testSplitVersionDouble = {
506 expr = versions.splitVersion "1.2";
507 expected = [ "1" "2" ];
510 testSplitVersionTriple = {
511 expr = versions.splitVersion "1.2.3";
512 expected = [ "1" "2" "3" ];
515 testPadVersionLess = {
516 expr = versions.pad 3 "1.2";
520 testPadVersionLessExtra = {
521 expr = versions.pad 3 "1.3-rc1";
522 expected = "1.3.0-rc1";
525 testPadVersionMore = {
526 expr = versions.pad 3 "1.2.3.4";
533 "${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11";
535 storePath = isStorePath goodPath;
536 storePathDerivation = isStorePath (import ../.. { system = "x86_64-linux"; }).hello;
537 storePathAppendix = isStorePath
538 "${goodPath}/bin/python";
539 nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath)));
540 asPath = isStorePath (/. + goodPath);
541 otherPath = isStorePath "/something/else";
543 attrset = isStorePath {};
544 list = isStorePath [];
545 int = isStorePath 42;
550 storePathDerivation = true;
551 storePathAppendix = false;
564 expr = escapeXML ''"test" 'test' < & >'';
565 expected = ""test" 'test' < & >";
571 STRing01 = "just a 'string'";
572 _array_ = [ "with" "more strings" ];
573 assoc."with some" = ''
579 foo = "ignored attribute";
583 __toString = _: "hello toString";
584 bar = "ignored attribute";
589 STRing01='just a '\'''string'\''''
590 declare -a _array_=(with 'more strings')
591 declare -A assoc=(['with some']='strings
596 stringable='hello toString'
600 testHasInfixFalse = {
601 expr = hasInfix "c" "abde";
606 expr = hasInfix "c" "abcde";
610 testHasInfixDerivation = {
611 expr = hasInfix "hello" (import ../.. { system = "x86_64-linux"; }).hello;
616 expr = hasInfix "tests" ./.;
620 testHasInfixPathStoreDir = {
621 expr = hasInfix builtins.storeDir ./.;
625 testHasInfixToString = {
626 expr = hasInfix "a" { __toString = _: "a"; };
630 testRemovePrefixExample1 = {
631 expr = removePrefix "foo." "foo.bar.baz";
632 expected = "bar.baz";
634 testRemovePrefixExample2 = {
635 expr = removePrefix "xxx" "foo.bar.baz";
636 expected = "foo.bar.baz";
638 testRemovePrefixEmptyPrefix = {
639 expr = removePrefix "" "foo";
642 testRemovePrefixEmptyString = {
643 expr = removePrefix "foo" "";
646 testRemovePrefixEmptyBoth = {
647 expr = removePrefix "" "";
651 testNormalizePath = {
652 expr = strings.normalizePath "//a/b//c////d/";
653 expected = "/a/b/c/d/";
657 expr = strings.charToInt "A";
662 expr = strings.escapeC [ " " ] "Hello World";
663 expected = "Hello\\x20World";
666 testEscapeURL = testAllTrue [
667 ("" == strings.escapeURL "")
668 ("Hello" == strings.escapeURL "Hello")
669 ("Hello%20World" == strings.escapeURL "Hello World")
670 ("Hello%2FWorld" == strings.escapeURL "Hello/World")
671 ("42%25" == strings.escapeURL "42%")
672 ("%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:/@$'()*,;")
675 testToInt = testAllTrue [
680 (123 == toInt " 123")
681 (123 == toInt "123 ")
682 (123 == toInt " 123 ")
683 (123 == toInt " 123 ")
691 testToIntFails = testAllTrue [
692 ( builtins.tryEval (toInt "") == { success = false; value = false; } )
693 ( builtins.tryEval (toInt "123 123") == { success = false; value = false; } )
694 ( builtins.tryEval (toInt "0 123") == { success = false; value = false; } )
695 ( builtins.tryEval (toInt " 0d ") == { success = false; value = false; } )
696 ( builtins.tryEval (toInt " 1d ") == { success = false; value = false; } )
697 ( builtins.tryEval (toInt " d0 ") == { success = false; value = false; } )
698 ( builtins.tryEval (toInt "00") == { success = false; value = false; } )
699 ( builtins.tryEval (toInt "01") == { success = false; value = false; } )
700 ( builtins.tryEval (toInt "002") == { success = false; value = false; } )
701 ( builtins.tryEval (toInt " 002 ") == { success = false; value = false; } )
702 ( builtins.tryEval (toInt " foo ") == { success = false; value = false; } )
703 ( builtins.tryEval (toInt " foo 123 ") == { success = false; value = false; } )
704 ( builtins.tryEval (toInt " foo123 ") == { success = false; value = false; } )
707 testToIntBase10 = testAllTrue [
709 (123 == toIntBase10 "123")
710 (0 == toIntBase10 "0")
712 (123 == toIntBase10 " 123")
713 (123 == toIntBase10 "123 ")
714 (123 == toIntBase10 " 123 ")
715 (123 == toIntBase10 " 123 ")
716 (0 == toIntBase10 " 0")
717 (0 == toIntBase10 "0 ")
718 (0 == toIntBase10 " 0 ")
720 (123 == toIntBase10 "0123")
721 (123 == toIntBase10 "0000123")
722 (0 == toIntBase10 "000000")
723 # Whitespace and Zero Padding
724 (123 == toIntBase10 " 0123")
725 (123 == toIntBase10 "0123 ")
726 (123 == toIntBase10 " 0123 ")
727 (123 == toIntBase10 " 0000123")
728 (123 == toIntBase10 "0000123 ")
729 (123 == toIntBase10 " 0000123 ")
730 (0 == toIntBase10 " 000000")
731 (0 == toIntBase10 "000000 ")
732 (0 == toIntBase10 " 000000 ")
733 (-1 == toIntBase10 "-1")
734 (-1 == toIntBase10 " -1 ")
737 testToIntBase10Fails = testAllTrue [
738 ( builtins.tryEval (toIntBase10 "") == { success = false; value = false; } )
739 ( builtins.tryEval (toIntBase10 "123 123") == { success = false; value = false; } )
740 ( builtins.tryEval (toIntBase10 "0 123") == { success = false; value = false; } )
741 ( builtins.tryEval (toIntBase10 " 0d ") == { success = false; value = false; } )
742 ( builtins.tryEval (toIntBase10 " 1d ") == { success = false; value = false; } )
743 ( builtins.tryEval (toIntBase10 " d0 ") == { success = false; value = false; } )
744 ( builtins.tryEval (toIntBase10 " foo ") == { success = false; value = false; } )
745 ( builtins.tryEval (toIntBase10 " foo 123 ") == { success = false; value = false; } )
746 ( builtins.tryEval (toIntBase10 " foo 00123 ") == { success = false; value = false; } )
747 ( builtins.tryEval (toIntBase10 " foo00123 ") == { success = false; value = false; } )
753 expr = filter (x: x != "a") ["a" "b" "c" "a"];
754 expected = ["b" "c"];
757 testIfilter0Example = {
758 expr = ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ];
761 testIfilter0Empty = {
762 expr = ifilter0 (i: v: abort "shouldn't be evaluated!") [ ];
765 testIfilter0IndexOnly = {
766 expr = length (ifilter0 (i: v: mod i 2 == 0) [ (throw "0") (throw "1") (throw "2") (throw "3")]);
770 expr = ifilter0 (i: v: true) [ 10 11 12 13 14 15 ];
771 expected = [ 10 11 12 13 14 15 ];
773 testIfilter0First = {
774 expr = ifilter0 (i: v: i == 0) [ 10 11 12 13 14 15 ];
778 expr = ifilter0 (i: v: i == 5) [ 10 11 12 13 14 15 ];
784 f = op: fold: fold op 0 (range 0 100);
785 # fold with associative operator
786 assoc = f builtins.add;
787 # fold with non-associative operator
788 nonAssoc = f builtins.sub;
791 assocRight = assoc foldr;
792 # right fold with assoc operator is same as left fold
793 assocRightIsLeft = assoc foldr == assoc foldl;
794 nonAssocRight = nonAssoc foldr;
795 nonAssocLeft = nonAssoc foldl;
796 # with non-assoc operator the fold results are not the same
797 nonAssocRightIsNotLeft = nonAssoc foldl != nonAssoc foldr;
798 # fold is an alias for foldr
799 foldIsRight = nonAssoc fold == nonAssoc foldr;
803 assocRightIsLeft = true;
805 nonAssocLeft = (-5050);
806 nonAssocRightIsNotLeft = true;
812 expr = foldl' (acc: el: abort "operation not called") 0 [ ];
816 testFoldl'IntegerAdding = {
817 expr = foldl' (acc: el: acc + el) 0 [ 1 2 3 ];
821 # The accumulator isn't forced deeply
822 testFoldl'NonDeep = {
823 expr = take 3 (foldl'
824 (acc: el: [ el ] ++ acc)
825 [ (abort "unevaluated list entry") ]
827 expected = [ 3 2 1 ];
830 # Compared to builtins.foldl', lib.foldl' evaluates the first accumulator strictly too
831 testFoldl'StrictInitial = {
832 expr = (builtins.tryEval (foldl' (acc: el: el) (throw "hello") [])).success;
836 # Make sure we don't get a stack overflow for large lists
837 # This number of elements would notably cause a stack overflow if it was implemented without the `foldl'` builtin
839 expr = foldl' (acc: el: acc + el) 0 (range 0 100000);
840 expected = 5000050000;
843 testTake = testAllTrue [
844 ([] == (take 0 [ 1 2 3 ]))
845 ([1] == (take 1 [ 1 2 3 ]))
846 ([ 1 2 ] == (take 2 [ 1 2 3 ]))
847 ([ 1 2 3 ] == (take 3 [ 1 2 3 ]))
848 ([ 1 2 3 ] == (take 4 [ 1 2 3 ]))
851 testListHasPrefixExample1 = {
852 expr = lists.hasPrefix [ 1 2 ] [ 1 2 3 4 ];
855 testListHasPrefixExample2 = {
856 expr = lists.hasPrefix [ 0 1 ] [ 1 2 3 4 ];
859 testListHasPrefixLazy = {
860 expr = lists.hasPrefix [ 1 ] [ 1 (abort "lib.lists.hasPrefix is not lazy") ];
863 testListHasPrefixEmptyPrefix = {
864 expr = lists.hasPrefix [ ] [ 1 2 ];
867 testListHasPrefixEmptyList = {
868 expr = lists.hasPrefix [ 1 2 ] [ ];
872 testListRemovePrefixExample1 = {
873 expr = lists.removePrefix [ 1 2 ] [ 1 2 3 4 ];
876 testListRemovePrefixExample2 = {
877 expr = (builtins.tryEval (lists.removePrefix [ 0 1 ] [ 1 2 3 4 ])).success;
880 testListRemovePrefixEmptyPrefix = {
881 expr = lists.removePrefix [ ] [ 1 2 ];
884 testListRemovePrefixEmptyList = {
885 expr = (builtins.tryEval (lists.removePrefix [ 1 2 ] [ ])).success;
890 expr = foldAttrs (n: a: [n] ++ a) [] [
894 expected = { a = [ 2 3 ]; b = [7]; c = [8];};
897 testListCommonPrefixExample1 = {
898 expr = lists.commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ];
901 testListCommonPrefixExample2 = {
902 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ];
903 expected = [ 1 2 3 ];
905 testListCommonPrefixExample3 = {
906 expr = lists.commonPrefix [ 1 2 3 ] [ 4 5 6 ];
909 testListCommonPrefixEmpty = {
910 expr = lists.commonPrefix [ ] [ 1 2 3 ];
913 testListCommonPrefixSame = {
914 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 ];
915 expected = [ 1 2 3 ];
917 testListCommonPrefixLazy = {
918 expr = lists.commonPrefix [ 1 ] [ 1 (abort "lib.lists.commonPrefix shouldn't evaluate this")];
921 # This would stack overflow if `commonPrefix` were implemented using recursion
922 testListCommonPrefixLong =
924 longList = genList (n: n) 100000;
926 expr = lists.commonPrefix longList longList;
931 expr = sort builtins.lessThan [ 40 2 30 42 ];
932 expected = [2 30 40 42];
936 expr = sortOn stringLength [ "aa" "b" "cccc" ];
937 expected = [ "b" "aa" "cccc" ];
941 expr = sortOn (throw "nope") [ ];
945 testSortOnIncomparable = {
950 { ok = 1; f = x: x; }
951 { ok = 3; f = x: x + 3; }
952 { ok = 2; f = x: x; }
954 expected = [ 1 2 6 ];
958 expr = replicate 3 "a";
959 expected = ["a" "a" "a"];
962 testToIntShouldConvertStringToInt = {
967 testToIntShouldThrowErrorIfItCouldNotConvertToInt = {
968 expr = builtins.tryEval (toInt "\"foo\"");
969 expected = { success = false; value = false; };
972 testHasAttrByPathTrue = {
973 expr = hasAttrByPath ["a" "b"] { a = { b = "yey"; }; };
977 testHasAttrByPathFalse = {
978 expr = hasAttrByPath ["a" "b"] { a = { c = "yey"; }; };
982 testHasAttrByPathNonStrict = {
983 expr = hasAttrByPath [] (throw "do not use");
987 testLongestValidPathPrefix_empty_empty = {
988 expr = attrsets.longestValidPathPrefix [ ] { };
992 testLongestValidPathPrefix_empty_nonStrict = {
993 expr = attrsets.longestValidPathPrefix [ ] (throw "do not use");
997 testLongestValidPathPrefix_zero = {
998 expr = attrsets.longestValidPathPrefix [ "a" (throw "do not use") ] { d = null; };
1002 testLongestValidPathPrefix_zero_b = {
1003 expr = attrsets.longestValidPathPrefix [ "z" "z" ] "remarkably harmonious";
1007 testLongestValidPathPrefix_one = {
1008 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a = null; };
1012 testLongestValidPathPrefix_two = {
1013 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b = null; };
1014 expected = [ "a" "b" ];
1017 testLongestValidPathPrefix_three = {
1018 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c = null; };
1019 expected = [ "a" "b" "c" ];
1022 testLongestValidPathPrefix_three_extra = {
1023 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c.d = throw "nope"; };
1024 expected = [ "a" "b" "c" ];
1027 testFindFirstIndexExample1 = {
1028 expr = lists.findFirstIndex (x: x > 3) (abort "index found, so a default must not be evaluated") [ 1 6 4 ];
1032 testFindFirstIndexExample2 = {
1033 expr = lists.findFirstIndex (x: x > 9) "a very specific default" [ 1 6 4 ];
1034 expected = "a very specific default";
1037 testFindFirstIndexEmpty = {
1038 expr = lists.findFirstIndex (abort "when the list is empty, the predicate is not needed") null [];
1042 testFindFirstIndexSingleMatch = {
1043 expr = lists.findFirstIndex (x: x == 5) null [ 5 ];
1047 testFindFirstIndexSingleDefault = {
1048 expr = lists.findFirstIndex (x: false) null [ (abort "if the predicate doesn't access the value, it must not be evaluated") ];
1052 testFindFirstIndexNone = {
1053 expr = builtins.tryEval (lists.findFirstIndex (x: x == 2) null [ 1 (throw "the last element must be evaluated when there's no match") ]);
1054 expected = { success = false; value = false; };
1057 # Makes sure that the implementation doesn't cause a stack overflow
1058 testFindFirstIndexBig = {
1059 expr = lists.findFirstIndex (x: x == 1000000) null (range 0 1000000);
1063 testFindFirstIndexLazy = {
1064 expr = lists.findFirstIndex (x: x == 1) null [ 1 (abort "list elements after the match must not be evaluated") ];
1068 testFindFirstExample1 = {
1069 expr = lists.findFirst (x: x > 3) 7 [ 1 6 4 ];
1073 testFindFirstExample2 = {
1074 expr = lists.findFirst (x: x > 9) 7 [ 1 6 4 ];
1078 testAllUnique_true = {
1079 expr = allUnique [ 3 2 4 1 ];
1082 testAllUnique_false = {
1083 expr = allUnique [ 3 2 3 4 ];
1089 testConcatMapAttrs = {
1090 expr = concatMapAttrs
1093 ${name + value} = value;
1107 expr = filterAttrs (n: v: n != "a" && (v.hello or false) == true) {
1128 example = foldlAttrs
1129 (acc: name: value: {
1130 sum = acc.sum + value;
1131 names = acc.names ++ [ name ];
1133 { sum = 0; names = [ ]; }
1138 # should just return the initial value
1139 emptySet = foldlAttrs (throw "function not needed") 123 { };
1140 # should just evaluate to the last value
1141 valuesNotNeeded = foldlAttrs (acc: _name: _v: acc) 3 { z = throw "value z not needed"; a = throw "value a not needed"; };
1142 # the accumulator doesnt have to be an attrset it can be as trivial as being just a number or string
1143 trivialAcc = foldlAttrs (acc: _name: v: acc * 10 + v) 1 { z = 1; a = 2; };
1148 names = [ "bar" "foo" ];
1151 valuesNotNeeded = 3;
1157 testMergeAttrsListExample1 = {
1158 expr = attrsets.mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ];
1159 expected = { a = 0; b = 1; c = 2; d = 3; };
1161 testMergeAttrsListExample2 = {
1162 expr = attrsets.mergeAttrsList [ { a = 0; } { a = 1; } ];
1163 expected = { a = 1; };
1165 testMergeAttrsListExampleMany =
1168 listToAttrs (genList (m:
1170 # Integer divide n by two to create duplicate attributes
1171 str = "halfn${toString (n / 2)}m${toString m}";
1173 nameValuePair str str
1177 expr = attrsets.mergeAttrsList list;
1178 expected = foldl' mergeAttrs { } list;
1181 # code from the example
1182 testRecursiveUpdateUntil = {
1183 expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) {
1184 # first attribute set
1189 #second attribute set
1195 foo.bar = 1; # 'foo.*' from the second set
1197 bar = 3; # 'bar' from the first set
1198 baz = 4; # 'baz' from the second set
1202 testMatchAttrsMatchingExact = {
1203 expr = matchAttrs { cpu = { bits = 64; }; } { cpu = { bits = 64; }; };
1207 testMatchAttrsMismatch = {
1208 expr = matchAttrs { cpu = { bits = 128; }; } { cpu = { bits = 64; }; };
1212 testMatchAttrsMatchingImplicit = {
1213 expr = matchAttrs { cpu = { }; } { cpu = { bits = 64; }; };
1217 testMatchAttrsMissingAttrs = {
1218 expr = matchAttrs { cpu = {}; } { };
1222 testOverrideExistingEmpty = {
1223 expr = overrideExisting {} { a = 1; };
1227 testOverrideExistingDisjoint = {
1228 expr = overrideExisting { b = 2; } { a = 1; };
1229 expected = { b = 2; };
1232 testOverrideExistingOverride = {
1233 expr = overrideExisting { a = 3; b = 2; } { a = 1; };
1234 expected = { a = 1; b = 2; };
1237 testListAttrsReverse = let
1238 exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;};
1239 exampleSingletonList = [{name="foo"; value=1;}];
1242 isReverseToListToAttrs = builtins.listToAttrs (attrsToList exampleAttrs) == exampleAttrs;
1243 isReverseToAttrsToList = attrsToList (builtins.listToAttrs exampleSingletonList) == exampleSingletonList;
1244 testDuplicatePruningBehaviour = attrsToList (builtins.listToAttrs [{name="a"; value=2;} {name="a"; value=1;}]);
1247 isReverseToAttrsToList = true;
1248 isReverseToListToAttrs = true;
1249 testDuplicatePruningBehaviour = [{name="a"; value=2;}];
1253 testAttrsToListsCanDealWithFunctions = testingEval (
1254 attrsToList { someFunc= a: a + 1;}
1260 expr = fix (x: {a = if x ? a then "a" else "b";});
1261 expected = {a = "a";};
1266 (fix (final: { a = 0; c = final.a; }))
1267 (fix (extends (toExtension { a = 1; b = 2; }) (final: { a = 0; c = final.a; })))
1268 (fix (extends (toExtension (prev: { a = 1; b = prev.a; })) (final: { a = 0; c = final.a; })))
1269 (fix (extends (toExtension (final: prev: { a = 1; b = prev.a; c = final.a + 1; })) (final: { a = 0; c = final.a; })))
1273 { a = 1; b = 2; c = 1; }
1274 { a = 1; b = 0; c = 1; }
1275 { a = 1; b = 0; c = 2; }
1280 # these tests assume attributes are converted to lists
1281 # in alphabetical order
1283 testMkKeyValueDefault = {
1284 expr = generators.mkKeyValueDefault {} ":" "f:oo" "bar";
1285 expected = ''f\:oo:bar'';
1288 testMkValueString = {
1296 # float = 42.23; # floats are strange
1299 (const (generators.mkValueStringDefault {}))
1307 # float = "42.23" true false [ "bar" ] ]'';
1312 expr = generators.toKeyValue {} {
1314 "other=key" = "baz";
1323 expr = generators.toINI {} {};
1327 testToINIEmptySection = {
1328 expr = generators.toINI {} { foo = {}; bar = {}; };
1336 testToINIDuplicateKeys = {
1337 expr = generators.toINI { listsAsDuplicateKeys = true; } { foo.bar = true; baz.qux = [ 1 false ]; };
1348 testToINIDefaultEscapes = {
1349 expr = generators.toINI {} {
1350 "no [ and ] allowed unescaped" = {
1351 "and also no = in keys" = 42;
1355 [no \[ and \] allowed unescaped]
1356 and also no \= in keys=42
1360 testToINIDefaultFull = {
1361 expr = generators.toINI {} {
1364 x = "Me-se JarJar Binx";
1365 # booleans are converted verbatim by default
1369 "he\\h=he" = "this is okay";
1374 he\h\=he=this is okay
1383 testToINIWithGlobalSectionEmpty = {
1384 expr = generators.toINIWithGlobalSection {} {
1394 testToINIWithGlobalSectionGlobalEmptyIsTheSameAsToINI =
1399 x = "Me-se JarJar Binx";
1402 "he\\h=he" = "this is okay";
1407 generators.toINIWithGlobalSection {} {
1409 sections = sections;
1411 expected = generators.toINI {} sections;
1414 testToINIWithGlobalSectionFull = {
1415 expr = generators.toINIWithGlobalSection {} {
1423 x = "Me-se JarJar Binx";
1426 "he\\h=he" = "this is okay";
1435 he\h\=he=this is okay
1444 expr = generators.toGitINI {
1446 email = "user@example.org";
1448 signingKey = "00112233445566778899AABBCCDDEEFF";
1450 gpg.program = "path-to-gpg";
1452 include.path = "~/path/to/config.inc";
1453 includeIf."gitdif:~/src/dir".path = "~/path/to/conditional.inc";
1458 subsection.value = "test";
1462 ${"\t"}boolean = true
1464 ${"\t"}name = "value"
1466 [extra "subsection"]
1467 ${"\t"}value = "test"
1470 ${"\t"}program = "path-to-gpg"
1473 ${"\t"}path = "~/path/to/config.inc"
1475 [includeIf "gitdif:~/src/dir"]
1476 ${"\t"}path = "~/path/to/conditional.inc"
1479 ${"\t"}gpgSign = true
1482 ${"\t"}email = "user@example.org"
1483 ${"\t"}name = "John Doe"
1484 ${"\t"}signingKey = "00112233445566778899AABBCCDDEEFF"
1488 # right now only invocation check
1491 foobar = [ "baz" 1 2 3 ];
1494 expr = generators.toJSON {} val;
1495 # trivial implementation
1496 expected = builtins.toJSON val;
1499 # right now only invocation check
1502 list = [ { one = 1; } { two = 2; } ];
1506 expr = generators.toYAML {} val;
1507 # trivial implementation
1508 expected = builtins.toJSON val;
1513 deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
1515 expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec {
1520 string = "fn\${o}\"r\\d";
1521 newlinestring = "\n";
1525 functionArgs = { arg ? 4, foo }: arg;
1526 list = [ 3 4 function [ false ] ];
1528 attrs = { foo = null; "foo b/ar" = "baz"; };
1536 emptystring = ''""'';
1537 string = ''"fn\''${o}\"r\\d"'';
1538 newlinestring = "\"\\n\"";
1541 function = "<function>";
1542 functionArgs = "<function, args: {arg?, foo}>";
1543 list = "[ 3 4 ${function} [ false ] ]";
1545 attrs = "{ foo = null; \"foo b/ar\" = \"baz\"; }";
1547 drv = "<derivation ${deriv.name}>";
1556 expr = generators.toPretty { } (generators.withRecursion { throwOnDepthLimit = false; depthLimit = 2; } a);
1557 expected = "{\n b = 1;\n c = {\n b = \"<unevaluated>\";\n c = {\n b = \"<unevaluated>\";\n c = \"<unevaluated>\";\n };\n };\n}";
1560 testToPrettyLimitThrow =
1565 expr = (builtins.tryEval
1566 (generators.toPretty { } (generators.withRecursion { depthLimit = 2; } a))).success;
1570 testWithRecursionDealsWithFunctors =
1573 __functor = self: { a, b, }: null;
1581 expr = generators.toPretty { } (generators.withRecursion { depthLimit = 1; throwOnDepthLimit = false; } a);
1582 expected = "{\n b = <function, args: {a, b}>;\n c = {\n d = \"<unevaluated>\";\n };\n value = \"<unevaluated>\";\n}";
1585 testToPrettyMultiline = {
1586 expr = mapAttrs (const (generators.toPretty { })) {
1587 list = [ 3 4 [ false ] ];
1588 attrs = { foo = null; bar.foo = "baz"; };
1589 newlinestring = "\n";
1590 multilinestring = ''
1595 multilinestring' = ''
1616 newlinestring = "''\n \n''";
1617 multilinestring = ''
1623 multilinestring' = ''
1632 testToPrettyAllowPrettyValues = {
1633 expr = generators.toPretty { allowPrettyValues = true; }
1634 { __pretty = v: "«" + v + "»"; val = "foo"; };
1635 expected = "«foo»";
1639 expr = mapAttrs (const (generators.toPlist { })) {
1646 string = "fn\${o}\"r\\d";
1647 newlinestring = "\n";
1650 list = [ 3 4 "test" ];
1652 attrs = { foo = null; "foo b/ar" = "baz"; };
1657 expected = { value = builtins.readFile ./test-to-plist-expected.plist; };
1660 testToLuaEmptyAttrSet = {
1661 expr = generators.toLua {} {};
1665 testToLuaEmptyList = {
1666 expr = generators.toLua {} [];
1670 testToLuaListOfVariousTypes = {
1671 expr = generators.toLua {} [ null 43 3.14159 true ];
1682 expr = generators.toLua {} ''double-quote (") and single quotes (')'';
1683 expected = ''"double-quote (\") and single quotes (')"'';
1686 testToLuaAttrsetWithLuaInline = {
1687 expr = generators.toLua {} { x = generators.mkLuaInline ''"abc" .. "def"''; };
1690 ["x"] = ("abc" .. "def")
1694 testToLuaAttrsetWithSpaceInKey = {
1695 expr = generators.toLua {} { "some space and double-quote (\")" = 42; };
1698 ["some space and double-quote (\")"] = 42
1702 testToLuaWithoutMultiline = {
1703 expr = generators.toLua { multiline = false; } [ 41 43 ];
1704 expected = ''{ 41, 43 }'';
1707 testToLuaEmptyBindings = {
1708 expr = generators.toLua { asBindings = true; } {};
1712 testToLuaBindings = {
1713 expr = generators.toLua { asBindings = true; } { x1 = 41; _y = { a = 43; }; };
1722 testToLuaPartialTableBindings = {
1723 expr = generators.toLua { asBindings = true; } { "x.y" = 42; };
1729 testToLuaIndentedBindings = {
1730 expr = generators.toLua { asBindings = true; indent = " "; } { x = { y = 42; }; };
1731 expected = " x = {\n [\"y\"] = 42\n }\n";
1734 testToLuaBindingsWithSpace = testingThrow (
1735 generators.toLua { asBindings = true; } { "with space" = 42; }
1738 testToLuaBindingsWithLeadingDigit = testingThrow (
1739 generators.toLua { asBindings = true; } { "11eleven" = 42; }
1742 testToLuaBasicExample = {
1743 expr = generators.toLua {} {
1744 cmd = [ "typescript-language-server" "--stdio" ];
1745 settings.workspace.library = generators.mkLuaInline ''vim.api.nvim_get_runtime_file("", true)'';
1750 "typescript-language-server",
1755 ["library"] = (vim.api.nvim_get_runtime_file("", true))
1763 testToGNUCommandLine = {
1764 expr = cli.toGNUCommandLine {} {
1765 data = builtins.toJSON { id = 0; };
1769 url = [ "https://example.com/foo" "https://example.com/bar" ];
1776 "--data" "{\"id\":0}"
1778 "--url" "https://example.com/foo"
1779 "--url" "https://example.com/bar"
1784 testToGNUCommandLineSeparator = {
1785 expr = cli.toGNUCommandLine { optionValueSeparator = "="; } {
1786 data = builtins.toJSON { id = 0; };
1790 url = [ "https://example.com/foo" "https://example.com/bar" ];
1799 "--url=https://example.com/foo"
1800 "--url=https://example.com/bar"
1805 testToGNUCommandLineShell = {
1806 expr = cli.toGNUCommandLineShell {} {
1807 data = builtins.toJSON { id = 0; };
1811 url = [ "https://example.com/foo" "https://example.com/bar" ];
1816 expected = "-X PUT --data '{\"id\":0}' --retry 3 --url https://example.com/foo --url https://example.com/bar --verbose";
1819 testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName {
1824 testSanitizeDerivationNameUnicode = testSanitizeDerivationName {
1829 testSanitizeDerivationNameAscii = testSanitizeDerivationName {
1830 name = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
1831 expected = "-+--.-0123456789-=-?-ABCDEFGHIJKLMNOPQRSTUVWXYZ-_-abcdefghijklmnopqrstuvwxyz-";
1834 testSanitizeDerivationNameTooLong = testSanitizeDerivationName {
1835 name = "This string is loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1836 expected = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1839 testSanitizeDerivationNameTooLongWithInvalid = testSanitizeDerivationName {
1840 name = "Hello there aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&&&&&&&";
1841 expected = "there-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-";
1844 testSanitizeDerivationNameEmpty = testSanitizeDerivationName {
1846 expected = "unknown";
1849 testFreeformOptions = {
1852 submodule = { lib, ... }: {
1853 freeformType = lib.types.attrsOf (lib.types.submodule {
1854 options.bar = lib.mkOption {};
1856 options.bar = lib.mkOption {};
1859 module = { lib, ... }: {
1860 options.foo = lib.mkOption {
1861 type = lib.types.submodule submodule;
1865 options = (evalModules {
1866 modules = [ module ];
1869 locs = filter (o: ! o.internal) (optionAttrSetToDocList options);
1870 in map (o: o.loc) locs;
1871 expected = [ [ "_module" "args" ] [ "foo" ] [ "foo" "<name>" "bar" ] [ "foo" "bar" ] ];
1874 testCartesianProductOfEmptySet = {
1875 expr = cartesianProduct {};
1879 testCartesianProductOfOneSet = {
1880 expr = cartesianProduct { a = [ 1 2 3 ]; };
1881 expected = [ { a = 1; } { a = 2; } { a = 3; } ];
1884 testCartesianProductOfTwoSets = {
1885 expr = cartesianProduct { a = [ 1 ]; b = [ 10 20 ]; };
1892 testCartesianProductOfTwoSetsWithOneEmpty = {
1893 expr = cartesianProduct { a = [ ]; b = [ 10 20 ]; };
1897 testCartesianProductOfThreeSets = {
1898 expr = cartesianProduct {
1901 c = [ 100 200 300 ];
1904 { a = 1; b = 10; c = 100; }
1905 { a = 1; b = 10; c = 200; }
1906 { a = 1; b = 10; c = 300; }
1908 { a = 1; b = 20; c = 100; }
1909 { a = 1; b = 20; c = 200; }
1910 { a = 1; b = 20; c = 300; }
1912 { a = 1; b = 30; c = 100; }
1913 { a = 1; b = 30; c = 200; }
1914 { a = 1; b = 30; c = 300; }
1916 { a = 2; b = 10; c = 100; }
1917 { a = 2; b = 10; c = 200; }
1918 { a = 2; b = 10; c = 300; }
1920 { a = 2; b = 20; c = 100; }
1921 { a = 2; b = 20; c = 200; }
1922 { a = 2; b = 20; c = 300; }
1924 { a = 2; b = 30; c = 100; }
1925 { a = 2; b = 30; c = 200; }
1926 { a = 2; b = 30; c = 300; }
1928 { a = 3; b = 10; c = 100; }
1929 { a = 3; b = 10; c = 200; }
1930 { a = 3; b = 10; c = 300; }
1932 { a = 3; b = 20; c = 100; }
1933 { a = 3; b = 20; c = 200; }
1934 { a = 3; b = 20; c = 300; }
1936 { a = 3; b = 30; c = 100; }
1937 { a = 3; b = 30; c = 200; }
1938 { a = 3; b = 30; c = 300; }
1942 testMapCartesianProductOfOneSet = {
1943 expr = mapCartesianProduct ({a}: a * 2) { a = [ 1 2 3 ]; };
1944 expected = [ 2 4 6 ];
1947 testMapCartesianProductOfTwoSets = {
1948 expr = mapCartesianProduct ({a,b}: a + b) { a = [ 1 ]; b = [ 10 20 ]; };
1949 expected = [ 11 21 ];
1952 testMapCartesianProcutOfTwoSetsWithOneEmpty = {
1953 expr = mapCartesianProduct (x: x.a + x.b) { a = [ ]; b = [ 10 20 ]; };
1957 testMapCartesianProductOfThreeSets = {
1958 expr = mapCartesianProduct ({a,b,c}: a + b + c) {
1961 c = [ 100 200 300 ];
1963 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 ];
1966 # The example from the showAttrPath documentation
1967 testShowAttrPathExample = {
1968 expr = showAttrPath [ "foo" "10" "bar" ];
1969 expected = "foo.\"10\".bar";
1972 testShowAttrPathEmpty = {
1973 expr = showAttrPath [];
1974 expected = "<root attribute path>";
1977 testShowAttrPathVarious = {
1978 expr = showAttrPath [
1985 expected = ''".".foo."2".a2-b._bc'de'';
1989 expr = groupBy (n: toString (mod n 5)) (range 0 16);
1991 "0" = [ 0 5 10 15 ];
1992 "1" = [ 1 6 11 16 ];
2000 expr = groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ];
2001 expected = { false = 3; true = 12; };
2004 # The example from the updateManyAttrsByPath documentation
2005 testUpdateManyAttrsByPathExample = {
2006 expr = updateManyAttrsByPath [
2009 update = old: { d = old.c; };
2012 path = [ "a" "b" "c" ];
2013 update = old: old + 1;
2020 expected = { a = { b = { d = 1; }; }; x = { y = "xy"; }; };
2023 # If there are no updates, the value is passed through
2024 testUpdateManyAttrsByPathNone = {
2025 expr = updateManyAttrsByPath [] "something";
2026 expected = "something";
2029 # A single update to the root path is just like applying the function directly
2030 testUpdateManyAttrsByPathSingleIncrement = {
2031 expr = updateManyAttrsByPath [
2034 update = old: old + 1;
2040 # Multiple updates can be applied are done in order
2041 testUpdateManyAttrsByPathMultipleIncrements = {
2042 expr = updateManyAttrsByPath [
2045 update = old: old + "a";
2049 update = old: old + "b";
2053 update = old: old + "c";
2059 # If an update doesn't use the value, all previous updates are not evaluated
2060 testUpdateManyAttrsByPathLazy = {
2061 expr = updateManyAttrsByPath [
2064 update = old: old + throw "nope";
2068 update = old: "untainted";
2071 expected = "untainted";
2074 # Deeply nested attributes can be updated without affecting others
2075 testUpdateManyAttrsByPathDeep = {
2076 expr = updateManyAttrsByPath [
2078 path = [ "a" "b" "c" ];
2079 update = old: old + 1;
2097 # Nested attributes are updated first
2098 testUpdateManyAttrsByPathNestedBeforehand = {
2099 expr = updateManyAttrsByPath [
2102 update = old: old // { x = old.b; };
2106 update = old: old + 1;
2117 ## Levenshtein distance functions and co.
2118 testCommonPrefixLengthEmpty = {
2119 expr = strings.commonPrefixLength "" "hello";
2123 testCommonPrefixLengthSame = {
2124 expr = strings.commonPrefixLength "hello" "hello";
2128 testCommonPrefixLengthDiffering = {
2129 expr = strings.commonPrefixLength "hello" "hey";
2133 testCommonSuffixLengthEmpty = {
2134 expr = strings.commonSuffixLength "" "hello";
2138 testCommonSuffixLengthSame = {
2139 expr = strings.commonSuffixLength "hello" "hello";
2143 testCommonSuffixLengthDiffering = {
2144 expr = strings.commonSuffixLength "test" "rest";
2148 testLevenshteinEmpty = {
2149 expr = strings.levenshtein "" "";
2153 testLevenshteinOnlyAdd = {
2154 expr = strings.levenshtein "" "hello there";
2158 testLevenshteinOnlyRemove = {
2159 expr = strings.levenshtein "hello there" "";
2163 testLevenshteinOnlyTransform = {
2164 expr = strings.levenshtein "abcdef" "ghijkl";
2168 testLevenshteinMixed = {
2169 expr = strings.levenshtein "kitchen" "sitting";
2173 testLevenshteinAtMostZeroFalse = {
2174 expr = strings.levenshteinAtMost 0 "foo" "boo";
2178 testLevenshteinAtMostZeroTrue = {
2179 expr = strings.levenshteinAtMost 0 "foo" "foo";
2183 testLevenshteinAtMostOneFalse = {
2184 expr = strings.levenshteinAtMost 1 "car" "ct";
2188 testLevenshteinAtMostOneTrue = {
2189 expr = strings.levenshteinAtMost 1 "car" "cr";
2193 # We test levenshteinAtMost 2 particularly well because it uses a complicated
2195 testLevenshteinAtMostTwoIsEmpty = {
2196 expr = strings.levenshteinAtMost 2 "" "";
2200 testLevenshteinAtMostTwoIsZero = {
2201 expr = strings.levenshteinAtMost 2 "abcdef" "abcdef";
2205 testLevenshteinAtMostTwoIsOne = {
2206 expr = strings.levenshteinAtMost 2 "abcdef" "abddef";
2210 testLevenshteinAtMostTwoDiff0False = {
2211 expr = strings.levenshteinAtMost 2 "abcdef" "aczyef";
2215 testLevenshteinAtMostTwoDiff0Outer = {
2216 expr = strings.levenshteinAtMost 2 "abcdef" "zbcdez";
2220 testLevenshteinAtMostTwoDiff0DelLeft = {
2221 expr = strings.levenshteinAtMost 2 "abcdef" "bcdefz";
2225 testLevenshteinAtMostTwoDiff0DelRight = {
2226 expr = strings.levenshteinAtMost 2 "abcdef" "zabcde";
2230 testLevenshteinAtMostTwoDiff1False = {
2231 expr = strings.levenshteinAtMost 2 "abcdef" "bddez";
2235 testLevenshteinAtMostTwoDiff1DelLeft = {
2236 expr = strings.levenshteinAtMost 2 "abcdef" "bcdez";
2240 testLevenshteinAtMostTwoDiff1DelRight = {
2241 expr = strings.levenshteinAtMost 2 "abcdef" "zbcde";
2245 testLevenshteinAtMostTwoDiff2False = {
2246 expr = strings.levenshteinAtMost 2 "hello" "hxo";
2250 testLevenshteinAtMostTwoDiff2True = {
2251 expr = strings.levenshteinAtMost 2 "hello" "heo";
2255 testLevenshteinAtMostTwoDiff3 = {
2256 expr = strings.levenshteinAtMost 2 "hello" "ho";
2260 testLevenshteinAtMostThreeFalse = {
2261 expr = strings.levenshteinAtMost 3 "hello" "Holla!";
2265 testLevenshteinAtMostThreeTrue = {
2266 expr = strings.levenshteinAtMost 3 "hello" "Holla";
2272 testLazyDerivationIsLazyInDerivationForAttrNames = {
2273 expr = attrNames (lazyDerivation {
2274 derivation = throw "not lazy enough";
2276 # It's ok to add attribute names here when lazyDerivation is improved
2277 # in accordance with its inline comments.
2278 expected = [ "drvPath" "meta" "name" "out" "outPath" "outputName" "outputs" "system" "type" ];
2281 testLazyDerivationIsLazyInDerivationForPassthruAttr = {
2282 expr = (lazyDerivation {
2283 derivation = throw "not lazy enough";
2284 passthru.tests = "whatever is in tests";
2286 expected = "whatever is in tests";
2289 testLazyDerivationIsLazyInDerivationForPassthruAttr2 = {
2290 # passthru.tests is not a special case. It works for any attr.
2291 expr = (lazyDerivation {
2292 derivation = throw "not lazy enough";
2293 passthru.foo = "whatever is in foo";
2295 expected = "whatever is in foo";
2298 testLazyDerivationIsLazyInDerivationForMeta = {
2299 expr = (lazyDerivation {
2300 derivation = throw "not lazy enough";
2301 meta = "whatever is in meta";
2303 expected = "whatever is in meta";
2306 testLazyDerivationReturnsDerivationAttrs = let
2308 type = "derivation";
2311 outPath = "test outPath";
2313 drvPath = "test drvPath";
2315 system = "test system";
2319 expr = lazyDerivation { inherit derivation; };
2320 expected = derivation;
2323 testOptionalDrvAttr = let
2324 mkDerivation = args: derivation (args // {
2325 builder = "builder";
2327 __ignoreNulls = true;
2330 expr = (mkDerivation {
2332 x = optionalDrvAttr true 1;
2333 y = optionalDrvAttr false 1;
2335 expected = (mkDerivation {
2341 testLazyDerivationMultiOutputReturnsDerivationAttrs = let
2343 type = "derivation";
2344 outputs = ["out" "dev"];
2347 outPath = "test outPath";
2349 drvPath = "test drvPath";
2351 system = "test system";
2352 meta.position = "/hi:23";
2355 expr = lazyDerivation { inherit derivation; outputs = ["out" "dev"]; passthru.meta.position = "/hi:23"; };
2356 expected = derivation;
2359 testTypeDescriptionInt = {
2360 expr = (with types; int).description;
2361 expected = "signed integer";
2363 testTypeDescriptionIntsPositive = {
2364 expr = (with types; ints.positive).description;
2365 expected = "positive integer, meaning >0";
2367 testTypeDescriptionIntsPositiveOrEnumAuto = {
2368 expr = (with types; either ints.positive (enum ["auto"])).description;
2369 expected = ''positive integer, meaning >0, or value "auto" (singular enum)'';
2371 testTypeDescriptionListOfPositive = {
2372 expr = (with types; listOf ints.positive).description;
2373 expected = "list of (positive integer, meaning >0)";
2375 testTypeDescriptionListOfInt = {
2376 expr = (with types; listOf int).description;
2377 expected = "list of signed integer";
2379 testTypeDescriptionListOfListOfInt = {
2380 expr = (with types; listOf (listOf int)).description;
2381 expected = "list of list of signed integer";
2383 testTypeDescriptionListOfEitherStrOrBool = {
2384 expr = (with types; listOf (either str bool)).description;
2385 expected = "list of (string or boolean)";
2387 testTypeDescriptionEitherListOfStrOrBool = {
2388 expr = (with types; either (listOf bool) str).description;
2389 expected = "(list of boolean) or string";
2391 testTypeDescriptionEitherStrOrListOfBool = {
2392 expr = (with types; either str (listOf bool)).description;
2393 expected = "string or list of boolean";
2395 testTypeDescriptionOneOfListOfStrOrBool = {
2396 expr = (with types; oneOf [ (listOf bool) str ]).description;
2397 expected = "(list of boolean) or string";
2399 testTypeDescriptionOneOfListOfStrOrBoolOrNumber = {
2400 expr = (with types; oneOf [ (listOf bool) str number ]).description;
2401 expected = "(list of boolean) or string or signed integer or floating point number";
2403 testTypeDescriptionEitherListOfBoolOrEitherStringOrNumber = {
2404 expr = (with types; either (listOf bool) (either str number)).description;
2405 expected = "(list of boolean) or string or signed integer or floating point number";
2407 testTypeDescriptionEitherEitherListOfBoolOrStringOrNumber = {
2408 expr = (with types; either (either (listOf bool) str) number).description;
2409 expected = "(list of boolean) or string or signed integer or floating point number";
2411 testTypeDescriptionEitherNullOrBoolOrString = {
2412 expr = (with types; either (nullOr bool) str).description;
2413 expected = "null or boolean or string";
2415 testTypeDescriptionEitherListOfEitherBoolOrStrOrInt = {
2416 expr = (with types; either (listOf (either bool str)) int).description;
2417 expected = "(list of (boolean or string)) or signed integer";
2419 testTypeDescriptionEitherIntOrListOrEitherBoolOrStr = {
2420 expr = (with types; either int (listOf (either bool str))).description;
2421 expected = "signed integer or list of (boolean or string)";
2425 testGetExe'Output = {
2427 type = "derivation";
2428 out = "somelonghash";
2429 bin = "somelonghash";
2431 expected = "somelonghash/bin/executable";
2434 testGetExeOutput = {
2436 type = "derivation";
2437 out = "somelonghash";
2438 bin = "somelonghash";
2439 meta.mainProgram = "mainProgram";
2441 expected = "somelonghash/bin/mainProgram";
2444 testGetExe'FailureFirstArg = testingThrow (
2445 getExe' "not a derivation" "executable"
2448 testGetExe'FailureSecondArg = testingThrow (
2449 getExe' { type = "derivation"; } "dir/executable"
2452 testGetLicenseFromSpdxIdOrExamples = {
2454 (getLicenseFromSpdxIdOr "MIT" null)
2455 (getLicenseFromSpdxIdOr "mIt" null)
2456 (getLicenseFromSpdxIdOr "MY LICENSE" lib.licenses.free)
2457 (getLicenseFromSpdxIdOr "MY LICENSE" null)
2467 testGetLicenseFromSpdxIdOrThrow = testingThrow (
2468 getLicenseFromSpdxIdOr "MY LICENSE" (throw "No SPDX ID matches MY LICENSE")
2471 testPlatformMatch = {
2472 expr = meta.platformMatch { system = "x86_64-linux"; } "x86_64-linux";
2476 testPlatformMatchAttrs = {
2477 expr = meta.platformMatch (systems.elaborate "x86_64-linux") (systems.elaborate "x86_64-linux").parsed;
2481 testPlatformMatchNoMatch = {
2482 expr = meta.platformMatch { system = "x86_64-darwin"; } "x86_64-linux";
2486 testPlatformMatchMissingSystem = {
2487 expr = meta.platformMatch { } "x86_64-linux";
2491 testPackagesFromDirectoryRecursive = {
2492 expr = packagesFromDirectoryRecursive {
2493 callPackage = path: overrides: import path overrides;
2494 directory = ./packages-from-directory;
2499 # Note: Other files/directories in `./test-data/c/` are ignored and can be
2500 # used by `package.nix`.
2506 my-sub-namespace = {
2514 # Check that `packagesFromDirectoryRecursive` can process a directory with a
2515 # top-level `package.nix` file into a single package.
2516 testPackagesFromDirectoryRecursiveTopLevelPackageNix = {
2517 expr = packagesFromDirectoryRecursive {
2518 callPackage = path: overrides: import path overrides;
2519 directory = ./packages-from-directory/c;