1# Copyright 2023 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Tests for truth.bzl.""" 16 17load("@bazel_skylib//lib:unittest.bzl", ut_asserts = "asserts") 18load("//lib:truth.bzl", "matching", "subjects", "truth") 19load("//lib:analysis_test.bzl", "analysis_test", "test_suite") 20 21# Bazel 5 has a bug where every access of testing.ExecutionInfo is a new 22# object that isn't equal to itself. This is fixed in Bazel 6. 23_IS_BAZEL_6_OR_HIGHER = (testing.ExecutionInfo == testing.ExecutionInfo) 24 25_suite = [] 26 27def _fake_env(env): 28 failures = [] 29 env1 = struct( 30 ctx = env.ctx, 31 failures = failures, 32 fail = lambda msg: failures.append(msg), # Silent fail 33 ) 34 env2 = struct( 35 ctx = env.ctx, 36 failures = failures, 37 fail = lambda msg: failures.append(msg), # Silent fail 38 expect = truth.expect(env1), 39 reset = lambda: failures.clear(), 40 ) 41 return env2 42 43def _end(env, fake_env): 44 _guard_against_stray_failures(env = env, fake_env = fake_env) 45 46def _guard_against_stray_failures(*, env, fake_env): 47 ut_asserts.true( 48 env, 49 len(fake_env.failures) == 0, 50 "failures remain: clear after each expected failure\n{}".format( 51 "\n".join(fake_env.failures), 52 ), 53 ) 54 55def action_subject_test(name): 56 analysis_test(name, impl = _action_subject_test, target = "truth_tests_helper") 57 58def _action_subject_test(env, target): 59 fake_env = _fake_env(env) 60 subject = fake_env.expect.that_target( 61 target, 62 ).action_named("Action1") 63 64 subject.contains_flag_values([ 65 ("--arg1flag", "arg1value"), 66 ("--arg2flag", "arg2value"), 67 ]) 68 _assert_no_failures( 69 fake_env, 70 env = env, 71 msg = "check contains_flag_values success", 72 ) 73 74 subject.contains_flag_values([ 75 ("--missingflag", "whatever"), 76 ("--arg1flag", "wrongvalue"), 77 ]) 78 _assert_failure( 79 fake_env, 80 [ 81 "2 expected flags with values missing from argv", 82 "0: '--arg1flag' with value 'wrongvalue'", 83 "1: '--missingflag' (not specified)", 84 "actual argv", 85 "1: arg1", 86 "2: --boolflag", 87 "3: --arg1flag", 88 "4: arg1value", 89 "5: --arg2flag=arg2value", 90 ], 91 env = env, 92 msg = "check contains_flag_values failure", 93 ) 94 95 subject.contains_none_of_flag_values([ 96 ("--doesnotexist", "whatever"), 97 ("--arg1flag", "differentvalue"), 98 ]) 99 _assert_no_failures( 100 fake_env, 101 env = env, 102 msg = "check contains_none_of_flag_values success", 103 ) 104 105 subject.contains_none_of_flag_values([ 106 ("--arg1flag", "arg1value"), 107 ]) 108 _assert_failure( 109 fake_env, 110 [ 111 ("expected not to contain any of: \n" + # note space after colon 112 " 0: '--arg1flag' with value 'arg1value'\n"), 113 ("but 1 found:\n" + 114 " 0: '--arg1flag' with value 'arg1value'\n"), 115 "actual values:\n", 116 # Element 0 of actual is omitted because it has build-config 117 # specific values within it. 118 (" 1: arg1\n" + 119 " 2: --boolflag\n" + 120 " 3: --arg1flag\n" + 121 " 4: arg1value\n" + 122 " 5: --arg2flag=arg2value\n"), 123 ], 124 env = env, 125 msg = "check contains_none_of_flag_values failure", 126 ) 127 _end(env, fake_env) 128 129_suite.append(action_subject_test) 130 131def bool_subject_test(name): 132 analysis_test(name, impl = _bool_subject_test, target = "truth_tests_helper") 133 134def _bool_subject_test(env, _target): 135 fake_env = _fake_env(env) 136 fake_env.expect.that_bool(True).equals(True) 137 _assert_no_failures(fake_env, env = env) 138 fake_env.expect.that_bool(False).equals(False) 139 _assert_no_failures(fake_env, env = env) 140 141 fake_env.expect.that_bool(True).equals(False) 142 _assert_failure(fake_env, [ 143 "expected: False", 144 "actual: True", 145 ], env = env) 146 147 fake_env.expect.that_bool(True, "MYEXPR").equals(False) 148 _assert_failure(fake_env, ["MYEXPR"], env = env) 149 150 subject = truth.expect(fake_env).that_bool(True) 151 subject.not_equals(True) 152 _assert_failure( 153 fake_env, 154 ["expected not to be: True", "actual: True"], 155 env = env, 156 msg = "check not_equals fails with same type", 157 ) 158 subject.not_equals(None) 159 _assert_failure( 160 fake_env, 161 ["expected not to be: None (type: NoneType)", "actual: True (type: bool)"], 162 env = env, 163 msg = "check not_equals due to different type", 164 ) 165 subject.not_equals(False) 166 _assert_no_failures( 167 fake_env, 168 env = env, 169 msg = "check BoolSubject.not_equals with unequal value of same type", 170 ) 171 172 subject.is_in([True, False]) 173 _assert_no_failures( 174 fake_env, 175 env = env, 176 msg = "check BoolSubject.is_in with matching values", 177 ) 178 subject.is_in([None, 39]) 179 _assert_failure( 180 fake_env, 181 ["expected any of:", "None", "39", "actual: True"], 182 env = env, 183 msg = "check is_in mismatched values", 184 ) 185 186 _end(env, fake_env) 187 188_suite.append(bool_subject_test) 189 190def collection_custom_expr_test(name): 191 analysis_test(name, impl = _collection_custom_expr_test, target = "truth_tests_helper") 192 193def _collection_custom_expr_test(env, _target): 194 fake_env = _fake_env(env) 195 subject = fake_env.expect.that_collection(["a"], "MYEXPR") 196 subject.contains_exactly([]) 197 _assert_failure(fake_env, ["MYEXPR"], env = env) 198 _end(env, fake_env) 199 200_suite.append(collection_custom_expr_test) 201 202def collection_has_size_test(name): 203 analysis_test(name, impl = _collection_has_size_test, target = "truth_tests_helper") 204 205def _collection_has_size_test(env, _target): 206 fake_env = _fake_env(env) 207 subject = fake_env.expect.that_collection(["a", "b", "c", "d"]) 208 209 subject.has_size(4) 210 _assert_no_failures( 211 fake_env, 212 env = env, 213 msg = "check actual has expected size", 214 ) 215 216 subject.has_size(0) 217 _assert_failure( 218 fake_env, 219 ["value of: collection.size()"], 220 env = env, 221 msg = "check actual does not have expected size", 222 ) 223 224 _end(env, fake_env) 225 226_suite.append(collection_has_size_test) 227 228def collection_contains_test(name): 229 analysis_test(name, impl = _collection_contains_test, target = "truth_tests_helper") 230 231def _collection_contains_test(env, _target): 232 fake_env = _fake_env(env) 233 subject = fake_env.expect.that_collection(["a", "b", "c", "d"]) 234 235 subject.contains("a") 236 _assert_no_failures( 237 fake_env, 238 env = env, 239 msg = "check actual does contain expected", 240 ) 241 242 subject.contains("never") 243 _assert_failure( 244 fake_env, 245 ["expected to contain: never", "actual values", "0: a"], 246 env = env, 247 msg = "check actual is missing expected", 248 ) 249 250 _end(env, fake_env) 251 252_suite.append(collection_contains_test) 253 254def collection_contains_predicate_test(name): 255 analysis_test(name, impl = _collection_contains_predicate_test, target = "truth_tests_helper") 256 257def _collection_contains_predicate_test(env, _target): 258 fake_env = _fake_env(env) 259 subject = truth.expect(fake_env).that_collection(["a", "b", "c", "d"]) 260 261 subject.contains_predicate(matching.contains("a")) 262 _assert_no_failures( 263 fake_env, 264 env = env, 265 msg = "check actual does contains expected", 266 ) 267 268 subject.contains_predicate(matching.contains("never")) 269 _assert_failure( 270 fake_env, 271 ["expected to contain: <contains never>", "actual values", "0: a"], 272 env = env, 273 msg = "check actual is missing a value", 274 ) 275 _end(env, fake_env) 276 277_suite.append(collection_contains_predicate_test) 278 279def collection_contains_at_least_test(name): 280 analysis_test(name, impl = _collection_contains_at_least_test, target = "truth_tests_helper") 281 282def _collection_contains_at_least_test(env, _target): 283 fake_env = _fake_env(env) 284 subject = truth.expect(fake_env).that_collection(["a", "b", "c", "d"]) 285 286 subject.contains_at_least(["a", "b", "c"]).in_order() 287 _assert_no_failures( 288 fake_env, 289 env = env, 290 msg = "check expected and actual with same elements in same order", 291 ) 292 293 subject.contains_at_least(["never"]) 294 _assert_failure( 295 fake_env, 296 ["expected elements missing", "never", "actual values", "0: a"], 297 env = env, 298 msg = "check actual is missing a value", 299 ) 300 301 subject.contains_at_least([ 302 "b", 303 "a", 304 ]).in_order() 305 _assert_failure( 306 fake_env, 307 [ 308 "incorrect order", 309 "0: b found at offset 1", 310 "1: a found at offset 0", 311 ], 312 env = env, 313 msg = "check expected values present in wrong order", 314 ) 315 316 _end(env, fake_env) 317 318_suite.append(collection_contains_at_least_test) 319 320def collection_contains_at_least_predicates_test(name): 321 analysis_test(name, impl = _collection_contains_at_least_predicates_test, target = "truth_tests_helper") 322 323def _collection_contains_at_least_predicates_test(env, _target): 324 fake_env = _fake_env(env) 325 subject = truth.expect(fake_env).that_collection(["a", "b", "c", "d"]) 326 subject.contains_at_least_predicates([ 327 matching.contains("a"), 328 matching.contains("b"), 329 matching.contains("c"), 330 ]).in_order() 331 332 subject.contains_at_least_predicates([ 333 matching.never("never"), 334 ]) 335 _assert_failure( 336 fake_env, 337 ["expected elements missing", "never", "actual values", "0: a"], 338 env = env, 339 ) 340 341 subject.contains_at_least_predicates([ 342 matching.custom("<MATCHER-B>", lambda v: "b" in v), 343 matching.custom("<MATCHER-A>", lambda v: "a" in v), 344 ]).in_order() 345 _assert_failure( 346 fake_env, 347 [ 348 "incorrect order", 349 "0: <MATCHER-B> matched at offset 1 (matched: b)", 350 "1: <MATCHER-A> matched at offset 0 (matched: a)", 351 ], 352 env = env, 353 ) 354 355 _end(env, fake_env) 356 357_suite.append(collection_contains_at_least_predicates_test) 358 359def collection_contains_exactly_test(name): 360 analysis_test(name, impl = _collection_contains_exactly_test, target = "truth_tests_helper") 361 362def _collection_contains_exactly_test(env, _target): 363 fake_env = _fake_env(env) 364 365 subject = truth.expect(fake_env).that_collection([]) 366 subject.contains_exactly(["a"]) 367 _assert_failure( 368 fake_env, 369 [ 370 "1 missing:\n 0: a", 371 "expected exactly:\n 0: a", 372 "actual values:\n <empty>", 373 ], 374 env = env, 375 msg = "check empty actual vs non-empty expected", 376 ) 377 378 subject = truth.expect(fake_env).that_collection(["b"]) 379 subject.contains_exactly([]) 380 _assert_failure( 381 fake_env, 382 [ 383 "1 unexpected:\n 0: b", 384 "expected exactly:\n <empty>", 385 "actual values:\n 0: b", 386 ], 387 env = env, 388 msg = "check non-empty actual vs empty expected", 389 ) 390 391 subject = truth.expect(fake_env).that_collection(["c"]) 392 order = subject.contains_exactly(["c"]) 393 _assert_no_failures( 394 fake_env, 395 env = env, 396 msg = "check expected and actual with same elements in same order", 397 ) 398 order.in_order() 399 _assert_no_failures( 400 fake_env, 401 env = env, 402 msg = "check exact elements are in order", 403 ) 404 405 subject = truth.expect(fake_env).that_collection(["d"]) 406 subject.contains_exactly(["e"]) 407 _assert_failure( 408 fake_env, 409 [ 410 "1 missing:\n 0: e", 411 "1 unexpected:\n 0: d", 412 "expected exactly:\n 0: e", 413 "actual values:\n 0: d", 414 ], 415 env = env, 416 msg = "check disjoint values; same length", 417 ) 418 419 subject = truth.expect(fake_env).that_collection(["f", "g"]) 420 order = subject.contains_exactly(["g", "f"]) 421 _assert_no_failures( 422 fake_env, 423 env = env, 424 msg = "check same elements with expected in different order", 425 ) 426 order.in_order() 427 _assert_failure( 428 fake_env, 429 [ 430 "expected values all found, but with incorrect order", 431 "0: g found at offset 1", 432 "1: f found at offset 0", 433 "actual values:", 434 "0: f", 435 "1: g", 436 ], 437 env = env, 438 msg = "check same elements out of order", 439 ) 440 441 subject = truth.expect(fake_env).that_collection(["x", "y"]) 442 subject.contains_exactly(["y"]) 443 _assert_failure( 444 fake_env, 445 [ 446 "1 unexpected:\n 0: x", 447 "expected exactly:\n 0: y", 448 "actual values:\n 0: x\n 1: y", 449 ], 450 env = env, 451 msg = "check expected subset of actual", 452 ) 453 454 subject = truth.expect(fake_env).that_collection(["a", "b", "c", "d"]) 455 subject.contains_exactly(["a", "b", "c", "d"]) 456 _assert_no_failures( 457 fake_env, 458 env = env, 459 msg = "check expected and actual with exact elements and order; 4 values", 460 ) 461 462 subject.contains_exactly(["d", "b", "a", "c"]) 463 _assert_no_failures( 464 fake_env, 465 env = env, 466 msg = "check expected and actual same elements and different order; 4 values", 467 ) 468 469 subject = truth.expect(fake_env).that_collection(["a", "b", "a"]) 470 subject.contains_exactly(["a", "b", "a"]) 471 _assert_no_failures( 472 fake_env, 473 env = env, 474 msg = "check multiplicity, same expected/actual order", 475 ) 476 477 subject.contains_exactly(["b", "a", "a"]) 478 _assert_no_failures( 479 fake_env, 480 env = env, 481 msg = "check multiplicity; different expected/actual order", 482 ) 483 484 subject = truth.expect(fake_env).that_collection([ 485 "one", 486 "two", 487 "one", 488 "three", 489 "one", 490 "four", 491 ]) 492 493 subject.contains_exactly(["one", "two", "three", "five"]) 494 _assert_failure( 495 fake_env, 496 [ 497 ("1 missing:\n" + 498 " 0: five"), 499 ("3 unexpected:\n" + 500 " 0: four\n" + 501 " 1: one\n" + 502 " 2: one\n"), 503 ("expected exactly:\n" + 504 " 0: one\n" + 505 " 1: two\n" + 506 " 2: three\n" + 507 " 3: five\n"), 508 ], 509 env = env, 510 msg = "check multiplicity; expected with multiple, expected with unique", 511 ) 512 513 subject = truth.expect(fake_env).that_collection(["one", "four", "three", "two", "five"]) 514 order = subject.contains_exactly(["one", "two", "three", "four", "five"]) 515 _assert_no_failures( 516 fake_env, 517 env = env, 518 msg = "check same elements with expected in different order", 519 ) 520 order.in_order() 521 _assert_failure( 522 fake_env, 523 [ 524 "expected values all found, but with incorrect order:", 525 "0: one found at offset 0", 526 "1: two found at offset 3", 527 "2: three found at offset 2", 528 "3: four found at offset 1", 529 "4: five found at offset 4", 530 "actual values:", 531 "0: one", 532 "1: four", 533 "2: three", 534 "3: two", 535 "4: five", 536 ], 537 env = env, 538 msg = "check same elements out of order", 539 ) 540 541 _end(env, fake_env) 542 543_suite.append(collection_contains_exactly_test) 544 545def collection_contains_exactly_predicates_test(name): 546 analysis_test(name, impl = _collection_contains_exactly_predicates_test, target = "truth_tests_helper") 547 548def _collection_contains_exactly_predicates_test(env, _target): 549 fake_env = _fake_env(env) 550 551 subject = truth.expect(fake_env).that_collection([]) 552 subject.contains_exactly_predicates([matching.contains("a")]) 553 _assert_failure( 554 fake_env, 555 [ 556 "1 missing:\n 0: <contains a>", 557 "expected exactly:\n 0: <contains a>", 558 "actual values:\n <empty>", 559 ], 560 env = env, 561 msg = "check empty actual vs non-empty expected", 562 ) 563 564 subject = truth.expect(fake_env).that_collection(["b"]) 565 subject.contains_exactly_predicates([]) 566 _assert_failure( 567 fake_env, 568 [ 569 "1 unexpected:\n 0: b", 570 "expected exactly:\n <empty>", 571 "actual values:\n 0: b", 572 ], 573 env = env, 574 msg = "check non-empty actual vs empty expected", 575 ) 576 577 subject = truth.expect(fake_env).that_collection(["c"]) 578 order = subject.contains_exactly_predicates([matching.contains("c")]) 579 _assert_no_failures( 580 fake_env, 581 env = env, 582 msg = "check expected and actual with same elements in same order", 583 ) 584 order.in_order() 585 _assert_no_failures( 586 fake_env, 587 env = env, 588 msg = "check exact elements are in order", 589 ) 590 591 subject = truth.expect(fake_env).that_collection(["d"]) 592 subject.contains_exactly_predicates([matching.contains("e")]) 593 _assert_failure( 594 fake_env, 595 [ 596 "1 missing:\n 0: <contains e>", 597 "1 unexpected:\n 0: d", 598 "expected exactly:\n 0: <contains e>", 599 "actual values:\n 0: d", 600 ], 601 env = env, 602 msg = "check disjoint values; same length", 603 ) 604 605 subject = truth.expect(fake_env).that_collection(["f", "g"]) 606 order = subject.contains_exactly_predicates([ 607 matching.contains("g"), 608 matching.contains("f"), 609 ]) 610 _assert_no_failures( 611 fake_env, 612 env = env, 613 msg = "check same elements with expected in different order", 614 ) 615 order.in_order() 616 _assert_failure( 617 fake_env, 618 [ 619 "expected values all found, but with incorrect order", 620 "0: <contains g> matched at offset 1 (matched: g)", 621 "1: <contains f> matched at offset 0 (matched: f)", 622 "actual values:", 623 "0: f", 624 "1: g", 625 ], 626 env = env, 627 msg = "check same elements out of order", 628 ) 629 630 subject = truth.expect(fake_env).that_collection(["x", "y"]) 631 subject.contains_exactly_predicates([matching.contains("y")]) 632 _assert_failure( 633 fake_env, 634 [ 635 "1 unexpected:\n 0: x", 636 "expected exactly:\n 0: <contains y>", 637 "actual values:\n 0: x\n 1: y", 638 ], 639 env = env, 640 msg = "check expected subset of actual", 641 ) 642 643 subject = truth.expect(fake_env).that_collection(["a", "b", "c", "d"]) 644 subject.contains_exactly_predicates([ 645 matching.contains("a"), 646 matching.contains("b"), 647 matching.contains("c"), 648 matching.contains("d"), 649 ]) 650 _assert_no_failures( 651 fake_env, 652 env = env, 653 msg = "check expected and actual with exact elements and order; 4 values", 654 ) 655 656 subject.contains_exactly_predicates([ 657 matching.contains("d"), 658 matching.contains("b"), 659 matching.contains("a"), 660 matching.contains("c"), 661 ]) 662 _assert_no_failures( 663 fake_env, 664 env = env, 665 msg = "check expected and actual same elements and different order; 4 values", 666 ) 667 668 subject = truth.expect(fake_env).that_collection(["a", "b", "a"]) 669 subject.contains_exactly_predicates([ 670 matching.contains("a"), 671 matching.contains("b"), 672 matching.contains("a"), 673 ]) 674 _assert_no_failures( 675 fake_env, 676 env = env, 677 msg = "check multiplicity, same expected/actual order", 678 ) 679 680 subject.contains_exactly_predicates([ 681 matching.contains("b"), 682 matching.contains("a"), 683 matching.contains("a"), 684 ]) 685 _assert_no_failures( 686 fake_env, 687 env = env, 688 msg = "check multiplicity; different expected/actual order", 689 ) 690 691 subject = truth.expect(fake_env).that_collection([ 692 "one", 693 "two", 694 "one", 695 "three", 696 "one", 697 "four", 698 ]) 699 700 subject.contains_exactly_predicates([ 701 matching.contains("one"), 702 matching.contains("two"), 703 matching.contains("three"), 704 matching.contains("five"), 705 ]) 706 _assert_failure( 707 fake_env, 708 [ 709 ("1 missing:\n" + 710 " 0: <contains five>"), 711 ("3 unexpected:\n" + 712 " 0: four\n" + 713 " 1: one\n" + 714 " 2: one\n"), 715 ("expected exactly:\n" + 716 " 0: <contains one>\n" + 717 " 1: <contains two>\n" + 718 " 2: <contains three>\n" + 719 " 3: <contains five>\n"), 720 ], 721 env = env, 722 msg = "check multiplicity; expected with multiple, expected with unique", 723 ) 724 _end(env, fake_env) 725 726_suite.append(collection_contains_exactly_predicates_test) 727 728def collection_contains_none_of_test(name): 729 analysis_test(name, impl = _collection_contains_none_of_test, target = "truth_tests_helper") 730 731def _collection_contains_none_of_test(env, _target): 732 fake_env = _fake_env(env) 733 subject = truth.expect(fake_env).that_collection(["a"]) 734 735 subject.contains_none_of(["b"]) 736 _assert_no_failures( 737 fake_env, 738 env = env, 739 msg = "check actual contains none of", 740 ) 741 742 subject.contains_none_of(["a"]) 743 _assert_failure( 744 fake_env, 745 [ 746 "expected not to contain any of:", 747 " 0: a", 748 "but 1 found", 749 "actual values:", 750 ], 751 env = env, 752 msg = "check actual contains an unexpected value", 753 ) 754 _end(env, fake_env) 755 756_suite.append(collection_contains_none_of_test) 757 758def collection_not_contains_test(name): 759 analysis_test(name, impl = _collection_not_contains_test, target = "truth_tests_helper") 760 761def _collection_not_contains_test(env, _target): 762 fake_env = _fake_env(env) 763 subject = truth.expect(fake_env).that_collection(["a"]) 764 765 subject.not_contains("b") 766 _assert_no_failures( 767 fake_env, 768 env = env, 769 msg = "check not_contains passes", 770 ) 771 subject.not_contains("a") 772 _assert_failure( 773 fake_env, 774 [ 775 "expected not to contain", 776 "0: a", 777 ], 778 env = env, 779 msg = "check not_contains fails", 780 ) 781 782_suite.append(collection_not_contains_test) 783 784def collection_not_contains_predicate_test(name): 785 analysis_test(name, impl = _collection_not_contains_predicate_test, target = "truth_tests_helper") 786 787def _collection_not_contains_predicate_test(env, _target): 788 fake_env = _fake_env(env) 789 subject = truth.expect(fake_env).that_collection(["a"]) 790 791 subject.not_contains_predicate(matching.contains("b")) 792 _assert_no_failures( 793 fake_env, 794 env = env, 795 msg = "check actual does not contain a value", 796 ) 797 798 subject.not_contains_predicate(matching.contains("a")) 799 _assert_failure( 800 fake_env, 801 ["expected not to contain any of: <contains a>", "but 1 found:", "0: a"], 802 env = env, 803 msg = "check actual contains an unexpected value", 804 ) 805 _end(env, fake_env) 806 807_suite.append(collection_not_contains_predicate_test) 808 809def collection_offset_test(name): 810 analysis_test(name, impl = _collection_offset_test, target = "truth_tests_helper") 811 812def _collection_offset_test(env, _target): 813 fake_env = _fake_env(env) 814 subject = truth.expect(fake_env).that_collection(["a", "b", "c"]) 815 816 offset_value = subject.offset(0, factory = lambda v, meta: v) 817 ut_asserts.true(env, offset_value == "a", "unexpected offset value at 0") 818 819 offset_value = subject.offset(-1, factory = lambda v, meta: v) 820 ut_asserts.true(env, offset_value == "c", "unexpected offset value at -1") 821 822 subject.offset(1, factory = subjects.str).equals("not-b") 823 824 _assert_failure( 825 fake_env, 826 [".offset(1)"], 827 env = env, 828 msg = "offset error message context not found", 829 ) 830 831 _end(env, fake_env) 832 833_suite.append(collection_offset_test) 834 835def _collection_transform_test(name): 836 analysis_test(name, impl = _collection_transform_test_impl, target = "truth_tests_helper") 837 838def _collection_transform_test_impl(env, target): 839 _ = target # @unused 840 fake_env = _fake_env(env) 841 starter = truth.expect(fake_env).that_collection(["alan", "bert", "cari"]) 842 843 actual = starter.transform( 844 "values that contain a", 845 filter = lambda v: "a" in v, 846 ) 847 actual.contains("not-present") 848 _assert_failure( 849 fake_env, 850 [ 851 "transform()", 852 "0: alan", 853 "1: cari", 854 "transform: values that contain a", 855 ], 856 env = env, 857 msg = "transform with lambda filter", 858 ) 859 860 actual = starter.transform(filter = matching.contains("b")) 861 actual.contains("not-present") 862 _assert_failure( 863 fake_env, 864 [ 865 "0: bert", 866 "transform: filter=<contains b>", 867 ], 868 env = env, 869 msg = "transform with matcher filter", 870 ) 871 872 def contains_c(v): 873 return "c" in v 874 875 actual = starter.transform(filter = contains_c) 876 actual.contains("not-present") 877 _assert_failure( 878 fake_env, 879 [ 880 "0: cari", 881 "transform: filter=contains_c(...)", 882 ], 883 env = env, 884 msg = "transform with named function filter", 885 ) 886 887 actual = starter.transform( 888 "v.upper(); match even offsets", 889 map_each = lambda v: "{}-{}".format(v[0], v[1].upper()), 890 loop = enumerate, 891 ) 892 actual.contains("not-present") 893 _assert_failure( 894 fake_env, 895 [ 896 "transform()", 897 "0: 0-ALAN", 898 "1: 1-BERT", 899 "2: 2-CARI", 900 "transform: v.upper(); match even offsets", 901 ], 902 env = env, 903 msg = "transform with all args", 904 ) 905 906 _end(env, fake_env) 907 908_suite.append(_collection_transform_test) 909 910def execution_info_test(name): 911 analysis_test(name, impl = _execution_info_test, target = "truth_tests_helper") 912 913def _execution_info_test(env, target): 914 # TODO(rlevasseur): Remove this after cl/474597236 is released in Blaze 915 exec_info_is_ctor = str(testing.ExecutionInfo) == "<function ExecutionInfo>" 916 if not exec_info_is_ctor: 917 return 918 fake_env = _fake_env(env) 919 920 subject = truth.expect(fake_env).that_target(target).provider(testing.ExecutionInfo) 921 subject.requirements().contains_exactly({"EIKEY1": "EIVALUE1"}) 922 _assert_no_failures(fake_env, env = env) 923 if _IS_BAZEL_6_OR_HIGHER: 924 subject.exec_group().equals("THE_EXEC_GROUP") 925 _assert_no_failures(fake_env, env = env) 926 _end(env, fake_env) 927 928_suite.append(execution_info_test) 929 930def depset_file_subject_test(name): 931 analysis_test(name, impl = _depset_file_subject_test, target = "truth_tests_data_files") 932 933def _depset_file_subject_test(env, target): 934 fake_env = _fake_env(env) 935 936 # We go through a target so that the usual format_str kwargs are present. 937 subject = truth.expect(fake_env).that_target(target).default_outputs() 938 939 # The CollectionSubject tests cover contains_at_least_predicates in 940 # more depth, so just do some basic tests here. 941 subject.contains_at_least_predicates([ 942 matching.file_path_matches("txt"), 943 ]) 944 _assert_no_failures(fake_env, env = env) 945 946 subject.contains_at_least_predicates([ 947 matching.file_path_matches("NOT THERE"), 948 ]) 949 _assert_failure( 950 fake_env, 951 ["NOT THERE", "file1.txt"], 952 env = env, 953 ) 954 955 subject.contains_predicate(matching.file_path_matches("txt")) 956 _assert_no_failures(fake_env, env = env) 957 subject.contains_predicate(matching.file_path_matches("NOT THERE")) 958 _assert_failure( 959 fake_env, 960 ["NOT THERE", "file1.txt"], 961 env = env, 962 ) 963 964 subject.contains_exactly(["{package}/testdata/file1.txt"]) 965 _assert_no_failures(fake_env, env = env) 966 subject.contains_exactly(["NOT THERE"]) 967 _assert_failure( 968 fake_env, 969 ["NOT THERE", "file1.txt"], 970 env = env, 971 ) 972 973 subject.not_contains("does-not-contain") 974 _assert_no_failures( 975 fake_env, 976 env = env, 977 msg = "DepsetFilesubject.not_contains success test", 978 ) 979 subject.not_contains("{package}/testdata/file1.txt") 980 _assert_failure( 981 fake_env, 982 ["expected not to contain any of", "file1.txt"], 983 env = env, 984 msg = "DepsetFilesubject.not_contains failure test", 985 ) 986 987 _end(env, fake_env) 988 989_suite.append(depset_file_subject_test) 990 991def dict_subject_test(name): 992 analysis_test(name, impl = _dict_subject_test, target = "truth_tests_helper") 993 994def _dict_subject_test(env, _target): 995 fake_env = _fake_env(env) 996 subject = truth.expect(fake_env).that_dict({"a": 1, "b": 2, "c": 3}) 997 998 def factory(value, *, meta): 999 return struct(value = value, meta = meta) 1000 1001 actual = subject.get("a", factory = factory) 1002 1003 truth.expect(env).that_int(actual.value).equals(1) 1004 truth.expect(env).that_collection(actual.meta._exprs).contains("get(a)") 1005 1006 subject.contains_exactly({"a": 1, "b": 2, "c": 3}) 1007 _assert_no_failures(fake_env, env = env) 1008 1009 subject.contains_exactly({"d": 4, "a": 99}) 1010 _assert_failure( 1011 fake_env, 1012 [ 1013 ("expected dict: {\n" + 1014 " a: <int 99>\n" + 1015 " d: <int 4>\n" + 1016 "}\n"), 1017 ("1 missing keys:\n" + 1018 " 0: d\n"), 1019 ("2 unexpected keys:\n" + 1020 " 0: b\n" + 1021 " 1: c\n"), 1022 ("1 incorrect entries:\n" + 1023 "key a:\n" + 1024 " expected: 99\n" + 1025 " but was : 1\n"), 1026 ("actual: {\n" + 1027 " a: <int 1>\n" + 1028 " b: <int 2>\n" + 1029 " c: <int 3>\n" + 1030 "}\n"), 1031 ], 1032 env = env, 1033 ) 1034 1035 subject.contains_at_least({"a": 1}) 1036 _assert_no_failures(fake_env, env = env) 1037 1038 subject.contains_at_least({"d": 91, "a": 74}) 1039 _assert_failure( 1040 fake_env, 1041 [ 1042 ("expected dict: {\n" + 1043 " a: <int 74>\n" + 1044 " d: <int 91>\n" + 1045 "}\n"), 1046 ("1 missing keys:\n" + 1047 " 0: d\n"), 1048 ("1 incorrect entries:\n" + 1049 "key a:\n" + 1050 " expected: 74\n" + 1051 " but was : 1\n"), 1052 ("actual: {\n" + 1053 " a: <int 1>\n" + 1054 " b: <int 2>\n" + 1055 " c: <int 3>\n" + 1056 "}\n"), 1057 ], 1058 env = env, 1059 ) 1060 1061 # NOTE: we use the real env for this, since we're doing a real assert 1062 truth.expect(env).that_collection( 1063 subject.keys().actual, 1064 ).contains_exactly(["a", "b", "c"]) 1065 1066 _end(env, fake_env) 1067 1068_suite.append(dict_subject_test) 1069 1070def expect_test(name): 1071 analysis_test(name, impl = _expect_test, target = "truth_tests_helper") 1072 1073def _expect_test(env, target): 1074 fake_env = _fake_env(env) 1075 expect = truth.expect(fake_env) 1076 1077 ut_asserts.true( 1078 env, 1079 expect.that_target(target) != None, 1080 msg = "expect.that_target", 1081 ) 1082 _assert_no_failures(fake_env, env = env) 1083 1084 expect.where( 1085 foo = "bar", 1086 baz = "qux", 1087 ).that_bool(True).equals(False) 1088 _assert_failure( 1089 fake_env, 1090 ["foo: bar", "baz: qux"], 1091 env = env, 1092 ) 1093 _end(env, fake_env) 1094 1095_suite.append(expect_test) 1096 1097def file_subject_test(name): 1098 analysis_test(name, impl = _file_subject_test, target = "truth_tests_data_files") 1099 1100def _file_subject_test(env, target): 1101 fake_env = _fake_env(env) 1102 package = target.label.package 1103 expect = truth.expect(fake_env) 1104 subject = expect.that_file(target.files.to_list()[0]) 1105 subject.short_path_equals(package + "/testdata/file1.txt") 1106 _assert_no_failures(fake_env, env = env) 1107 1108 subject.short_path_equals("landon-and-hope-forever.txt") 1109 _assert_failure( 1110 fake_env, 1111 [ 1112 "value of: file", 1113 "expected: landon-and-hope-forever.txt", 1114 "actual: {}/testdata/file1.txt".format(package), 1115 ], 1116 env = env, 1117 ) 1118 1119 subject = expect.that_file( 1120 target.files.to_list()[0], 1121 meta = expect.meta.derive( 1122 format_str_kwargs = {"custom": "file1.txt"}, 1123 ), 1124 ) 1125 1126 # NOTE: We purposefully don't use `{package}` because we're just 1127 # testing the `{custom}` keyword 1128 subject.short_path_equals(package + "/testdata/{custom}") 1129 _assert_no_failures(fake_env, env = env) 1130 1131 _end(env, fake_env) 1132 1133_suite.append(file_subject_test) 1134 1135def label_subject_test(name): 1136 analysis_test(name, impl = _label_subject_test, target = "truth_tests_helper") 1137 1138def _label_subject_test(env, target): 1139 fake_env = _fake_env(env) 1140 1141 expect = truth.expect(fake_env) 1142 subject = expect.that_target(target).label() 1143 1144 subject.equals("//tests:truth_tests_helper") 1145 _assert_no_failures(fake_env, env = env) 1146 1147 subject.equals(Label("//tests:truth_tests_helper")) 1148 _assert_no_failures(fake_env, env = env) 1149 1150 subject.equals("//nope") 1151 _assert_failure( 1152 fake_env, 1153 ["expected: " + str(Label("//nope")), "actual:", "_helper"], 1154 env = env, 1155 ) 1156 1157 subject = subjects.label(Label("//some/pkg:label"), expect.meta) 1158 subject.is_in(["//foo:bar", "//some/pkg:label"]) 1159 _assert_no_failures(fake_env, msg = "is_in with matched str values", env = env) 1160 subject.is_in([Label("//bar:baz"), Label("//some/pkg:label")]) 1161 _assert_no_failures(fake_env, msg = "is_in with matched label values", env = env) 1162 subject.is_in(["//not:there", Label("//other:value")]) 1163 _assert_failure( 1164 fake_env, 1165 [ 1166 "expected any of:", 1167 "//not:there", 1168 "//other:value", 1169 "actual: " + str(Label("//some/pkg:label")), 1170 ], 1171 msg = "check is_in fails", 1172 env = env, 1173 ) 1174 1175 _end(env, fake_env) 1176 1177_suite.append(label_subject_test) 1178 1179def runfiles_subject_test(name): 1180 analysis_test(name, impl = _runfiles_subject_test, target = "truth_tests_helper") 1181 1182def _runfiles_subject_test(env, target): 1183 fake_env = _fake_env(env) 1184 1185 subject = truth.expect(fake_env).that_target(target).runfiles() 1186 subject.contains("{workspace}/{package}/default_runfile1.txt") 1187 _assert_no_failures(fake_env, env = env) 1188 1189 subject.contains("does-not-exist") 1190 _assert_failure( 1191 fake_env, 1192 [ 1193 "expected to contain: does-not-exist", 1194 "actual default runfiles:", 1195 "default_runfile1.txt", 1196 "target: ".format(target.label), 1197 ], 1198 env = env, 1199 msg = "check contains", 1200 ) 1201 1202 subject.contains_none_of(["{workspace}/{package}/not-there.txt"]) 1203 _assert_no_failures(fake_env, env = env) 1204 1205 subject.contains_none_of(["{workspace}/{package}/default_runfile1.txt"]) 1206 _assert_failure( 1207 fake_env, 1208 [ 1209 "expected not to contain any of", 1210 "default_runfile1.txt", 1211 env.ctx.workspace_name, 1212 ], 1213 env = env, 1214 msg = "check contains none of", 1215 ) 1216 1217 subject.contains_exactly([ 1218 "{workspace}/{package}/default_runfile1.txt", 1219 "{workspace}/{package}/truth_tests_helper.txt", 1220 ]) 1221 _assert_no_failures(fake_env, env = env) 1222 subject.contains_exactly([ 1223 "{workspace}/{package}/not-there.txt", 1224 ]) 1225 _assert_failure( 1226 fake_env, 1227 [ 1228 "1 missing", 1229 "not-there.txt", 1230 env.ctx.workspace_name, 1231 ], 1232 env = env, 1233 msg = "check contains_exactly fails", 1234 ) 1235 1236 subject.contains_at_least([ 1237 "{workspace}/{package}/default_runfile1.txt", 1238 ]) 1239 _assert_no_failures(fake_env, env = env) 1240 subject.contains_at_least([ 1241 "not-there.txt", 1242 ]) 1243 _assert_failure( 1244 fake_env, 1245 [ 1246 "1 expected paths missing", 1247 "not-there.txt", 1248 env.ctx.workspace_name, 1249 ], 1250 env = env, 1251 msg = "check contains_at_least fails", 1252 ) 1253 1254 _end(env, fake_env) 1255 1256_suite.append(runfiles_subject_test) 1257 1258def str_subject_test(name): 1259 analysis_test(name, impl = _str_subject_test, target = "truth_tests_helper") 1260 1261def _str_subject_test(env, _target): 1262 fake_env = _fake_env(env) 1263 subject = truth.expect(fake_env).that_str("foobar") 1264 1265 subject.contains("ob") 1266 _assert_no_failures(fake_env, env = env) 1267 1268 subject.contains("nope") 1269 _assert_failure( 1270 fake_env, 1271 ["expected to contain: nope", "actual: foobar"], 1272 env = env, 1273 msg = "check contains", 1274 ) 1275 1276 subject.equals("foobar") 1277 _assert_no_failures(fake_env, env = env) 1278 1279 subject.equals("not foobar") 1280 _assert_failure( 1281 fake_env, 1282 ["expected: not foobar", "actual: foobar"], 1283 env = env, 1284 msg = "check equals", 1285 ) 1286 1287 result = subject.split("b") 1288 ut_asserts.true(env, result.actual == ["foo", "ar"], "incorrectly split") 1289 1290 subject.not_equals("foobar") 1291 _assert_failure( 1292 fake_env, 1293 ["expected not to be: foobar", "actual: foobar"], 1294 env = env, 1295 msg = "check not_equals with equal value", 1296 ) 1297 subject.not_equals(47) 1298 _assert_failure( 1299 fake_env, 1300 ["expected not to be: 47 (type: int)", "actual: foobar (type: string)"], 1301 env = env, 1302 msg = "check not_equals with different type", 1303 ) 1304 subject.not_equals("not-foobar") 1305 _assert_no_failures( 1306 fake_env, 1307 env = env, 1308 msg = "check not_equals with unequal value of same type", 1309 ) 1310 1311 subject.is_in(["xxx", "yyy", "zzz"]) 1312 _assert_failure( 1313 fake_env, 1314 ["expected any of:", "xxx", "yyy", "zzz", "actual: foobar"], 1315 env = env, 1316 msg = "check is_in with non-matching values", 1317 ) 1318 subject.is_in(["foobar", "y", "z"]) 1319 _assert_no_failures( 1320 fake_env, 1321 env = env, 1322 msg = "check is_in with matching values", 1323 ) 1324 _end(env, fake_env) 1325 1326_suite.append(str_subject_test) 1327 1328def target_subject_test(name): 1329 analysis_test(name, impl = _target_subject_test, target = "truth_tests_helper") #TODO also file target 1330 1331def _target_subject_test(env, target): 1332 fake_env = _fake_env(env) 1333 subject = truth.expect(fake_env).that_target(target) 1334 1335 # First a static string, no formatting parameters 1336 result = subject.action_generating("{package}/default_runfile1.txt") 1337 ut_asserts.true(env, result != None, msg = "action_generating gave None") 1338 1339 # Now try it with formatting parameters 1340 result = subject.action_generating("{package}/{name}.txt") 1341 ut_asserts.true(env, result != None, msg = "action_generating gave None") 1342 1343 result = subject.label() 1344 ut_asserts.true(env, result != None, msg = "label gave None") 1345 1346 subject = truth.expect(fake_env).that_target(target) 1347 1348 tags = subject.tags() 1349 ut_asserts.true(env, tags != None, msg = "tags gave None") 1350 1351 tags.contains_exactly(["tag1", "tag2"]) 1352 _assert_no_failures( 1353 fake_env, 1354 env = env, 1355 msg = "check TargetSubject.tags()", 1356 ) 1357 1358 attr_subject = subject.attr("testonly") 1359 ut_asserts.true(env, attr_subject != None, msg = "attr(testonly) gave None") 1360 1361 custom_subject = subject.attr( 1362 "testonly", 1363 factory = lambda v, meta: struct(custom = True), 1364 ) 1365 ut_asserts.true( 1366 env, 1367 custom_subject.custom == True, 1368 msg = "attr() with custom factory gave wrong value", 1369 ) 1370 1371 output_group_subject = subject.output_group("some_group") 1372 output_group_subject.contains("{package}/output_group_file.txt") 1373 _assert_no_failures( 1374 fake_env, 1375 env = env, 1376 msg = "check TargetSubject.output_group()", 1377 ) 1378 1379 _end(env, fake_env) 1380 1381_suite.append(target_subject_test) 1382 1383def run_environment_info_subject_test(name): 1384 analysis_test(name, impl = _run_environment_info_subject_test, target = "truth_tests_helper") 1385 1386def _run_environment_info_subject_test(env, target): 1387 fake_env = _fake_env(env) 1388 1389 subject = truth.expect(fake_env).that_target(target).provider( 1390 RunEnvironmentInfo, 1391 ) 1392 1393 subject.environment().contains_exactly({ 1394 "EKEY1": "EVALUE1", 1395 "EKEY2": "EVALUE2", 1396 }) 1397 _assert_no_failures(fake_env, env = env) 1398 1399 subject.inherited_environment().contains_exactly(["INHERIT1", "INHERIT2"]) 1400 _assert_no_failures(fake_env, env = env) 1401 1402 _end(env, fake_env) 1403 1404_suite.append(run_environment_info_subject_test) 1405 1406def _add_failure_works_test(name): 1407 analysis_test( 1408 name, 1409 impl = _add_failure_works_test_impl, 1410 target = "truth_tests_noop", 1411 expect_failure = True, 1412 ) 1413 1414def _add_failure_works_test_impl(env, target): 1415 """Test that the real add_failure() codepath works. 1416 1417 All the other tests mock out the fail() call, this is the one test that doesn't. 1418 """ 1419 _ = target # @unused 1420 1421 # NOTE: this prints a spurious message. 1422 env.expect.meta.add_failure("FAKE PROBLEM", "FAKE ACTUAL") 1423 1424 failures = list(env._failures) 1425 env._failures.clear() 1426 1427 if len(failures) != 1: 1428 env.fail("Expected len(failures) == 1, got " + str(len(failures))) 1429 else: 1430 failure = failures[0] 1431 if "FAKE PROBLEM" not in failure: 1432 env.fail("Expected string 'FAKE PROBLEM' not found in failure message") 1433 if "FAKE ACTUAL" not in failure: 1434 env.fail("Expected string 'FAKE ACTUAL' not found in failure message") 1435 1436_suite.append(_add_failure_works_test) 1437 1438def _assert_no_failures(fake_env, *, env, msg = ""): 1439 fail_lines = [ 1440 "expected no failures, but found failures", 1441 msg, 1442 "===== FAILURE MESSAGES =====", 1443 ] 1444 fail_lines.extend(fake_env.failures) 1445 fail_lines.append("===== END FAILURE MESSAGES ====") 1446 fail_msg = "\n".join(fail_lines) 1447 ut_asserts.true(env, len(fake_env.failures) == 0, msg = fail_msg) 1448 fake_env.reset() 1449 1450def _assert_failure(fake_env, expected_strs, *, env, msg = ""): 1451 if len(fake_env.failures) != 1: 1452 env.fail("expected exactly 1 failure, but found {}".format(len(fake_env.failures))) 1453 1454 if len(fake_env.failures) > 0: 1455 failure = fake_env.failures[0] 1456 for expected in expected_strs: 1457 if expected not in failure: 1458 env.fail(( 1459 "\nFailure message incorrect:\n{}\n" + 1460 "===== EXPECTED ERROR SUBSTRING =====\n{}\n" + 1461 "===== END EXPECTED ERROR SUBSTRING =====\n" + 1462 "===== ACTUAL FAILURE MESSAGE =====\n{}\n" + 1463 "===== END ACTUAL FAILURE MESSAGE =====" 1464 ).format( 1465 msg, 1466 expected, 1467 failure, 1468 )) 1469 1470 fake_env.reset() 1471 1472def _test_helper_impl(ctx): 1473 action_output = ctx.actions.declare_file("action.txt") 1474 ctx.actions.run( 1475 outputs = [action_output], 1476 executable = ctx.executable.tool, 1477 arguments = [ 1478 "arg1", 1479 "--boolflag", 1480 "--arg1flag", 1481 "arg1value", 1482 "--arg2flag=arg2value", 1483 ], 1484 mnemonic = "Action1", 1485 ) 1486 if _IS_BAZEL_6_OR_HIGHER: 1487 exec_info_bazel_6_kwargs = {"exec_group": "THE_EXEC_GROUP"} 1488 else: 1489 exec_info_bazel_6_kwargs = {} 1490 1491 return [ 1492 DefaultInfo( 1493 default_runfiles = ctx.runfiles( 1494 files = [ 1495 _empty_file(ctx, "default_runfile1.txt"), 1496 _empty_file(ctx, ctx.label.name + ".txt"), 1497 ], 1498 ), 1499 ), 1500 testing.TestEnvironment( 1501 environment = {"EKEY1": "EVALUE1", "EKEY2": "EVALUE2"}, 1502 inherited_environment = ["INHERIT1", "INHERIT2"], 1503 ), 1504 testing.ExecutionInfo({"EIKEY1": "EIVALUE1"}, **exec_info_bazel_6_kwargs), 1505 OutputGroupInfo( 1506 some_group = depset([_empty_file(ctx, "output_group_file.txt")]), 1507 ), 1508 ] 1509 1510test_helper = rule( 1511 implementation = _test_helper_impl, 1512 attrs = { 1513 "tool": attr.label( 1514 default = ":truth_tests_noop", 1515 executable = True, 1516 cfg = "exec", 1517 ), 1518 }, 1519) 1520 1521def _empty_file(ctx, name): 1522 file = ctx.actions.declare_file(name) 1523 ctx.actions.write(file, content = "") 1524 return file 1525 1526def _noop_binary_impl(ctx): 1527 return DefaultInfo(executable = _empty_file(ctx, ctx.label.name)) 1528 1529noop_binary = rule( 1530 implementation = _noop_binary_impl, 1531 executable = True, 1532) 1533 1534def truth_test_suite(name): 1535 # Unit tests can't directly create File objects, so we have a generic 1536 # collection of files they can put in custom attributes to use. 1537 native.filegroup( 1538 name = "truth_tests_data_files", 1539 srcs = native.glob(["testdata/**"]), 1540 ) 1541 test_helper( 1542 name = "truth_tests_helper", 1543 tags = ["tag1", "tag2"], 1544 ) 1545 noop_binary(name = "truth_tests_noop") 1546 1547 test_suite( 1548 name = name, 1549 tests = _suite, 1550 ) 1551