at 23.05-pre 36 kB view raw
1# to run these tests: 2# nix-instantiate --eval --strict nixpkgs/lib/tests/misc.nix 3# if the resulting list is empty, all tests passed 4with import ../default.nix; 5 6let 7 8 testSanitizeDerivationName = { name, expected }: 9 let 10 drv = derivation { 11 name = strings.sanitizeDerivationName name; 12 builder = "x"; 13 system = "x"; 14 }; 15 in { 16 # Evaluate the derivation so an invalid name would be caught 17 expr = builtins.seq drv.drvPath drv.name; 18 inherit expected; 19 }; 20 21in 22 23runTests { 24 25# TRIVIAL 26 27 testId = { 28 expr = id 1; 29 expected = 1; 30 }; 31 32 testConst = { 33 expr = const 2 3; 34 expected = 2; 35 }; 36 37 testPipe = { 38 expr = pipe 2 [ 39 (x: x + 2) # 2 + 2 = 4 40 (x: x * 2) # 4 * 2 = 8 41 ]; 42 expected = 8; 43 }; 44 45 testPipeEmpty = { 46 expr = pipe 2 []; 47 expected = 2; 48 }; 49 50 testPipeStrings = { 51 expr = pipe [ 3 4 ] [ 52 (map toString) 53 (map (s: s + "\n")) 54 concatStrings 55 ]; 56 expected = '' 57 3 58 4 59 ''; 60 }; 61 62 /* 63 testOr = { 64 expr = or true false; 65 expected = true; 66 }; 67 */ 68 69 testAnd = { 70 expr = and true false; 71 expected = false; 72 }; 73 74 testFix = { 75 expr = fix (x: {a = if x ? a then "a" else "b";}); 76 expected = {a = "a";}; 77 }; 78 79 testComposeExtensions = { 80 expr = let obj = makeExtensible (self: { foo = self.bar; }); 81 f = self: super: { bar = false; baz = true; }; 82 g = self: super: { bar = super.baz or false; }; 83 f_o_g = composeExtensions f g; 84 composed = obj.extend f_o_g; 85 in composed.foo; 86 expected = true; 87 }; 88 89 testComposeManyExtensions0 = { 90 expr = let obj = makeExtensible (self: { foo = true; }); 91 emptyComposition = composeManyExtensions []; 92 composed = obj.extend emptyComposition; 93 in composed.foo; 94 expected = true; 95 }; 96 97 testComposeManyExtensions = 98 let f = self: super: { bar = false; baz = true; }; 99 g = self: super: { bar = super.baz or false; }; 100 h = self: super: { qux = super.bar or false; }; 101 obj = makeExtensible (self: { foo = self.qux; }); 102 in { 103 expr = let composition = composeManyExtensions [f g h]; 104 composed = obj.extend composition; 105 in composed.foo; 106 expected = (obj.extend (composeExtensions f (composeExtensions g h))).foo; 107 }; 108 109 testBitAnd = { 110 expr = (bitAnd 3 10); 111 expected = 2; 112 }; 113 114 testBitOr = { 115 expr = (bitOr 3 10); 116 expected = 11; 117 }; 118 119 testBitXor = { 120 expr = (bitXor 3 10); 121 expected = 9; 122 }; 123 124 testToHexString = { 125 expr = toHexString 250; 126 expected = "FA"; 127 }; 128 129 testToBaseDigits = { 130 expr = toBaseDigits 2 6; 131 expected = [ 1 1 0 ]; 132 }; 133 134 testFunctionArgsFunctor = { 135 expr = functionArgs { __functor = self: { a, b }: null; }; 136 expected = { a = false; b = false; }; 137 }; 138 139 testFunctionArgsSetFunctionArgs = { 140 expr = functionArgs (setFunctionArgs (args: args.x) { x = false; }); 141 expected = { x = false; }; 142 }; 143 144# STRINGS 145 146 testConcatMapStrings = { 147 expr = concatMapStrings (x: x + ";") ["a" "b" "c"]; 148 expected = "a;b;c;"; 149 }; 150 151 testConcatStringsSep = { 152 expr = concatStringsSep "," ["a" "b" "c"]; 153 expected = "a,b,c"; 154 }; 155 156 testSplitStringsSimple = { 157 expr = strings.splitString "." "a.b.c.d"; 158 expected = [ "a" "b" "c" "d" ]; 159 }; 160 161 testSplitStringsEmpty = { 162 expr = strings.splitString "." "a..b"; 163 expected = [ "a" "" "b" ]; 164 }; 165 166 testSplitStringsOne = { 167 expr = strings.splitString ":" "a.b"; 168 expected = [ "a.b" ]; 169 }; 170 171 testSplitStringsNone = { 172 expr = strings.splitString "." ""; 173 expected = [ "" ]; 174 }; 175 176 testSplitStringsFirstEmpty = { 177 expr = strings.splitString "/" "/a/b/c"; 178 expected = [ "" "a" "b" "c" ]; 179 }; 180 181 testSplitStringsLastEmpty = { 182 expr = strings.splitString ":" "2001:db8:0:0042::8a2e:370:"; 183 expected = [ "2001" "db8" "0" "0042" "" "8a2e" "370" "" ]; 184 }; 185 186 testSplitStringsRegex = { 187 expr = strings.splitString "\\[{}]()^$?*+|." "A\\[{}]()^$?*+|.B"; 188 expected = [ "A" "B" ]; 189 }; 190 191 testSplitStringsDerivation = { 192 expr = take 3 (strings.splitString "/" (derivation { 193 name = "name"; 194 builder = "builder"; 195 system = "system"; 196 })); 197 expected = ["" "nix" "store"]; 198 }; 199 200 testSplitVersionSingle = { 201 expr = versions.splitVersion "1"; 202 expected = [ "1" ]; 203 }; 204 205 testSplitVersionDouble = { 206 expr = versions.splitVersion "1.2"; 207 expected = [ "1" "2" ]; 208 }; 209 210 testSplitVersionTriple = { 211 expr = versions.splitVersion "1.2.3"; 212 expected = [ "1" "2" "3" ]; 213 }; 214 215 testIsStorePath = { 216 expr = 217 let goodPath = 218 "${builtins.storeDir}/d945ibfx9x185xf04b890y4f9g3cbb63-python-2.7.11"; 219 in { 220 storePath = isStorePath goodPath; 221 storePathDerivation = isStorePath (import ../.. { system = "x86_64-linux"; }).hello; 222 storePathAppendix = isStorePath 223 "${goodPath}/bin/python"; 224 nonAbsolute = isStorePath (concatStrings (tail (stringToCharacters goodPath))); 225 asPath = isStorePath (/. + goodPath); 226 otherPath = isStorePath "/something/else"; 227 otherVals = { 228 attrset = isStorePath {}; 229 list = isStorePath []; 230 int = isStorePath 42; 231 }; 232 }; 233 expected = { 234 storePath = true; 235 storePathDerivation = true; 236 storePathAppendix = false; 237 nonAbsolute = false; 238 asPath = true; 239 otherPath = false; 240 otherVals = { 241 attrset = false; 242 list = false; 243 int = false; 244 }; 245 }; 246 }; 247 248 testEscapeXML = { 249 expr = escapeXML ''"test" 'test' < & >''; 250 expected = "&quot;test&quot; &apos;test&apos; &lt; &amp; &gt;"; 251 }; 252 253 testToShellVars = { 254 expr = '' 255 ${toShellVars { 256 STRing01 = "just a 'string'"; 257 _array_ = [ "with" "more strings" ]; 258 assoc."with some" = '' 259 strings 260 possibly newlines 261 ''; 262 drv = { 263 outPath = "/drv"; 264 foo = "ignored attribute"; 265 }; 266 path = /path; 267 stringable = { 268 __toString = _: "hello toString"; 269 bar = "ignored attribute"; 270 }; 271 }} 272 ''; 273 expected = '' 274 STRing01='just a '\'''string'\'''' 275 declare -a _array_=('with' 'more strings') 276 declare -A assoc=(['with some']='strings 277 possibly newlines 278 ') 279 drv='/drv' 280 path='/path' 281 stringable='hello toString' 282 ''; 283 }; 284 285 testHasInfixFalse = { 286 expr = hasInfix "c" "abde"; 287 expected = false; 288 }; 289 290 testHasInfixTrue = { 291 expr = hasInfix "c" "abcde"; 292 expected = true; 293 }; 294 295 testHasInfixDerivation = { 296 expr = hasInfix "hello" (import ../.. { system = "x86_64-linux"; }).hello; 297 expected = true; 298 }; 299 300 testHasInfixPath = { 301 expr = hasInfix "tests" ./.; 302 expected = true; 303 }; 304 305 testHasInfixPathStoreDir = { 306 expr = hasInfix builtins.storeDir ./.; 307 expected = true; 308 }; 309 310 testHasInfixToString = { 311 expr = hasInfix "a" { __toString = _: "a"; }; 312 expected = true; 313 }; 314 315 testNormalizePath = { 316 expr = strings.normalizePath "//a/b//c////d/"; 317 expected = "/a/b/c/d/"; 318 }; 319 320 testCharToInt = { 321 expr = strings.charToInt "A"; 322 expected = 65; 323 }; 324 325 testEscapeC = { 326 expr = strings.escapeC [ " " ] "Hello World"; 327 expected = "Hello\\x20World"; 328 }; 329 330 testToInt = testAllTrue [ 331 # Naive 332 (123 == toInt "123") 333 (0 == toInt "0") 334 # Whitespace Padding 335 (123 == toInt " 123") 336 (123 == toInt "123 ") 337 (123 == toInt " 123 ") 338 (123 == toInt " 123 ") 339 (0 == toInt " 0") 340 (0 == toInt "0 ") 341 (0 == toInt " 0 ") 342 ]; 343 344 testToIntFails = testAllTrue [ 345 ( builtins.tryEval (toInt "") == { success = false; value = false; } ) 346 ( builtins.tryEval (toInt "123 123") == { success = false; value = false; } ) 347 ( builtins.tryEval (toInt "0 123") == { success = false; value = false; } ) 348 ( builtins.tryEval (toInt " 0d ") == { success = false; value = false; } ) 349 ( builtins.tryEval (toInt " 1d ") == { success = false; value = false; } ) 350 ( builtins.tryEval (toInt " d0 ") == { success = false; value = false; } ) 351 ( builtins.tryEval (toInt "00") == { success = false; value = false; } ) 352 ( builtins.tryEval (toInt "01") == { success = false; value = false; } ) 353 ( builtins.tryEval (toInt "002") == { success = false; value = false; } ) 354 ( builtins.tryEval (toInt " 002 ") == { success = false; value = false; } ) 355 ( builtins.tryEval (toInt " foo ") == { success = false; value = false; } ) 356 ( builtins.tryEval (toInt " foo 123 ") == { success = false; value = false; } ) 357 ( builtins.tryEval (toInt " foo123 ") == { success = false; value = false; } ) 358 ]; 359 360 testToIntBase10 = testAllTrue [ 361 # Naive 362 (123 == toIntBase10 "123") 363 (0 == toIntBase10 "0") 364 # Whitespace Padding 365 (123 == toIntBase10 " 123") 366 (123 == toIntBase10 "123 ") 367 (123 == toIntBase10 " 123 ") 368 (123 == toIntBase10 " 123 ") 369 (0 == toIntBase10 " 0") 370 (0 == toIntBase10 "0 ") 371 (0 == toIntBase10 " 0 ") 372 # Zero Padding 373 (123 == toIntBase10 "0123") 374 (123 == toIntBase10 "0000123") 375 (0 == toIntBase10 "000000") 376 # Whitespace and Zero Padding 377 (123 == toIntBase10 " 0123") 378 (123 == toIntBase10 "0123 ") 379 (123 == toIntBase10 " 0123 ") 380 (123 == toIntBase10 " 0000123") 381 (123 == toIntBase10 "0000123 ") 382 (123 == toIntBase10 " 0000123 ") 383 (0 == toIntBase10 " 000000") 384 (0 == toIntBase10 "000000 ") 385 (0 == toIntBase10 " 000000 ") 386 ]; 387 388 testToIntBase10Fails = testAllTrue [ 389 ( builtins.tryEval (toIntBase10 "") == { success = false; value = false; } ) 390 ( builtins.tryEval (toIntBase10 "123 123") == { success = false; value = false; } ) 391 ( builtins.tryEval (toIntBase10 "0 123") == { success = false; value = false; } ) 392 ( builtins.tryEval (toIntBase10 " 0d ") == { success = false; value = false; } ) 393 ( builtins.tryEval (toIntBase10 " 1d ") == { success = false; value = false; } ) 394 ( builtins.tryEval (toIntBase10 " d0 ") == { success = false; value = false; } ) 395 ( builtins.tryEval (toIntBase10 " foo ") == { success = false; value = false; } ) 396 ( builtins.tryEval (toIntBase10 " foo 123 ") == { success = false; value = false; } ) 397 ( builtins.tryEval (toIntBase10 " foo 00123 ") == { success = false; value = false; } ) 398 ( builtins.tryEval (toIntBase10 " foo00123 ") == { success = false; value = false; } ) 399 ]; 400 401# LISTS 402 403 testFilter = { 404 expr = filter (x: x != "a") ["a" "b" "c" "a"]; 405 expected = ["b" "c"]; 406 }; 407 408 testFold = 409 let 410 f = op: fold: fold op 0 (range 0 100); 411 # fold with associative operator 412 assoc = f builtins.add; 413 # fold with non-associative operator 414 nonAssoc = f builtins.sub; 415 in { 416 expr = { 417 assocRight = assoc foldr; 418 # right fold with assoc operator is same as left fold 419 assocRightIsLeft = assoc foldr == assoc foldl; 420 nonAssocRight = nonAssoc foldr; 421 nonAssocLeft = nonAssoc foldl; 422 # with non-assoc operator the fold results are not the same 423 nonAssocRightIsNotLeft = nonAssoc foldl != nonAssoc foldr; 424 # fold is an alias for foldr 425 foldIsRight = nonAssoc fold == nonAssoc foldr; 426 }; 427 expected = { 428 assocRight = 5050; 429 assocRightIsLeft = true; 430 nonAssocRight = 50; 431 nonAssocLeft = (-5050); 432 nonAssocRightIsNotLeft = true; 433 foldIsRight = true; 434 }; 435 }; 436 437 testTake = testAllTrue [ 438 ([] == (take 0 [ 1 2 3 ])) 439 ([1] == (take 1 [ 1 2 3 ])) 440 ([ 1 2 ] == (take 2 [ 1 2 3 ])) 441 ([ 1 2 3 ] == (take 3 [ 1 2 3 ])) 442 ([ 1 2 3 ] == (take 4 [ 1 2 3 ])) 443 ]; 444 445 testFoldAttrs = { 446 expr = foldAttrs (n: a: [n] ++ a) [] [ 447 { a = 2; b = 7; } 448 { a = 3; c = 8; } 449 ]; 450 expected = { a = [ 2 3 ]; b = [7]; c = [8];}; 451 }; 452 453 testSort = { 454 expr = sort builtins.lessThan [ 40 2 30 42 ]; 455 expected = [2 30 40 42]; 456 }; 457 458 testToIntShouldConvertStringToInt = { 459 expr = toInt "27"; 460 expected = 27; 461 }; 462 463 testToIntShouldThrowErrorIfItCouldNotConvertToInt = { 464 expr = builtins.tryEval (toInt "\"foo\""); 465 expected = { success = false; value = false; }; 466 }; 467 468 testHasAttrByPathTrue = { 469 expr = hasAttrByPath ["a" "b"] { a = { b = "yey"; }; }; 470 expected = true; 471 }; 472 473 testHasAttrByPathFalse = { 474 expr = hasAttrByPath ["a" "b"] { a = { c = "yey"; }; }; 475 expected = false; 476 }; 477 478 479# ATTRSETS 480 481 testConcatMapAttrs = { 482 expr = concatMapAttrs 483 (name: value: { 484 ${name} = value; 485 ${name + value} = value; 486 }) 487 { 488 foo = "bar"; 489 foobar = "baz"; 490 }; 491 expected = { 492 foo = "bar"; 493 foobar = "baz"; 494 foobarbaz = "baz"; 495 }; 496 }; 497 498 # code from the example 499 testRecursiveUpdateUntil = { 500 expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) { 501 # first attribute set 502 foo.bar = 1; 503 foo.baz = 2; 504 bar = 3; 505 } { 506 #second attribute set 507 foo.bar = 1; 508 foo.quz = 2; 509 baz = 4; 510 }; 511 expected = { 512 foo.bar = 1; # 'foo.*' from the second set 513 foo.quz = 2; # 514 bar = 3; # 'bar' from the first set 515 baz = 4; # 'baz' from the second set 516 }; 517 }; 518 519 testOverrideExistingEmpty = { 520 expr = overrideExisting {} { a = 1; }; 521 expected = {}; 522 }; 523 524 testOverrideExistingDisjoint = { 525 expr = overrideExisting { b = 2; } { a = 1; }; 526 expected = { b = 2; }; 527 }; 528 529 testOverrideExistingOverride = { 530 expr = overrideExisting { a = 3; b = 2; } { a = 1; }; 531 expected = { a = 1; b = 2; }; 532 }; 533 534# GENERATORS 535# these tests assume attributes are converted to lists 536# in alphabetical order 537 538 testMkKeyValueDefault = { 539 expr = generators.mkKeyValueDefault {} ":" "f:oo" "bar"; 540 expected = ''f\:oo:bar''; 541 }; 542 543 testMkValueString = { 544 expr = let 545 vals = { 546 int = 42; 547 string = ''fo"o''; 548 bool = true; 549 bool2 = false; 550 null = null; 551 # float = 42.23; # floats are strange 552 }; 553 in mapAttrs 554 (const (generators.mkValueStringDefault {})) 555 vals; 556 expected = { 557 int = "42"; 558 string = ''fo"o''; 559 bool = "true"; 560 bool2 = "false"; 561 null = "null"; 562 # float = "42.23" true false [ "bar" ] ]''; 563 }; 564 }; 565 566 testToKeyValue = { 567 expr = generators.toKeyValue {} { 568 key = "value"; 569 "other=key" = "baz"; 570 }; 571 expected = '' 572 key=value 573 other\=key=baz 574 ''; 575 }; 576 577 testToINIEmpty = { 578 expr = generators.toINI {} {}; 579 expected = ""; 580 }; 581 582 testToINIEmptySection = { 583 expr = generators.toINI {} { foo = {}; bar = {}; }; 584 expected = '' 585 [bar] 586 587 [foo] 588 ''; 589 }; 590 591 testToINIDuplicateKeys = { 592 expr = generators.toINI { listsAsDuplicateKeys = true; } { foo.bar = true; baz.qux = [ 1 false ]; }; 593 expected = '' 594 [baz] 595 qux=1 596 qux=false 597 598 [foo] 599 bar=true 600 ''; 601 }; 602 603 testToINIDefaultEscapes = { 604 expr = generators.toINI {} { 605 "no [ and ] allowed unescaped" = { 606 "and also no = in keys" = 42; 607 }; 608 }; 609 expected = '' 610 [no \[ and \] allowed unescaped] 611 and also no \= in keys=42 612 ''; 613 }; 614 615 testToINIDefaultFull = { 616 expr = generators.toINI {} { 617 "section 1" = { 618 attribute1 = 5; 619 x = "Me-se JarJar Binx"; 620 # booleans are converted verbatim by default 621 boolean = false; 622 }; 623 "foo[]" = { 624 "he\\h=he" = "this is okay"; 625 }; 626 }; 627 expected = '' 628 [foo\[\]] 629 he\h\=he=this is okay 630 631 [section 1] 632 attribute1=5 633 boolean=false 634 x=Me-se JarJar Binx 635 ''; 636 }; 637 638 testToINIWithGlobalSectionEmpty = { 639 expr = generators.toINIWithGlobalSection {} { 640 globalSection = { 641 }; 642 sections = { 643 }; 644 }; 645 expected = '' 646 ''; 647 }; 648 649 testToINIWithGlobalSectionGlobalEmptyIsTheSameAsToINI = 650 let 651 sections = { 652 "section 1" = { 653 attribute1 = 5; 654 x = "Me-se JarJar Binx"; 655 }; 656 "foo" = { 657 "he\\h=he" = "this is okay"; 658 }; 659 }; 660 in { 661 expr = 662 generators.toINIWithGlobalSection {} { 663 globalSection = {}; 664 sections = sections; 665 }; 666 expected = generators.toINI {} sections; 667 }; 668 669 testToINIWithGlobalSectionFull = { 670 expr = generators.toINIWithGlobalSection {} { 671 globalSection = { 672 foo = "bar"; 673 test = false; 674 }; 675 sections = { 676 "section 1" = { 677 attribute1 = 5; 678 x = "Me-se JarJar Binx"; 679 }; 680 "foo" = { 681 "he\\h=he" = "this is okay"; 682 }; 683 }; 684 }; 685 expected = '' 686 foo=bar 687 test=false 688 689 [foo] 690 he\h\=he=this is okay 691 692 [section 1] 693 attribute1=5 694 x=Me-se JarJar Binx 695 ''; 696 }; 697 698 /* right now only invocation check */ 699 testToJSONSimple = 700 let val = { 701 foobar = [ "baz" 1 2 3 ]; 702 }; 703 in { 704 expr = generators.toJSON {} val; 705 # trivial implementation 706 expected = builtins.toJSON val; 707 }; 708 709 /* right now only invocation check */ 710 testToYAMLSimple = 711 let val = { 712 list = [ { one = 1; } { two = 2; } ]; 713 all = 42; 714 }; 715 in { 716 expr = generators.toYAML {} val; 717 # trivial implementation 718 expected = builtins.toJSON val; 719 }; 720 721 testToPretty = 722 let 723 deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; }; 724 in { 725 expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec { 726 int = 42; 727 float = 0.1337; 728 bool = true; 729 emptystring = ""; 730 string = ''fno"rd''; 731 newlinestring = "\n"; 732 path = /. + "/foo"; 733 null_ = null; 734 function = x: x; 735 functionArgs = { arg ? 4, foo }: arg; 736 list = [ 3 4 function [ false ] ]; 737 emptylist = []; 738 attrs = { foo = null; "foo bar" = "baz"; }; 739 emptyattrs = {}; 740 drv = deriv; 741 }; 742 expected = rec { 743 int = "42"; 744 float = "~0.133700"; 745 bool = "true"; 746 emptystring = ''""''; 747 string = ''"fno\"rd"''; 748 newlinestring = "\"\\n\""; 749 path = "/foo"; 750 null_ = "null"; 751 function = "<function>"; 752 functionArgs = "<function, args: {arg?, foo}>"; 753 list = "[ 3 4 ${function} [ false ] ]"; 754 emptylist = "[ ]"; 755 attrs = "{ foo = null; \"foo bar\" = \"baz\"; }"; 756 emptyattrs = "{ }"; 757 drv = "<derivation ${deriv.drvPath}>"; 758 }; 759 }; 760 761 testToPrettyLimit = 762 let 763 a.b = 1; 764 a.c = a; 765 in { 766 expr = generators.toPretty { } (generators.withRecursion { throwOnDepthLimit = false; depthLimit = 2; } a); 767 expected = "{\n b = 1;\n c = {\n b = \"<unevaluated>\";\n c = {\n b = \"<unevaluated>\";\n c = \"<unevaluated>\";\n };\n };\n}"; 768 }; 769 770 testToPrettyLimitThrow = 771 let 772 a.b = 1; 773 a.c = a; 774 in { 775 expr = (builtins.tryEval 776 (generators.toPretty { } (generators.withRecursion { depthLimit = 2; } a))).success; 777 expected = false; 778 }; 779 780 testWithRecursionDealsWithFunctors = 781 let 782 functor = { 783 __functor = self: { a, b, }: null; 784 }; 785 a = { 786 value = "1234"; 787 b = functor; 788 c.d = functor; 789 }; 790 in { 791 expr = generators.toPretty { } (generators.withRecursion { depthLimit = 1; throwOnDepthLimit = false; } a); 792 expected = "{\n b = <function, args: {a, b}>;\n c = {\n d = \"<unevaluated>\";\n };\n value = \"<unevaluated>\";\n}"; 793 }; 794 795 testToPrettyMultiline = { 796 expr = mapAttrs (const (generators.toPretty { })) rec { 797 list = [ 3 4 [ false ] ]; 798 attrs = { foo = null; bar.foo = "baz"; }; 799 newlinestring = "\n"; 800 multilinestring = '' 801 hello 802 there 803 test 804 ''; 805 multilinestring' = '' 806 hello 807 there 808 test''; 809 }; 810 expected = rec { 811 list = '' 812 [ 813 3 814 4 815 [ 816 false 817 ] 818 ]''; 819 attrs = '' 820 { 821 bar = { 822 foo = "baz"; 823 }; 824 foo = null; 825 }''; 826 newlinestring = "''\n \n''"; 827 multilinestring = '' 828 ''' 829 hello 830 there 831 test 832 '''''; 833 multilinestring' = '' 834 ''' 835 hello 836 there 837 test'''''; 838 839 }; 840 }; 841 842 testToPrettyAllowPrettyValues = { 843 expr = generators.toPretty { allowPrettyValues = true; } 844 { __pretty = v: "«" + v + "»"; val = "foo"; }; 845 expected = "«foo»"; 846 }; 847 848 849# CLI 850 851 testToGNUCommandLine = { 852 expr = cli.toGNUCommandLine {} { 853 data = builtins.toJSON { id = 0; }; 854 X = "PUT"; 855 retry = 3; 856 retry-delay = null; 857 url = [ "https://example.com/foo" "https://example.com/bar" ]; 858 silent = false; 859 verbose = true; 860 }; 861 862 expected = [ 863 "-X" "PUT" 864 "--data" "{\"id\":0}" 865 "--retry" "3" 866 "--url" "https://example.com/foo" 867 "--url" "https://example.com/bar" 868 "--verbose" 869 ]; 870 }; 871 872 testToGNUCommandLineShell = { 873 expr = cli.toGNUCommandLineShell {} { 874 data = builtins.toJSON { id = 0; }; 875 X = "PUT"; 876 retry = 3; 877 retry-delay = null; 878 url = [ "https://example.com/foo" "https://example.com/bar" ]; 879 silent = false; 880 verbose = true; 881 }; 882 883 expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'"; 884 }; 885 886 testSanitizeDerivationNameLeadingDots = testSanitizeDerivationName { 887 name = "..foo"; 888 expected = "foo"; 889 }; 890 891 testSanitizeDerivationNameUnicode = testSanitizeDerivationName { 892 name = "fö"; 893 expected = "f-"; 894 }; 895 896 testSanitizeDerivationNameAscii = testSanitizeDerivationName { 897 name = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; 898 expected = "-+--.-0123456789-=-?-ABCDEFGHIJKLMNOPQRSTUVWXYZ-_-abcdefghijklmnopqrstuvwxyz-"; 899 }; 900 901 testSanitizeDerivationNameTooLong = testSanitizeDerivationName { 902 name = "This string is loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"; 903 expected = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"; 904 }; 905 906 testSanitizeDerivationNameTooLongWithInvalid = testSanitizeDerivationName { 907 name = "Hello there aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&&&&&&&"; 908 expected = "there-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-"; 909 }; 910 911 testSanitizeDerivationNameEmpty = testSanitizeDerivationName { 912 name = ""; 913 expected = "unknown"; 914 }; 915 916 testFreeformOptions = { 917 expr = 918 let 919 submodule = { lib, ... }: { 920 freeformType = lib.types.attrsOf (lib.types.submodule { 921 options.bar = lib.mkOption {}; 922 }); 923 options.bar = lib.mkOption {}; 924 }; 925 926 module = { lib, ... }: { 927 options.foo = lib.mkOption { 928 type = lib.types.submodule submodule; 929 }; 930 }; 931 932 options = (evalModules { 933 modules = [ module ]; 934 }).options; 935 936 locs = filter (o: ! o.internal) (optionAttrSetToDocList options); 937 in map (o: o.loc) locs; 938 expected = [ [ "_module" "args" ] [ "foo" ] [ "foo" "<name>" "bar" ] [ "foo" "bar" ] ]; 939 }; 940 941 testCartesianProductOfEmptySet = { 942 expr = cartesianProductOfSets {}; 943 expected = [ {} ]; 944 }; 945 946 testCartesianProductOfOneSet = { 947 expr = cartesianProductOfSets { a = [ 1 2 3 ]; }; 948 expected = [ { a = 1; } { a = 2; } { a = 3; } ]; 949 }; 950 951 testCartesianProductOfTwoSets = { 952 expr = cartesianProductOfSets { a = [ 1 ]; b = [ 10 20 ]; }; 953 expected = [ 954 { a = 1; b = 10; } 955 { a = 1; b = 20; } 956 ]; 957 }; 958 959 testCartesianProductOfTwoSetsWithOneEmpty = { 960 expr = cartesianProductOfSets { a = [ ]; b = [ 10 20 ]; }; 961 expected = [ ]; 962 }; 963 964 testCartesianProductOfThreeSets = { 965 expr = cartesianProductOfSets { 966 a = [ 1 2 3 ]; 967 b = [ 10 20 30 ]; 968 c = [ 100 200 300 ]; 969 }; 970 expected = [ 971 { a = 1; b = 10; c = 100; } 972 { a = 1; b = 10; c = 200; } 973 { a = 1; b = 10; c = 300; } 974 975 { a = 1; b = 20; c = 100; } 976 { a = 1; b = 20; c = 200; } 977 { a = 1; b = 20; c = 300; } 978 979 { a = 1; b = 30; c = 100; } 980 { a = 1; b = 30; c = 200; } 981 { a = 1; b = 30; c = 300; } 982 983 { a = 2; b = 10; c = 100; } 984 { a = 2; b = 10; c = 200; } 985 { a = 2; b = 10; c = 300; } 986 987 { a = 2; b = 20; c = 100; } 988 { a = 2; b = 20; c = 200; } 989 { a = 2; b = 20; c = 300; } 990 991 { a = 2; b = 30; c = 100; } 992 { a = 2; b = 30; c = 200; } 993 { a = 2; b = 30; c = 300; } 994 995 { a = 3; b = 10; c = 100; } 996 { a = 3; b = 10; c = 200; } 997 { a = 3; b = 10; c = 300; } 998 999 { a = 3; b = 20; c = 100; } 1000 { a = 3; b = 20; c = 200; } 1001 { a = 3; b = 20; c = 300; } 1002 1003 { a = 3; b = 30; c = 100; } 1004 { a = 3; b = 30; c = 200; } 1005 { a = 3; b = 30; c = 300; } 1006 ]; 1007 }; 1008 1009 # The example from the showAttrPath documentation 1010 testShowAttrPathExample = { 1011 expr = showAttrPath [ "foo" "10" "bar" ]; 1012 expected = "foo.\"10\".bar"; 1013 }; 1014 1015 testShowAttrPathEmpty = { 1016 expr = showAttrPath []; 1017 expected = "<root attribute path>"; 1018 }; 1019 1020 testShowAttrPathVarious = { 1021 expr = showAttrPath [ 1022 "." 1023 "foo" 1024 "2" 1025 "a2-b" 1026 "_bc'de" 1027 ]; 1028 expected = ''".".foo."2".a2-b._bc'de''; 1029 }; 1030 1031 testGroupBy = { 1032 expr = groupBy (n: toString (mod n 5)) (range 0 16); 1033 expected = { 1034 "0" = [ 0 5 10 15 ]; 1035 "1" = [ 1 6 11 16 ]; 1036 "2" = [ 2 7 12 ]; 1037 "3" = [ 3 8 13 ]; 1038 "4" = [ 4 9 14 ]; 1039 }; 1040 }; 1041 1042 testGroupBy' = { 1043 expr = groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]; 1044 expected = { false = 3; true = 12; }; 1045 }; 1046 1047 # The example from the updateManyAttrsByPath documentation 1048 testUpdateManyAttrsByPathExample = { 1049 expr = updateManyAttrsByPath [ 1050 { 1051 path = [ "a" "b" ]; 1052 update = old: { d = old.c; }; 1053 } 1054 { 1055 path = [ "a" "b" "c" ]; 1056 update = old: old + 1; 1057 } 1058 { 1059 path = [ "x" "y" ]; 1060 update = old: "xy"; 1061 } 1062 ] { a.b.c = 0; }; 1063 expected = { a = { b = { d = 1; }; }; x = { y = "xy"; }; }; 1064 }; 1065 1066 # If there are no updates, the value is passed through 1067 testUpdateManyAttrsByPathNone = { 1068 expr = updateManyAttrsByPath [] "something"; 1069 expected = "something"; 1070 }; 1071 1072 # A single update to the root path is just like applying the function directly 1073 testUpdateManyAttrsByPathSingleIncrement = { 1074 expr = updateManyAttrsByPath [ 1075 { 1076 path = [ ]; 1077 update = old: old + 1; 1078 } 1079 ] 0; 1080 expected = 1; 1081 }; 1082 1083 # Multiple updates can be applied are done in order 1084 testUpdateManyAttrsByPathMultipleIncrements = { 1085 expr = updateManyAttrsByPath [ 1086 { 1087 path = [ ]; 1088 update = old: old + "a"; 1089 } 1090 { 1091 path = [ ]; 1092 update = old: old + "b"; 1093 } 1094 { 1095 path = [ ]; 1096 update = old: old + "c"; 1097 } 1098 ] ""; 1099 expected = "abc"; 1100 }; 1101 1102 # If an update doesn't use the value, all previous updates are not evaluated 1103 testUpdateManyAttrsByPathLazy = { 1104 expr = updateManyAttrsByPath [ 1105 { 1106 path = [ ]; 1107 update = old: old + throw "nope"; 1108 } 1109 { 1110 path = [ ]; 1111 update = old: "untainted"; 1112 } 1113 ] (throw "start"); 1114 expected = "untainted"; 1115 }; 1116 1117 # Deeply nested attributes can be updated without affecting others 1118 testUpdateManyAttrsByPathDeep = { 1119 expr = updateManyAttrsByPath [ 1120 { 1121 path = [ "a" "b" "c" ]; 1122 update = old: old + 1; 1123 } 1124 ] { 1125 a.b.c = 0; 1126 1127 a.b.z = 0; 1128 a.y.z = 0; 1129 x.y.z = 0; 1130 }; 1131 expected = { 1132 a.b.c = 1; 1133 1134 a.b.z = 0; 1135 a.y.z = 0; 1136 x.y.z = 0; 1137 }; 1138 }; 1139 1140 # Nested attributes are updated first 1141 testUpdateManyAttrsByPathNestedBeforehand = { 1142 expr = updateManyAttrsByPath [ 1143 { 1144 path = [ "a" ]; 1145 update = old: old // { x = old.b; }; 1146 } 1147 { 1148 path = [ "a" "b" ]; 1149 update = old: old + 1; 1150 } 1151 ] { 1152 a.b = 0; 1153 }; 1154 expected = { 1155 a.b = 1; 1156 a.x = 1; 1157 }; 1158 }; 1159 1160 ## Levenshtein distance functions and co. 1161 testCommonPrefixLengthEmpty = { 1162 expr = strings.commonPrefixLength "" "hello"; 1163 expected = 0; 1164 }; 1165 1166 testCommonPrefixLengthSame = { 1167 expr = strings.commonPrefixLength "hello" "hello"; 1168 expected = 5; 1169 }; 1170 1171 testCommonPrefixLengthDiffering = { 1172 expr = strings.commonPrefixLength "hello" "hey"; 1173 expected = 2; 1174 }; 1175 1176 testCommonSuffixLengthEmpty = { 1177 expr = strings.commonSuffixLength "" "hello"; 1178 expected = 0; 1179 }; 1180 1181 testCommonSuffixLengthSame = { 1182 expr = strings.commonSuffixLength "hello" "hello"; 1183 expected = 5; 1184 }; 1185 1186 testCommonSuffixLengthDiffering = { 1187 expr = strings.commonSuffixLength "test" "rest"; 1188 expected = 3; 1189 }; 1190 1191 testLevenshteinEmpty = { 1192 expr = strings.levenshtein "" ""; 1193 expected = 0; 1194 }; 1195 1196 testLevenshteinOnlyAdd = { 1197 expr = strings.levenshtein "" "hello there"; 1198 expected = 11; 1199 }; 1200 1201 testLevenshteinOnlyRemove = { 1202 expr = strings.levenshtein "hello there" ""; 1203 expected = 11; 1204 }; 1205 1206 testLevenshteinOnlyTransform = { 1207 expr = strings.levenshtein "abcdef" "ghijkl"; 1208 expected = 6; 1209 }; 1210 1211 testLevenshteinMixed = { 1212 expr = strings.levenshtein "kitchen" "sitting"; 1213 expected = 5; 1214 }; 1215 1216 testLevenshteinAtMostZeroFalse = { 1217 expr = strings.levenshteinAtMost 0 "foo" "boo"; 1218 expected = false; 1219 }; 1220 1221 testLevenshteinAtMostZeroTrue = { 1222 expr = strings.levenshteinAtMost 0 "foo" "foo"; 1223 expected = true; 1224 }; 1225 1226 testLevenshteinAtMostOneFalse = { 1227 expr = strings.levenshteinAtMost 1 "car" "ct"; 1228 expected = false; 1229 }; 1230 1231 testLevenshteinAtMostOneTrue = { 1232 expr = strings.levenshteinAtMost 1 "car" "cr"; 1233 expected = true; 1234 }; 1235 1236 # We test levenshteinAtMost 2 particularly well because it uses a complicated 1237 # implementation 1238 testLevenshteinAtMostTwoIsEmpty = { 1239 expr = strings.levenshteinAtMost 2 "" ""; 1240 expected = true; 1241 }; 1242 1243 testLevenshteinAtMostTwoIsZero = { 1244 expr = strings.levenshteinAtMost 2 "abcdef" "abcdef"; 1245 expected = true; 1246 }; 1247 1248 testLevenshteinAtMostTwoIsOne = { 1249 expr = strings.levenshteinAtMost 2 "abcdef" "abddef"; 1250 expected = true; 1251 }; 1252 1253 testLevenshteinAtMostTwoDiff0False = { 1254 expr = strings.levenshteinAtMost 2 "abcdef" "aczyef"; 1255 expected = false; 1256 }; 1257 1258 testLevenshteinAtMostTwoDiff0Outer = { 1259 expr = strings.levenshteinAtMost 2 "abcdef" "zbcdez"; 1260 expected = true; 1261 }; 1262 1263 testLevenshteinAtMostTwoDiff0DelLeft = { 1264 expr = strings.levenshteinAtMost 2 "abcdef" "bcdefz"; 1265 expected = true; 1266 }; 1267 1268 testLevenshteinAtMostTwoDiff0DelRight = { 1269 expr = strings.levenshteinAtMost 2 "abcdef" "zabcde"; 1270 expected = true; 1271 }; 1272 1273 testLevenshteinAtMostTwoDiff1False = { 1274 expr = strings.levenshteinAtMost 2 "abcdef" "bddez"; 1275 expected = false; 1276 }; 1277 1278 testLevenshteinAtMostTwoDiff1DelLeft = { 1279 expr = strings.levenshteinAtMost 2 "abcdef" "bcdez"; 1280 expected = true; 1281 }; 1282 1283 testLevenshteinAtMostTwoDiff1DelRight = { 1284 expr = strings.levenshteinAtMost 2 "abcdef" "zbcde"; 1285 expected = true; 1286 }; 1287 1288 testLevenshteinAtMostTwoDiff2False = { 1289 expr = strings.levenshteinAtMost 2 "hello" "hxo"; 1290 expected = false; 1291 }; 1292 1293 testLevenshteinAtMostTwoDiff2True = { 1294 expr = strings.levenshteinAtMost 2 "hello" "heo"; 1295 expected = true; 1296 }; 1297 1298 testLevenshteinAtMostTwoDiff3 = { 1299 expr = strings.levenshteinAtMost 2 "hello" "ho"; 1300 expected = false; 1301 }; 1302 1303 testLevenshteinAtMostThreeFalse = { 1304 expr = strings.levenshteinAtMost 3 "hello" "Holla!"; 1305 expected = false; 1306 }; 1307 1308 testLevenshteinAtMostThreeTrue = { 1309 expr = strings.levenshteinAtMost 3 "hello" "Holla"; 1310 expected = true; 1311 }; 1312 1313 # lazyDerivation 1314 1315 testLazyDerivationIsLazyInDerivationForAttrNames = { 1316 expr = attrNames (lazyDerivation { 1317 derivation = throw "not lazy enough"; 1318 }); 1319 # It's ok to add attribute names here when lazyDerivation is improved 1320 # in accordance with its inline comments. 1321 expected = [ "drvPath" "meta" "name" "out" "outPath" "outputName" "outputs" "system" "type" ]; 1322 }; 1323 1324 testLazyDerivationIsLazyInDerivationForPassthruAttr = { 1325 expr = (lazyDerivation { 1326 derivation = throw "not lazy enough"; 1327 passthru.tests = "whatever is in tests"; 1328 }).tests; 1329 expected = "whatever is in tests"; 1330 }; 1331 1332 testLazyDerivationIsLazyInDerivationForPassthruAttr2 = { 1333 # passthru.tests is not a special case. It works for any attr. 1334 expr = (lazyDerivation { 1335 derivation = throw "not lazy enough"; 1336 passthru.foo = "whatever is in foo"; 1337 }).foo; 1338 expected = "whatever is in foo"; 1339 }; 1340 1341 testLazyDerivationIsLazyInDerivationForMeta = { 1342 expr = (lazyDerivation { 1343 derivation = throw "not lazy enough"; 1344 meta = "whatever is in meta"; 1345 }).meta; 1346 expected = "whatever is in meta"; 1347 }; 1348 1349 testLazyDerivationReturnsDerivationAttrs = let 1350 derivation = { 1351 type = "derivation"; 1352 outputs = ["out"]; 1353 out = "test out"; 1354 outPath = "test outPath"; 1355 outputName = "out"; 1356 drvPath = "test drvPath"; 1357 name = "test name"; 1358 system = "test system"; 1359 meta = "test meta"; 1360 }; 1361 in { 1362 expr = lazyDerivation { inherit derivation; }; 1363 expected = derivation; 1364 }; 1365 1366 testTypeDescriptionInt = { 1367 expr = (with types; int).description; 1368 expected = "signed integer"; 1369 }; 1370 testTypeDescriptionListOfInt = { 1371 expr = (with types; listOf int).description; 1372 expected = "list of signed integer"; 1373 }; 1374 testTypeDescriptionListOfListOfInt = { 1375 expr = (with types; listOf (listOf int)).description; 1376 expected = "list of list of signed integer"; 1377 }; 1378 testTypeDescriptionListOfEitherStrOrBool = { 1379 expr = (with types; listOf (either str bool)).description; 1380 expected = "list of (string or boolean)"; 1381 }; 1382 testTypeDescriptionEitherListOfStrOrBool = { 1383 expr = (with types; either (listOf bool) str).description; 1384 expected = "(list of boolean) or string"; 1385 }; 1386 testTypeDescriptionEitherStrOrListOfBool = { 1387 expr = (with types; either str (listOf bool)).description; 1388 expected = "string or list of boolean"; 1389 }; 1390 testTypeDescriptionOneOfListOfStrOrBool = { 1391 expr = (with types; oneOf [ (listOf bool) str ]).description; 1392 expected = "(list of boolean) or string"; 1393 }; 1394 testTypeDescriptionOneOfListOfStrOrBoolOrNumber = { 1395 expr = (with types; oneOf [ (listOf bool) str number ]).description; 1396 expected = "(list of boolean) or string or signed integer or floating point number"; 1397 }; 1398 testTypeDescriptionEitherListOfBoolOrEitherStringOrNumber = { 1399 expr = (with types; either (listOf bool) (either str number)).description; 1400 expected = "(list of boolean) or string or signed integer or floating point number"; 1401 }; 1402 testTypeDescriptionEitherEitherListOfBoolOrStringOrNumber = { 1403 expr = (with types; either (either (listOf bool) str) number).description; 1404 expected = "(list of boolean) or string or signed integer or floating point number"; 1405 }; 1406 testTypeDescriptionEitherNullOrBoolOrString = { 1407 expr = (with types; either (nullOr bool) str).description; 1408 expected = "null or boolean or string"; 1409 }; 1410 testTypeDescriptionEitherListOfEitherBoolOrStrOrInt = { 1411 expr = (with types; either (listOf (either bool str)) int).description; 1412 expected = "(list of (boolean or string)) or signed integer"; 1413 }; 1414 testTypeDescriptionEitherIntOrListOrEitherBoolOrStr = { 1415 expr = (with types; either int (listOf (either bool str))).description; 1416 expected = "signed integer or list of (boolean or string)"; 1417 }; 1418}