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;
83 optionAttrSetToDocList
85 packagesFromDirectoryRecursive
109 updateManyAttrsByPath
114 testingThrow = expr: {
115 expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
116 expected = { success = false; value = false; };
118 testingEval = expr: {
119 expr = (builtins.tryEval expr).success;
123 testSanitizeDerivationName = { name, expected }:
126 name = strings.sanitizeDerivationName name;
131 # Evaluate the derivation so an invalid name would be caught
132 expr = builtins.seq drv.drvPath drv.name;
142 testFunctionArgsMakeOverridable = {
143 expr = functionArgs (makeOverridable ({ a, b, c ? null}: {}));
144 expected = { a = false; b = false; c = true; };
147 testFunctionArgsMakeOverridableOverride = {
148 expr = functionArgs (makeOverridable ({ a, b, c ? null }: {}) { a = 1; b = 2; }).override;
149 expected = { a = false; b = false; c = true; };
152 testCallPackageWithOverridePreservesArguments =
154 f = { a ? 0, b }: {};
155 f' = callPackageWith { a = 1; b = 2; } f {};
157 expr = functionArgs f'.override;
158 expected = functionArgs f;
161 testCallPackagesWithOverridePreservesArguments =
163 f = { a ? 0, b }: { nested = {}; };
164 f' = callPackagesWith { a = 1; b = 2; } f {};
166 expr = functionArgs f'.nested.override;
167 expected = functionArgs f;
184 (x: x + 2) # 2 + 2 = 4
185 (x: x * 2) # 4 * 2 = 8
196 expr = pipe [ 3 4 ] [
209 expr = or true false;
215 expr = and true false;
235 expr = fix (x: {a = if x ? a then "a" else "b";});
236 expected = {a = "a";};
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;
290 expr = toBaseDigits 2 6;
291 expected = [ 1 1 0 ];
294 testFunctionArgsFunctor = {
295 expr = functionArgs { __functor = self: { a, b }: null; };
296 expected = { a = false; b = false; };
299 testFunctionArgsSetFunctionArgs = {
300 expr = functionArgs (setFunctionArgs (args: args.x) { x = false; });
301 expected = { x = false; };
306 testConcatMapStrings = {
307 expr = concatMapStrings (x: x + ";") ["a" "b" "c"];
311 testConcatStringsSep = {
312 expr = concatStringsSep "," ["a" "b" "c"];
317 expr = concatLines ["a" "b" "c"];
318 expected = "a\nb\nc\n";
321 testMakeIncludePathWithPkgs = {
322 expr = (makeIncludePath [
323 # makeIncludePath preferably selects the "dev" output
324 { dev.outPath = "/dev"; out.outPath = "/out"; outPath = "/default"; }
325 # "out" is used if "dev" is not found
326 { out.outPath = "/out"; outPath = "/default"; }
327 # And it returns the derivation directly if there's no "out" either
328 { outPath = "/default"; }
329 # Same if the output is specified explicitly, even if there's a "dev"
330 { dev.outPath = "/dev"; outPath = "/default"; outputSpecified = true; }
332 expected = "/dev/include:/out/include:/default/include:/default/include";
335 testMakeIncludePathWithEmptyList = {
336 expr = (makeIncludePath [ ]);
340 testMakeIncludePathWithOneString = {
341 expr = (makeIncludePath [ "/usr" ]);
342 expected = "/usr/include";
345 testMakeIncludePathWithManyString = {
346 expr = (makeIncludePath [ "/usr" "/usr/local" ]);
347 expected = "/usr/include:/usr/local/include";
350 testReplicateString = {
351 expr = strings.replicate 5 "hello";
352 expected = "hellohellohellohellohello";
355 testSplitStringsSimple = {
356 expr = strings.splitString "." "a.b.c.d";
357 expected = [ "a" "b" "c" "d" ];
360 testSplitStringsEmpty = {
361 expr = strings.splitString "." "a..b";
362 expected = [ "a" "" "b" ];
365 testSplitStringsOne = {
366 expr = strings.splitString ":" "a.b";
367 expected = [ "a.b" ];
370 testSplitStringsNone = {
371 expr = strings.splitString "." "";
375 testSplitStringsFirstEmpty = {
376 expr = strings.splitString "/" "/a/b/c";
377 expected = [ "" "a" "b" "c" ];
380 testSplitStringsLastEmpty = {
381 expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:";
382 expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ];
385 testSplitStringsRegex = {
386 expr = strings.splitString "\\[{}]()^$?*+|." "A\\[{}]()^$?*+|.B";
387 expected = [ "A" "B" ];
390 testSplitStringsDerivation = {
391 expr = take 3 (strings.splitString "/" (derivation {
396 expected = ["" "nix" "store"];
399 testSplitVersionSingle = {
400 expr = versions.splitVersion "1";
404 testSplitVersionDouble = {
405 expr = versions.splitVersion "1.2";
406 expected = [ "1" "2" ];
409 testSplitVersionTriple = {
410 expr = versions.splitVersion "1.2.3";
411 expected = [ "1" "2" "3" ];
414 testPadVersionLess = {
415 expr = versions.pad 3 "1.2";
419 testPadVersionLessExtra = {
420 expr = versions.pad 3 "1.3-rc1";
421 expected = "1.3.0-rc1";
424 testPadVersionMore = {
425 expr = versions.pad 3 "1.2.3.4";
432 "${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11";
434 storePath = isStorePath goodPath;
435 storePathDerivation = isStorePath (import ../.. { system = "x86_64-linux"; }).hello;
436 storePathAppendix = isStorePath
437 "${goodPath}/bin/python";
438 nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath)));
439 asPath = isStorePath (/. + goodPath);
440 otherPath = isStorePath "/something/else";
442 attrset = isStorePath {};
443 list = isStorePath [];
444 int = isStorePath 42;
449 storePathDerivation = true;
450 storePathAppendix = false;
463 expr = escapeXML ''"test" 'test' < & >'';
464 expected = ""test" 'test' < & >";
470 STRing01 = "just a 'string'";
471 _array_ = [ "with" "more strings" ];
472 assoc."with some" = ''
478 foo = "ignored attribute";
482 __toString = _: "hello toString";
483 bar = "ignored attribute";
488 STRing01='just a '\'''string'\''''
489 declare -a _array_=('with' 'more strings')
490 declare -A assoc=(['with some']='strings
495 stringable='hello toString'
499 testHasInfixFalse = {
500 expr = hasInfix "c" "abde";
505 expr = hasInfix "c" "abcde";
509 testHasInfixDerivation = {
510 expr = hasInfix "hello" (import ../.. { system = "x86_64-linux"; }).hello;
515 expr = hasInfix "tests" ./.;
519 testHasInfixPathStoreDir = {
520 expr = hasInfix builtins.storeDir ./.;
524 testHasInfixToString = {
525 expr = hasInfix "a" { __toString = _: "a"; };
529 testRemovePrefixExample1 = {
530 expr = removePrefix "foo." "foo.bar.baz";
531 expected = "bar.baz";
533 testRemovePrefixExample2 = {
534 expr = removePrefix "xxx" "foo.bar.baz";
535 expected = "foo.bar.baz";
537 testRemovePrefixEmptyPrefix = {
538 expr = removePrefix "" "foo";
541 testRemovePrefixEmptyString = {
542 expr = removePrefix "foo" "";
545 testRemovePrefixEmptyBoth = {
546 expr = removePrefix "" "";
550 testNormalizePath = {
551 expr = strings.normalizePath "//a/b//c////d/";
552 expected = "/a/b/c/d/";
556 expr = strings.charToInt "A";
561 expr = strings.escapeC [ " " ] "Hello World";
562 expected = "Hello\\x20World";
565 testEscapeURL = testAllTrue [
566 ("" == strings.escapeURL "")
567 ("Hello" == strings.escapeURL "Hello")
568 ("Hello%20World" == strings.escapeURL "Hello World")
569 ("Hello%2FWorld" == strings.escapeURL "Hello/World")
570 ("42%25" == strings.escapeURL "42%")
571 ("%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:/@$'()*,;")
574 testToInt = testAllTrue [
579 (123 == toInt " 123")
580 (123 == toInt "123 ")
581 (123 == toInt " 123 ")
582 (123 == toInt " 123 ")
590 testToIntFails = testAllTrue [
591 ( builtins.tryEval (toInt "") == { success = false; value = false; } )
592 ( builtins.tryEval (toInt "123 123") == { success = false; value = false; } )
593 ( builtins.tryEval (toInt "0 123") == { success = false; value = false; } )
594 ( builtins.tryEval (toInt " 0d ") == { success = false; value = false; } )
595 ( builtins.tryEval (toInt " 1d ") == { success = false; value = false; } )
596 ( builtins.tryEval (toInt " d0 ") == { success = false; value = false; } )
597 ( builtins.tryEval (toInt "00") == { success = false; value = false; } )
598 ( builtins.tryEval (toInt "01") == { success = false; value = false; } )
599 ( builtins.tryEval (toInt "002") == { success = false; value = false; } )
600 ( builtins.tryEval (toInt " 002 ") == { success = false; value = false; } )
601 ( builtins.tryEval (toInt " foo ") == { success = false; value = false; } )
602 ( builtins.tryEval (toInt " foo 123 ") == { success = false; value = false; } )
603 ( builtins.tryEval (toInt " foo123 ") == { success = false; value = false; } )
606 testToIntBase10 = testAllTrue [
608 (123 == toIntBase10 "123")
609 (0 == toIntBase10 "0")
611 (123 == toIntBase10 " 123")
612 (123 == toIntBase10 "123 ")
613 (123 == toIntBase10 " 123 ")
614 (123 == toIntBase10 " 123 ")
615 (0 == toIntBase10 " 0")
616 (0 == toIntBase10 "0 ")
617 (0 == toIntBase10 " 0 ")
619 (123 == toIntBase10 "0123")
620 (123 == toIntBase10 "0000123")
621 (0 == toIntBase10 "000000")
622 # Whitespace and Zero Padding
623 (123 == toIntBase10 " 0123")
624 (123 == toIntBase10 "0123 ")
625 (123 == toIntBase10 " 0123 ")
626 (123 == toIntBase10 " 0000123")
627 (123 == toIntBase10 "0000123 ")
628 (123 == toIntBase10 " 0000123 ")
629 (0 == toIntBase10 " 000000")
630 (0 == toIntBase10 "000000 ")
631 (0 == toIntBase10 " 000000 ")
632 (-1 == toIntBase10 "-1")
633 (-1 == toIntBase10 " -1 ")
636 testToIntBase10Fails = testAllTrue [
637 ( builtins.tryEval (toIntBase10 "") == { success = false; value = false; } )
638 ( builtins.tryEval (toIntBase10 "123 123") == { success = false; value = false; } )
639 ( builtins.tryEval (toIntBase10 "0 123") == { success = false; value = false; } )
640 ( builtins.tryEval (toIntBase10 " 0d ") == { success = false; value = false; } )
641 ( builtins.tryEval (toIntBase10 " 1d ") == { success = false; value = false; } )
642 ( builtins.tryEval (toIntBase10 " d0 ") == { success = false; value = false; } )
643 ( builtins.tryEval (toIntBase10 " foo ") == { success = false; value = false; } )
644 ( builtins.tryEval (toIntBase10 " foo 123 ") == { success = false; value = false; } )
645 ( builtins.tryEval (toIntBase10 " foo 00123 ") == { success = false; value = false; } )
646 ( builtins.tryEval (toIntBase10 " foo00123 ") == { success = false; value = false; } )
652 expr = filter (x: x != "a") ["a" "b" "c" "a"];
653 expected = ["b" "c"];
656 testIfilter0Example = {
657 expr = ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ];
660 testIfilter0Empty = {
661 expr = ifilter0 (i: v: abort "shouldn't be evaluated!") [ ];
664 testIfilter0IndexOnly = {
665 expr = length (ifilter0 (i: v: mod i 2 == 0) [ (throw "0") (throw "1") (throw "2") (throw "3")]);
669 expr = ifilter0 (i: v: true) [ 10 11 12 13 14 15 ];
670 expected = [ 10 11 12 13 14 15 ];
672 testIfilter0First = {
673 expr = ifilter0 (i: v: i == 0) [ 10 11 12 13 14 15 ];
677 expr = ifilter0 (i: v: i == 5) [ 10 11 12 13 14 15 ];
683 f = op: fold: fold op 0 (range 0 100);
684 # fold with associative operator
685 assoc = f builtins.add;
686 # fold with non-associative operator
687 nonAssoc = f builtins.sub;
690 assocRight = assoc foldr;
691 # right fold with assoc operator is same as left fold
692 assocRightIsLeft = assoc foldr == assoc foldl;
693 nonAssocRight = nonAssoc foldr;
694 nonAssocLeft = nonAssoc foldl;
695 # with non-assoc operator the fold results are not the same
696 nonAssocRightIsNotLeft = nonAssoc foldl != nonAssoc foldr;
697 # fold is an alias for foldr
698 foldIsRight = nonAssoc fold == nonAssoc foldr;
702 assocRightIsLeft = true;
704 nonAssocLeft = (-5050);
705 nonAssocRightIsNotLeft = true;
711 expr = foldl' (acc: el: abort "operation not called") 0 [ ];
715 testFoldl'IntegerAdding = {
716 expr = foldl' (acc: el: acc + el) 0 [ 1 2 3 ];
720 # The accumulator isn't forced deeply
721 testFoldl'NonDeep = {
722 expr = take 3 (foldl'
723 (acc: el: [ el ] ++ acc)
724 [ (abort "unevaluated list entry") ]
726 expected = [ 3 2 1 ];
729 # Compared to builtins.foldl', lib.foldl' evaluates the first accumulator strictly too
730 testFoldl'StrictInitial = {
731 expr = (builtins.tryEval (foldl' (acc: el: el) (throw "hello") [])).success;
735 # Make sure we don't get a stack overflow for large lists
736 # This number of elements would notably cause a stack overflow if it was implemented without the `foldl'` builtin
738 expr = foldl' (acc: el: acc + el) 0 (range 0 100000);
739 expected = 5000050000;
742 testTake = testAllTrue [
743 ([] == (take 0 [ 1 2 3 ]))
744 ([1] == (take 1 [ 1 2 3 ]))
745 ([ 1 2 ] == (take 2 [ 1 2 3 ]))
746 ([ 1 2 3 ] == (take 3 [ 1 2 3 ]))
747 ([ 1 2 3 ] == (take 4 [ 1 2 3 ]))
750 testListHasPrefixExample1 = {
751 expr = lists.hasPrefix [ 1 2 ] [ 1 2 3 4 ];
754 testListHasPrefixExample2 = {
755 expr = lists.hasPrefix [ 0 1 ] [ 1 2 3 4 ];
758 testListHasPrefixLazy = {
759 expr = lists.hasPrefix [ 1 ] [ 1 (abort "lib.lists.hasPrefix is not lazy") ];
762 testListHasPrefixEmptyPrefix = {
763 expr = lists.hasPrefix [ ] [ 1 2 ];
766 testListHasPrefixEmptyList = {
767 expr = lists.hasPrefix [ 1 2 ] [ ];
771 testListRemovePrefixExample1 = {
772 expr = lists.removePrefix [ 1 2 ] [ 1 2 3 4 ];
775 testListRemovePrefixExample2 = {
776 expr = (builtins.tryEval (lists.removePrefix [ 0 1 ] [ 1 2 3 4 ])).success;
779 testListRemovePrefixEmptyPrefix = {
780 expr = lists.removePrefix [ ] [ 1 2 ];
783 testListRemovePrefixEmptyList = {
784 expr = (builtins.tryEval (lists.removePrefix [ 1 2 ] [ ])).success;
789 expr = foldAttrs (n: a: [n] ++ a) [] [
793 expected = { a = [ 2 3 ]; b = [7]; c = [8];};
796 testListCommonPrefixExample1 = {
797 expr = lists.commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ];
800 testListCommonPrefixExample2 = {
801 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ];
802 expected = [ 1 2 3 ];
804 testListCommonPrefixExample3 = {
805 expr = lists.commonPrefix [ 1 2 3 ] [ 4 5 6 ];
808 testListCommonPrefixEmpty = {
809 expr = lists.commonPrefix [ ] [ 1 2 3 ];
812 testListCommonPrefixSame = {
813 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 ];
814 expected = [ 1 2 3 ];
816 testListCommonPrefixLazy = {
817 expr = lists.commonPrefix [ 1 ] [ 1 (abort "lib.lists.commonPrefix shouldn't evaluate this")];
820 # This would stack overflow if `commonPrefix` were implemented using recursion
821 testListCommonPrefixLong =
823 longList = genList (n: n) 100000;
825 expr = lists.commonPrefix longList longList;
830 expr = sort builtins.lessThan [ 40 2 30 42 ];
831 expected = [2 30 40 42];
835 expr = sortOn stringLength [ "aa" "b" "cccc" ];
836 expected = [ "b" "aa" "cccc" ];
840 expr = sortOn (throw "nope") [ ];
844 testSortOnIncomparable = {
849 { ok = 1; f = x: x; }
850 { ok = 3; f = x: x + 3; }
851 { ok = 2; f = x: x; }
853 expected = [ 1 2 6 ];
857 expr = replicate 3 "a";
858 expected = ["a" "a" "a"];
861 testToIntShouldConvertStringToInt = {
866 testToIntShouldThrowErrorIfItCouldNotConvertToInt = {
867 expr = builtins.tryEval (toInt "\"foo\"");
868 expected = { success = false; value = false; };
871 testHasAttrByPathTrue = {
872 expr = hasAttrByPath ["a" "b"] { a = { b = "yey"; }; };
876 testHasAttrByPathFalse = {
877 expr = hasAttrByPath ["a" "b"] { a = { c = "yey"; }; };
881 testHasAttrByPathNonStrict = {
882 expr = hasAttrByPath [] (throw "do not use");
886 testLongestValidPathPrefix_empty_empty = {
887 expr = attrsets.longestValidPathPrefix [ ] { };
891 testLongestValidPathPrefix_empty_nonStrict = {
892 expr = attrsets.longestValidPathPrefix [ ] (throw "do not use");
896 testLongestValidPathPrefix_zero = {
897 expr = attrsets.longestValidPathPrefix [ "a" (throw "do not use") ] { d = null; };
901 testLongestValidPathPrefix_zero_b = {
902 expr = attrsets.longestValidPathPrefix [ "z" "z" ] "remarkably harmonious";
906 testLongestValidPathPrefix_one = {
907 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a = null; };
911 testLongestValidPathPrefix_two = {
912 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b = null; };
913 expected = [ "a" "b" ];
916 testLongestValidPathPrefix_three = {
917 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c = null; };
918 expected = [ "a" "b" "c" ];
921 testLongestValidPathPrefix_three_extra = {
922 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c.d = throw "nope"; };
923 expected = [ "a" "b" "c" ];
926 testFindFirstIndexExample1 = {
927 expr = lists.findFirstIndex (x: x > 3) (abort "index found, so a default must not be evaluated") [ 1 6 4 ];
931 testFindFirstIndexExample2 = {
932 expr = lists.findFirstIndex (x: x > 9) "a very specific default" [ 1 6 4 ];
933 expected = "a very specific default";
936 testFindFirstIndexEmpty = {
937 expr = lists.findFirstIndex (abort "when the list is empty, the predicate is not needed") null [];
941 testFindFirstIndexSingleMatch = {
942 expr = lists.findFirstIndex (x: x == 5) null [ 5 ];
946 testFindFirstIndexSingleDefault = {
947 expr = lists.findFirstIndex (x: false) null [ (abort "if the predicate doesn't access the value, it must not be evaluated") ];
951 testFindFirstIndexNone = {
952 expr = builtins.tryEval (lists.findFirstIndex (x: x == 2) null [ 1 (throw "the last element must be evaluated when there's no match") ]);
953 expected = { success = false; value = false; };
956 # Makes sure that the implementation doesn't cause a stack overflow
957 testFindFirstIndexBig = {
958 expr = lists.findFirstIndex (x: x == 1000000) null (range 0 1000000);
962 testFindFirstIndexLazy = {
963 expr = lists.findFirstIndex (x: x == 1) null [ 1 (abort "list elements after the match must not be evaluated") ];
967 testFindFirstExample1 = {
968 expr = lists.findFirst (x: x > 3) 7 [ 1 6 4 ];
972 testFindFirstExample2 = {
973 expr = lists.findFirst (x: x > 9) 7 [ 1 6 4 ];
977 testAllUnique_true = {
978 expr = allUnique [ 3 2 4 1 ];
981 testAllUnique_false = {
982 expr = allUnique [ 3 2 3 4 ];
988 testConcatMapAttrs = {
989 expr = concatMapAttrs
992 ${name + value} = value;
1008 example = foldlAttrs
1009 (acc: name: value: {
1010 sum = acc.sum + value;
1011 names = acc.names ++ [ name ];
1013 { sum = 0; names = [ ]; }
1018 # should just return the initial value
1019 emptySet = foldlAttrs (throw "function not needed") 123 { };
1020 # should just evaluate to the last value
1021 valuesNotNeeded = foldlAttrs (acc: _name: _v: acc) 3 { z = throw "value z not needed"; a = throw "value a not needed"; };
1022 # the accumulator doesnt have to be an attrset it can be as trivial as being just a number or string
1023 trivialAcc = foldlAttrs (acc: _name: v: acc * 10 + v) 1 { z = 1; a = 2; };
1028 names = [ "bar" "foo" ];
1031 valuesNotNeeded = 3;
1037 testMergeAttrsListExample1 = {
1038 expr = attrsets.mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ];
1039 expected = { a = 0; b = 1; c = 2; d = 3; };
1041 testMergeAttrsListExample2 = {
1042 expr = attrsets.mergeAttrsList [ { a = 0; } { a = 1; } ];
1043 expected = { a = 1; };
1045 testMergeAttrsListExampleMany =
1048 listToAttrs (genList (m:
1050 # Integer divide n by two to create duplicate attributes
1051 str = "halfn${toString (n / 2)}m${toString m}";
1053 nameValuePair str str
1057 expr = attrsets.mergeAttrsList list;
1058 expected = foldl' mergeAttrs { } list;
1061 # code from the example
1062 testRecursiveUpdateUntil = {
1063 expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) {
1064 # first attribute set
1069 #second attribute set
1075 foo.bar = 1; # 'foo.*' from the second set
1077 bar = 3; # 'bar' from the first set
1078 baz = 4; # 'baz' from the second set
1082 testMatchAttrsMatchingExact = {
1083 expr = matchAttrs { cpu = { bits = 64; }; } { cpu = { bits = 64; }; };
1087 testMatchAttrsMismatch = {
1088 expr = matchAttrs { cpu = { bits = 128; }; } { cpu = { bits = 64; }; };
1092 testMatchAttrsMatchingImplicit = {
1093 expr = matchAttrs { cpu = { }; } { cpu = { bits = 64; }; };
1097 testMatchAttrsMissingAttrs = {
1098 expr = matchAttrs { cpu = {}; } { };
1102 testOverrideExistingEmpty = {
1103 expr = overrideExisting {} { a = 1; };
1107 testOverrideExistingDisjoint = {
1108 expr = overrideExisting { b = 2; } { a = 1; };
1109 expected = { b = 2; };
1112 testOverrideExistingOverride = {
1113 expr = overrideExisting { a = 3; b = 2; } { a = 1; };
1114 expected = { a = 1; b = 2; };
1117 testListAttrsReverse = let
1118 exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;};
1119 exampleSingletonList = [{name="foo"; value=1;}];
1122 isReverseToListToAttrs = builtins.listToAttrs (attrsToList exampleAttrs) == exampleAttrs;
1123 isReverseToAttrsToList = attrsToList (builtins.listToAttrs exampleSingletonList) == exampleSingletonList;
1124 testDuplicatePruningBehaviour = attrsToList (builtins.listToAttrs [{name="a"; value=2;} {name="a"; value=1;}]);
1127 isReverseToAttrsToList = true;
1128 isReverseToListToAttrs = true;
1129 testDuplicatePruningBehaviour = [{name="a"; value=2;}];
1133 testAttrsToListsCanDealWithFunctions = testingEval (
1134 attrsToList { someFunc= a: a + 1;}
1138 # these tests assume attributes are converted to lists
1139 # in alphabetical order
1141 testMkKeyValueDefault = {
1142 expr = generators.mkKeyValueDefault {} ":" "f:oo" "bar";
1143 expected = ''f\:oo:bar'';
1146 testMkValueString = {
1154 # float = 42.23; # floats are strange
1157 (const (generators.mkValueStringDefault {}))
1165 # float = "42.23" true false [ "bar" ] ]'';
1170 expr = generators.toKeyValue {} {
1172 "other=key" = "baz";
1181 expr = generators.toINI {} {};
1185 testToINIEmptySection = {
1186 expr = generators.toINI {} { foo = {}; bar = {}; };
1194 testToINIDuplicateKeys = {
1195 expr = generators.toINI { listsAsDuplicateKeys = true; } { foo.bar = true; baz.qux = [ 1 false ]; };
1206 testToINIDefaultEscapes = {
1207 expr = generators.toINI {} {
1208 "no [ and ] allowed unescaped" = {
1209 "and also no = in keys" = 42;
1213 [no \[ and \] allowed unescaped]
1214 and also no \= in keys=42
1218 testToINIDefaultFull = {
1219 expr = generators.toINI {} {
1222 x = "Me-se JarJar Binx";
1223 # booleans are converted verbatim by default
1227 "he\\h=he" = "this is okay";
1232 he\h\=he=this is okay
1241 testToINIWithGlobalSectionEmpty = {
1242 expr = generators.toINIWithGlobalSection {} {
1252 testToINIWithGlobalSectionGlobalEmptyIsTheSameAsToINI =
1257 x = "Me-se JarJar Binx";
1260 "he\\h=he" = "this is okay";
1265 generators.toINIWithGlobalSection {} {
1267 sections = sections;
1269 expected = generators.toINI {} sections;
1272 testToINIWithGlobalSectionFull = {
1273 expr = generators.toINIWithGlobalSection {} {
1281 x = "Me-se JarJar Binx";
1284 "he\\h=he" = "this is okay";
1293 he\h\=he=this is okay
1302 expr = generators.toGitINI {
1304 email = "user@example.org";
1306 signingKey = "00112233445566778899AABBCCDDEEFF";
1308 gpg.program = "path-to-gpg";
1310 include.path = "~/path/to/config.inc";
1311 includeIf."gitdif:~/src/dir".path = "~/path/to/conditional.inc";
1316 subsection.value = "test";
1320 ${"\t"}boolean = true
1322 ${"\t"}name = "value"
1324 [extra "subsection"]
1325 ${"\t"}value = "test"
1328 ${"\t"}program = "path-to-gpg"
1331 ${"\t"}path = "~/path/to/config.inc"
1333 [includeIf "gitdif:~/src/dir"]
1334 ${"\t"}path = "~/path/to/conditional.inc"
1337 ${"\t"}gpgSign = true
1340 ${"\t"}email = "user@example.org"
1341 ${"\t"}name = "John Doe"
1342 ${"\t"}signingKey = "00112233445566778899AABBCCDDEEFF"
1346 # right now only invocation check
1349 foobar = [ "baz" 1 2 3 ];
1352 expr = generators.toJSON {} val;
1353 # trivial implementation
1354 expected = builtins.toJSON val;
1357 # right now only invocation check
1360 list = [ { one = 1; } { two = 2; } ];
1364 expr = generators.toYAML {} val;
1365 # trivial implementation
1366 expected = builtins.toJSON val;
1371 deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
1373 expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec {
1378 string = "fn\${o}\"r\\d";
1379 newlinestring = "\n";
1383 functionArgs = { arg ? 4, foo }: arg;
1384 list = [ 3 4 function [ false ] ];
1386 attrs = { foo = null; "foo b/ar" = "baz"; };
1394 emptystring = ''""'';
1395 string = ''"fn\''${o}\"r\\d"'';
1396 newlinestring = "\"\\n\"";
1399 function = "<function>";
1400 functionArgs = "<function, args: {arg?, foo}>";
1401 list = "[ 3 4 ${function} [ false ] ]";
1403 attrs = "{ foo = null; \"foo b/ar\" = \"baz\"; }";
1405 drv = "<derivation ${deriv.name}>";
1414 expr = generators.toPretty { } (generators.withRecursion { throwOnDepthLimit = false; depthLimit = 2; } a);
1415 expected = "{\n b = 1;\n c = {\n b = \"<unevaluated>\";\n c = {\n b = \"<unevaluated>\";\n c = \"<unevaluated>\";\n };\n };\n}";
1418 testToPrettyLimitThrow =
1423 expr = (builtins.tryEval
1424 (generators.toPretty { } (generators.withRecursion { depthLimit = 2; } a))).success;
1428 testWithRecursionDealsWithFunctors =
1431 __functor = self: { a, b, }: null;
1439 expr = generators.toPretty { } (generators.withRecursion { depthLimit = 1; throwOnDepthLimit = false; } a);
1440 expected = "{\n b = <function, args: {a, b}>;\n c = {\n d = \"<unevaluated>\";\n };\n value = \"<unevaluated>\";\n}";
1443 testToPrettyMultiline = {
1444 expr = mapAttrs (const (generators.toPretty { })) {
1445 list = [ 3 4 [ false ] ];
1446 attrs = { foo = null; bar.foo = "baz"; };
1447 newlinestring = "\n";
1448 multilinestring = ''
1453 multilinestring' = ''
1474 newlinestring = "''\n \n''";
1475 multilinestring = ''
1481 multilinestring' = ''
1490 testToPrettyAllowPrettyValues = {
1491 expr = generators.toPretty { allowPrettyValues = true; }
1492 { __pretty = v: "«" + v + "»"; val = "foo"; };
1493 expected = "«foo»";
1497 expr = mapAttrs (const (generators.toPlist { })) {
1504 string = "fn\${o}\"r\\d";
1505 newlinestring = "\n";
1508 list = [ 3 4 "test" ];
1510 attrs = { foo = null; "foo b/ar" = "baz"; };
1515 expected = { value = builtins.readFile ./test-to-plist-expected.plist; };
1518 testToLuaEmptyAttrSet = {
1519 expr = generators.toLua {} {};
1523 testToLuaEmptyList = {
1524 expr = generators.toLua {} [];
1528 testToLuaListOfVariousTypes = {
1529 expr = generators.toLua {} [ null 43 3.14159 true ];
1540 expr = generators.toLua {} ''double-quote (") and single quotes (')'';
1541 expected = ''"double-quote (\") and single quotes (')"'';
1544 testToLuaAttrsetWithLuaInline = {
1545 expr = generators.toLua {} { x = generators.mkLuaInline ''"abc" .. "def"''; };
1548 ["x"] = ("abc" .. "def")
1552 testToLuaAttrsetWithSpaceInKey = {
1553 expr = generators.toLua {} { "some space and double-quote (\")" = 42; };
1556 ["some space and double-quote (\")"] = 42
1560 testToLuaWithoutMultiline = {
1561 expr = generators.toLua { multiline = false; } [ 41 43 ];
1562 expected = ''{ 41, 43 }'';
1565 testToLuaEmptyBindings = {
1566 expr = generators.toLua { asBindings = true; } {};
1570 testToLuaBindings = {
1571 expr = generators.toLua { asBindings = true; } { x1 = 41; _y = { a = 43; }; };
1580 testToLuaPartialTableBindings = {
1581 expr = generators.toLua { asBindings = true; } { "x.y" = 42; };
1587 testToLuaIndentedBindings = {
1588 expr = generators.toLua { asBindings = true; indent = " "; } { x = { y = 42; }; };
1589 expected = " x = {\n [\"y\"] = 42\n }\n";
1592 testToLuaBindingsWithSpace = testingThrow (
1593 generators.toLua { asBindings = true; } { "with space" = 42; }
1596 testToLuaBindingsWithLeadingDigit = testingThrow (
1597 generators.toLua { asBindings = true; } { "11eleven" = 42; }
1600 testToLuaBasicExample = {
1601 expr = generators.toLua {} {
1602 cmd = [ "typescript-language-server" "--stdio" ];
1603 settings.workspace.library = generators.mkLuaInline ''vim.api.nvim_get_runtime_file("", true)'';
1608 "typescript-language-server",
1613 ["library"] = (vim.api.nvim_get_runtime_file("", true))
1621 testToGNUCommandLine = {
1622 expr = cli.toGNUCommandLine {} {
1623 data = builtins.toJSON { id = 0; };
1627 url = [ "https://example.com/foo" "https://example.com/bar" ];
1634 "--data" "{\"id\":0}"
1636 "--url" "https://example.com/foo"
1637 "--url" "https://example.com/bar"
1642 testToGNUCommandLineShell = {
1643 expr = cli.toGNUCommandLineShell {} {
1644 data = builtins.toJSON { id = 0; };
1648 url = [ "https://example.com/foo" "https://example.com/bar" ];
1653 expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
1656 testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName {
1661 testSanitizeDerivationNameUnicode = testSanitizeDerivationName {
1666 testSanitizeDerivationNameAscii = testSanitizeDerivationName {
1667 name = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
1668 expected = "-+--.-0123456789-=-?-ABCDEFGHIJKLMNOPQRSTUVWXYZ-_-abcdefghijklmnopqrstuvwxyz-";
1671 testSanitizeDerivationNameTooLong = testSanitizeDerivationName {
1672 name = "This string is loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1673 expected = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1676 testSanitizeDerivationNameTooLongWithInvalid = testSanitizeDerivationName {
1677 name = "Hello there aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&&&&&&&";
1678 expected = "there-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-";
1681 testSanitizeDerivationNameEmpty = testSanitizeDerivationName {
1683 expected = "unknown";
1686 testFreeformOptions = {
1689 submodule = { lib, ... }: {
1690 freeformType = lib.types.attrsOf (lib.types.submodule {
1691 options.bar = lib.mkOption {};
1693 options.bar = lib.mkOption {};
1696 module = { lib, ... }: {
1697 options.foo = lib.mkOption {
1698 type = lib.types.submodule submodule;
1702 options = (evalModules {
1703 modules = [ module ];
1706 locs = filter (o: ! o.internal) (optionAttrSetToDocList options);
1707 in map (o: o.loc) locs;
1708 expected = [ [ "_module" "args" ] [ "foo" ] [ "foo" "<name>" "bar" ] [ "foo" "bar" ] ];
1711 testCartesianProductOfEmptySet = {
1712 expr = cartesianProduct {};
1716 testCartesianProductOfOneSet = {
1717 expr = cartesianProduct { a = [ 1 2 3 ]; };
1718 expected = [ { a = 1; } { a = 2; } { a = 3; } ];
1721 testCartesianProductOfTwoSets = {
1722 expr = cartesianProduct { a = [ 1 ]; b = [ 10 20 ]; };
1729 testCartesianProductOfTwoSetsWithOneEmpty = {
1730 expr = cartesianProduct { a = [ ]; b = [ 10 20 ]; };
1734 testCartesianProductOfThreeSets = {
1735 expr = cartesianProduct {
1738 c = [ 100 200 300 ];
1741 { a = 1; b = 10; c = 100; }
1742 { a = 1; b = 10; c = 200; }
1743 { a = 1; b = 10; c = 300; }
1745 { a = 1; b = 20; c = 100; }
1746 { a = 1; b = 20; c = 200; }
1747 { a = 1; b = 20; c = 300; }
1749 { a = 1; b = 30; c = 100; }
1750 { a = 1; b = 30; c = 200; }
1751 { a = 1; b = 30; c = 300; }
1753 { a = 2; b = 10; c = 100; }
1754 { a = 2; b = 10; c = 200; }
1755 { a = 2; b = 10; c = 300; }
1757 { a = 2; b = 20; c = 100; }
1758 { a = 2; b = 20; c = 200; }
1759 { a = 2; b = 20; c = 300; }
1761 { a = 2; b = 30; c = 100; }
1762 { a = 2; b = 30; c = 200; }
1763 { a = 2; b = 30; c = 300; }
1765 { a = 3; b = 10; c = 100; }
1766 { a = 3; b = 10; c = 200; }
1767 { a = 3; b = 10; c = 300; }
1769 { a = 3; b = 20; c = 100; }
1770 { a = 3; b = 20; c = 200; }
1771 { a = 3; b = 20; c = 300; }
1773 { a = 3; b = 30; c = 100; }
1774 { a = 3; b = 30; c = 200; }
1775 { a = 3; b = 30; c = 300; }
1779 testMapCartesianProductOfOneSet = {
1780 expr = mapCartesianProduct ({a}: a * 2) { a = [ 1 2 3 ]; };
1781 expected = [ 2 4 6 ];
1784 testMapCartesianProductOfTwoSets = {
1785 expr = mapCartesianProduct ({a,b}: a + b) { a = [ 1 ]; b = [ 10 20 ]; };
1786 expected = [ 11 21 ];
1789 testMapCartesianProcutOfTwoSetsWithOneEmpty = {
1790 expr = mapCartesianProduct (x: x.a + x.b) { a = [ ]; b = [ 10 20 ]; };
1794 testMapCartesianProductOfThreeSets = {
1795 expr = mapCartesianProduct ({a,b,c}: a + b + c) {
1798 c = [ 100 200 300 ];
1800 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 ];
1803 # The example from the showAttrPath documentation
1804 testShowAttrPathExample = {
1805 expr = showAttrPath [ "foo" "10" "bar" ];
1806 expected = "foo.\"10\".bar";
1809 testShowAttrPathEmpty = {
1810 expr = showAttrPath [];
1811 expected = "<root attribute path>";
1814 testShowAttrPathVarious = {
1815 expr = showAttrPath [
1822 expected = ''".".foo."2".a2-b._bc'de'';
1826 expr = groupBy (n: toString (mod n 5)) (range 0 16);
1828 "0" = [ 0 5 10 15 ];
1829 "1" = [ 1 6 11 16 ];
1837 expr = groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ];
1838 expected = { false = 3; true = 12; };
1841 # The example from the updateManyAttrsByPath documentation
1842 testUpdateManyAttrsByPathExample = {
1843 expr = updateManyAttrsByPath [
1846 update = old: { d = old.c; };
1849 path = [ "a" "b" "c" ];
1850 update = old: old + 1;
1857 expected = { a = { b = { d = 1; }; }; x = { y = "xy"; }; };
1860 # If there are no updates, the value is passed through
1861 testUpdateManyAttrsByPathNone = {
1862 expr = updateManyAttrsByPath [] "something";
1863 expected = "something";
1866 # A single update to the root path is just like applying the function directly
1867 testUpdateManyAttrsByPathSingleIncrement = {
1868 expr = updateManyAttrsByPath [
1871 update = old: old + 1;
1877 # Multiple updates can be applied are done in order
1878 testUpdateManyAttrsByPathMultipleIncrements = {
1879 expr = updateManyAttrsByPath [
1882 update = old: old + "a";
1886 update = old: old + "b";
1890 update = old: old + "c";
1896 # If an update doesn't use the value, all previous updates are not evaluated
1897 testUpdateManyAttrsByPathLazy = {
1898 expr = updateManyAttrsByPath [
1901 update = old: old + throw "nope";
1905 update = old: "untainted";
1908 expected = "untainted";
1911 # Deeply nested attributes can be updated without affecting others
1912 testUpdateManyAttrsByPathDeep = {
1913 expr = updateManyAttrsByPath [
1915 path = [ "a" "b" "c" ];
1916 update = old: old + 1;
1934 # Nested attributes are updated first
1935 testUpdateManyAttrsByPathNestedBeforehand = {
1936 expr = updateManyAttrsByPath [
1939 update = old: old // { x = old.b; };
1943 update = old: old + 1;
1954 ## Levenshtein distance functions and co.
1955 testCommonPrefixLengthEmpty = {
1956 expr = strings.commonPrefixLength "" "hello";
1960 testCommonPrefixLengthSame = {
1961 expr = strings.commonPrefixLength "hello" "hello";
1965 testCommonPrefixLengthDiffering = {
1966 expr = strings.commonPrefixLength "hello" "hey";
1970 testCommonSuffixLengthEmpty = {
1971 expr = strings.commonSuffixLength "" "hello";
1975 testCommonSuffixLengthSame = {
1976 expr = strings.commonSuffixLength "hello" "hello";
1980 testCommonSuffixLengthDiffering = {
1981 expr = strings.commonSuffixLength "test" "rest";
1985 testLevenshteinEmpty = {
1986 expr = strings.levenshtein "" "";
1990 testLevenshteinOnlyAdd = {
1991 expr = strings.levenshtein "" "hello there";
1995 testLevenshteinOnlyRemove = {
1996 expr = strings.levenshtein "hello there" "";
2000 testLevenshteinOnlyTransform = {
2001 expr = strings.levenshtein "abcdef" "ghijkl";
2005 testLevenshteinMixed = {
2006 expr = strings.levenshtein "kitchen" "sitting";
2010 testLevenshteinAtMostZeroFalse = {
2011 expr = strings.levenshteinAtMost 0 "foo" "boo";
2015 testLevenshteinAtMostZeroTrue = {
2016 expr = strings.levenshteinAtMost 0 "foo" "foo";
2020 testLevenshteinAtMostOneFalse = {
2021 expr = strings.levenshteinAtMost 1 "car" "ct";
2025 testLevenshteinAtMostOneTrue = {
2026 expr = strings.levenshteinAtMost 1 "car" "cr";
2030 # We test levenshteinAtMost 2 particularly well because it uses a complicated
2032 testLevenshteinAtMostTwoIsEmpty = {
2033 expr = strings.levenshteinAtMost 2 "" "";
2037 testLevenshteinAtMostTwoIsZero = {
2038 expr = strings.levenshteinAtMost 2 "abcdef" "abcdef";
2042 testLevenshteinAtMostTwoIsOne = {
2043 expr = strings.levenshteinAtMost 2 "abcdef" "abddef";
2047 testLevenshteinAtMostTwoDiff0False = {
2048 expr = strings.levenshteinAtMost 2 "abcdef" "aczyef";
2052 testLevenshteinAtMostTwoDiff0Outer = {
2053 expr = strings.levenshteinAtMost 2 "abcdef" "zbcdez";
2057 testLevenshteinAtMostTwoDiff0DelLeft = {
2058 expr = strings.levenshteinAtMost 2 "abcdef" "bcdefz";
2062 testLevenshteinAtMostTwoDiff0DelRight = {
2063 expr = strings.levenshteinAtMost 2 "abcdef" "zabcde";
2067 testLevenshteinAtMostTwoDiff1False = {
2068 expr = strings.levenshteinAtMost 2 "abcdef" "bddez";
2072 testLevenshteinAtMostTwoDiff1DelLeft = {
2073 expr = strings.levenshteinAtMost 2 "abcdef" "bcdez";
2077 testLevenshteinAtMostTwoDiff1DelRight = {
2078 expr = strings.levenshteinAtMost 2 "abcdef" "zbcde";
2082 testLevenshteinAtMostTwoDiff2False = {
2083 expr = strings.levenshteinAtMost 2 "hello" "hxo";
2087 testLevenshteinAtMostTwoDiff2True = {
2088 expr = strings.levenshteinAtMost 2 "hello" "heo";
2092 testLevenshteinAtMostTwoDiff3 = {
2093 expr = strings.levenshteinAtMost 2 "hello" "ho";
2097 testLevenshteinAtMostThreeFalse = {
2098 expr = strings.levenshteinAtMost 3 "hello" "Holla!";
2102 testLevenshteinAtMostThreeTrue = {
2103 expr = strings.levenshteinAtMost 3 "hello" "Holla";
2109 testLazyDerivationIsLazyInDerivationForAttrNames = {
2110 expr = attrNames (lazyDerivation {
2111 derivation = throw "not lazy enough";
2113 # It's ok to add attribute names here when lazyDerivation is improved
2114 # in accordance with its inline comments.
2115 expected = [ "drvPath" "meta" "name" "out" "outPath" "outputName" "outputs" "system" "type" ];
2118 testLazyDerivationIsLazyInDerivationForPassthruAttr = {
2119 expr = (lazyDerivation {
2120 derivation = throw "not lazy enough";
2121 passthru.tests = "whatever is in tests";
2123 expected = "whatever is in tests";
2126 testLazyDerivationIsLazyInDerivationForPassthruAttr2 = {
2127 # passthru.tests is not a special case. It works for any attr.
2128 expr = (lazyDerivation {
2129 derivation = throw "not lazy enough";
2130 passthru.foo = "whatever is in foo";
2132 expected = "whatever is in foo";
2135 testLazyDerivationIsLazyInDerivationForMeta = {
2136 expr = (lazyDerivation {
2137 derivation = throw "not lazy enough";
2138 meta = "whatever is in meta";
2140 expected = "whatever is in meta";
2143 testLazyDerivationReturnsDerivationAttrs = let
2145 type = "derivation";
2148 outPath = "test outPath";
2150 drvPath = "test drvPath";
2152 system = "test system";
2156 expr = lazyDerivation { inherit derivation; };
2157 expected = derivation;
2160 testOptionalDrvAttr = let
2161 mkDerivation = args: derivation (args // {
2162 builder = "builder";
2164 __ignoreNulls = true;
2167 expr = (mkDerivation {
2169 x = optionalDrvAttr true 1;
2170 y = optionalDrvAttr false 1;
2172 expected = (mkDerivation {
2178 testLazyDerivationMultiOutputReturnsDerivationAttrs = let
2180 type = "derivation";
2181 outputs = ["out" "dev"];
2184 outPath = "test outPath";
2186 drvPath = "test drvPath";
2188 system = "test system";
2189 meta.position = "/hi:23";
2192 expr = lazyDerivation { inherit derivation; outputs = ["out" "dev"]; passthru.meta.position = "/hi:23"; };
2193 expected = derivation;
2196 testTypeDescriptionInt = {
2197 expr = (with types; int).description;
2198 expected = "signed integer";
2200 testTypeDescriptionIntsPositive = {
2201 expr = (with types; ints.positive).description;
2202 expected = "positive integer, meaning >0";
2204 testTypeDescriptionIntsPositiveOrEnumAuto = {
2205 expr = (with types; either ints.positive (enum ["auto"])).description;
2206 expected = ''positive integer, meaning >0, or value "auto" (singular enum)'';
2208 testTypeDescriptionListOfPositive = {
2209 expr = (with types; listOf ints.positive).description;
2210 expected = "list of (positive integer, meaning >0)";
2212 testTypeDescriptionListOfInt = {
2213 expr = (with types; listOf int).description;
2214 expected = "list of signed integer";
2216 testTypeDescriptionListOfListOfInt = {
2217 expr = (with types; listOf (listOf int)).description;
2218 expected = "list of list of signed integer";
2220 testTypeDescriptionListOfEitherStrOrBool = {
2221 expr = (with types; listOf (either str bool)).description;
2222 expected = "list of (string or boolean)";
2224 testTypeDescriptionEitherListOfStrOrBool = {
2225 expr = (with types; either (listOf bool) str).description;
2226 expected = "(list of boolean) or string";
2228 testTypeDescriptionEitherStrOrListOfBool = {
2229 expr = (with types; either str (listOf bool)).description;
2230 expected = "string or list of boolean";
2232 testTypeDescriptionOneOfListOfStrOrBool = {
2233 expr = (with types; oneOf [ (listOf bool) str ]).description;
2234 expected = "(list of boolean) or string";
2236 testTypeDescriptionOneOfListOfStrOrBoolOrNumber = {
2237 expr = (with types; oneOf [ (listOf bool) str number ]).description;
2238 expected = "(list of boolean) or string or signed integer or floating point number";
2240 testTypeDescriptionEitherListOfBoolOrEitherStringOrNumber = {
2241 expr = (with types; either (listOf bool) (either str number)).description;
2242 expected = "(list of boolean) or string or signed integer or floating point number";
2244 testTypeDescriptionEitherEitherListOfBoolOrStringOrNumber = {
2245 expr = (with types; either (either (listOf bool) str) number).description;
2246 expected = "(list of boolean) or string or signed integer or floating point number";
2248 testTypeDescriptionEitherNullOrBoolOrString = {
2249 expr = (with types; either (nullOr bool) str).description;
2250 expected = "null or boolean or string";
2252 testTypeDescriptionEitherListOfEitherBoolOrStrOrInt = {
2253 expr = (with types; either (listOf (either bool str)) int).description;
2254 expected = "(list of (boolean or string)) or signed integer";
2256 testTypeDescriptionEitherIntOrListOrEitherBoolOrStr = {
2257 expr = (with types; either int (listOf (either bool str))).description;
2258 expected = "signed integer or list of (boolean or string)";
2262 testGetExe'Output = {
2264 type = "derivation";
2265 out = "somelonghash";
2266 bin = "somelonghash";
2268 expected = "somelonghash/bin/executable";
2271 testGetExeOutput = {
2273 type = "derivation";
2274 out = "somelonghash";
2275 bin = "somelonghash";
2276 meta.mainProgram = "mainProgram";
2278 expected = "somelonghash/bin/mainProgram";
2281 testGetExe'FailureFirstArg = testingThrow (
2282 getExe' "not a derivation" "executable"
2285 testGetExe'FailureSecondArg = testingThrow (
2286 getExe' { type = "derivation"; } "dir/executable"
2289 testPlatformMatch = {
2290 expr = meta.platformMatch { system = "x86_64-linux"; } "x86_64-linux";
2294 testPlatformMatchAttrs = {
2295 expr = meta.platformMatch (systems.elaborate "x86_64-linux") (systems.elaborate "x86_64-linux").parsed;
2299 testPlatformMatchNoMatch = {
2300 expr = meta.platformMatch { system = "x86_64-darwin"; } "x86_64-linux";
2304 testPlatformMatchMissingSystem = {
2305 expr = meta.platformMatch { } "x86_64-linux";
2309 testPackagesFromDirectoryRecursive = {
2310 expr = packagesFromDirectoryRecursive {
2311 callPackage = path: overrides: import path overrides;
2312 directory = ./packages-from-directory;
2317 # Note: Other files/directories in `./test-data/c/` are ignored and can be
2318 # used by `package.nix`.
2324 my-sub-namespace = {
2332 # Check that `packagesFromDirectoryRecursive` can process a directory with a
2333 # top-level `package.nix` file into a single package.
2334 testPackagesFromDirectoryRecursiveTopLevelPackageNix = {
2335 expr = packagesFromDirectoryRecursive {
2336 callPackage = path: overrides: import path overrides;
2337 directory = ./packages-from-directory/c;