at 24.11-pre 61 kB view raw
1/** 2 Nix evaluation tests for various lib functions. 3 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. 7 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. 10 11 To run these tests: 12 13 [nixpkgs]$ nix-instantiate --eval --strict lib/tests/misc.nix 14 15 If the resulting list is empty, all tests passed. 16 Alternatively, to run all `lib` tests: 17 18 [nixpkgs]$ nix-build lib/tests/release.nix 19*/ 20 21let 22 lib = import ../default.nix; 23 24 inherit (lib) 25 allUnique 26 and 27 attrNames 28 attrsets 29 attrsToList 30 bitAnd 31 bitOr 32 bitXor 33 boolToString 34 callPackagesWith 35 callPackageWith 36 cartesianProduct 37 cli 38 composeExtensions 39 composeManyExtensions 40 concatLines 41 concatMapAttrs 42 concatMapStrings 43 concatStrings 44 concatStringsSep 45 const 46 escapeXML 47 evalModules 48 filter 49 fix 50 fold 51 foldAttrs 52 foldl 53 foldl' 54 foldlAttrs 55 foldr 56 functionArgs 57 generators 58 genList 59 getExe 60 getExe' 61 groupBy 62 groupBy' 63 hasAttrByPath 64 hasInfix 65 id 66 ifilter0 67 isStorePath 68 lazyDerivation 69 length 70 lists 71 listToAttrs 72 makeExtensible 73 makeIncludePath 74 makeOverridable 75 mapAttrs 76 mapCartesianProduct 77 matchAttrs 78 mergeAttrs 79 meta 80 mod 81 nameValuePair 82 optionalDrvAttr 83 optionAttrSetToDocList 84 overrideExisting 85 packagesFromDirectoryRecursive 86 pipe 87 range 88 recursiveUpdateUntil 89 removePrefix 90 replicate 91 runTests 92 setFunctionArgs 93 showAttrPath 94 sort 95 sortOn 96 stringLength 97 strings 98 stringToCharacters 99 systems 100 tail 101 take 102 testAllTrue 103 toBaseDigits 104 toHexString 105 toInt 106 toIntBase10 107 toShellVars 108 types 109 updateManyAttrsByPath 110 versions 111 xor 112 ; 113 114 testingThrow = expr: { 115 expr = (builtins.tryEval (builtins.seq expr "didn't throw")); 116 expected = { success = false; value = false; }; 117 }; 118 testingEval = expr: { 119 expr = (builtins.tryEval expr).success; 120 expected = true; 121 }; 122 123 testSanitizeDerivationName = { name, expected }: 124 let 125 drv = derivation { 126 name = strings.sanitizeDerivationName name; 127 builder = "x"; 128 system = "x"; 129 }; 130 in { 131 # Evaluate the derivation so an invalid name would be caught 132 expr = builtins.seq drv.drvPath drv.name; 133 inherit expected; 134 }; 135 136in 137 138runTests { 139 140# CUSTOMIZATION 141 142 testFunctionArgsMakeOverridable = { 143 expr = functionArgs (makeOverridable ({ a, b, c ? null}: {})); 144 expected = { a = false; b = false; c = true; }; 145 }; 146 147 testFunctionArgsMakeOverridableOverride = { 148 expr = functionArgs (makeOverridable ({ a, b, c ? null }: {}) { a = 1; b = 2; }).override; 149 expected = { a = false; b = false; c = true; }; 150 }; 151 152 testCallPackageWithOverridePreservesArguments = 153 let 154 f = { a ? 0, b }: {}; 155 f' = callPackageWith { a = 1; b = 2; } f {}; 156 in { 157 expr = functionArgs f'.override; 158 expected = functionArgs f; 159 }; 160 161 testCallPackagesWithOverridePreservesArguments = 162 let 163 f = { a ? 0, b }: { nested = {}; }; 164 f' = callPackagesWith { a = 1; b = 2; } f {}; 165 in { 166 expr = functionArgs f'.nested.override; 167 expected = functionArgs f; 168 }; 169 170# TRIVIAL 171 172 testId = { 173 expr = id 1; 174 expected = 1; 175 }; 176 177 testConst = { 178 expr = const 2 3; 179 expected = 2; 180 }; 181 182 testPipe = { 183 expr = pipe 2 [ 184 (x: x + 2) # 2 + 2 = 4 185 (x: x * 2) # 4 * 2 = 8 186 ]; 187 expected = 8; 188 }; 189 190 testPipeEmpty = { 191 expr = pipe 2 []; 192 expected = 2; 193 }; 194 195 testPipeStrings = { 196 expr = pipe [ 3 4 ] [ 197 (map toString) 198 (map (s: s + "\n")) 199 concatStrings 200 ]; 201 expected = '' 202 3 203 4 204 ''; 205 }; 206 207 /* 208 testOr = { 209 expr = or true false; 210 expected = true; 211 }; 212 */ 213 214 testAnd = { 215 expr = and true false; 216 expected = false; 217 }; 218 219 testXor = { 220 expr = [ 221 (xor true false) 222 (xor true true) 223 (xor false false) 224 (xor false true) 225 ]; 226 expected = [ 227 true 228 false 229 false 230 true 231 ]; 232 }; 233 234 testFix = { 235 expr = fix (x: {a = if x ? a then "a" else "b";}); 236 expected = {a = "a";}; 237 }; 238 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; 245 in composed.foo; 246 expected = true; 247 }; 248 249 testComposeManyExtensions0 = { 250 expr = let obj = makeExtensible (self: { foo = true; }); 251 emptyComposition = composeManyExtensions []; 252 composed = obj.extend emptyComposition; 253 in composed.foo; 254 expected = true; 255 }; 256 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; }); 262 in { 263 expr = let composition = composeManyExtensions [f g h]; 264 composed = obj.extend composition; 265 in composed.foo; 266 expected = (obj.extend (composeExtensions f (composeExtensions g h))).foo; 267 }; 268 269 testBitAnd = { 270 expr = (bitAnd 3 10); 271 expected = 2; 272 }; 273 274 testBitOr = { 275 expr = (bitOr 3 10); 276 expected = 11; 277 }; 278 279 testBitXor = { 280 expr = (bitXor 3 10); 281 expected = 9; 282 }; 283 284 testToHexString = { 285 expr = toHexString 250; 286 expected = "FA"; 287 }; 288 289 testToBaseDigits = { 290 expr = toBaseDigits 2 6; 291 expected = [ 1 1 0 ]; 292 }; 293 294 testFunctionArgsFunctor = { 295 expr = functionArgs { __functor = self: { a, b }: null; }; 296 expected = { a = false; b = false; }; 297 }; 298 299 testFunctionArgsSetFunctionArgs = { 300 expr = functionArgs (setFunctionArgs (args: args.x) { x = false; }); 301 expected = { x = false; }; 302 }; 303 304# STRINGS 305 306 testConcatMapStrings = { 307 expr = concatMapStrings (x: x + ";") ["a" "b" "c"]; 308 expected = "a;b;c;"; 309 }; 310 311 testConcatStringsSep = { 312 expr = concatStringsSep "," ["a" "b" "c"]; 313 expected = "a,b,c"; 314 }; 315 316 testConcatLines = { 317 expr = concatLines ["a" "b" "c"]; 318 expected = "a\nb\nc\n"; 319 }; 320 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; } 331 ]); 332 expected = "/dev/include:/out/include:/default/include:/default/include"; 333 }; 334 335 testMakeIncludePathWithEmptyList = { 336 expr = (makeIncludePath [ ]); 337 expected = ""; 338 }; 339 340 testMakeIncludePathWithOneString = { 341 expr = (makeIncludePath [ "/usr" ]); 342 expected = "/usr/include"; 343 }; 344 345 testMakeIncludePathWithManyString = { 346 expr = (makeIncludePath [ "/usr" "/usr/local" ]); 347 expected = "/usr/include:/usr/local/include"; 348 }; 349 350 testReplicateString = { 351 expr = strings.replicate 5 "hello"; 352 expected = "hellohellohellohellohello"; 353 }; 354 355 testSplitStringsSimple = { 356 expr = strings.splitString "." "a.b.c.d"; 357 expected = [ "a" "b" "c" "d" ]; 358 }; 359 360 testSplitStringsEmpty = { 361 expr = strings.splitString "." "a..b"; 362 expected = [ "a" "" "b" ]; 363 }; 364 365 testSplitStringsOne = { 366 expr = strings.splitString ":" "a.b"; 367 expected = [ "a.b" ]; 368 }; 369 370 testSplitStringsNone = { 371 expr = strings.splitString "." ""; 372 expected = [ "" ]; 373 }; 374 375 testSplitStringsFirstEmpty = { 376 expr = strings.splitString "/" "/a/b/c"; 377 expected = [ "" "a" "b" "c" ]; 378 }; 379 380 testSplitStringsLastEmpty = { 381 expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:"; 382 expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ]; 383 }; 384 385 testSplitStringsRegex = { 386 expr = strings.splitString "\\[{}]()^$?*+|." "A\\[{}]()^$?*+|.B"; 387 expected = [ "A" "B" ]; 388 }; 389 390 testSplitStringsDerivation = { 391 expr = take 3 (strings.splitString "/" (derivation { 392 name = "name"; 393 builder = "builder"; 394 system = "system"; 395 })); 396 expected = ["" "nix" "store"]; 397 }; 398 399 testSplitVersionSingle = { 400 expr = versions.splitVersion "1"; 401 expected = [ "1" ]; 402 }; 403 404 testSplitVersionDouble = { 405 expr = versions.splitVersion "1.2"; 406 expected = [ "1" "2" ]; 407 }; 408 409 testSplitVersionTriple = { 410 expr = versions.splitVersion "1.2.3"; 411 expected = [ "1" "2" "3" ]; 412 }; 413 414 testPadVersionLess = { 415 expr = versions.pad 3 "1.2"; 416 expected = "1.2.0"; 417 }; 418 419 testPadVersionLessExtra = { 420 expr = versions.pad 3 "1.3-rc1"; 421 expected = "1.3.0-rc1"; 422 }; 423 424 testPadVersionMore = { 425 expr = versions.pad 3 "1.2.3.4"; 426 expected = "1.2.3"; 427 }; 428 429 testIsStorePath = { 430 expr = 431 let goodPath = 432 "${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11"; 433 in { 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"; 441 otherVals = { 442 attrset = isStorePath {}; 443 list = isStorePath []; 444 int = isStorePath 42; 445 }; 446 }; 447 expected = { 448 storePath = true; 449 storePathDerivation = true; 450 storePathAppendix = false; 451 nonAbsolute = false; 452 asPath = true; 453 otherPath = false; 454 otherVals = { 455 attrset = false; 456 list = false; 457 int = false; 458 }; 459 }; 460 }; 461 462 testEscapeXML = { 463 expr = escapeXML ''"test" 'test' < & >''; 464 expected = "&quot;test&quot; &apos;test&apos; &lt; &amp; &gt;"; 465 }; 466 467 testToShellVars = { 468 expr = '' 469 ${toShellVars { 470 STRing01 = "just a 'string'"; 471 _array_ = [ "with" "more strings" ]; 472 assoc."with some" = '' 473 strings 474 possibly newlines 475 ''; 476 drv = { 477 outPath = "/drv"; 478 foo = "ignored attribute"; 479 }; 480 path = /path; 481 stringable = { 482 __toString = _: "hello toString"; 483 bar = "ignored attribute"; 484 }; 485 }} 486 ''; 487 expected = '' 488 STRing01='just a '\'''string'\'''' 489 declare -a _array_=('with' 'more strings') 490 declare -A assoc=(['with some']='strings 491 possibly newlines 492 ') 493 drv='/drv' 494 path='/path' 495 stringable='hello toString' 496 ''; 497 }; 498 499 testHasInfixFalse = { 500 expr = hasInfix "c" "abde"; 501 expected = false; 502 }; 503 504 testHasInfixTrue = { 505 expr = hasInfix "c" "abcde"; 506 expected = true; 507 }; 508 509 testHasInfixDerivation = { 510 expr = hasInfix "hello" (import ../.. { system = "x86_64-linux"; }).hello; 511 expected = true; 512 }; 513 514 testHasInfixPath = { 515 expr = hasInfix "tests" ./.; 516 expected = true; 517 }; 518 519 testHasInfixPathStoreDir = { 520 expr = hasInfix builtins.storeDir ./.; 521 expected = true; 522 }; 523 524 testHasInfixToString = { 525 expr = hasInfix "a" { __toString = _: "a"; }; 526 expected = true; 527 }; 528 529 testRemovePrefixExample1 = { 530 expr = removePrefix "foo." "foo.bar.baz"; 531 expected = "bar.baz"; 532 }; 533 testRemovePrefixExample2 = { 534 expr = removePrefix "xxx" "foo.bar.baz"; 535 expected = "foo.bar.baz"; 536 }; 537 testRemovePrefixEmptyPrefix = { 538 expr = removePrefix "" "foo"; 539 expected = "foo"; 540 }; 541 testRemovePrefixEmptyString = { 542 expr = removePrefix "foo" ""; 543 expected = ""; 544 }; 545 testRemovePrefixEmptyBoth = { 546 expr = removePrefix "" ""; 547 expected = ""; 548 }; 549 550 testNormalizePath = { 551 expr = strings.normalizePath "//a/b//c////d/"; 552 expected = "/a/b/c/d/"; 553 }; 554 555 testCharToInt = { 556 expr = strings.charToInt "A"; 557 expected = 65; 558 }; 559 560 testEscapeC = { 561 expr = strings.escapeC [ " " ] "Hello World"; 562 expected = "Hello\\x20World"; 563 }; 564 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:/@$'()*,;") 572 ]; 573 574 testToInt = testAllTrue [ 575 # Naive 576 (123 == toInt "123") 577 (0 == toInt "0") 578 # Whitespace Padding 579 (123 == toInt " 123") 580 (123 == toInt "123 ") 581 (123 == toInt " 123 ") 582 (123 == toInt " 123 ") 583 (0 == toInt " 0") 584 (0 == toInt "0 ") 585 (0 == toInt " 0 ") 586 (-1 == toInt "-1") 587 (-1 == toInt " -1 ") 588 ]; 589 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; } ) 604 ]; 605 606 testToIntBase10 = testAllTrue [ 607 # Naive 608 (123 == toIntBase10 "123") 609 (0 == toIntBase10 "0") 610 # Whitespace Padding 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 ") 618 # Zero Padding 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 ") 634 ]; 635 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; } ) 647 ]; 648 649# LISTS 650 651 testFilter = { 652 expr = filter (x: x != "a") ["a" "b" "c" "a"]; 653 expected = ["b" "c"]; 654 }; 655 656 testIfilter0Example = { 657 expr = ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ]; 658 expected = [ 1 3 ]; 659 }; 660 testIfilter0Empty = { 661 expr = ifilter0 (i: v: abort "shouldn't be evaluated!") [ ]; 662 expected = [ ]; 663 }; 664 testIfilter0IndexOnly = { 665 expr = length (ifilter0 (i: v: mod i 2 == 0) [ (throw "0") (throw "1") (throw "2") (throw "3")]); 666 expected = 2; 667 }; 668 testIfilter0All = { 669 expr = ifilter0 (i: v: true) [ 10 11 12 13 14 15 ]; 670 expected = [ 10 11 12 13 14 15 ]; 671 }; 672 testIfilter0First = { 673 expr = ifilter0 (i: v: i == 0) [ 10 11 12 13 14 15 ]; 674 expected = [ 10 ]; 675 }; 676 testIfilter0Last = { 677 expr = ifilter0 (i: v: i == 5) [ 10 11 12 13 14 15 ]; 678 expected = [ 15 ]; 679 }; 680 681 testFold = 682 let 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; 688 in { 689 expr = { 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; 699 }; 700 expected = { 701 assocRight = 5050; 702 assocRightIsLeft = true; 703 nonAssocRight = 50; 704 nonAssocLeft = (-5050); 705 nonAssocRightIsNotLeft = true; 706 foldIsRight = true; 707 }; 708 }; 709 710 testFoldl'Empty = { 711 expr = foldl' (acc: el: abort "operation not called") 0 [ ]; 712 expected = 0; 713 }; 714 715 testFoldl'IntegerAdding = { 716 expr = foldl' (acc: el: acc + el) 0 [ 1 2 3 ]; 717 expected = 6; 718 }; 719 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") ] 725 [ 1 2 3 ]); 726 expected = [ 3 2 1 ]; 727 }; 728 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; 732 expected = false; 733 }; 734 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 737 testFoldl'Large = { 738 expr = foldl' (acc: el: acc + el) 0 (range 0 100000); 739 expected = 5000050000; 740 }; 741 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 ])) 748 ]; 749 750 testListHasPrefixExample1 = { 751 expr = lists.hasPrefix [ 1 2 ] [ 1 2 3 4 ]; 752 expected = true; 753 }; 754 testListHasPrefixExample2 = { 755 expr = lists.hasPrefix [ 0 1 ] [ 1 2 3 4 ]; 756 expected = false; 757 }; 758 testListHasPrefixLazy = { 759 expr = lists.hasPrefix [ 1 ] [ 1 (abort "lib.lists.hasPrefix is not lazy") ]; 760 expected = true; 761 }; 762 testListHasPrefixEmptyPrefix = { 763 expr = lists.hasPrefix [ ] [ 1 2 ]; 764 expected = true; 765 }; 766 testListHasPrefixEmptyList = { 767 expr = lists.hasPrefix [ 1 2 ] [ ]; 768 expected = false; 769 }; 770 771 testListRemovePrefixExample1 = { 772 expr = lists.removePrefix [ 1 2 ] [ 1 2 3 4 ]; 773 expected = [ 3 4 ]; 774 }; 775 testListRemovePrefixExample2 = { 776 expr = (builtins.tryEval (lists.removePrefix [ 0 1 ] [ 1 2 3 4 ])).success; 777 expected = false; 778 }; 779 testListRemovePrefixEmptyPrefix = { 780 expr = lists.removePrefix [ ] [ 1 2 ]; 781 expected = [ 1 2 ]; 782 }; 783 testListRemovePrefixEmptyList = { 784 expr = (builtins.tryEval (lists.removePrefix [ 1 2 ] [ ])).success; 785 expected = false; 786 }; 787 788 testFoldAttrs = { 789 expr = foldAttrs (n: a: [n] ++ a) [] [ 790 { a = 2; b = 7; } 791 { a = 3; c = 8; } 792 ]; 793 expected = { a = [ 2 3 ]; b = [7]; c = [8];}; 794 }; 795 796 testListCommonPrefixExample1 = { 797 expr = lists.commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ]; 798 expected = [ 1 2 ]; 799 }; 800 testListCommonPrefixExample2 = { 801 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ]; 802 expected = [ 1 2 3 ]; 803 }; 804 testListCommonPrefixExample3 = { 805 expr = lists.commonPrefix [ 1 2 3 ] [ 4 5 6 ]; 806 expected = [ ]; 807 }; 808 testListCommonPrefixEmpty = { 809 expr = lists.commonPrefix [ ] [ 1 2 3 ]; 810 expected = [ ]; 811 }; 812 testListCommonPrefixSame = { 813 expr = lists.commonPrefix [ 1 2 3 ] [ 1 2 3 ]; 814 expected = [ 1 2 3 ]; 815 }; 816 testListCommonPrefixLazy = { 817 expr = lists.commonPrefix [ 1 ] [ 1 (abort "lib.lists.commonPrefix shouldn't evaluate this")]; 818 expected = [ 1 ]; 819 }; 820 # This would stack overflow if `commonPrefix` were implemented using recursion 821 testListCommonPrefixLong = 822 let 823 longList = genList (n: n) 100000; 824 in { 825 expr = lists.commonPrefix longList longList; 826 expected = longList; 827 }; 828 829 testSort = { 830 expr = sort builtins.lessThan [ 40 2 30 42 ]; 831 expected = [2 30 40 42]; 832 }; 833 834 testSortOn = { 835 expr = sortOn stringLength [ "aa" "b" "cccc" ]; 836 expected = [ "b" "aa" "cccc" ]; 837 }; 838 839 testSortOnEmpty = { 840 expr = sortOn (throw "nope") [ ]; 841 expected = [ ]; 842 }; 843 844 testSortOnIncomparable = { 845 expr = 846 map 847 (x: x.f x.ok) 848 (sortOn (x: x.ok) [ 849 { ok = 1; f = x: x; } 850 { ok = 3; f = x: x + 3; } 851 { ok = 2; f = x: x; } 852 ]); 853 expected = [ 1 2 6 ]; 854 }; 855 856 testReplicate = { 857 expr = replicate 3 "a"; 858 expected = ["a" "a" "a"]; 859 }; 860 861 testToIntShouldConvertStringToInt = { 862 expr = toInt "27"; 863 expected = 27; 864 }; 865 866 testToIntShouldThrowErrorIfItCouldNotConvertToInt = { 867 expr = builtins.tryEval (toInt "\"foo\""); 868 expected = { success = false; value = false; }; 869 }; 870 871 testHasAttrByPathTrue = { 872 expr = hasAttrByPath ["a" "b"] { a = { b = "yey"; }; }; 873 expected = true; 874 }; 875 876 testHasAttrByPathFalse = { 877 expr = hasAttrByPath ["a" "b"] { a = { c = "yey"; }; }; 878 expected = false; 879 }; 880 881 testHasAttrByPathNonStrict = { 882 expr = hasAttrByPath [] (throw "do not use"); 883 expected = true; 884 }; 885 886 testLongestValidPathPrefix_empty_empty = { 887 expr = attrsets.longestValidPathPrefix [ ] { }; 888 expected = [ ]; 889 }; 890 891 testLongestValidPathPrefix_empty_nonStrict = { 892 expr = attrsets.longestValidPathPrefix [ ] (throw "do not use"); 893 expected = [ ]; 894 }; 895 896 testLongestValidPathPrefix_zero = { 897 expr = attrsets.longestValidPathPrefix [ "a" (throw "do not use") ] { d = null; }; 898 expected = [ ]; 899 }; 900 901 testLongestValidPathPrefix_zero_b = { 902 expr = attrsets.longestValidPathPrefix [ "z" "z" ] "remarkably harmonious"; 903 expected = [ ]; 904 }; 905 906 testLongestValidPathPrefix_one = { 907 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a = null; }; 908 expected = [ "a" ]; 909 }; 910 911 testLongestValidPathPrefix_two = { 912 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b = null; }; 913 expected = [ "a" "b" ]; 914 }; 915 916 testLongestValidPathPrefix_three = { 917 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c = null; }; 918 expected = [ "a" "b" "c" ]; 919 }; 920 921 testLongestValidPathPrefix_three_extra = { 922 expr = attrsets.longestValidPathPrefix [ "a" "b" "c" ] { a.b.c.d = throw "nope"; }; 923 expected = [ "a" "b" "c" ]; 924 }; 925 926 testFindFirstIndexExample1 = { 927 expr = lists.findFirstIndex (x: x > 3) (abort "index found, so a default must not be evaluated") [ 1 6 4 ]; 928 expected = 1; 929 }; 930 931 testFindFirstIndexExample2 = { 932 expr = lists.findFirstIndex (x: x > 9) "a very specific default" [ 1 6 4 ]; 933 expected = "a very specific default"; 934 }; 935 936 testFindFirstIndexEmpty = { 937 expr = lists.findFirstIndex (abort "when the list is empty, the predicate is not needed") null []; 938 expected = null; 939 }; 940 941 testFindFirstIndexSingleMatch = { 942 expr = lists.findFirstIndex (x: x == 5) null [ 5 ]; 943 expected = 0; 944 }; 945 946 testFindFirstIndexSingleDefault = { 947 expr = lists.findFirstIndex (x: false) null [ (abort "if the predicate doesn't access the value, it must not be evaluated") ]; 948 expected = null; 949 }; 950 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; }; 954 }; 955 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); 959 expected = 1000000; 960 }; 961 962 testFindFirstIndexLazy = { 963 expr = lists.findFirstIndex (x: x == 1) null [ 1 (abort "list elements after the match must not be evaluated") ]; 964 expected = 0; 965 }; 966 967 testFindFirstExample1 = { 968 expr = lists.findFirst (x: x > 3) 7 [ 1 6 4 ]; 969 expected = 6; 970 }; 971 972 testFindFirstExample2 = { 973 expr = lists.findFirst (x: x > 9) 7 [ 1 6 4 ]; 974 expected = 7; 975 }; 976 977 testAllUnique_true = { 978 expr = allUnique [ 3 2 4 1 ]; 979 expected = true; 980 }; 981 testAllUnique_false = { 982 expr = allUnique [ 3 2 3 4 ]; 983 expected = false; 984 }; 985 986# ATTRSETS 987 988 testConcatMapAttrs = { 989 expr = concatMapAttrs 990 (name: value: { 991 ${name} = value; 992 ${name + value} = value; 993 }) 994 { 995 foo = "bar"; 996 foobar = "baz"; 997 }; 998 expected = { 999 foo = "bar"; 1000 foobar = "baz"; 1001 foobarbaz = "baz"; 1002 }; 1003 }; 1004 1005 # code from example 1006 testFoldlAttrs = { 1007 expr = { 1008 example = foldlAttrs 1009 (acc: name: value: { 1010 sum = acc.sum + value; 1011 names = acc.names ++ [ name ]; 1012 }) 1013 { sum = 0; names = [ ]; } 1014 { 1015 foo = 1; 1016 bar = 10; 1017 }; 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; }; 1024 }; 1025 expected = { 1026 example = { 1027 sum = 11; 1028 names = [ "bar" "foo" ]; 1029 }; 1030 emptySet = 123; 1031 valuesNotNeeded = 3; 1032 trivialAcc = 121; 1033 }; 1034 }; 1035 1036 1037 testMergeAttrsListExample1 = { 1038 expr = attrsets.mergeAttrsList [ { a = 0; b = 1; } { c = 2; d = 3; } ]; 1039 expected = { a = 0; b = 1; c = 2; d = 3; }; 1040 }; 1041 testMergeAttrsListExample2 = { 1042 expr = attrsets.mergeAttrsList [ { a = 0; } { a = 1; } ]; 1043 expected = { a = 1; }; 1044 }; 1045 testMergeAttrsListExampleMany = 1046 let 1047 list = genList (n: 1048 listToAttrs (genList (m: 1049 let 1050 # Integer divide n by two to create duplicate attributes 1051 str = "halfn${toString (n / 2)}m${toString m}"; 1052 in 1053 nameValuePair str str 1054 ) 100) 1055 ) 100; 1056 in { 1057 expr = attrsets.mergeAttrsList list; 1058 expected = foldl' mergeAttrs { } list; 1059 }; 1060 1061 # code from the example 1062 testRecursiveUpdateUntil = { 1063 expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) { 1064 # first attribute set 1065 foo.bar = 1; 1066 foo.baz = 2; 1067 bar = 3; 1068 } { 1069 #second attribute set 1070 foo.bar = 1; 1071 foo.quz = 2; 1072 baz = 4; 1073 }; 1074 expected = { 1075 foo.bar = 1; # 'foo.*' from the second set 1076 foo.quz = 2; # 1077 bar = 3; # 'bar' from the first set 1078 baz = 4; # 'baz' from the second set 1079 }; 1080 }; 1081 1082 testMatchAttrsMatchingExact = { 1083 expr = matchAttrs { cpu = { bits = 64; }; } { cpu = { bits = 64; }; }; 1084 expected = true; 1085 }; 1086 1087 testMatchAttrsMismatch = { 1088 expr = matchAttrs { cpu = { bits = 128; }; } { cpu = { bits = 64; }; }; 1089 expected = false; 1090 }; 1091 1092 testMatchAttrsMatchingImplicit = { 1093 expr = matchAttrs { cpu = { }; } { cpu = { bits = 64; }; }; 1094 expected = true; 1095 }; 1096 1097 testMatchAttrsMissingAttrs = { 1098 expr = matchAttrs { cpu = {}; } { }; 1099 expected = false; 1100 }; 1101 1102 testOverrideExistingEmpty = { 1103 expr = overrideExisting {} { a = 1; }; 1104 expected = {}; 1105 }; 1106 1107 testOverrideExistingDisjoint = { 1108 expr = overrideExisting { b = 2; } { a = 1; }; 1109 expected = { b = 2; }; 1110 }; 1111 1112 testOverrideExistingOverride = { 1113 expr = overrideExisting { a = 3; b = 2; } { a = 1; }; 1114 expected = { a = 1; b = 2; }; 1115 }; 1116 1117 testListAttrsReverse = let 1118 exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;}; 1119 exampleSingletonList = [{name="foo"; value=1;}]; 1120 in { 1121 expr = { 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;}]); 1125 }; 1126 expected = { 1127 isReverseToAttrsToList = true; 1128 isReverseToListToAttrs = true; 1129 testDuplicatePruningBehaviour = [{name="a"; value=2;}]; 1130 }; 1131 }; 1132 1133 testAttrsToListsCanDealWithFunctions = testingEval ( 1134 attrsToList { someFunc= a: a + 1;} 1135 ); 1136 1137# GENERATORS 1138# these tests assume attributes are converted to lists 1139# in alphabetical order 1140 1141 testMkKeyValueDefault = { 1142 expr = generators.mkKeyValueDefault {} ":" "f:oo" "bar"; 1143 expected = ''f\:oo:bar''; 1144 }; 1145 1146 testMkValueString = { 1147 expr = let 1148 vals = { 1149 int = 42; 1150 string = ''fo"o''; 1151 bool = true; 1152 bool2 = false; 1153 null = null; 1154 # float = 42.23; # floats are strange 1155 }; 1156 in mapAttrs 1157 (const (generators.mkValueStringDefault {})) 1158 vals; 1159 expected = { 1160 int = "42"; 1161 string = ''fo"o''; 1162 bool = "true"; 1163 bool2 = "false"; 1164 null = "null"; 1165 # float = "42.23" true false [ "bar" ] ]''; 1166 }; 1167 }; 1168 1169 testToKeyValue = { 1170 expr = generators.toKeyValue {} { 1171 key = "value"; 1172 "other=key" = "baz"; 1173 }; 1174 expected = '' 1175 key=value 1176 other\=key=baz 1177 ''; 1178 }; 1179 1180 testToINIEmpty = { 1181 expr = generators.toINI {} {}; 1182 expected = ""; 1183 }; 1184 1185 testToINIEmptySection = { 1186 expr = generators.toINI {} { foo = {}; bar = {}; }; 1187 expected = '' 1188 [bar] 1189 1190 [foo] 1191 ''; 1192 }; 1193 1194 testToINIDuplicateKeys = { 1195 expr = generators.toINI { listsAsDuplicateKeys = true; } { foo.bar = true; baz.qux = [ 1 false ]; }; 1196 expected = '' 1197 [baz] 1198 qux=1 1199 qux=false 1200 1201 [foo] 1202 bar=true 1203 ''; 1204 }; 1205 1206 testToINIDefaultEscapes = { 1207 expr = generators.toINI {} { 1208 "no [ and ] allowed unescaped" = { 1209 "and also no = in keys" = 42; 1210 }; 1211 }; 1212 expected = '' 1213 [no \[ and \] allowed unescaped] 1214 and also no \= in keys=42 1215 ''; 1216 }; 1217 1218 testToINIDefaultFull = { 1219 expr = generators.toINI {} { 1220 "section 1" = { 1221 attribute1 = 5; 1222 x = "Me-se JarJar Binx"; 1223 # booleans are converted verbatim by default 1224 boolean = false; 1225 }; 1226 "foo[]" = { 1227 "he\\h=he" = "this is okay"; 1228 }; 1229 }; 1230 expected = '' 1231 [foo\[\]] 1232 he\h\=he=this is okay 1233 1234 [section 1] 1235 attribute1=5 1236 boolean=false 1237 x=Me-se JarJar Binx 1238 ''; 1239 }; 1240 1241 testToINIWithGlobalSectionEmpty = { 1242 expr = generators.toINIWithGlobalSection {} { 1243 globalSection = { 1244 }; 1245 sections = { 1246 }; 1247 }; 1248 expected = '' 1249 ''; 1250 }; 1251 1252 testToINIWithGlobalSectionGlobalEmptyIsTheSameAsToINI = 1253 let 1254 sections = { 1255 "section 1" = { 1256 attribute1 = 5; 1257 x = "Me-se JarJar Binx"; 1258 }; 1259 "foo" = { 1260 "he\\h=he" = "this is okay"; 1261 }; 1262 }; 1263 in { 1264 expr = 1265 generators.toINIWithGlobalSection {} { 1266 globalSection = {}; 1267 sections = sections; 1268 }; 1269 expected = generators.toINI {} sections; 1270 }; 1271 1272 testToINIWithGlobalSectionFull = { 1273 expr = generators.toINIWithGlobalSection {} { 1274 globalSection = { 1275 foo = "bar"; 1276 test = false; 1277 }; 1278 sections = { 1279 "section 1" = { 1280 attribute1 = 5; 1281 x = "Me-se JarJar Binx"; 1282 }; 1283 "foo" = { 1284 "he\\h=he" = "this is okay"; 1285 }; 1286 }; 1287 }; 1288 expected = '' 1289 foo=bar 1290 test=false 1291 1292 [foo] 1293 he\h\=he=this is okay 1294 1295 [section 1] 1296 attribute1=5 1297 x=Me-se JarJar Binx 1298 ''; 1299 }; 1300 1301 testToGitINI = { 1302 expr = generators.toGitINI { 1303 user = { 1304 email = "user@example.org"; 1305 name = "John Doe"; 1306 signingKey = "00112233445566778899AABBCCDDEEFF"; 1307 }; 1308 gpg.program = "path-to-gpg"; 1309 tag.gpgSign = true; 1310 include.path = "~/path/to/config.inc"; 1311 includeIf."gitdif:~/src/dir".path = "~/path/to/conditional.inc"; 1312 extra = { 1313 boolean = true; 1314 integer = 38; 1315 name = "value"; 1316 subsection.value = "test"; 1317 };}; 1318 expected = '' 1319 [extra] 1320 ${"\t"}boolean = true 1321 ${"\t"}integer = 38 1322 ${"\t"}name = "value" 1323 1324 [extra "subsection"] 1325 ${"\t"}value = "test" 1326 1327 [gpg] 1328 ${"\t"}program = "path-to-gpg" 1329 1330 [include] 1331 ${"\t"}path = "~/path/to/config.inc" 1332 1333 [includeIf "gitdif:~/src/dir"] 1334 ${"\t"}path = "~/path/to/conditional.inc" 1335 1336 [tag] 1337 ${"\t"}gpgSign = true 1338 1339 [user] 1340 ${"\t"}email = "user@example.org" 1341 ${"\t"}name = "John Doe" 1342 ${"\t"}signingKey = "00112233445566778899AABBCCDDEEFF" 1343 ''; 1344 }; 1345 1346 # right now only invocation check 1347 testToJSONSimple = 1348 let val = { 1349 foobar = [ "baz" 1 2 3 ]; 1350 }; 1351 in { 1352 expr = generators.toJSON {} val; 1353 # trivial implementation 1354 expected = builtins.toJSON val; 1355 }; 1356 1357 # right now only invocation check 1358 testToYAMLSimple = 1359 let val = { 1360 list = [ { one = 1; } { two = 2; } ]; 1361 all = 42; 1362 }; 1363 in { 1364 expr = generators.toYAML {} val; 1365 # trivial implementation 1366 expected = builtins.toJSON val; 1367 }; 1368 1369 testToPretty = 1370 let 1371 deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; }; 1372 in { 1373 expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec { 1374 int = 42; 1375 float = 0.1337; 1376 bool = true; 1377 emptystring = ""; 1378 string = "fn\${o}\"r\\d"; 1379 newlinestring = "\n"; 1380 path = /. + "/foo"; 1381 null_ = null; 1382 function = x: x; 1383 functionArgs = { arg ? 4, foo }: arg; 1384 list = [ 3 4 function [ false ] ]; 1385 emptylist = []; 1386 attrs = { foo = null; "foo b/ar" = "baz"; }; 1387 emptyattrs = {}; 1388 drv = deriv; 1389 }; 1390 expected = rec { 1391 int = "42"; 1392 float = "0.1337"; 1393 bool = "true"; 1394 emptystring = ''""''; 1395 string = ''"fn\''${o}\"r\\d"''; 1396 newlinestring = "\"\\n\""; 1397 path = "/foo"; 1398 null_ = "null"; 1399 function = "<function>"; 1400 functionArgs = "<function, args: {arg?, foo}>"; 1401 list = "[ 3 4 ${function} [ false ] ]"; 1402 emptylist = "[ ]"; 1403 attrs = "{ foo = null; \"foo b/ar\" = \"baz\"; }"; 1404 emptyattrs = "{ }"; 1405 drv = "<derivation ${deriv.name}>"; 1406 }; 1407 }; 1408 1409 testToPrettyLimit = 1410 let 1411 a.b = 1; 1412 a.c = a; 1413 in { 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}"; 1416 }; 1417 1418 testToPrettyLimitThrow = 1419 let 1420 a.b = 1; 1421 a.c = a; 1422 in { 1423 expr = (builtins.tryEval 1424 (generators.toPretty { } (generators.withRecursion { depthLimit = 2; } a))).success; 1425 expected = false; 1426 }; 1427 1428 testWithRecursionDealsWithFunctors = 1429 let 1430 functor = { 1431 __functor = self: { a, b, }: null; 1432 }; 1433 a = { 1434 value = "1234"; 1435 b = functor; 1436 c.d = functor; 1437 }; 1438 in { 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}"; 1441 }; 1442 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 = '' 1449 hello 1450 ''${there} 1451 te'''st 1452 ''; 1453 multilinestring' = '' 1454 hello 1455 there 1456 test''; 1457 }; 1458 expected = { 1459 list = '' 1460 [ 1461 3 1462 4 1463 [ 1464 false 1465 ] 1466 ]''; 1467 attrs = '' 1468 { 1469 bar = { 1470 foo = "baz"; 1471 }; 1472 foo = null; 1473 }''; 1474 newlinestring = "''\n \n''"; 1475 multilinestring = '' 1476 ''' 1477 hello 1478 '''''${there} 1479 te''''st 1480 '''''; 1481 multilinestring' = '' 1482 ''' 1483 hello 1484 there 1485 test'''''; 1486 1487 }; 1488 }; 1489 1490 testToPrettyAllowPrettyValues = { 1491 expr = generators.toPretty { allowPrettyValues = true; } 1492 { __pretty = v: "«" + v + "»"; val = "foo"; }; 1493 expected = "«foo»"; 1494 }; 1495 1496 testToPlist = { 1497 expr = mapAttrs (const (generators.toPlist { })) { 1498 value = { 1499 nested.values = { 1500 int = 42; 1501 float = 0.1337; 1502 bool = true; 1503 emptystring = ""; 1504 string = "fn\${o}\"r\\d"; 1505 newlinestring = "\n"; 1506 path = /. + "/foo"; 1507 null_ = null; 1508 list = [ 3 4 "test" ]; 1509 emptylist = []; 1510 attrs = { foo = null; "foo b/ar" = "baz"; }; 1511 emptyattrs = {}; 1512 }; 1513 }; 1514 }; 1515 expected = { value = builtins.readFile ./test-to-plist-expected.plist; }; 1516 }; 1517 1518 testToLuaEmptyAttrSet = { 1519 expr = generators.toLua {} {}; 1520 expected = ''{}''; 1521 }; 1522 1523 testToLuaEmptyList = { 1524 expr = generators.toLua {} []; 1525 expected = ''{}''; 1526 }; 1527 1528 testToLuaListOfVariousTypes = { 1529 expr = generators.toLua {} [ null 43 3.14159 true ]; 1530 expected = '' 1531 { 1532 nil, 1533 43, 1534 3.14159, 1535 true 1536 }''; 1537 }; 1538 1539 testToLuaString = { 1540 expr = generators.toLua {} ''double-quote (") and single quotes (')''; 1541 expected = ''"double-quote (\") and single quotes (')"''; 1542 }; 1543 1544 testToLuaAttrsetWithLuaInline = { 1545 expr = generators.toLua {} { x = generators.mkLuaInline ''"abc" .. "def"''; }; 1546 expected = '' 1547 { 1548 ["x"] = ("abc" .. "def") 1549 }''; 1550 }; 1551 1552 testToLuaAttrsetWithSpaceInKey = { 1553 expr = generators.toLua {} { "some space and double-quote (\")" = 42; }; 1554 expected = '' 1555 { 1556 ["some space and double-quote (\")"] = 42 1557 }''; 1558 }; 1559 1560 testToLuaWithoutMultiline = { 1561 expr = generators.toLua { multiline = false; } [ 41 43 ]; 1562 expected = ''{ 41, 43 }''; 1563 }; 1564 1565 testToLuaEmptyBindings = { 1566 expr = generators.toLua { asBindings = true; } {}; 1567 expected = ""; 1568 }; 1569 1570 testToLuaBindings = { 1571 expr = generators.toLua { asBindings = true; } { x1 = 41; _y = { a = 43; }; }; 1572 expected = '' 1573 _y = { 1574 ["a"] = 43 1575 } 1576 x1 = 41 1577 ''; 1578 }; 1579 1580 testToLuaPartialTableBindings = { 1581 expr = generators.toLua { asBindings = true; } { "x.y" = 42; }; 1582 expected = '' 1583 x.y = 42 1584 ''; 1585 }; 1586 1587 testToLuaIndentedBindings = { 1588 expr = generators.toLua { asBindings = true; indent = " "; } { x = { y = 42; }; }; 1589 expected = " x = {\n [\"y\"] = 42\n }\n"; 1590 }; 1591 1592 testToLuaBindingsWithSpace = testingThrow ( 1593 generators.toLua { asBindings = true; } { "with space" = 42; } 1594 ); 1595 1596 testToLuaBindingsWithLeadingDigit = testingThrow ( 1597 generators.toLua { asBindings = true; } { "11eleven" = 42; } 1598 ); 1599 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)''; 1604 }; 1605 expected = '' 1606 { 1607 ["cmd"] = { 1608 "typescript-language-server", 1609 "--stdio" 1610 }, 1611 ["settings"] = { 1612 ["workspace"] = { 1613 ["library"] = (vim.api.nvim_get_runtime_file("", true)) 1614 } 1615 } 1616 }''; 1617 }; 1618 1619# CLI 1620 1621 testToGNUCommandLine = { 1622 expr = cli.toGNUCommandLine {} { 1623 data = builtins.toJSON { id = 0; }; 1624 X = "PUT"; 1625 retry = 3; 1626 retry-delay = null; 1627 url = [ "https://example.com/foo" "https://example.com/bar" ]; 1628 silent = false; 1629 verbose = true; 1630 }; 1631 1632 expected = [ 1633 "-X" "PUT" 1634 "--data" "{\"id\":0}" 1635 "--retry" "3" 1636 "--url" "https://example.com/foo" 1637 "--url" "https://example.com/bar" 1638 "--verbose" 1639 ]; 1640 }; 1641 1642 testToGNUCommandLineShell = { 1643 expr = cli.toGNUCommandLineShell {} { 1644 data = builtins.toJSON { id = 0; }; 1645 X = "PUT"; 1646 retry = 3; 1647 retry-delay = null; 1648 url = [ "https://example.com/foo" "https://example.com/bar" ]; 1649 silent = false; 1650 verbose = true; 1651 }; 1652 1653 expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'"; 1654 }; 1655 1656 testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName { 1657 name = "..foo"; 1658 expected = "foo"; 1659 }; 1660 1661 testSanitizeDerivationNameUnicode = testSanitizeDerivationName { 1662 name = "fö"; 1663 expected = "f-"; 1664 }; 1665 1666 testSanitizeDerivationNameAscii = testSanitizeDerivationName { 1667 name = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; 1668 expected = "-+--.-0123456789-=-?-ABCDEFGHIJKLMNOPQRSTUVWXYZ-_-abcdefghijklmnopqrstuvwxyz-"; 1669 }; 1670 1671 testSanitizeDerivationNameTooLong = testSanitizeDerivationName { 1672 name = "This string is loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"; 1673 expected = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"; 1674 }; 1675 1676 testSanitizeDerivationNameTooLongWithInvalid = testSanitizeDerivationName { 1677 name = "Hello there aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&&&&&&&"; 1678 expected = "there-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-"; 1679 }; 1680 1681 testSanitizeDerivationNameEmpty = testSanitizeDerivationName { 1682 name = ""; 1683 expected = "unknown"; 1684 }; 1685 1686 testFreeformOptions = { 1687 expr = 1688 let 1689 submodule = { lib, ... }: { 1690 freeformType = lib.types.attrsOf (lib.types.submodule { 1691 options.bar = lib.mkOption {}; 1692 }); 1693 options.bar = lib.mkOption {}; 1694 }; 1695 1696 module = { lib, ... }: { 1697 options.foo = lib.mkOption { 1698 type = lib.types.submodule submodule; 1699 }; 1700 }; 1701 1702 options = (evalModules { 1703 modules = [ module ]; 1704 }).options; 1705 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" ] ]; 1709 }; 1710 1711 testCartesianProductOfEmptySet = { 1712 expr = cartesianProduct {}; 1713 expected = [ {} ]; 1714 }; 1715 1716 testCartesianProductOfOneSet = { 1717 expr = cartesianProduct { a = [ 1 2 3 ]; }; 1718 expected = [ { a = 1; } { a = 2; } { a = 3; } ]; 1719 }; 1720 1721 testCartesianProductOfTwoSets = { 1722 expr = cartesianProduct { a = [ 1 ]; b = [ 10 20 ]; }; 1723 expected = [ 1724 { a = 1; b = 10; } 1725 { a = 1; b = 20; } 1726 ]; 1727 }; 1728 1729 testCartesianProductOfTwoSetsWithOneEmpty = { 1730 expr = cartesianProduct { a = [ ]; b = [ 10 20 ]; }; 1731 expected = [ ]; 1732 }; 1733 1734 testCartesianProductOfThreeSets = { 1735 expr = cartesianProduct { 1736 a = [ 1 2 3 ]; 1737 b = [ 10 20 30 ]; 1738 c = [ 100 200 300 ]; 1739 }; 1740 expected = [ 1741 { a = 1; b = 10; c = 100; } 1742 { a = 1; b = 10; c = 200; } 1743 { a = 1; b = 10; c = 300; } 1744 1745 { a = 1; b = 20; c = 100; } 1746 { a = 1; b = 20; c = 200; } 1747 { a = 1; b = 20; c = 300; } 1748 1749 { a = 1; b = 30; c = 100; } 1750 { a = 1; b = 30; c = 200; } 1751 { a = 1; b = 30; c = 300; } 1752 1753 { a = 2; b = 10; c = 100; } 1754 { a = 2; b = 10; c = 200; } 1755 { a = 2; b = 10; c = 300; } 1756 1757 { a = 2; b = 20; c = 100; } 1758 { a = 2; b = 20; c = 200; } 1759 { a = 2; b = 20; c = 300; } 1760 1761 { a = 2; b = 30; c = 100; } 1762 { a = 2; b = 30; c = 200; } 1763 { a = 2; b = 30; c = 300; } 1764 1765 { a = 3; b = 10; c = 100; } 1766 { a = 3; b = 10; c = 200; } 1767 { a = 3; b = 10; c = 300; } 1768 1769 { a = 3; b = 20; c = 100; } 1770 { a = 3; b = 20; c = 200; } 1771 { a = 3; b = 20; c = 300; } 1772 1773 { a = 3; b = 30; c = 100; } 1774 { a = 3; b = 30; c = 200; } 1775 { a = 3; b = 30; c = 300; } 1776 ]; 1777 }; 1778 1779 testMapCartesianProductOfOneSet = { 1780 expr = mapCartesianProduct ({a}: a * 2) { a = [ 1 2 3 ]; }; 1781 expected = [ 2 4 6 ]; 1782 }; 1783 1784 testMapCartesianProductOfTwoSets = { 1785 expr = mapCartesianProduct ({a,b}: a + b) { a = [ 1 ]; b = [ 10 20 ]; }; 1786 expected = [ 11 21 ]; 1787 }; 1788 1789 testMapCartesianProcutOfTwoSetsWithOneEmpty = { 1790 expr = mapCartesianProduct (x: x.a + x.b) { a = [ ]; b = [ 10 20 ]; }; 1791 expected = [ ]; 1792 }; 1793 1794 testMapCartesianProductOfThreeSets = { 1795 expr = mapCartesianProduct ({a,b,c}: a + b + c) { 1796 a = [ 1 2 3 ]; 1797 b = [ 10 20 30 ]; 1798 c = [ 100 200 300 ]; 1799 }; 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 ]; 1801 }; 1802 1803 # The example from the showAttrPath documentation 1804 testShowAttrPathExample = { 1805 expr = showAttrPath [ "foo" "10" "bar" ]; 1806 expected = "foo.\"10\".bar"; 1807 }; 1808 1809 testShowAttrPathEmpty = { 1810 expr = showAttrPath []; 1811 expected = "<root attribute path>"; 1812 }; 1813 1814 testShowAttrPathVarious = { 1815 expr = showAttrPath [ 1816 "." 1817 "foo" 1818 "2" 1819 "a2-b" 1820 "_bc'de" 1821 ]; 1822 expected = ''".".foo."2".a2-b._bc'de''; 1823 }; 1824 1825 testGroupBy = { 1826 expr = groupBy (n: toString (mod n 5)) (range 0 16); 1827 expected = { 1828 "0" = [ 0 5 10 15 ]; 1829 "1" = [ 1 6 11 16 ]; 1830 "2" = [ 2 7 12 ]; 1831 "3" = [ 3 8 13 ]; 1832 "4" = [ 4 9 14 ]; 1833 }; 1834 }; 1835 1836 testGroupBy' = { 1837 expr = groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]; 1838 expected = { false = 3; true = 12; }; 1839 }; 1840 1841 # The example from the updateManyAttrsByPath documentation 1842 testUpdateManyAttrsByPathExample = { 1843 expr = updateManyAttrsByPath [ 1844 { 1845 path = [ "a" "b" ]; 1846 update = old: { d = old.c; }; 1847 } 1848 { 1849 path = [ "a" "b" "c" ]; 1850 update = old: old + 1; 1851 } 1852 { 1853 path = [ "x" "y" ]; 1854 update = old: "xy"; 1855 } 1856 ] { a.b.c = 0; }; 1857 expected = { a = { b = { d = 1; }; }; x = { y = "xy"; }; }; 1858 }; 1859 1860 # If there are no updates, the value is passed through 1861 testUpdateManyAttrsByPathNone = { 1862 expr = updateManyAttrsByPath [] "something"; 1863 expected = "something"; 1864 }; 1865 1866 # A single update to the root path is just like applying the function directly 1867 testUpdateManyAttrsByPathSingleIncrement = { 1868 expr = updateManyAttrsByPath [ 1869 { 1870 path = [ ]; 1871 update = old: old + 1; 1872 } 1873 ] 0; 1874 expected = 1; 1875 }; 1876 1877 # Multiple updates can be applied are done in order 1878 testUpdateManyAttrsByPathMultipleIncrements = { 1879 expr = updateManyAttrsByPath [ 1880 { 1881 path = [ ]; 1882 update = old: old + "a"; 1883 } 1884 { 1885 path = [ ]; 1886 update = old: old + "b"; 1887 } 1888 { 1889 path = [ ]; 1890 update = old: old + "c"; 1891 } 1892 ] ""; 1893 expected = "abc"; 1894 }; 1895 1896 # If an update doesn't use the value, all previous updates are not evaluated 1897 testUpdateManyAttrsByPathLazy = { 1898 expr = updateManyAttrsByPath [ 1899 { 1900 path = [ ]; 1901 update = old: old + throw "nope"; 1902 } 1903 { 1904 path = [ ]; 1905 update = old: "untainted"; 1906 } 1907 ] (throw "start"); 1908 expected = "untainted"; 1909 }; 1910 1911 # Deeply nested attributes can be updated without affecting others 1912 testUpdateManyAttrsByPathDeep = { 1913 expr = updateManyAttrsByPath [ 1914 { 1915 path = [ "a" "b" "c" ]; 1916 update = old: old + 1; 1917 } 1918 ] { 1919 a.b.c = 0; 1920 1921 a.b.z = 0; 1922 a.y.z = 0; 1923 x.y.z = 0; 1924 }; 1925 expected = { 1926 a.b.c = 1; 1927 1928 a.b.z = 0; 1929 a.y.z = 0; 1930 x.y.z = 0; 1931 }; 1932 }; 1933 1934 # Nested attributes are updated first 1935 testUpdateManyAttrsByPathNestedBeforehand = { 1936 expr = updateManyAttrsByPath [ 1937 { 1938 path = [ "a" ]; 1939 update = old: old // { x = old.b; }; 1940 } 1941 { 1942 path = [ "a" "b" ]; 1943 update = old: old + 1; 1944 } 1945 ] { 1946 a.b = 0; 1947 }; 1948 expected = { 1949 a.b = 1; 1950 a.x = 1; 1951 }; 1952 }; 1953 1954 ## Levenshtein distance functions and co. 1955 testCommonPrefixLengthEmpty = { 1956 expr = strings.commonPrefixLength "" "hello"; 1957 expected = 0; 1958 }; 1959 1960 testCommonPrefixLengthSame = { 1961 expr = strings.commonPrefixLength "hello" "hello"; 1962 expected = 5; 1963 }; 1964 1965 testCommonPrefixLengthDiffering = { 1966 expr = strings.commonPrefixLength "hello" "hey"; 1967 expected = 2; 1968 }; 1969 1970 testCommonSuffixLengthEmpty = { 1971 expr = strings.commonSuffixLength "" "hello"; 1972 expected = 0; 1973 }; 1974 1975 testCommonSuffixLengthSame = { 1976 expr = strings.commonSuffixLength "hello" "hello"; 1977 expected = 5; 1978 }; 1979 1980 testCommonSuffixLengthDiffering = { 1981 expr = strings.commonSuffixLength "test" "rest"; 1982 expected = 3; 1983 }; 1984 1985 testLevenshteinEmpty = { 1986 expr = strings.levenshtein "" ""; 1987 expected = 0; 1988 }; 1989 1990 testLevenshteinOnlyAdd = { 1991 expr = strings.levenshtein "" "hello there"; 1992 expected = 11; 1993 }; 1994 1995 testLevenshteinOnlyRemove = { 1996 expr = strings.levenshtein "hello there" ""; 1997 expected = 11; 1998 }; 1999 2000 testLevenshteinOnlyTransform = { 2001 expr = strings.levenshtein "abcdef" "ghijkl"; 2002 expected = 6; 2003 }; 2004 2005 testLevenshteinMixed = { 2006 expr = strings.levenshtein "kitchen" "sitting"; 2007 expected = 5; 2008 }; 2009 2010 testLevenshteinAtMostZeroFalse = { 2011 expr = strings.levenshteinAtMost 0 "foo" "boo"; 2012 expected = false; 2013 }; 2014 2015 testLevenshteinAtMostZeroTrue = { 2016 expr = strings.levenshteinAtMost 0 "foo" "foo"; 2017 expected = true; 2018 }; 2019 2020 testLevenshteinAtMostOneFalse = { 2021 expr = strings.levenshteinAtMost 1 "car" "ct"; 2022 expected = false; 2023 }; 2024 2025 testLevenshteinAtMostOneTrue = { 2026 expr = strings.levenshteinAtMost 1 "car" "cr"; 2027 expected = true; 2028 }; 2029 2030 # We test levenshteinAtMost 2 particularly well because it uses a complicated 2031 # implementation 2032 testLevenshteinAtMostTwoIsEmpty = { 2033 expr = strings.levenshteinAtMost 2 "" ""; 2034 expected = true; 2035 }; 2036 2037 testLevenshteinAtMostTwoIsZero = { 2038 expr = strings.levenshteinAtMost 2 "abcdef" "abcdef"; 2039 expected = true; 2040 }; 2041 2042 testLevenshteinAtMostTwoIsOne = { 2043 expr = strings.levenshteinAtMost 2 "abcdef" "abddef"; 2044 expected = true; 2045 }; 2046 2047 testLevenshteinAtMostTwoDiff0False = { 2048 expr = strings.levenshteinAtMost 2 "abcdef" "aczyef"; 2049 expected = false; 2050 }; 2051 2052 testLevenshteinAtMostTwoDiff0Outer = { 2053 expr = strings.levenshteinAtMost 2 "abcdef" "zbcdez"; 2054 expected = true; 2055 }; 2056 2057 testLevenshteinAtMostTwoDiff0DelLeft = { 2058 expr = strings.levenshteinAtMost 2 "abcdef" "bcdefz"; 2059 expected = true; 2060 }; 2061 2062 testLevenshteinAtMostTwoDiff0DelRight = { 2063 expr = strings.levenshteinAtMost 2 "abcdef" "zabcde"; 2064 expected = true; 2065 }; 2066 2067 testLevenshteinAtMostTwoDiff1False = { 2068 expr = strings.levenshteinAtMost 2 "abcdef" "bddez"; 2069 expected = false; 2070 }; 2071 2072 testLevenshteinAtMostTwoDiff1DelLeft = { 2073 expr = strings.levenshteinAtMost 2 "abcdef" "bcdez"; 2074 expected = true; 2075 }; 2076 2077 testLevenshteinAtMostTwoDiff1DelRight = { 2078 expr = strings.levenshteinAtMost 2 "abcdef" "zbcde"; 2079 expected = true; 2080 }; 2081 2082 testLevenshteinAtMostTwoDiff2False = { 2083 expr = strings.levenshteinAtMost 2 "hello" "hxo"; 2084 expected = false; 2085 }; 2086 2087 testLevenshteinAtMostTwoDiff2True = { 2088 expr = strings.levenshteinAtMost 2 "hello" "heo"; 2089 expected = true; 2090 }; 2091 2092 testLevenshteinAtMostTwoDiff3 = { 2093 expr = strings.levenshteinAtMost 2 "hello" "ho"; 2094 expected = false; 2095 }; 2096 2097 testLevenshteinAtMostThreeFalse = { 2098 expr = strings.levenshteinAtMost 3 "hello" "Holla!"; 2099 expected = false; 2100 }; 2101 2102 testLevenshteinAtMostThreeTrue = { 2103 expr = strings.levenshteinAtMost 3 "hello" "Holla"; 2104 expected = true; 2105 }; 2106 2107 # DERIVATIONS 2108 2109 testLazyDerivationIsLazyInDerivationForAttrNames = { 2110 expr = attrNames (lazyDerivation { 2111 derivation = throw "not lazy enough"; 2112 }); 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" ]; 2116 }; 2117 2118 testLazyDerivationIsLazyInDerivationForPassthruAttr = { 2119 expr = (lazyDerivation { 2120 derivation = throw "not lazy enough"; 2121 passthru.tests = "whatever is in tests"; 2122 }).tests; 2123 expected = "whatever is in tests"; 2124 }; 2125 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"; 2131 }).foo; 2132 expected = "whatever is in foo"; 2133 }; 2134 2135 testLazyDerivationIsLazyInDerivationForMeta = { 2136 expr = (lazyDerivation { 2137 derivation = throw "not lazy enough"; 2138 meta = "whatever is in meta"; 2139 }).meta; 2140 expected = "whatever is in meta"; 2141 }; 2142 2143 testLazyDerivationReturnsDerivationAttrs = let 2144 derivation = { 2145 type = "derivation"; 2146 outputs = ["out"]; 2147 out = "test out"; 2148 outPath = "test outPath"; 2149 outputName = "out"; 2150 drvPath = "test drvPath"; 2151 name = "test name"; 2152 system = "test system"; 2153 meta = "test meta"; 2154 }; 2155 in { 2156 expr = lazyDerivation { inherit derivation; }; 2157 expected = derivation; 2158 }; 2159 2160 testOptionalDrvAttr = let 2161 mkDerivation = args: derivation (args // { 2162 builder = "builder"; 2163 system = "system"; 2164 __ignoreNulls = true; 2165 }); 2166 in { 2167 expr = (mkDerivation { 2168 name = "foo"; 2169 x = optionalDrvAttr true 1; 2170 y = optionalDrvAttr false 1; 2171 }).drvPath; 2172 expected = (mkDerivation { 2173 name = "foo"; 2174 x = 1; 2175 }).drvPath; 2176 }; 2177 2178 testLazyDerivationMultiOutputReturnsDerivationAttrs = let 2179 derivation = { 2180 type = "derivation"; 2181 outputs = ["out" "dev"]; 2182 dev = "test dev"; 2183 out = "test out"; 2184 outPath = "test outPath"; 2185 outputName = "out"; 2186 drvPath = "test drvPath"; 2187 name = "test name"; 2188 system = "test system"; 2189 meta.position = "/hi:23"; 2190 }; 2191 in { 2192 expr = lazyDerivation { inherit derivation; outputs = ["out" "dev"]; passthru.meta.position = "/hi:23"; }; 2193 expected = derivation; 2194 }; 2195 2196 testTypeDescriptionInt = { 2197 expr = (with types; int).description; 2198 expected = "signed integer"; 2199 }; 2200 testTypeDescriptionIntsPositive = { 2201 expr = (with types; ints.positive).description; 2202 expected = "positive integer, meaning >0"; 2203 }; 2204 testTypeDescriptionIntsPositiveOrEnumAuto = { 2205 expr = (with types; either ints.positive (enum ["auto"])).description; 2206 expected = ''positive integer, meaning >0, or value "auto" (singular enum)''; 2207 }; 2208 testTypeDescriptionListOfPositive = { 2209 expr = (with types; listOf ints.positive).description; 2210 expected = "list of (positive integer, meaning >0)"; 2211 }; 2212 testTypeDescriptionListOfInt = { 2213 expr = (with types; listOf int).description; 2214 expected = "list of signed integer"; 2215 }; 2216 testTypeDescriptionListOfListOfInt = { 2217 expr = (with types; listOf (listOf int)).description; 2218 expected = "list of list of signed integer"; 2219 }; 2220 testTypeDescriptionListOfEitherStrOrBool = { 2221 expr = (with types; listOf (either str bool)).description; 2222 expected = "list of (string or boolean)"; 2223 }; 2224 testTypeDescriptionEitherListOfStrOrBool = { 2225 expr = (with types; either (listOf bool) str).description; 2226 expected = "(list of boolean) or string"; 2227 }; 2228 testTypeDescriptionEitherStrOrListOfBool = { 2229 expr = (with types; either str (listOf bool)).description; 2230 expected = "string or list of boolean"; 2231 }; 2232 testTypeDescriptionOneOfListOfStrOrBool = { 2233 expr = (with types; oneOf [ (listOf bool) str ]).description; 2234 expected = "(list of boolean) or string"; 2235 }; 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"; 2239 }; 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"; 2243 }; 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"; 2247 }; 2248 testTypeDescriptionEitherNullOrBoolOrString = { 2249 expr = (with types; either (nullOr bool) str).description; 2250 expected = "null or boolean or string"; 2251 }; 2252 testTypeDescriptionEitherListOfEitherBoolOrStrOrInt = { 2253 expr = (with types; either (listOf (either bool str)) int).description; 2254 expected = "(list of (boolean or string)) or signed integer"; 2255 }; 2256 testTypeDescriptionEitherIntOrListOrEitherBoolOrStr = { 2257 expr = (with types; either int (listOf (either bool str))).description; 2258 expected = "signed integer or list of (boolean or string)"; 2259 }; 2260 2261# Meta 2262 testGetExe'Output = { 2263 expr = getExe' { 2264 type = "derivation"; 2265 out = "somelonghash"; 2266 bin = "somelonghash"; 2267 } "executable"; 2268 expected = "somelonghash/bin/executable"; 2269 }; 2270 2271 testGetExeOutput = { 2272 expr = getExe { 2273 type = "derivation"; 2274 out = "somelonghash"; 2275 bin = "somelonghash"; 2276 meta.mainProgram = "mainProgram"; 2277 }; 2278 expected = "somelonghash/bin/mainProgram"; 2279 }; 2280 2281 testGetExe'FailureFirstArg = testingThrow ( 2282 getExe' "not a derivation" "executable" 2283 ); 2284 2285 testGetExe'FailureSecondArg = testingThrow ( 2286 getExe' { type = "derivation"; } "dir/executable" 2287 ); 2288 2289 testPlatformMatch = { 2290 expr = meta.platformMatch { system = "x86_64-linux"; } "x86_64-linux"; 2291 expected = true; 2292 }; 2293 2294 testPlatformMatchAttrs = { 2295 expr = meta.platformMatch (systems.elaborate "x86_64-linux") (systems.elaborate "x86_64-linux").parsed; 2296 expected = true; 2297 }; 2298 2299 testPlatformMatchNoMatch = { 2300 expr = meta.platformMatch { system = "x86_64-darwin"; } "x86_64-linux"; 2301 expected = false; 2302 }; 2303 2304 testPlatformMatchMissingSystem = { 2305 expr = meta.platformMatch { } "x86_64-linux"; 2306 expected = false; 2307 }; 2308 2309 testPackagesFromDirectoryRecursive = { 2310 expr = packagesFromDirectoryRecursive { 2311 callPackage = path: overrides: import path overrides; 2312 directory = ./packages-from-directory; 2313 }; 2314 expected = { 2315 a = "a"; 2316 b = "b"; 2317 # Note: Other files/directories in `./test-data/c/` are ignored and can be 2318 # used by `package.nix`. 2319 c = "c"; 2320 my-namespace = { 2321 d = "d"; 2322 e = "e"; 2323 f = "f"; 2324 my-sub-namespace = { 2325 g = "g"; 2326 h = "h"; 2327 }; 2328 }; 2329 }; 2330 }; 2331 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; 2338 }; 2339 expected = "c"; 2340 }; 2341}