2 Nix evaluation tests for various lib functions.
4 Since these tests are implemented with Nix evaluation, error checking is limited to what `builtins.tryEval` can detect, which is `throw`'s and `abort`'s, without error messages.
5 If you need to test error messages or more complex evaluations, see ./modules.sh, ./sources.sh or ./filesystem.sh as examples.
9 [nixpkgs]$ nix-instantiate --eval --strict lib/tests/misc.nix
11 If the resulting list is empty, all tests passed.
12 Alternatively, to run all `lib` tests:
14 [nixpkgs]$ nix-build lib/tests/release.nix
18 lib = import ../default.nix;
32 cartesianProductOfSets
76 optionAttrSetToDocList
78 packagesFromDirectoryRecursive
102 updateManyAttrsByPath
106 testingThrow = expr: {
107 expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
108 expected = { success = false; value = false; };
110 testingEval = expr: {
111 expr = (builtins.tryEval expr).success;
114 testingDeepThrow = expr: testingThrow (builtins.deepSeq expr expr);
116 testSanitizeDerivationName = { name, expected }:
119 name = strings.sanitizeDerivationName name;
124 # Evaluate the derivation so an invalid name would be caught
125 expr = builtins.seq drv.drvPath drv.name;
135 testFunctionArgsMakeOverridable = {
136 expr = functionArgs (makeOverridable ({ a, b, c ? null}: {}));
137 expected = { a = false; b = false; c = true; };
140 testFunctionArgsMakeOverridableOverride = {
141 expr = functionArgs (makeOverridable ({ a, b, c ? null }: {}) { a = 1; b = 2; }).override;
142 expected = { a = false; b = false; c = true; };
145 testCallPackageWithOverridePreservesArguments =
147 f = { a ? 0, b }: {};
148 f' = callPackageWith { a = 1; b = 2; } f {};
150 expr = functionArgs f'.override;
151 expected = functionArgs f;
154 testCallPackagesWithOverridePreservesArguments =
156 f = { a ? 0, b }: { nested = {}; };
157 f' = callPackagesWith { a = 1; b = 2; } f {};
159 expr = functionArgs f'.nested.override;
160 expected = functionArgs f;
177 (x: x + 2) # 2 + 2 = 4
178 (x: x * 2) # 4 * 2 = 8
189 expr = pipe [ 3 4 ] [
202 expr = or true false;
208 expr = and true false;
213 expr = fix (x: {a = if x ? a then "a" else "b";});
214 expected = {a = "a";};
217 testComposeExtensions = {
218 expr = let obj = makeExtensible (self: { foo = self.bar; });
219 f = self: super: { bar = false; baz = true; };
220 g = self: super: { bar = super.baz or false; };
221 f_o_g = composeExtensions f g;
222 composed = obj.extend f_o_g;
227 testComposeManyExtensions0 = {
228 expr = let obj = makeExtensible (self: { foo = true; });
229 emptyComposition = composeManyExtensions [];
230 composed = obj.extend emptyComposition;
235 testComposeManyExtensions =
236 let f = self: super: { bar = false; baz = true; };
237 g = self: super: { bar = super.baz or false; };
238 h = self: super: { qux = super.bar or false; };
239 obj = makeExtensible (self: { foo = self.qux; });
241 expr = let composition = composeManyExtensions [f g h];
242 composed = obj.extend composition;
244 expected = (obj.extend (composeExtensions f (composeExtensions g h))).foo;
248 expr = (bitAnd 3 10);
258 expr = (bitXor 3 10);
263 expr = toHexString 250;
268 expr = toBaseDigits 2 6;
269 expected = [ 1 1 0 ];
272 testFunctionArgsFunctor = {
273 expr = functionArgs { __functor = self: { a, b }: null; };
274 expected = { a = false; b = false; };
277 testFunctionArgsSetFunctionArgs = {
278 expr = functionArgs (setFunctionArgs (args: args.x) { x = false; });
279 expected = { x = false; };
284 testConcatMapStrings = {
285 expr = concatMapStrings (x: x + ";") ["a" "b" "c"];
289 testConcatStringsSep = {
290 expr = concatStringsSep "," ["a" "b" "c"];
295 expr = concatLines ["a" "b" "c"];
296 expected = "a\nb\nc\n";
299 testReplicateString = {
300 expr = strings.replicate 5 "hello";
301 expected = "hellohellohellohellohello";
304 testSplitStringsSimple = {
305 expr = strings.splitString "." "a.b.c.d";
306 expected = [ "a" "b" "c" "d" ];
309 testSplitStringsEmpty = {
310 expr = strings.splitString "." "a..b";
311 expected = [ "a" "" "b" ];
314 testSplitStringsOne = {
315 expr = strings.splitString ":" "a.b";
316 expected = [ "a.b" ];
319 testSplitStringsNone = {
320 expr = strings.splitString "." "";
324 testSplitStringsFirstEmpty = {
325 expr = strings.splitString "/" "/a/b/c";
326 expected = [ "" "a" "b" "c" ];
329 testSplitStringsLastEmpty = {
330 expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:";
331 expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ];
334 testSplitStringsRegex = {
335 expr = strings.splitString "\\[{}]()^$?*+|." "A\\[{}]()^$?*+|.B";
336 expected = [ "A" "B" ];
339 testSplitStringsDerivation = {
340 expr = take 3 (strings.splitString "/" (derivation {
345 expected = ["" "nix" "store"];
348 testSplitVersionSingle = {
349 expr = versions.splitVersion "1";
353 testSplitVersionDouble = {
354 expr = versions.splitVersion "1.2";
355 expected = [ "1" "2" ];
358 testSplitVersionTriple = {
359 expr = versions.splitVersion "1.2.3";
360 expected = [ "1" "2" "3" ];
363 testPadVersionLess = {
364 expr = versions.pad 3 "1.2";
368 testPadVersionLessExtra = {
369 expr = versions.pad 3 "1.3-rc1";
370 expected = "1.3.0-rc1";
373 testPadVersionMore = {
374 expr = versions.pad 3 "1.2.3.4";
381 "${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11";
383 storePath = isStorePath goodPath;
384 storePathDerivation = isStorePath (import ../.. { system = "x86_64-linux"; }).hello;
385 storePathAppendix = isStorePath
386 "${goodPath}/bin/python";
387 nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath)));
388 asPath = isStorePath (/. + goodPath);
389 otherPath = isStorePath "/something/else";
391 attrset = isStorePath {};
392 list = isStorePath [];
393 int = isStorePath 42;
398 storePathDerivation = true;
399 storePathAppendix = false;
412 expr = escapeXML ''"test" 'test' < & >'';
413 expected = ""test" 'test' < & >";
419 STRing01 = "just a 'string'";
420 _array_ = [ "with" "more strings" ];
421 assoc."with some" = ''
427 foo = "ignored attribute";
431 __toString = _: "hello toString";
432 bar = "ignored attribute";
437 STRing01='just a '\'''string'\''''
438 declare -a _array_=('with' 'more strings')
439 declare -A assoc=(['with some']='strings
444 stringable='hello toString'
448 testHasInfixFalse = {
449 expr = hasInfix "c" "abde";
454 expr = hasInfix "c" "abcde";
458 testHasInfixDerivation = {
459 expr = hasInfix "hello" (import ../.. { system = "x86_64-linux"; }).hello;
464 expr = hasInfix "tests" ./.;
468 testHasInfixPathStoreDir = {
469 expr = hasInfix builtins.storeDir ./.;
473 testHasInfixToString = {
474 expr = hasInfix "a" { __toString = _: "a"; };
478 testRemovePrefixExample1 = {
479 expr = removePrefix "foo." "foo.bar.baz";
480 expected = "bar.baz";
482 testRemovePrefixExample2 = {
483 expr = removePrefix "xxx" "foo.bar.baz";
484 expected = "foo.bar.baz";
486 testRemovePrefixEmptyPrefix = {
487 expr = removePrefix "" "foo";
490 testRemovePrefixEmptyString = {
491 expr = removePrefix "foo" "";
494 testRemovePrefixEmptyBoth = {
495 expr = removePrefix "" "";
499 testNormalizePath = {
500 expr = strings.normalizePath "//a/b//c////d/";
501 expected = "/a/b/c/d/";
505 expr = strings.charToInt "A";
510 expr = strings.escapeC [ " " ] "Hello World";
511 expected = "Hello\\x20World";
514 testEscapeURL = testAllTrue [
515 ("" == strings.escapeURL "")
516 ("Hello" == strings.escapeURL "Hello")
517 ("Hello%20World" == strings.escapeURL "Hello World")
518 ("Hello%2FWorld" == strings.escapeURL "Hello/World")
519 ("42%25" == strings.escapeURL "42%")
520 ("%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:/@$'()*,;")
523 testToInt = testAllTrue [
528 (123 == toInt " 123")
529 (123 == toInt "123 ")
530 (123 == toInt " 123 ")
531 (123 == toInt " 123 ")
539 testToIntFails = testAllTrue [
540 ( builtins.tryEval (toInt "") == { success = false; value = false; } )
541 ( builtins.tryEval (toInt "123 123") == { success = false; value = false; } )
542 ( builtins.tryEval (toInt "0 123") == { success = false; value = false; } )
543 ( builtins.tryEval (toInt " 0d ") == { success = false; value = false; } )
544 ( builtins.tryEval (toInt " 1d ") == { success = false; value = false; } )
545 ( builtins.tryEval (toInt " d0 ") == { success = false; value = false; } )
546 ( builtins.tryEval (toInt "00") == { success = false; value = false; } )
547 ( builtins.tryEval (toInt "01") == { success = false; value = false; } )
548 ( builtins.tryEval (toInt "002") == { success = false; value = false; } )
549 ( builtins.tryEval (toInt " 002 ") == { success = false; value = false; } )
550 ( builtins.tryEval (toInt " foo ") == { success = false; value = false; } )
551 ( builtins.tryEval (toInt " foo 123 ") == { success = false; value = false; } )
552 ( builtins.tryEval (toInt " foo123 ") == { success = false; value = false; } )
555 testToIntBase10 = testAllTrue [
557 (123 == toIntBase10 "123")
558 (0 == toIntBase10 "0")
560 (123 == toIntBase10 " 123")
561 (123 == toIntBase10 "123 ")
562 (123 == toIntBase10 " 123 ")
563 (123 == toIntBase10 " 123 ")
564 (0 == toIntBase10 " 0")
565 (0 == toIntBase10 "0 ")
566 (0 == toIntBase10 " 0 ")
568 (123 == toIntBase10 "0123")
569 (123 == toIntBase10 "0000123")
570 (0 == toIntBase10 "000000")
571 # Whitespace and Zero Padding
572 (123 == toIntBase10 " 0123")
573 (123 == toIntBase10 "0123 ")
574 (123 == toIntBase10 " 0123 ")
575 (123 == toIntBase10 " 0000123")
576 (123 == toIntBase10 "0000123 ")
577 (123 == toIntBase10 " 0000123 ")
578 (0 == toIntBase10 " 000000")
579 (0 == toIntBase10 "000000 ")
580 (0 == toIntBase10 " 000000 ")
581 (-1 == toIntBase10 "-1")
582 (-1 == toIntBase10 " -1 ")
585 testToIntBase10Fails = testAllTrue [
586 ( builtins.tryEval (toIntBase10 "") == { success = false; value = false; } )
587 ( builtins.tryEval (toIntBase10 "123 123") == { success = false; value = false; } )
588 ( builtins.tryEval (toIntBase10 "0 123") == { success = false; value = false; } )
589 ( builtins.tryEval (toIntBase10 " 0d ") == { success = false; value = false; } )
590 ( builtins.tryEval (toIntBase10 " 1d ") == { success = false; value = false; } )
591 ( builtins.tryEval (toIntBase10 " d0 ") == { success = false; value = false; } )
592 ( builtins.tryEval (toIntBase10 " foo ") == { success = false; value = false; } )
593 ( builtins.tryEval (toIntBase10 " foo 123 ") == { success = false; value = false; } )
594 ( builtins.tryEval (toIntBase10 " foo 00123 ") == { success = false; value = false; } )
595 ( builtins.tryEval (toIntBase10 " foo00123 ") == { success = false; value = false; } )
601 expr = filter (x: x != "a") ["a" "b" "c" "a"];
602 expected = ["b" "c"];
607 f = op: fold: fold op 0 (range 0 100);
608 # fold with associative operator
609 assoc = f builtins.add;
610 # fold with non-associative operator
611 nonAssoc = f builtins.sub;
614 assocRight = assoc foldr;
615 # right fold with assoc operator is same as left fold
616 assocRightIsLeft = assoc foldr == assoc foldl;
617 nonAssocRight = nonAssoc foldr;
618 nonAssocLeft = nonAssoc foldl;
619 # with non-assoc operator the fold results are not the same
620 nonAssocRightIsNotLeft = nonAssoc foldl != nonAssoc foldr;
621 # fold is an alias for foldr
622 foldIsRight = nonAssoc fold == nonAssoc foldr;
626 assocRightIsLeft = true;
628 nonAssocLeft = (-5050);
629 nonAssocRightIsNotLeft = true;
635 expr = foldl' (acc: el: abort "operation not called") 0 [ ];
639 testFoldl'IntegerAdding = {
640 expr = foldl' (acc: el: acc + el) 0 [ 1 2 3 ];
644 # The accumulator isn't forced deeply
645 testFoldl'NonDeep = {
646 expr = take 3 (foldl'
647 (acc: el: [ el ] ++ acc)
648 [ (abort "unevaluated list entry") ]
650 expected = [ 3 2 1 ];
653 # Compared to builtins.foldl', lib.foldl' evaluates the first accumulator strictly too
654 testFoldl'StrictInitial = {
655 expr = (builtins.tryEval (foldl' (acc: el: el) (throw "hello") [])).success;
659 # Make sure we don't get a stack overflow for large lists
660 # This number of elements would notably cause a stack overflow if it was implemented without the `foldl'` builtin
662 expr = foldl' (acc: el: acc + el) 0 (range 0 100000);
663 expected = 5000050000;
666 testTake = testAllTrue [
667 ([] == (take 0 [ 1 2 3 ]))
668 ([1] == (take 1 [ 1 2 3 ]))
669 ([ 1 2 ] == (take 2 [ 1 2 3 ]))
670 ([ 1 2 3 ] == (take 3 [ 1 2 3 ]))
671 ([ 1 2 3 ] == (take 4 [ 1 2 3 ]))
674 testListHasPrefixExample1 = {
675 expr = lists.hasPrefix [ 1 2 ] [ 1 2 3 4 ];
678 testListHasPrefixExample2 = {
679 expr = lists.hasPrefix [ 0 1 ] [ 1 2 3 4 ];
682 testListHasPrefixLazy = {
683 expr = lists.hasPrefix [ 1 ] [ 1 (abort "lib.lists.hasPrefix is not lazy") ];
686 testListHasPrefixEmptyPrefix = {
687 expr = lists.hasPrefix [ ] [ 1 2 ];
690 testListHasPrefixEmptyList = {
691 expr = lists.hasPrefix [ 1 2 ] [ ];
695 testListRemovePrefixExample1 = {
696 expr = lists.removePrefix [ 1 2 ] [ 1 2 3 4 ];
699 testListRemovePrefixExample2 = {
700 expr = (builtins.tryEval (lists.removePrefix [ 0 1 ] [ 1 2 3 4 ])).success;
703 testListRemovePrefixEmptyPrefix = {
704 expr = lists.removePrefix [ ] [ 1 2 ];
707 testListRemovePrefixEmptyList = {
708 expr = (builtins.tryEval (lists.removePrefix [ 1 2 ] [ ])).success;
713 expr = foldAttrs (n: a: [n] ++ a) [] [
717 expected = { a = [ 2 3 ]; b = [7]; c = [8];};
720 testListCommonPrefixExample1 = {
721 expr = lists.commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ];
724 testListCommonPrefixExample2 = {
725 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ];
726 expected = [ 1 2 3 ];
728 testListCommonPrefixExample3 = {
729 expr = lists.commonPrefix [ 1 2 3 ] [ 4 5 6 ];
732 testListCommonPrefixEmpty = {
733 expr = lists.commonPrefix [ ] [ 1 2 3 ];
736 testListCommonPrefixSame = {
737 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 ];
738 expected = [ 1 2 3 ];
740 testListCommonPrefixLazy = {
741 expr = lists.commonPrefix [ 1 ] [ 1 (abort "lib.lists.commonPrefix shouldn't evaluate this")];
744 # This would stack overflow if `commonPrefix` were implemented using recursion
745 testListCommonPrefixLong =
747 longList = genList (n: n) 100000;
749 expr = lists.commonPrefix longList longList;
754 expr = sort builtins.lessThan [ 40 2 30 42 ];
755 expected = [2 30 40 42];
759 expr = sortOn stringLength [ "aa" "b" "cccc" ];
760 expected = [ "b" "aa" "cccc" ];
764 expr = sortOn (throw "nope") [ ];
768 testSortOnIncomparable = {
773 { ok = 1; f = x: x; }
774 { ok = 3; f = x: x + 3; }
775 { ok = 2; f = x: x; }
777 expected = [ 1 2 6 ];
781 expr = replicate 3 "a";
782 expected = ["a" "a" "a"];
785 testToIntShouldConvertStringToInt = {
790 testToIntShouldThrowErrorIfItCouldNotConvertToInt = {
791 expr = builtins.tryEval (toInt "\"foo\"");
792 expected = { success = false; value = false; };
795 testHasAttrByPathTrue = {
796 expr = hasAttrByPath ["a" "b"] { a = { b = "yey"; }; };
800 testHasAttrByPathFalse = {
801 expr = hasAttrByPath ["a" "b"] { a = { c = "yey"; }; };
805 testHasAttrByPathNonStrict = {
806 expr = hasAttrByPath [] (throw "do not use");
810 testLongestValidPathPrefix_empty_empty = {
811 expr = attrsets.longestValidPathPrefix [ ] { };
815 testLongestValidPathPrefix_empty_nonStrict = {
816 expr = attrsets.longestValidPathPrefix [ ] (throw "do not use");
820 testLongestValidPathPrefix_zero = {
821 expr = attrsets.longestValidPathPrefix [ "a" (throw "do not use") ] { d = null; };
825 testLongestValidPathPrefix_zero_b = {
826 expr = attrsets.longestValidPathPrefix [ "z" "z" ] "remarkably harmonious";
830 testLongestValidPathPrefix_one = {
831 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a = null; };
835 testLongestValidPathPrefix_two = {
836 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b = null; };
837 expected = [ "a" "b" ];
840 testLongestValidPathPrefix_three = {
841 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c = null; };
842 expected = [ "a" "b" "c" ];
845 testLongestValidPathPrefix_three_extra = {
846 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c.d = throw "nope"; };
847 expected = [ "a" "b" "c" ];
850 testFindFirstIndexExample1 = {
851 expr = lists.findFirstIndex (x: x > 3) (abort "index found, so a default must not be evaluated") [ 1 6 4 ];
855 testFindFirstIndexExample2 = {
856 expr = lists.findFirstIndex (x: x > 9) "a very specific default" [ 1 6 4 ];
857 expected = "a very specific default";
860 testFindFirstIndexEmpty = {
861 expr = lists.findFirstIndex (abort "when the list is empty, the predicate is not needed") null [];
865 testFindFirstIndexSingleMatch = {
866 expr = lists.findFirstIndex (x: x == 5) null [ 5 ];
870 testFindFirstIndexSingleDefault = {
871 expr = lists.findFirstIndex (x: false) null [ (abort "if the predicate doesn't access the value, it must not be evaluated") ];
875 testFindFirstIndexNone = {
876 expr = builtins.tryEval (lists.findFirstIndex (x: x == 2) null [ 1 (throw "the last element must be evaluated when there's no match") ]);
877 expected = { success = false; value = false; };
880 # Makes sure that the implementation doesn't cause a stack overflow
881 testFindFirstIndexBig = {
882 expr = lists.findFirstIndex (x: x == 1000000) null (range 0 1000000);
886 testFindFirstIndexLazy = {
887 expr = lists.findFirstIndex (x: x == 1) null [ 1 (abort "list elements after the match must not be evaluated") ];
891 testFindFirstExample1 = {
892 expr = lists.findFirst (x: x > 3) 7 [ 1 6 4 ];
896 testFindFirstExample2 = {
897 expr = lists.findFirst (x: x > 9) 7 [ 1 6 4 ];
901 testAllUnique_true = {
902 expr = allUnique [ 3 2 4 1 ];
905 testAllUnique_false = {
906 expr = allUnique [ 3 2 3 4 ];
912 testConcatMapAttrs = {
913 expr = concatMapAttrs
916 ${name + value} = value;
934 sum = acc.sum + value;
935 names = acc.names ++ [ name ];
937 { sum = 0; names = [ ]; }
942 # should just return the initial value
943 emptySet = foldlAttrs (throw "function not needed") 123 { };
944 # should just evaluate to the last value
945 valuesNotNeeded = foldlAttrs (acc: _name: _v: acc) 3 { z = throw "value z not needed"; a = throw "value a not needed"; };
946 # the accumulator doesnt have to be an attrset it can be as trivial as being just a number or string
947 trivialAcc = foldlAttrs (acc: _name: v: acc * 10 + v) 1 { z = 1; a = 2; };
952 names = [ "bar" "foo" ];
961 testMergeAttrsListExample1 = {
962 expr = attrsets.mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ];
963 expected = { a = 0; b = 1; c = 2; d = 3; };
965 testMergeAttrsListExample2 = {
966 expr = attrsets.mergeAttrsList [ { a = 0; } { a = 1; } ];
967 expected = { a = 1; };
969 testMergeAttrsListExampleMany =
972 listToAttrs (genList (m:
974 # Integer divide n by two to create duplicate attributes
975 str = "halfn${toString (n / 2)}m${toString m}";
977 nameValuePair str str
981 expr = attrsets.mergeAttrsList list;
982 expected = foldl' mergeAttrs { } list;
985 # code from the example
986 testRecursiveUpdateUntil = {
987 expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) {
988 # first attribute set
993 #second attribute set
999 foo.bar = 1; # 'foo.*' from the second set
1001 bar = 3; # 'bar' from the first set
1002 baz = 4; # 'baz' from the second set
1006 testMatchAttrsMatchingExact = {
1007 expr = matchAttrs { cpu = { bits = 64; }; } { cpu = { bits = 64; }; };
1011 testMatchAttrsMismatch = {
1012 expr = matchAttrs { cpu = { bits = 128; }; } { cpu = { bits = 64; }; };
1016 testMatchAttrsMatchingImplicit = {
1017 expr = matchAttrs { cpu = { }; } { cpu = { bits = 64; }; };
1021 testMatchAttrsMissingAttrs = {
1022 expr = matchAttrs { cpu = {}; } { };
1026 testOverrideExistingEmpty = {
1027 expr = overrideExisting {} { a = 1; };
1031 testOverrideExistingDisjoint = {
1032 expr = overrideExisting { b = 2; } { a = 1; };
1033 expected = { b = 2; };
1036 testOverrideExistingOverride = {
1037 expr = overrideExisting { a = 3; b = 2; } { a = 1; };
1038 expected = { a = 1; b = 2; };
1041 testListAttrsReverse = let
1042 exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;};
1043 exampleSingletonList = [{name="foo"; value=1;}];
1046 isReverseToListToAttrs = builtins.listToAttrs (attrsToList exampleAttrs) == exampleAttrs;
1047 isReverseToAttrsToList = attrsToList (builtins.listToAttrs exampleSingletonList) == exampleSingletonList;
1048 testDuplicatePruningBehaviour = attrsToList (builtins.listToAttrs [{name="a"; value=2;} {name="a"; value=1;}]);
1051 isReverseToAttrsToList = true;
1052 isReverseToListToAttrs = true;
1053 testDuplicatePruningBehaviour = [{name="a"; value=2;}];
1057 testAttrsToListsCanDealWithFunctions = testingEval (
1058 attrsToList { someFunc= a: a + 1;}
1062 # these tests assume attributes are converted to lists
1063 # in alphabetical order
1065 testMkKeyValueDefault = {
1066 expr = generators.mkKeyValueDefault {} ":" "f:oo" "bar";
1067 expected = ''f\:oo:bar'';
1070 testMkValueString = {
1078 # float = 42.23; # floats are strange
1081 (const (generators.mkValueStringDefault {}))
1089 # float = "42.23" true false [ "bar" ] ]'';
1094 expr = generators.toKeyValue {} {
1096 "other=key" = "baz";
1105 expr = generators.toINI {} {};
1109 testToINIEmptySection = {
1110 expr = generators.toINI {} { foo = {}; bar = {}; };
1118 testToINIDuplicateKeys = {
1119 expr = generators.toINI { listsAsDuplicateKeys = true; } { foo.bar = true; baz.qux = [ 1 false ]; };
1130 testToINIDefaultEscapes = {
1131 expr = generators.toINI {} {
1132 "no [ and ] allowed unescaped" = {
1133 "and also no = in keys" = 42;
1137 [no \[ and \] allowed unescaped]
1138 and also no \= in keys=42
1142 testToINIDefaultFull = {
1143 expr = generators.toINI {} {
1146 x = "Me-se JarJar Binx";
1147 # booleans are converted verbatim by default
1151 "he\\h=he" = "this is okay";
1156 he\h\=he=this is okay
1165 testToINIWithGlobalSectionEmpty = {
1166 expr = generators.toINIWithGlobalSection {} {
1176 testToINIWithGlobalSectionGlobalEmptyIsTheSameAsToINI =
1181 x = "Me-se JarJar Binx";
1184 "he\\h=he" = "this is okay";
1189 generators.toINIWithGlobalSection {} {
1191 sections = sections;
1193 expected = generators.toINI {} sections;
1196 testToINIWithGlobalSectionFull = {
1197 expr = generators.toINIWithGlobalSection {} {
1205 x = "Me-se JarJar Binx";
1208 "he\\h=he" = "this is okay";
1217 he\h\=he=this is okay
1226 expr = generators.toGitINI {
1228 email = "user@example.org";
1230 signingKey = "00112233445566778899AABBCCDDEEFF";
1232 gpg.program = "path-to-gpg";
1234 include.path = "~/path/to/config.inc";
1235 includeIf."gitdif:~/src/dir".path = "~/path/to/conditional.inc";
1240 subsection.value = "test";
1244 ${"\t"}boolean = true
1246 ${"\t"}name = "value"
1248 [extra "subsection"]
1249 ${"\t"}value = "test"
1252 ${"\t"}program = "path-to-gpg"
1255 ${"\t"}path = "~/path/to/config.inc"
1257 [includeIf "gitdif:~/src/dir"]
1258 ${"\t"}path = "~/path/to/conditional.inc"
1261 ${"\t"}gpgSign = true
1264 ${"\t"}email = "user@example.org"
1265 ${"\t"}name = "John Doe"
1266 ${"\t"}signingKey = "00112233445566778899AABBCCDDEEFF"
1270 /* right now only invocation check */
1273 foobar = [ "baz" 1 2 3 ];
1276 expr = generators.toJSON {} val;
1277 # trivial implementation
1278 expected = builtins.toJSON val;
1281 /* right now only invocation check */
1284 list = [ { one = 1; } { two = 2; } ];
1288 expr = generators.toYAML {} val;
1289 # trivial implementation
1290 expected = builtins.toJSON val;
1295 deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
1297 expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec {
1302 string = "fn\${o}\"r\\d";
1303 newlinestring = "\n";
1307 functionArgs = { arg ? 4, foo }: arg;
1308 list = [ 3 4 function [ false ] ];
1310 attrs = { foo = null; "foo b/ar" = "baz"; };
1318 emptystring = ''""'';
1319 string = ''"fn\''${o}\"r\\d"'';
1320 newlinestring = "\"\\n\"";
1323 function = "<function>";
1324 functionArgs = "<function, args: {arg?, foo}>";
1325 list = "[ 3 4 ${function} [ false ] ]";
1327 attrs = "{ foo = null; \"foo b/ar\" = \"baz\"; }";
1329 drv = "<derivation ${deriv.name}>";
1338 expr = generators.toPretty { } (generators.withRecursion { throwOnDepthLimit = false; depthLimit = 2; } a);
1339 expected = "{\n b = 1;\n c = {\n b = \"<unevaluated>\";\n c = {\n b = \"<unevaluated>\";\n c = \"<unevaluated>\";\n };\n };\n}";
1342 testToPrettyLimitThrow =
1347 expr = (builtins.tryEval
1348 (generators.toPretty { } (generators.withRecursion { depthLimit = 2; } a))).success;
1352 testWithRecursionDealsWithFunctors =
1355 __functor = self: { a, b, }: null;
1363 expr = generators.toPretty { } (generators.withRecursion { depthLimit = 1; throwOnDepthLimit = false; } a);
1364 expected = "{\n b = <function, args: {a, b}>;\n c = {\n d = \"<unevaluated>\";\n };\n value = \"<unevaluated>\";\n}";
1367 testToPrettyMultiline = {
1368 expr = mapAttrs (const (generators.toPretty { })) rec {
1369 list = [ 3 4 [ false ] ];
1370 attrs = { foo = null; bar.foo = "baz"; };
1371 newlinestring = "\n";
1372 multilinestring = ''
1377 multilinestring' = ''
1398 newlinestring = "''\n \n''";
1399 multilinestring = ''
1405 multilinestring' = ''
1414 testToPrettyAllowPrettyValues = {
1415 expr = generators.toPretty { allowPrettyValues = true; }
1416 { __pretty = v: "«" + v + "»"; val = "foo"; };
1417 expected = "«foo»";
1422 deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
1424 expr = mapAttrs (const (generators.toPlist { })) {
1426 nested.values = rec {
1431 string = "fn\${o}\"r\\d";
1432 newlinestring = "\n";
1435 list = [ 3 4 "test" ];
1437 attrs = { foo = null; "foo b/ar" = "baz"; };
1442 expected = { value = builtins.readFile ./test-to-plist-expected.plist; };
1445 testToLuaEmptyAttrSet = {
1446 expr = generators.toLua {} {};
1450 testToLuaEmptyList = {
1451 expr = generators.toLua {} [];
1455 testToLuaListOfVariousTypes = {
1456 expr = generators.toLua {} [ null 43 3.14159 true ];
1467 expr = generators.toLua {} ''double-quote (") and single quotes (')'';
1468 expected = ''"double-quote (\") and single quotes (')"'';
1471 testToLuaAttrsetWithLuaInline = {
1472 expr = generators.toLua {} { x = generators.mkLuaInline ''"abc" .. "def"''; };
1475 ["x"] = ("abc" .. "def")
1479 testToLuaAttrsetWithSpaceInKey = {
1480 expr = generators.toLua {} { "some space and double-quote (\")" = 42; };
1483 ["some space and double-quote (\")"] = 42
1487 testToLuaWithoutMultiline = {
1488 expr = generators.toLua { multiline = false; } [ 41 43 ];
1489 expected = ''{ 41, 43 }'';
1492 testToLuaEmptyBindings = {
1493 expr = generators.toLua { asBindings = true; } {};
1497 testToLuaBindings = {
1498 expr = generators.toLua { asBindings = true; } { x1 = 41; _y = { a = 43; }; };
1507 testToLuaPartialTableBindings = {
1508 expr = generators.toLua { asBindings = true; } { "x.y" = 42; };
1514 testToLuaIndentedBindings = {
1515 expr = generators.toLua { asBindings = true; indent = " "; } { x = { y = 42; }; };
1516 expected = " x = {\n [\"y\"] = 42\n }\n";
1519 testToLuaBindingsWithSpace = testingThrow (
1520 generators.toLua { asBindings = true; } { "with space" = 42; }
1523 testToLuaBindingsWithLeadingDigit = testingThrow (
1524 generators.toLua { asBindings = true; } { "11eleven" = 42; }
1527 testToLuaBasicExample = {
1528 expr = generators.toLua {} {
1529 cmd = [ "typescript-language-server" "--stdio" ];
1530 settings.workspace.library = generators.mkLuaInline ''vim.api.nvim_get_runtime_file("", true)'';
1535 "typescript-language-server",
1540 ["library"] = (vim.api.nvim_get_runtime_file("", true))
1548 testToGNUCommandLine = {
1549 expr = cli.toGNUCommandLine {} {
1550 data = builtins.toJSON { id = 0; };
1554 url = [ "https://example.com/foo" "https://example.com/bar" ];
1561 "--data" "{\"id\":0}"
1563 "--url" "https://example.com/foo"
1564 "--url" "https://example.com/bar"
1569 testToGNUCommandLineShell = {
1570 expr = cli.toGNUCommandLineShell {} {
1571 data = builtins.toJSON { id = 0; };
1575 url = [ "https://example.com/foo" "https://example.com/bar" ];
1580 expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
1583 testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName {
1588 testSanitizeDerivationNameUnicode = testSanitizeDerivationName {
1593 testSanitizeDerivationNameAscii = testSanitizeDerivationName {
1594 name = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
1595 expected = "-+--.-0123456789-=-?-ABCDEFGHIJKLMNOPQRSTUVWXYZ-_-abcdefghijklmnopqrstuvwxyz-";
1598 testSanitizeDerivationNameTooLong = testSanitizeDerivationName {
1599 name = "This string is loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1600 expected = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong";
1603 testSanitizeDerivationNameTooLongWithInvalid = testSanitizeDerivationName {
1604 name = "Hello there aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&&&&&&&";
1605 expected = "there-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-";
1608 testSanitizeDerivationNameEmpty = testSanitizeDerivationName {
1610 expected = "unknown";
1613 testFreeformOptions = {
1616 submodule = { lib, ... }: {
1617 freeformType = lib.types.attrsOf (lib.types.submodule {
1618 options.bar = lib.mkOption {};
1620 options.bar = lib.mkOption {};
1623 module = { lib, ... }: {
1624 options.foo = lib.mkOption {
1625 type = lib.types.submodule submodule;
1629 options = (evalModules {
1630 modules = [ module ];
1633 locs = filter (o: ! o.internal) (optionAttrSetToDocList options);
1634 in map (o: o.loc) locs;
1635 expected = [ [ "_module" "args" ] [ "foo" ] [ "foo" "<name>" "bar" ] [ "foo" "bar" ] ];
1638 testCartesianProductOfEmptySet = {
1639 expr = cartesianProductOfSets {};
1643 testCartesianProductOfOneSet = {
1644 expr = cartesianProductOfSets { a = [ 1 2 3 ]; };
1645 expected = [ { a = 1; } { a = 2; } { a = 3; } ];
1648 testCartesianProductOfTwoSets = {
1649 expr = cartesianProductOfSets { a = [ 1 ]; b = [ 10 20 ]; };
1656 testCartesianProductOfTwoSetsWithOneEmpty = {
1657 expr = cartesianProductOfSets { a = [ ]; b = [ 10 20 ]; };
1661 testCartesianProductOfThreeSets = {
1662 expr = cartesianProductOfSets {
1665 c = [ 100 200 300 ];
1668 { a = 1; b = 10; c = 100; }
1669 { a = 1; b = 10; c = 200; }
1670 { a = 1; b = 10; c = 300; }
1672 { a = 1; b = 20; c = 100; }
1673 { a = 1; b = 20; c = 200; }
1674 { a = 1; b = 20; c = 300; }
1676 { a = 1; b = 30; c = 100; }
1677 { a = 1; b = 30; c = 200; }
1678 { a = 1; b = 30; c = 300; }
1680 { a = 2; b = 10; c = 100; }
1681 { a = 2; b = 10; c = 200; }
1682 { a = 2; b = 10; c = 300; }
1684 { a = 2; b = 20; c = 100; }
1685 { a = 2; b = 20; c = 200; }
1686 { a = 2; b = 20; c = 300; }
1688 { a = 2; b = 30; c = 100; }
1689 { a = 2; b = 30; c = 200; }
1690 { a = 2; b = 30; c = 300; }
1692 { a = 3; b = 10; c = 100; }
1693 { a = 3; b = 10; c = 200; }
1694 { a = 3; b = 10; c = 300; }
1696 { a = 3; b = 20; c = 100; }
1697 { a = 3; b = 20; c = 200; }
1698 { a = 3; b = 20; c = 300; }
1700 { a = 3; b = 30; c = 100; }
1701 { a = 3; b = 30; c = 200; }
1702 { a = 3; b = 30; c = 300; }
1706 # The example from the showAttrPath documentation
1707 testShowAttrPathExample = {
1708 expr = showAttrPath [ "foo" "10" "bar" ];
1709 expected = "foo.\"10\".bar";
1712 testShowAttrPathEmpty = {
1713 expr = showAttrPath [];
1714 expected = "<root attribute path>";
1717 testShowAttrPathVarious = {
1718 expr = showAttrPath [
1725 expected = ''".".foo."2".a2-b._bc'de'';
1729 expr = groupBy (n: toString (mod n 5)) (range 0 16);
1731 "0" = [ 0 5 10 15 ];
1732 "1" = [ 1 6 11 16 ];
1740 expr = groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ];
1741 expected = { false = 3; true = 12; };
1744 # The example from the updateManyAttrsByPath documentation
1745 testUpdateManyAttrsByPathExample = {
1746 expr = updateManyAttrsByPath [
1749 update = old: { d = old.c; };
1752 path = [ "a" "b" "c" ];
1753 update = old: old + 1;
1760 expected = { a = { b = { d = 1; }; }; x = { y = "xy"; }; };
1763 # If there are no updates, the value is passed through
1764 testUpdateManyAttrsByPathNone = {
1765 expr = updateManyAttrsByPath [] "something";
1766 expected = "something";
1769 # A single update to the root path is just like applying the function directly
1770 testUpdateManyAttrsByPathSingleIncrement = {
1771 expr = updateManyAttrsByPath [
1774 update = old: old + 1;
1780 # Multiple updates can be applied are done in order
1781 testUpdateManyAttrsByPathMultipleIncrements = {
1782 expr = updateManyAttrsByPath [
1785 update = old: old + "a";
1789 update = old: old + "b";
1793 update = old: old + "c";
1799 # If an update doesn't use the value, all previous updates are not evaluated
1800 testUpdateManyAttrsByPathLazy = {
1801 expr = updateManyAttrsByPath [
1804 update = old: old + throw "nope";
1808 update = old: "untainted";
1811 expected = "untainted";
1814 # Deeply nested attributes can be updated without affecting others
1815 testUpdateManyAttrsByPathDeep = {
1816 expr = updateManyAttrsByPath [
1818 path = [ "a" "b" "c" ];
1819 update = old: old + 1;
1837 # Nested attributes are updated first
1838 testUpdateManyAttrsByPathNestedBeforehand = {
1839 expr = updateManyAttrsByPath [
1842 update = old: old // { x = old.b; };
1846 update = old: old + 1;
1857 ## Levenshtein distance functions and co.
1858 testCommonPrefixLengthEmpty = {
1859 expr = strings.commonPrefixLength "" "hello";
1863 testCommonPrefixLengthSame = {
1864 expr = strings.commonPrefixLength "hello" "hello";
1868 testCommonPrefixLengthDiffering = {
1869 expr = strings.commonPrefixLength "hello" "hey";
1873 testCommonSuffixLengthEmpty = {
1874 expr = strings.commonSuffixLength "" "hello";
1878 testCommonSuffixLengthSame = {
1879 expr = strings.commonSuffixLength "hello" "hello";
1883 testCommonSuffixLengthDiffering = {
1884 expr = strings.commonSuffixLength "test" "rest";
1888 testLevenshteinEmpty = {
1889 expr = strings.levenshtein "" "";
1893 testLevenshteinOnlyAdd = {
1894 expr = strings.levenshtein "" "hello there";
1898 testLevenshteinOnlyRemove = {
1899 expr = strings.levenshtein "hello there" "";
1903 testLevenshteinOnlyTransform = {
1904 expr = strings.levenshtein "abcdef" "ghijkl";
1908 testLevenshteinMixed = {
1909 expr = strings.levenshtein "kitchen" "sitting";
1913 testLevenshteinAtMostZeroFalse = {
1914 expr = strings.levenshteinAtMost 0 "foo" "boo";
1918 testLevenshteinAtMostZeroTrue = {
1919 expr = strings.levenshteinAtMost 0 "foo" "foo";
1923 testLevenshteinAtMostOneFalse = {
1924 expr = strings.levenshteinAtMost 1 "car" "ct";
1928 testLevenshteinAtMostOneTrue = {
1929 expr = strings.levenshteinAtMost 1 "car" "cr";
1933 # We test levenshteinAtMost 2 particularly well because it uses a complicated
1935 testLevenshteinAtMostTwoIsEmpty = {
1936 expr = strings.levenshteinAtMost 2 "" "";
1940 testLevenshteinAtMostTwoIsZero = {
1941 expr = strings.levenshteinAtMost 2 "abcdef" "abcdef";
1945 testLevenshteinAtMostTwoIsOne = {
1946 expr = strings.levenshteinAtMost 2 "abcdef" "abddef";
1950 testLevenshteinAtMostTwoDiff0False = {
1951 expr = strings.levenshteinAtMost 2 "abcdef" "aczyef";
1955 testLevenshteinAtMostTwoDiff0Outer = {
1956 expr = strings.levenshteinAtMost 2 "abcdef" "zbcdez";
1960 testLevenshteinAtMostTwoDiff0DelLeft = {
1961 expr = strings.levenshteinAtMost 2 "abcdef" "bcdefz";
1965 testLevenshteinAtMostTwoDiff0DelRight = {
1966 expr = strings.levenshteinAtMost 2 "abcdef" "zabcde";
1970 testLevenshteinAtMostTwoDiff1False = {
1971 expr = strings.levenshteinAtMost 2 "abcdef" "bddez";
1975 testLevenshteinAtMostTwoDiff1DelLeft = {
1976 expr = strings.levenshteinAtMost 2 "abcdef" "bcdez";
1980 testLevenshteinAtMostTwoDiff1DelRight = {
1981 expr = strings.levenshteinAtMost 2 "abcdef" "zbcde";
1985 testLevenshteinAtMostTwoDiff2False = {
1986 expr = strings.levenshteinAtMost 2 "hello" "hxo";
1990 testLevenshteinAtMostTwoDiff2True = {
1991 expr = strings.levenshteinAtMost 2 "hello" "heo";
1995 testLevenshteinAtMostTwoDiff3 = {
1996 expr = strings.levenshteinAtMost 2 "hello" "ho";
2000 testLevenshteinAtMostThreeFalse = {
2001 expr = strings.levenshteinAtMost 3 "hello" "Holla!";
2005 testLevenshteinAtMostThreeTrue = {
2006 expr = strings.levenshteinAtMost 3 "hello" "Holla";
2012 testLazyDerivationIsLazyInDerivationForAttrNames = {
2013 expr = attrNames (lazyDerivation {
2014 derivation = throw "not lazy enough";
2016 # It's ok to add attribute names here when lazyDerivation is improved
2017 # in accordance with its inline comments.
2018 expected = [ "drvPath" "meta" "name" "out" "outPath" "outputName" "outputs" "system" "type" ];
2021 testLazyDerivationIsLazyInDerivationForPassthruAttr = {
2022 expr = (lazyDerivation {
2023 derivation = throw "not lazy enough";
2024 passthru.tests = "whatever is in tests";
2026 expected = "whatever is in tests";
2029 testLazyDerivationIsLazyInDerivationForPassthruAttr2 = {
2030 # passthru.tests is not a special case. It works for any attr.
2031 expr = (lazyDerivation {
2032 derivation = throw "not lazy enough";
2033 passthru.foo = "whatever is in foo";
2035 expected = "whatever is in foo";
2038 testLazyDerivationIsLazyInDerivationForMeta = {
2039 expr = (lazyDerivation {
2040 derivation = throw "not lazy enough";
2041 meta = "whatever is in meta";
2043 expected = "whatever is in meta";
2046 testLazyDerivationReturnsDerivationAttrs = let
2048 type = "derivation";
2051 outPath = "test outPath";
2053 drvPath = "test drvPath";
2055 system = "test system";
2059 expr = lazyDerivation { inherit derivation; };
2060 expected = derivation;
2063 testOptionalDrvAttr = let
2064 mkDerivation = args: derivation (args // {
2065 builder = "builder";
2067 __ignoreNulls = true;
2070 expr = (mkDerivation {
2072 x = optionalDrvAttr true 1;
2073 y = optionalDrvAttr false 1;
2075 expected = (mkDerivation {
2081 testLazyDerivationMultiOutputReturnsDerivationAttrs = let
2083 type = "derivation";
2084 outputs = ["out" "dev"];
2087 outPath = "test outPath";
2089 drvPath = "test drvPath";
2091 system = "test system";
2092 meta.position = "/hi:23";
2095 expr = lazyDerivation { inherit derivation; outputs = ["out" "dev"]; passthru.meta.position = "/hi:23"; };
2096 expected = derivation;
2099 testTypeDescriptionInt = {
2100 expr = (with types; int).description;
2101 expected = "signed integer";
2103 testTypeDescriptionIntsPositive = {
2104 expr = (with types; ints.positive).description;
2105 expected = "positive integer, meaning >0";
2107 testTypeDescriptionIntsPositiveOrEnumAuto = {
2108 expr = (with types; either ints.positive (enum ["auto"])).description;
2109 expected = ''positive integer, meaning >0, or value "auto" (singular enum)'';
2111 testTypeDescriptionListOfPositive = {
2112 expr = (with types; listOf ints.positive).description;
2113 expected = "list of (positive integer, meaning >0)";
2115 testTypeDescriptionListOfInt = {
2116 expr = (with types; listOf int).description;
2117 expected = "list of signed integer";
2119 testTypeDescriptionListOfListOfInt = {
2120 expr = (with types; listOf (listOf int)).description;
2121 expected = "list of list of signed integer";
2123 testTypeDescriptionListOfEitherStrOrBool = {
2124 expr = (with types; listOf (either str bool)).description;
2125 expected = "list of (string or boolean)";
2127 testTypeDescriptionEitherListOfStrOrBool = {
2128 expr = (with types; either (listOf bool) str).description;
2129 expected = "(list of boolean) or string";
2131 testTypeDescriptionEitherStrOrListOfBool = {
2132 expr = (with types; either str (listOf bool)).description;
2133 expected = "string or list of boolean";
2135 testTypeDescriptionOneOfListOfStrOrBool = {
2136 expr = (with types; oneOf [ (listOf bool) str ]).description;
2137 expected = "(list of boolean) or string";
2139 testTypeDescriptionOneOfListOfStrOrBoolOrNumber = {
2140 expr = (with types; oneOf [ (listOf bool) str number ]).description;
2141 expected = "(list of boolean) or string or signed integer or floating point number";
2143 testTypeDescriptionEitherListOfBoolOrEitherStringOrNumber = {
2144 expr = (with types; either (listOf bool) (either str number)).description;
2145 expected = "(list of boolean) or string or signed integer or floating point number";
2147 testTypeDescriptionEitherEitherListOfBoolOrStringOrNumber = {
2148 expr = (with types; either (either (listOf bool) str) number).description;
2149 expected = "(list of boolean) or string or signed integer or floating point number";
2151 testTypeDescriptionEitherNullOrBoolOrString = {
2152 expr = (with types; either (nullOr bool) str).description;
2153 expected = "null or boolean or string";
2155 testTypeDescriptionEitherListOfEitherBoolOrStrOrInt = {
2156 expr = (with types; either (listOf (either bool str)) int).description;
2157 expected = "(list of (boolean or string)) or signed integer";
2159 testTypeDescriptionEitherIntOrListOrEitherBoolOrStr = {
2160 expr = (with types; either int (listOf (either bool str))).description;
2161 expected = "signed integer or list of (boolean or string)";
2165 testGetExe'Output = {
2167 type = "derivation";
2168 out = "somelonghash";
2169 bin = "somelonghash";
2171 expected = "somelonghash/bin/executable";
2174 testGetExeOutput = {
2176 type = "derivation";
2177 out = "somelonghash";
2178 bin = "somelonghash";
2179 meta.mainProgram = "mainProgram";
2181 expected = "somelonghash/bin/mainProgram";
2184 testGetExe'FailureFirstArg = testingThrow (
2185 getExe' "not a derivation" "executable"
2188 testGetExe'FailureSecondArg = testingThrow (
2189 getExe' { type = "derivation"; } "dir/executable"
2192 testPlatformMatch = {
2193 expr = meta.platformMatch { system = "x86_64-linux"; } "x86_64-linux";
2197 testPlatformMatchAttrs = {
2198 expr = meta.platformMatch (systems.elaborate "x86_64-linux") (systems.elaborate "x86_64-linux").parsed;
2202 testPlatformMatchNoMatch = {
2203 expr = meta.platformMatch { system = "x86_64-darwin"; } "x86_64-linux";
2207 testPlatformMatchMissingSystem = {
2208 expr = meta.platformMatch { } "x86_64-linux";
2212 testPackagesFromDirectoryRecursive = {
2213 expr = packagesFromDirectoryRecursive {
2214 callPackage = path: overrides: import path overrides;
2215 directory = ./packages-from-directory;
2220 # Note: Other files/directories in `./test-data/c/` are ignored and can be
2221 # used by `package.nix`.
2227 my-sub-namespace = {
2235 # Check that `packagesFromDirectoryRecursive` can process a directory with a
2236 # top-level `package.nix` file into a single package.
2237 testPackagesFromDirectoryRecursiveTopLevelPackageNix = {
2238 expr = packagesFromDirectoryRecursive {
2239 callPackage = path: overrides: import path overrides;
2240 directory = ./packages-from-directory/c;