1# Copyright 2018 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 15import unittest 16 17from py import mock 18 19from google.protobuf import text_format 20from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 21from tools.migration.ctoolchain_comparator_lib import compare_ctoolchains 22 23try: 24 # Python 2 25 from cStringIO import StringIO 26except ImportError: 27 # Python 3 28 from io import StringIO 29 30 31def make_toolchain(toolchain_proto): 32 toolchain = crosstool_config_pb2.CToolchain() 33 text_format.Merge(toolchain_proto, toolchain) 34 return toolchain 35 36 37class CtoolchainComparatorLibTest(unittest.TestCase): 38 39 def test_string_fields(self): 40 first = make_toolchain(""" 41 toolchain_identifier: "first-id" 42 host_system_name: "first-host" 43 target_system_name: "first-target" 44 target_cpu: "first-cpu" 45 target_libc: "first-libc" 46 compiler: "first-compiler" 47 abi_version: "first-abi" 48 abi_libc_version: "first-abi-libc" 49 builtin_sysroot: "sysroot" 50 """) 51 second = make_toolchain(""" 52 toolchain_identifier: "second-id" 53 host_system_name: "second-host" 54 target_system_name: "second-target" 55 target_cpu: "second-cpu" 56 target_libc: "second-libc" 57 compiler: "second-compiler" 58 abi_version: "second-abi" 59 abi_libc_version: "second-abi-libc" 60 cc_target_os: "os" 61 """) 62 error_toolchain_identifier = ( 63 "Difference in 'toolchain_identifier' field:\n" 64 "Value before change:\t'first-id'\n" 65 "Value after change:\t'second-id'\n" 66 ) 67 error_host_system_name = ( 68 "Difference in 'host_system_name' field:\n" 69 "Value before change:\t'first-host'\n" 70 "Value after change:\t'second-host'\n" 71 ) 72 error_target_system_name = ( 73 "Difference in 'target_system_name' field:\n" 74 "Value before change:\t'first-target'\n" 75 "Value after change:\t'second-target'\n" 76 ) 77 error_target_cpu = ( 78 "Difference in 'target_cpu' field:\n" 79 "Value before change:\t'first-cpu'\n" 80 "Value after change:\t'second-cpu'\n" 81 ) 82 error_target_libc = ( 83 "Difference in 'target_libc' field:\n" 84 "Value before change:\t'first-libc'\n" 85 "Value after change:\t'second-libc'\n" 86 ) 87 error_compiler = ( 88 "Difference in 'compiler' field:\n" 89 "Value before change:\t'first-compiler'\n" 90 "Value after change:\t'second-compiler'\n" 91 ) 92 error_abi_version = ( 93 "Difference in 'abi_version' field:\n" 94 "Value before change:\t'first-abi'\n" 95 "Value after change:\t'second-abi'\n" 96 ) 97 error_abi_libc_version = ( 98 "Difference in 'abi_libc_version' field:\n" 99 "Value before change:\t'first-abi-libc'\n" 100 "Value after change:\t'second-abi-libc'\n" 101 ) 102 error_builtin_sysroot = ( 103 "Difference in 'builtin_sysroot' field:\n" 104 "Value before change is set to 'sysroot'\n" 105 "Value after change is not set\n" 106 ) 107 error_cc_target_os = ( 108 "Difference in 'cc_target_os' field:\n" 109 "Value before change is not set\n" 110 "Value after change is set to 'os'\n" 111 ) 112 mock_stdout = StringIO() 113 with mock.patch("sys.stdout", mock_stdout): 114 compare_ctoolchains(first, second) 115 self.assertIn(error_toolchain_identifier, mock_stdout.getvalue()) 116 self.assertIn(error_host_system_name, mock_stdout.getvalue()) 117 self.assertIn(error_target_system_name, mock_stdout.getvalue()) 118 self.assertIn(error_target_cpu, mock_stdout.getvalue()) 119 self.assertIn(error_target_libc, mock_stdout.getvalue()) 120 self.assertIn(error_compiler, mock_stdout.getvalue()) 121 self.assertIn(error_abi_version, mock_stdout.getvalue()) 122 self.assertIn(error_abi_libc_version, mock_stdout.getvalue()) 123 self.assertIn(error_builtin_sysroot, mock_stdout.getvalue()) 124 self.assertIn(error_cc_target_os, mock_stdout.getvalue()) 125 126 def test_tool_path(self): 127 first = make_toolchain(""" 128 tool_path { 129 name: "only_first" 130 path: "/a/b/c" 131 } 132 tool_path { 133 name: "paths_differ" 134 path: "/path/first" 135 } 136 """) 137 second = make_toolchain(""" 138 tool_path { 139 name: "paths_differ" 140 path: "/path/second" 141 } 142 tool_path { 143 name: "only_second_1" 144 path: "/a/b/c" 145 } 146 tool_path { 147 name: "only_second_2" 148 path: "/a/b/c" 149 } 150 """) 151 error_only_first = ( 152 "* List before change contains entries for the " 153 "following tools that the list after the change " 154 "doesn't:\n[only_first]\n" 155 ) 156 error_only_second = ( 157 "* List after change contains entries for the " 158 "following tools that the list before the change " 159 "doesn't:\n" 160 "[\n" 161 "\tonly_second_1\n" 162 "\tonly_second_2\n" 163 "]\n" 164 ) 165 error_paths_differ = ( 166 "* Path for tool 'paths_differ' differs before and " 167 "after the change:\n" 168 "Value before change:\t'/path/first'\n" 169 "Value after change:\t'/path/second'\n" 170 ) 171 mock_stdout = StringIO() 172 with mock.patch("sys.stdout", mock_stdout): 173 compare_ctoolchains(first, second) 174 self.assertIn(error_only_first, mock_stdout.getvalue()) 175 self.assertIn(error_only_second, mock_stdout.getvalue()) 176 self.assertIn(error_paths_differ, mock_stdout.getvalue()) 177 178 def test_make_variable(self): 179 first = make_toolchain(""" 180 make_variable { 181 name: "only_first" 182 value: "val" 183 } 184 make_variable { 185 name: "value_differs" 186 value: "first_value" 187 } 188 """) 189 second = make_toolchain(""" 190 make_variable { 191 name: "value_differs" 192 value: "second_value" 193 } 194 make_variable { 195 name: "only_second_1" 196 value: "val" 197 } 198 make_variable { 199 name: "only_second_2" 200 value: "val" 201 } 202 """) 203 error_only_first = ( 204 "* List before change contains entries for the " 205 "following variables that the list after the " 206 "change doesn't:\n[only_first]\n" 207 ) 208 error_only_second = ( 209 "* List after change contains entries for the " 210 "following variables that the list before the " 211 "change doesn't:\n" 212 "[\n" 213 "\tonly_second_1\n" 214 "\tonly_second_2\n" 215 "]\n" 216 ) 217 error_value_differs = ( 218 "* Value for variable 'value_differs' differs before" 219 " and after the change:\n" 220 "Value before change:\t'first_value'\n" 221 "Value after change:\t'second_value'\n" 222 ) 223 mock_stdout = StringIO() 224 with mock.patch("sys.stdout", mock_stdout): 225 compare_ctoolchains(first, second) 226 self.assertIn(error_only_first, mock_stdout.getvalue()) 227 self.assertIn(error_only_second, mock_stdout.getvalue()) 228 self.assertIn(error_value_differs, mock_stdout.getvalue()) 229 230 def test_cxx_builtin_include_directories(self): 231 first = make_toolchain(""" 232 cxx_builtin_include_directory: "a/b/c" 233 cxx_builtin_include_directory: "d/e/f" 234 """) 235 second = make_toolchain(""" 236 cxx_builtin_include_directory: "d/e/f" 237 cxx_builtin_include_directory: "a/b/c" 238 """) 239 expect_error = ( 240 "Difference in 'cxx_builtin_include_directory' field:\n" 241 "List of elements before change:\n" 242 "[\n" 243 "\ta/b/c\n" 244 "\td/e/f\n" 245 "]\n" 246 "List of elements after change:\n" 247 "[\n" 248 "\td/e/f\n" 249 "\ta/b/c\n" 250 "]\n" 251 ) 252 mock_stdout = StringIO() 253 with mock.patch("sys.stdout", mock_stdout): 254 compare_ctoolchains(first, second) 255 self.assertIn(expect_error, mock_stdout.getvalue()) 256 257 def test_artifact_name_pattern(self): 258 first = make_toolchain(""" 259 artifact_name_pattern { 260 category_name: 'object_file' 261 prefix: '' 262 extension: '.obj1' 263 } 264 artifact_name_pattern { 265 category_name: 'executable' 266 prefix: 'first' 267 extension: '.exe' 268 } 269 artifact_name_pattern { 270 category_name: 'dynamic_library' 271 prefix: '' 272 extension: '.dll' 273 } 274 """) 275 second = make_toolchain(""" 276 artifact_name_pattern { 277 category_name: 'object_file' 278 prefix: '' 279 extension: '.obj2' 280 } 281 artifact_name_pattern { 282 category_name: 'static_library' 283 prefix: '' 284 extension: '.lib' 285 } 286 artifact_name_pattern { 287 category_name: 'executable' 288 prefix: 'second' 289 extension: '.exe' 290 } 291 artifact_name_pattern { 292 category_name: 'interface_library' 293 prefix: '' 294 extension: '.if.lib' 295 } 296 """) 297 error_only_first = ( 298 "* List before change contains entries for the " 299 "following categories that the list after the " 300 "change doesn't:\n[dynamic_library]\n" 301 ) 302 error_only_second = ( 303 "* List after change contains entries for the " 304 "following categories that the list before the " 305 "change doesn't:\n" 306 "[\n" 307 "\tinterface_library\n" 308 "\tstatic_library\n" 309 "]\n" 310 ) 311 error_extension_differs = ( 312 "* Value for category 'object_file' differs " 313 "before and after the change:\n" 314 "Value before change:" 315 "\tprefix:''" 316 "\textension:'.obj1'\n" 317 "Value after change:" 318 "\tprefix:''" 319 "\textension:'.obj2'\n" 320 ) 321 error_prefix_differs = ( 322 "* Value for category 'executable' differs " 323 "before and after the change:\n" 324 "Value before change:" 325 "\tprefix:'first'" 326 "\textension:'.exe'\n" 327 "Value after change:" 328 "\tprefix:'second'" 329 "\textension:'.exe'\n" 330 ) 331 mock_stdout = StringIO() 332 with mock.patch("sys.stdout", mock_stdout): 333 compare_ctoolchains(first, second) 334 self.assertIn(error_only_first, mock_stdout.getvalue()) 335 self.assertIn(error_only_second, mock_stdout.getvalue()) 336 self.assertIn(error_extension_differs, mock_stdout.getvalue()) 337 self.assertIn(error_prefix_differs, mock_stdout.getvalue()) 338 339 def test_features_not_ordered(self): 340 first = make_toolchain(""" 341 feature { 342 name: 'feature1' 343 } 344 feature { 345 name: 'feature2' 346 } 347 """) 348 second = make_toolchain(""" 349 feature { 350 name: 'feature2' 351 } 352 feature { 353 name: 'feature1' 354 } 355 """) 356 mock_stdout = StringIO() 357 with mock.patch("sys.stdout", mock_stdout): 358 compare_ctoolchains(first, second) 359 self.assertIn("Features not in right order", mock_stdout.getvalue()) 360 361 def test_features_missing(self): 362 first = make_toolchain(""" 363 feature { 364 name: 'feature1' 365 } 366 """) 367 second = make_toolchain(""" 368 feature { 369 name: 'feature2' 370 } 371 """) 372 error_only_first = ( 373 "* List before change contains entries for the " 374 "following features that the list after the " 375 "change doesn't:\n[feature1]\n" 376 ) 377 error_only_second = ( 378 "* List after change contains entries for the " 379 "following features that the list before the " 380 "change doesn't:\n[feature2]\n" 381 ) 382 mock_stdout = StringIO() 383 with mock.patch("sys.stdout", mock_stdout): 384 compare_ctoolchains(first, second) 385 self.assertIn(error_only_first, mock_stdout.getvalue()) 386 self.assertIn(error_only_second, mock_stdout.getvalue()) 387 388 def test_feature_enabled(self): 389 first = make_toolchain(""" 390 feature { 391 name: 'feature' 392 enabled: true 393 } 394 """) 395 second = make_toolchain(""" 396 feature { 397 name: 'feature' 398 enabled: false 399 } 400 """) 401 mock_stdout = StringIO() 402 with mock.patch("sys.stdout", mock_stdout): 403 compare_ctoolchains(first, second) 404 self.assertIn( 405 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 406 ) 407 408 def test_feature_provides(self): 409 first = make_toolchain(""" 410 feature { 411 name: 'feature' 412 provides: 'a' 413 } 414 """) 415 second = make_toolchain(""" 416 feature { 417 name: 'feature' 418 provides: 'b' 419 } 420 """) 421 mock_stdout = StringIO() 422 with mock.patch("sys.stdout", mock_stdout): 423 compare_ctoolchains(first, second) 424 self.assertIn( 425 "* Feature 'feature' differs before and after the change:", 426 mock_stdout.getvalue(), 427 ) 428 429 def test_feature_provides_preserves_order(self): 430 first = make_toolchain(""" 431 feature { 432 name: 'feature' 433 provides: 'a' 434 provides: 'b' 435 } 436 """) 437 second = make_toolchain(""" 438 feature { 439 name: 'feature' 440 provides: 'b' 441 provides: 'a' 442 } 443 """) 444 mock_stdout = StringIO() 445 with mock.patch("sys.stdout", mock_stdout): 446 compare_ctoolchains(first, second) 447 self.assertIn( 448 "* Feature 'feature' differs before and after the change:", 449 mock_stdout.getvalue(), 450 ) 451 452 def test_feature_implies(self): 453 first = make_toolchain(""" 454 feature { 455 name: 'feature' 456 implies: 'a' 457 } 458 """) 459 second = make_toolchain(""" 460 feature { 461 name: 'feature' 462 } 463 """) 464 mock_stdout = StringIO() 465 with mock.patch("sys.stdout", mock_stdout): 466 compare_ctoolchains(first, second) 467 self.assertIn( 468 "* Feature 'feature' differs before and after the change:", 469 mock_stdout.getvalue(), 470 ) 471 472 def test_feature_implies_preserves_order(self): 473 first = make_toolchain(""" 474 feature { 475 name: 'feature' 476 implies: 'a' 477 implies: 'b' 478 } 479 """) 480 second = make_toolchain(""" 481 feature { 482 name: 'feature' 483 implies: 'b' 484 implies: 'a' 485 } 486 """) 487 mock_stdout = StringIO() 488 with mock.patch("sys.stdout", mock_stdout): 489 compare_ctoolchains(first, second) 490 self.assertIn( 491 "* Feature 'feature' differs before and after the change:", 492 mock_stdout.getvalue(), 493 ) 494 495 def test_feature_requires_preserves_list_order(self): 496 first = make_toolchain(""" 497 feature { 498 name: 'feature' 499 requires: { 500 feature: 'feature1' 501 } 502 requires: { 503 feature: 'feature2' 504 } 505 } 506 """) 507 second = make_toolchain(""" 508 feature { 509 name: 'feature' 510 requires: { 511 feature: 'feature2' 512 } 513 requires: { 514 feature: 'feature1' 515 } 516 } 517 """) 518 mock_stdout = StringIO() 519 with mock.patch("sys.stdout", mock_stdout): 520 compare_ctoolchains(first, second) 521 self.assertIn( 522 "* Feature 'feature' differs before and after the change:", 523 mock_stdout.getvalue(), 524 ) 525 526 def test_feature_requires_ignores_required_features_order(self): 527 first = make_toolchain(""" 528 feature { 529 name: 'feature' 530 requires: { 531 feature: 'feature1' 532 feature: 'feature2' 533 } 534 } 535 """) 536 second = make_toolchain(""" 537 feature { 538 name: 'feature' 539 requires: { 540 feature: 'feature2' 541 feature: 'feature1' 542 } 543 } 544 """) 545 mock_stdout = StringIO() 546 with mock.patch("sys.stdout", mock_stdout): 547 compare_ctoolchains(first, second) 548 self.assertIn("No difference", mock_stdout.getvalue()) 549 550 def test_feature_requires_differs(self): 551 first = make_toolchain(""" 552 feature { 553 name: 'feature' 554 requires: { 555 feature: 'feature1' 556 } 557 } 558 """) 559 second = make_toolchain(""" 560 feature { 561 name: 'feature' 562 requires: { 563 feature: 'feature2' 564 } 565 } 566 """) 567 mock_stdout = StringIO() 568 with mock.patch("sys.stdout", mock_stdout): 569 compare_ctoolchains(first, second) 570 self.assertIn( 571 "* Feature 'feature' differs before and after the change:", 572 mock_stdout.getvalue(), 573 ) 574 575 def test_action_config_ignores_requires(self): 576 first = make_toolchain(""" 577 action_config { 578 config_name: 'config' 579 requires: { 580 feature: 'feature1' 581 } 582 } 583 """) 584 second = make_toolchain(""" 585 action_config { 586 config_name: 'config' 587 requires: { 588 feature: 'feature2' 589 } 590 } 591 """) 592 mock_stdout = StringIO() 593 with mock.patch("sys.stdout", mock_stdout): 594 compare_ctoolchains(first, second) 595 self.assertIn("No difference", mock_stdout.getvalue()) 596 597 def test_env_set_actions_differ(self): 598 first = make_toolchain(""" 599 feature { 600 name: 'feature' 601 env_set { 602 action: 'a1' 603 } 604 } 605 """) 606 second = make_toolchain(""" 607 feature { 608 name: 'feature' 609 env_set: { 610 action: 'a1' 611 action: 'a2' 612 } 613 } 614 """) 615 mock_stdout = StringIO() 616 with mock.patch("sys.stdout", mock_stdout): 617 compare_ctoolchains(first, second) 618 self.assertIn( 619 "* Feature 'feature' differs before and after the change:", 620 mock_stdout.getvalue(), 621 ) 622 623 def test_env_set_ignores_actions_order(self): 624 first = make_toolchain(""" 625 feature { 626 name: 'feature' 627 env_set { 628 action: 'a2' 629 action: 'a1' 630 } 631 } 632 """) 633 second = make_toolchain(""" 634 feature { 635 name: 'feature' 636 env_set: { 637 action: 'a1' 638 action: 'a2' 639 } 640 } 641 """) 642 mock_stdout = StringIO() 643 with mock.patch("sys.stdout", mock_stdout): 644 compare_ctoolchains(first, second) 645 self.assertIn("No difference", mock_stdout.getvalue()) 646 647 def test_env_set_env_entries_not_ordered(self): 648 first = make_toolchain(""" 649 feature { 650 name: 'feature' 651 env_set { 652 env_entry { 653 key: 'k1' 654 value: 'v1' 655 } 656 env_entry { 657 key: 'k2' 658 value: 'v2' 659 } 660 } 661 } 662 """) 663 second = make_toolchain(""" 664 feature { 665 name: 'feature' 666 env_set { 667 env_entry { 668 key: 'k2' 669 value: 'v2' 670 } 671 env_entry { 672 key: 'k1' 673 value: 'v1' 674 } 675 } 676 } 677 """) 678 mock_stdout = StringIO() 679 with mock.patch("sys.stdout", mock_stdout): 680 compare_ctoolchains(first, second) 681 self.assertIn( 682 "* Feature 'feature' differs before and after the change:", 683 mock_stdout.getvalue(), 684 ) 685 686 def test_env_set_env_entries_differ(self): 687 first = make_toolchain(""" 688 feature { 689 name: 'feature' 690 env_set { 691 env_entry { 692 key: 'k1' 693 value: 'value_first' 694 } 695 } 696 } 697 """) 698 second = make_toolchain(""" 699 feature { 700 name: 'feature' 701 env_set { 702 env_entry { 703 key: 'k1' 704 value: 'value_second' 705 } 706 } 707 } 708 """) 709 mock_stdout = StringIO() 710 with mock.patch("sys.stdout", mock_stdout): 711 compare_ctoolchains(first, second) 712 self.assertIn( 713 "* Feature 'feature' differs before and after the change:", 714 mock_stdout.getvalue(), 715 ) 716 717 def test_feature_preserves_env_set_order(self): 718 first = make_toolchain(""" 719 feature { 720 name: 'feature' 721 env_set { 722 env_entry { 723 key: 'first' 724 value: 'first' 725 } 726 } 727 env_set { 728 env_entry { 729 key: 'second' 730 value: 'second' 731 } 732 } 733 } 734 """) 735 second = make_toolchain(""" 736 feature { 737 name: 'feature' 738 env_set { 739 env_entry { 740 key: 'second' 741 value: 'second' 742 } 743 } 744 env_set { 745 env_entry { 746 key: 'first' 747 value: 'first' 748 } 749 } 750 } 751 """) 752 mock_stdout = StringIO() 753 with mock.patch("sys.stdout", mock_stdout): 754 compare_ctoolchains(first, second) 755 self.assertIn( 756 "* Feature 'feature' differs before and after the change:", 757 mock_stdout.getvalue(), 758 ) 759 760 def test_action_config_ignores_env_set(self): 761 first = make_toolchain(""" 762 action_config { 763 config_name: 'config' 764 env_set { 765 env_entry { 766 key: 'k1' 767 value: 'value_first' 768 } 769 } 770 } 771 """) 772 second = make_toolchain(""" 773 action_config { 774 config_name: 'config' 775 env_set { 776 env_entry { 777 key: 'k1' 778 value: 'value_second' 779 } 780 } 781 } 782 """) 783 mock_stdout = StringIO() 784 with mock.patch("sys.stdout", mock_stdout): 785 compare_ctoolchains(first, second) 786 self.assertIn("No difference", mock_stdout.getvalue()) 787 788 def test_env_set_ignores_with_feature_set_order(self): 789 first = make_toolchain(""" 790 feature { 791 name: 'feature' 792 env_set{ 793 with_feature { 794 feature: 'feature1' 795 } 796 with_feature { 797 not_feature: 'feature2' 798 } 799 } 800 } 801 """) 802 second = make_toolchain(""" 803 feature { 804 name: 'feature' 805 env_set { 806 with_feature { 807 not_feature: 'feature2' 808 } 809 with_feature { 810 feature: 'feature1' 811 } 812 } 813 } 814 """) 815 mock_stdout = StringIO() 816 with mock.patch("sys.stdout", mock_stdout): 817 compare_ctoolchains(first, second) 818 self.assertIn("No difference", mock_stdout.getvalue()) 819 820 def test_env_set_ignores_with_feature_set_lists_order(self): 821 first = make_toolchain(""" 822 feature { 823 name: 'feature' 824 env_set{ 825 with_feature { 826 feature: 'feature1' 827 feature: 'feature2' 828 not_feature: 'not_feature1' 829 not_feature: 'not_feature2' 830 } 831 } 832 } 833 """) 834 second = make_toolchain(""" 835 feature { 836 name: 'feature' 837 env_set{ 838 with_feature { 839 feature: 'feature2' 840 feature: 'feature1' 841 not_feature: 'not_feature2' 842 not_feature: 'not_feature1' 843 } 844 } 845 } 846 """) 847 mock_stdout = StringIO() 848 with mock.patch("sys.stdout", mock_stdout): 849 compare_ctoolchains(first, second) 850 self.assertIn("No difference", mock_stdout.getvalue()) 851 852 def test_flag_set_ignores_actions_order(self): 853 first = make_toolchain(""" 854 feature { 855 name: 'feature' 856 flag_set { 857 action: 'a1' 858 action: 'a2' 859 } 860 } 861 """) 862 second = make_toolchain(""" 863 feature { 864 name: 'feature' 865 flag_set { 866 action: 'a2' 867 action: 'a1' 868 } 869 } 870 """) 871 mock_stdout = StringIO() 872 with mock.patch("sys.stdout", mock_stdout): 873 compare_ctoolchains(first, second) 874 self.assertIn("No difference", mock_stdout.getvalue()) 875 876 def test_action_config_flag_set_actions_ignored(self): 877 first = make_toolchain(""" 878 action_config { 879 config_name: 'config' 880 flag_set { 881 action: 'a1' 882 } 883 } 884 """) 885 second = make_toolchain(""" 886 action_config { 887 config_name: 'config' 888 flag_set { 889 action: 'a2' 890 } 891 } 892 """) 893 mock_stdout = StringIO() 894 with mock.patch("sys.stdout", mock_stdout): 895 compare_ctoolchains(first, second) 896 self.assertIn("No difference", mock_stdout.getvalue()) 897 898 def test_flag_set_ignores_with_feature_set_order(self): 899 first = make_toolchain(""" 900 feature { 901 name: 'feature' 902 flag_set { 903 with_feature { 904 feature: 'feature1' 905 } 906 with_feature { 907 not_feature: 'feature2' 908 } 909 } 910 } 911 action_config { 912 config_name: 'config' 913 flag_set { 914 with_feature { 915 feature: 'feature1' 916 } 917 with_feature { 918 not_feature: 'feature2' 919 } 920 } 921 } 922 """) 923 second = make_toolchain(""" 924 feature { 925 name: 'feature' 926 flag_set { 927 with_feature { 928 not_feature: 'feature2' 929 } 930 with_feature { 931 feature: 'feature1' 932 } 933 } 934 } 935 action_config { 936 config_name: 'config' 937 flag_set { 938 with_feature { 939 not_feature: 'feature2' 940 } 941 with_feature { 942 feature: 'feature1' 943 } 944 } 945 } 946 """) 947 mock_stdout = StringIO() 948 with mock.patch("sys.stdout", mock_stdout): 949 compare_ctoolchains(first, second) 950 self.assertIn("No difference", mock_stdout.getvalue()) 951 952 def test_flag_set_ignores_with_feature_set_lists_order(self): 953 first = make_toolchain(""" 954 feature { 955 name: 'feature' 956 flag_set{ 957 with_feature { 958 feature: 'feature1' 959 feature: 'feature2' 960 not_feature: 'not_feature1' 961 not_feature: 'not_feature2' 962 } 963 } 964 } 965 action_config { 966 config_name: 'config' 967 flag_set{ 968 with_feature { 969 feature: 'feature1' 970 feature: 'feature2' 971 not_feature: 'not_feature1' 972 not_feature: 'not_feature2' 973 } 974 } 975 } 976 """) 977 second = make_toolchain(""" 978 feature { 979 name: 'feature' 980 flag_set{ 981 with_feature { 982 feature: 'feature2' 983 feature: 'feature1' 984 not_feature: 'not_feature2' 985 not_feature: 'not_feature1' 986 } 987 } 988 } 989 action_config { 990 config_name: 'config' 991 flag_set{ 992 with_feature { 993 feature: 'feature2' 994 feature: 'feature1' 995 not_feature: 'not_feature2' 996 not_feature: 'not_feature1' 997 } 998 } 999 } 1000 """) 1001 mock_stdout = StringIO() 1002 with mock.patch("sys.stdout", mock_stdout): 1003 compare_ctoolchains(first, second) 1004 self.assertIn("No difference", mock_stdout.getvalue()) 1005 1006 def test_flag_set_preserves_flag_group_order(self): 1007 first = make_toolchain(""" 1008 feature { 1009 name: 'feature' 1010 flag_set { 1011 flag_group { 1012 flag: 'a' 1013 } 1014 flag_group { 1015 flag: 'b' 1016 } 1017 } 1018 } 1019 action_config { 1020 config_name: 'config' 1021 flag_set { 1022 flag_group { 1023 flag: 'a' 1024 } 1025 flag_group { 1026 flag: 'b' 1027 } 1028 } 1029 } 1030 """) 1031 second = make_toolchain(""" 1032 feature { 1033 name: 'feature' 1034 flag_set { 1035 flag_group { 1036 flag: 'b' 1037 } 1038 flag_group { 1039 flag: 'a' 1040 } 1041 } 1042 } 1043 action_config { 1044 config_name: 'config' 1045 flag_set { 1046 flag_group { 1047 flag: 'b' 1048 } 1049 flag_group { 1050 flag: 'a' 1051 } 1052 } 1053 } 1054 """) 1055 mock_stdout = StringIO() 1056 with mock.patch("sys.stdout", mock_stdout): 1057 compare_ctoolchains(first, second) 1058 self.assertIn( 1059 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 1060 ) 1061 self.assertIn( 1062 "* Action config 'config' differs before and after", 1063 mock_stdout.getvalue(), 1064 ) 1065 1066 def test_flag_group_preserves_flags_order(self): 1067 first = make_toolchain(""" 1068 feature { 1069 name: 'feature' 1070 flag_set{ 1071 flag_group { 1072 flag: 'flag1' 1073 flag: 'flag2' 1074 } 1075 } 1076 } 1077 action_config { 1078 config_name: 'config' 1079 flag_set{ 1080 flag_group { 1081 flag: 'flag1' 1082 flag: 'flag2' 1083 } 1084 } 1085 } 1086 """) 1087 second = make_toolchain(""" 1088 feature { 1089 name: 'feature' 1090 flag_set{ 1091 flag_group { 1092 flag: 'flag2' 1093 flag: 'flag1' 1094 } 1095 } 1096 } 1097 action_config { 1098 config_name: 'config' 1099 flag_set{ 1100 flag_group { 1101 flag: 'flag2' 1102 flag: 'flag1' 1103 } 1104 } 1105 } 1106 """) 1107 mock_stdout = StringIO() 1108 with mock.patch("sys.stdout", mock_stdout): 1109 compare_ctoolchains(first, second) 1110 self.assertIn( 1111 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 1112 ) 1113 self.assertIn( 1114 "* Action config 'config' differs before and after", 1115 mock_stdout.getvalue(), 1116 ) 1117 1118 def test_flag_group_iterate_over_differs(self): 1119 first = make_toolchain(""" 1120 feature { 1121 name: 'feature' 1122 flag_set{ 1123 flag_group { 1124 iterate_over: 'a' 1125 } 1126 } 1127 } 1128 action_config { 1129 config_name: 'config' 1130 flag_set{ 1131 flag_group { 1132 iterate_over: 'a' 1133 } 1134 } 1135 } 1136 """) 1137 second = make_toolchain(""" 1138 feature { 1139 name: 'feature' 1140 flag_set{ 1141 flag_group { 1142 iterate_over: 'b' 1143 } 1144 } 1145 } 1146 action_config { 1147 config_name: 'config' 1148 flag_set{ 1149 flag_group { 1150 iterate_over: 'b' 1151 } 1152 } 1153 } 1154 """) 1155 mock_stdout = StringIO() 1156 with mock.patch("sys.stdout", mock_stdout): 1157 compare_ctoolchains(first, second) 1158 self.assertIn( 1159 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 1160 ) 1161 self.assertIn( 1162 "* Action config 'config' differs before and after", 1163 mock_stdout.getvalue(), 1164 ) 1165 1166 def test_flag_group_expand_if_true_differs(self): 1167 first = make_toolchain(""" 1168 feature { 1169 name: 'feature' 1170 flag_set{ 1171 flag_group { 1172 expand_if_true: 'a' 1173 } 1174 } 1175 } 1176 action_config { 1177 config_name: 'config' 1178 flag_set{ 1179 flag_group { 1180 expand_if_true: 'a' 1181 } 1182 } 1183 } 1184 """) 1185 second = make_toolchain(""" 1186 feature { 1187 name: 'feature' 1188 flag_set{ 1189 flag_group { 1190 expand_if_true: 'b' 1191 } 1192 } 1193 } 1194 action_config { 1195 config_name: 'config' 1196 flag_set{ 1197 flag_group { 1198 expand_if_true: 'b' 1199 } 1200 } 1201 } 1202 """) 1203 mock_stdout = StringIO() 1204 with mock.patch("sys.stdout", mock_stdout): 1205 compare_ctoolchains(first, second) 1206 self.assertIn( 1207 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 1208 ) 1209 self.assertIn( 1210 "* Action config 'config' differs before and after", 1211 mock_stdout.getvalue(), 1212 ) 1213 1214 def test_flag_group_expand_if_false_differs(self): 1215 first = make_toolchain(""" 1216 feature { 1217 name: 'feature' 1218 flag_set{ 1219 flag_group { 1220 expand_if_false: 'a' 1221 } 1222 } 1223 } 1224 action_config { 1225 config_name: 'config' 1226 flag_set{ 1227 flag_group { 1228 expand_if_false: 'a' 1229 } 1230 } 1231 } 1232 """) 1233 second = make_toolchain(""" 1234 feature { 1235 name: 'feature' 1236 flag_set{ 1237 flag_group { 1238 expand_if_false: 'b' 1239 } 1240 } 1241 } 1242 action_config { 1243 config_name: 'config' 1244 flag_set{ 1245 flag_group { 1246 expand_if_false: 'b' 1247 } 1248 } 1249 } 1250 """) 1251 mock_stdout = StringIO() 1252 with mock.patch("sys.stdout", mock_stdout): 1253 compare_ctoolchains(first, second) 1254 self.assertIn( 1255 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 1256 ) 1257 self.assertIn( 1258 "* Action config 'config' differs before and after", 1259 mock_stdout.getvalue(), 1260 ) 1261 1262 def test_flag_group_expand_if_all_available_differs(self): 1263 first = make_toolchain(""" 1264 feature { 1265 name: 'feature' 1266 flag_set{ 1267 flag_group { 1268 expand_if_all_available: 'a' 1269 } 1270 } 1271 } 1272 action_config { 1273 config_name: 'config' 1274 flag_set{ 1275 flag_group { 1276 expand_if_all_available: 'a' 1277 } 1278 } 1279 } 1280 """) 1281 second = make_toolchain(""" 1282 feature { 1283 name: 'feature' 1284 flag_set{ 1285 flag_group { 1286 expand_if_all_available: 'b' 1287 } 1288 } 1289 } 1290 action_config { 1291 config_name: 'config' 1292 flag_set{ 1293 flag_group { 1294 expand_if_all_available: 'b' 1295 } 1296 } 1297 } 1298 """) 1299 mock_stdout = StringIO() 1300 with mock.patch("sys.stdout", mock_stdout): 1301 compare_ctoolchains(first, second) 1302 self.assertIn( 1303 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 1304 ) 1305 self.assertIn( 1306 "* Action config 'config' differs before and after", 1307 mock_stdout.getvalue(), 1308 ) 1309 1310 def test_flag_group_expand_if_none_available_differs(self): 1311 first = make_toolchain(""" 1312 feature { 1313 name: 'feature' 1314 flag_set{ 1315 flag_group { 1316 expand_if_none_available: 'a' 1317 } 1318 } 1319 } 1320 action_config { 1321 config_name: 'config' 1322 flag_set{ 1323 flag_group { 1324 expand_if_none_available: 'a' 1325 } 1326 } 1327 } 1328 """) 1329 second = make_toolchain(""" 1330 feature { 1331 name: 'feature' 1332 flag_set{ 1333 flag_group { 1334 expand_if_none_available: 'b' 1335 } 1336 } 1337 } 1338 action_config { 1339 config_name: 'config' 1340 flag_set{ 1341 flag_group { 1342 expand_if_none_available: 'b' 1343 } 1344 } 1345 } 1346 """) 1347 mock_stdout = StringIO() 1348 with mock.patch("sys.stdout", mock_stdout): 1349 compare_ctoolchains(first, second) 1350 self.assertIn( 1351 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 1352 ) 1353 self.assertIn( 1354 "* Action config 'config' differs before and after", 1355 mock_stdout.getvalue(), 1356 ) 1357 1358 def test_flag_group_expand_if_all_available_ignores_order(self): 1359 first = make_toolchain(""" 1360 feature { 1361 name: 'feature' 1362 flag_set{ 1363 flag_group { 1364 expand_if_all_available: 'a' 1365 expand_if_all_available: 'b' 1366 } 1367 } 1368 } 1369 action_config { 1370 config_name: 'config' 1371 flag_set{ 1372 flag_group { 1373 expand_if_all_available: 'a' 1374 expand_if_all_available: 'b' 1375 } 1376 } 1377 } 1378 """) 1379 second = make_toolchain(""" 1380 feature { 1381 name: 'feature' 1382 flag_set{ 1383 flag_group { 1384 expand_if_all_available: 'b' 1385 expand_if_all_available: 'a' 1386 } 1387 } 1388 } 1389 action_config { 1390 config_name: 'config' 1391 flag_set{ 1392 flag_group { 1393 expand_if_all_available: 'b' 1394 expand_if_all_available: 'a' 1395 } 1396 } 1397 } 1398 """) 1399 mock_stdout = StringIO() 1400 with mock.patch("sys.stdout", mock_stdout): 1401 compare_ctoolchains(first, second) 1402 self.assertIn("No difference", mock_stdout.getvalue()) 1403 1404 def test_flag_group_expand_if_none_available_ignores_order(self): 1405 first = make_toolchain(""" 1406 feature { 1407 name: 'feature' 1408 flag_set{ 1409 flag_group { 1410 expand_if_none_available: 'a' 1411 expand_if_none_available: 'b' 1412 } 1413 } 1414 } 1415 action_config { 1416 config_name: 'config' 1417 flag_set{ 1418 flag_group { 1419 expand_if_none_available: 'a' 1420 expand_if_none_available: 'b' 1421 } 1422 } 1423 } 1424 """) 1425 second = make_toolchain(""" 1426 feature { 1427 name: 'feature' 1428 flag_set{ 1429 flag_group { 1430 expand_if_none_available: 'b' 1431 expand_if_none_available: 'a' 1432 } 1433 } 1434 } 1435 action_config { 1436 config_name: 'config' 1437 flag_set{ 1438 flag_group { 1439 expand_if_none_available: 'b' 1440 expand_if_none_available: 'a' 1441 } 1442 } 1443 } 1444 """) 1445 mock_stdout = StringIO() 1446 with mock.patch("sys.stdout", mock_stdout): 1447 compare_ctoolchains(first, second) 1448 self.assertIn("No difference", mock_stdout.getvalue()) 1449 1450 def test_flag_group_expand_if_equal_differs(self): 1451 first = make_toolchain(""" 1452 feature { 1453 name: 'feature' 1454 flag_set{ 1455 flag_group { 1456 expand_if_equal { 1457 variable: 'first' 1458 value: 'val' 1459 } 1460 } 1461 } 1462 } 1463 action_config { 1464 config_name: 'config' 1465 flag_set{ 1466 flag_group { 1467 expand_if_equal { 1468 variable: 'first' 1469 value: 'val' 1470 } 1471 } 1472 } 1473 } 1474 """) 1475 second = make_toolchain(""" 1476 feature { 1477 name: 'feature' 1478 flag_set{ 1479 flag_group { 1480 expand_if_equal { 1481 variable: 'second' 1482 value: 'val' 1483 } 1484 } 1485 } 1486 } 1487 action_config { 1488 config_name: 'config' 1489 flag_set{ 1490 flag_group { 1491 expand_if_equal { 1492 variable: 'second' 1493 value: 'val' 1494 } 1495 } 1496 } 1497 } 1498 """) 1499 mock_stdout = StringIO() 1500 with mock.patch("sys.stdout", mock_stdout): 1501 compare_ctoolchains(first, second) 1502 self.assertIn( 1503 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 1504 ) 1505 self.assertIn( 1506 "* Action config 'config' differs before and after", 1507 mock_stdout.getvalue(), 1508 ) 1509 1510 def test_flag_group_flag_groups_differ(self): 1511 first = make_toolchain(""" 1512 feature { 1513 name: 'feature' 1514 flag_set{ 1515 flag_group { 1516 flag_group { 1517 flag: 'a' 1518 flag: 'b' 1519 } 1520 } 1521 } 1522 } 1523 action_config { 1524 config_name: 'config' 1525 flag_set{ 1526 flag_group { 1527 flag_group { 1528 flag: 'a' 1529 flag: 'b' 1530 } 1531 } 1532 } 1533 } 1534 """) 1535 second = make_toolchain(""" 1536 feature { 1537 name: 'feature' 1538 flag_set{ 1539 flag_group { 1540 flag_group { 1541 flag: 'b' 1542 flag: 'a' 1543 } 1544 } 1545 } 1546 } 1547 action_config { 1548 config_name: 'config' 1549 flag_set{ 1550 flag_group { 1551 flag_group { 1552 flag: 'b' 1553 flag: 'a' 1554 } 1555 } 1556 } 1557 } 1558 """) 1559 mock_stdout = StringIO() 1560 with mock.patch("sys.stdout", mock_stdout): 1561 compare_ctoolchains(first, second) 1562 self.assertIn( 1563 "* Feature 'feature' differs before and after", mock_stdout.getvalue() 1564 ) 1565 self.assertIn( 1566 "* Action config 'config' differs before and after", 1567 mock_stdout.getvalue(), 1568 ) 1569 1570 def test_action_configs_not_ordered(self): 1571 first = make_toolchain(""" 1572 action_config { 1573 config_name: 'action1' 1574 } 1575 action_config { 1576 config_name: 'action2' 1577 } 1578 """) 1579 second = make_toolchain(""" 1580 action_config { 1581 config_name: 'action2' 1582 } 1583 action_config { 1584 config_name: 'action1' 1585 } 1586 """) 1587 mock_stdout = StringIO() 1588 with mock.patch("sys.stdout", mock_stdout): 1589 compare_ctoolchains(first, second) 1590 self.assertIn("Action configs not in right order", mock_stdout.getvalue()) 1591 1592 def test_action_configs_missing(self): 1593 first = make_toolchain(""" 1594 action_config { 1595 config_name: 'action1' 1596 } 1597 """) 1598 second = make_toolchain(""" 1599 action_config { 1600 config_name: 'action2' 1601 } 1602 """) 1603 error_only_first = ( 1604 "* List before change contains entries for the " 1605 "following action_configs that the list after the " 1606 "change doesn't:\n[action1]\n" 1607 ) 1608 error_only_second = ( 1609 "* List after change contains entries for the " 1610 "following action_configs that the list before the " 1611 "change doesn't:\n[action2]\n" 1612 ) 1613 mock_stdout = StringIO() 1614 with mock.patch("sys.stdout", mock_stdout): 1615 compare_ctoolchains(first, second) 1616 self.assertIn(error_only_first, mock_stdout.getvalue()) 1617 self.assertIn(error_only_second, mock_stdout.getvalue()) 1618 1619 def test_action_config_enabled(self): 1620 first = make_toolchain(""" 1621 action_config { 1622 config_name: 'config' 1623 enabled: true 1624 } 1625 """) 1626 second = make_toolchain(""" 1627 action_config { 1628 config_name: 'config' 1629 enabled: false 1630 } 1631 """) 1632 mock_stdout = StringIO() 1633 with mock.patch("sys.stdout", mock_stdout): 1634 compare_ctoolchains(first, second) 1635 self.assertIn( 1636 "* Action config 'config' differs before and after", 1637 mock_stdout.getvalue(), 1638 ) 1639 1640 def test_action_config_action_name(self): 1641 first = make_toolchain(""" 1642 action_config { 1643 config_name: 'config' 1644 action_name: 'config1' 1645 } 1646 """) 1647 second = make_toolchain(""" 1648 action_config { 1649 config_name: 'config' 1650 action_name: 'config2' 1651 } 1652 """) 1653 mock_stdout = StringIO() 1654 with mock.patch("sys.stdout", mock_stdout): 1655 compare_ctoolchains(first, second) 1656 self.assertIn( 1657 "* Action config 'config' differs before and after", 1658 mock_stdout.getvalue(), 1659 ) 1660 1661 def test_action_config_tool_tool_path_differs(self): 1662 first = make_toolchain(""" 1663 action_config { 1664 config_name: 'config' 1665 tool { 1666 tool_path: 'path1' 1667 } 1668 } 1669 """) 1670 second = make_toolchain(""" 1671 action_config { 1672 config_name: 'config' 1673 tool { 1674 tool_path: 'path2' 1675 } 1676 } 1677 """) 1678 mock_stdout = StringIO() 1679 with mock.patch("sys.stdout", mock_stdout): 1680 compare_ctoolchains(first, second) 1681 self.assertIn( 1682 "* Action config 'config' differs before and after", 1683 mock_stdout.getvalue(), 1684 ) 1685 1686 def test_action_config_tool_execution_requirements_differ(self): 1687 first = make_toolchain(""" 1688 action_config { 1689 config_name: 'config' 1690 tool { 1691 execution_requirement: 'a' 1692 } 1693 } 1694 """) 1695 second = make_toolchain(""" 1696 action_config { 1697 config_name: 'config' 1698 tool { 1699 execution_requirement: 'b' 1700 } 1701 } 1702 """) 1703 mock_stdout = StringIO() 1704 with mock.patch("sys.stdout", mock_stdout): 1705 compare_ctoolchains(first, second) 1706 self.assertIn( 1707 "* Action config 'config' differs before and after", 1708 mock_stdout.getvalue(), 1709 ) 1710 1711 def test_action_config_tool_execution_requirements_ignores_order(self): 1712 first = make_toolchain(""" 1713 action_config { 1714 config_name: 'config' 1715 tool { 1716 execution_requirement: 'a' 1717 execution_requirement: 'b' 1718 } 1719 } 1720 """) 1721 second = make_toolchain(""" 1722 action_config { 1723 config_name: 'config' 1724 tool { 1725 execution_requirement: 'b' 1726 execution_requirement: 'a' 1727 } 1728 } 1729 """) 1730 mock_stdout = StringIO() 1731 with mock.patch("sys.stdout", mock_stdout): 1732 compare_ctoolchains(first, second) 1733 self.assertIn("No difference", mock_stdout.getvalue()) 1734 1735 def test_action_config_implies_differs(self): 1736 first = make_toolchain(""" 1737 action_config { 1738 config_name: 'config' 1739 implies: 'a' 1740 } 1741 """) 1742 second = make_toolchain(""" 1743 action_config { 1744 config_name: 'config' 1745 implies: 'b' 1746 } 1747 """) 1748 mock_stdout = StringIO() 1749 with mock.patch("sys.stdout", mock_stdout): 1750 compare_ctoolchains(first, second) 1751 self.assertIn( 1752 "* Action config 'config' differs before and after", 1753 mock_stdout.getvalue(), 1754 ) 1755 1756 def test_action_config_implies_preserves_order(self): 1757 first = make_toolchain(""" 1758 action_config { 1759 config_name: 'config' 1760 implies: 'a' 1761 implies: 'b' 1762 } 1763 """) 1764 second = make_toolchain(""" 1765 action_config { 1766 config_name: 'config' 1767 implies: 'b' 1768 implies: 'a' 1769 } 1770 """) 1771 mock_stdout = StringIO() 1772 with mock.patch("sys.stdout", mock_stdout): 1773 compare_ctoolchains(first, second) 1774 self.assertIn( 1775 "* Action config 'config' differs before and after", 1776 mock_stdout.getvalue(), 1777 ) 1778 1779 def test_unused_tool_path(self): 1780 first = make_toolchain(""" 1781 tool_path { 1782 name: "empty" 1783 path: "" 1784 } 1785 """) 1786 second = make_toolchain(""" 1787 tool_path { 1788 name: "empty" 1789 path: "NOT_USED" 1790 } 1791 """) 1792 mock_stdout = StringIO() 1793 with mock.patch("sys.stdout", mock_stdout): 1794 compare_ctoolchains(first, second) 1795 self.assertIn("No difference", mock_stdout.getvalue()) 1796 1797 def test_unused_tool_path_in_tool(self): 1798 first = make_toolchain(""" 1799 action_config { 1800 config_name: 'config' 1801 tool { 1802 tool_path: '' 1803 } 1804 } 1805 """) 1806 second = make_toolchain(""" 1807 action_config { 1808 config_name: 'config' 1809 tool { 1810 tool_path: 'NOT_USED' 1811 } 1812 } 1813 """) 1814 mock_stdout = StringIO() 1815 with mock.patch("sys.stdout", mock_stdout): 1816 compare_ctoolchains(first, second) 1817 self.assertIn("No difference", mock_stdout.getvalue()) 1818 1819 1820if __name__ == "__main__": 1821 unittest.main() 1822