aboutsummaryrefslogtreecommitdiff
path: root/tools/migration/ctoolchain_comparator_lib_test.py
diff options
context:
space:
mode:
authorVinh Tran <vinhdaitran@google.com>2023-07-21 19:38:23 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-07-21 19:38:23 +0000
commitf0df148dbeb9b9ed3816aad328ebe7c65efaaa24 (patch)
treec75dabb560288e11786211bdc61ba40dde4b8674 /tools/migration/ctoolchain_comparator_lib_test.py
parent3544b5a539d9e51161befd2ac3fdc04525bced91 (diff)
parent9a4853f0327e0266818c8d6b4967e2e8f36b1a88 (diff)
downloadbazelbuild-rules_cc-f0df148dbeb9b9ed3816aad328ebe7c65efaaa24.tar.gz
Original change: https://android-review.googlesource.com/c/platform/external/bazelbuild-rules_cc/+/2663436 Change-Id: I450b9f32024fa1b0844cc21a825c26589feb3977 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'tools/migration/ctoolchain_comparator_lib_test.py')
-rw-r--r--tools/migration/ctoolchain_comparator_lib_test.py1709
1 files changed, 1709 insertions, 0 deletions
diff --git a/tools/migration/ctoolchain_comparator_lib_test.py b/tools/migration/ctoolchain_comparator_lib_test.py
new file mode 100644
index 0000000..c81ff47
--- /dev/null
+++ b/tools/migration/ctoolchain_comparator_lib_test.py
@@ -0,0 +1,1709 @@
+# Copyright 2018 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+from google.protobuf import text_format
+from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2
+from tools.migration.ctoolchain_comparator_lib import compare_ctoolchains
+
+from py import mock
+try:
+ # Python 2
+ from cStringIO import StringIO
+except ImportError:
+ # Python 3
+ from io import StringIO
+
+
+def make_toolchain(toolchain_proto):
+ toolchain = crosstool_config_pb2.CToolchain()
+ text_format.Merge(toolchain_proto, toolchain)
+ return toolchain
+
+
+class CtoolchainComparatorLibTest(unittest.TestCase):
+
+ def test_string_fields(self):
+ first = make_toolchain("""
+ toolchain_identifier: "first-id"
+ host_system_name: "first-host"
+ target_system_name: "first-target"
+ target_cpu: "first-cpu"
+ target_libc: "first-libc"
+ compiler: "first-compiler"
+ abi_version: "first-abi"
+ abi_libc_version: "first-abi-libc"
+ builtin_sysroot: "sysroot"
+ """)
+ second = make_toolchain("""
+ toolchain_identifier: "second-id"
+ host_system_name: "second-host"
+ target_system_name: "second-target"
+ target_cpu: "second-cpu"
+ target_libc: "second-libc"
+ compiler: "second-compiler"
+ abi_version: "second-abi"
+ abi_libc_version: "second-abi-libc"
+ cc_target_os: "os"
+ """)
+ error_toolchain_identifier = (
+ "Difference in 'toolchain_identifier' field:\n"
+ "Value before change:\t'first-id'\n"
+ "Value after change:\t'second-id'\n")
+ error_host_system_name = ("Difference in 'host_system_name' field:\n"
+ "Value before change:\t'first-host'\n"
+ "Value after change:\t'second-host'\n")
+ error_target_system_name = ("Difference in 'target_system_name' field:\n"
+ "Value before change:\t'first-target'\n"
+ "Value after change:\t'second-target'\n")
+ error_target_cpu = ("Difference in 'target_cpu' field:\n"
+ "Value before change:\t'first-cpu'\n"
+ "Value after change:\t'second-cpu'\n")
+ error_target_libc = ("Difference in 'target_libc' field:\n"
+ "Value before change:\t'first-libc'\n"
+ "Value after change:\t'second-libc'\n")
+ error_compiler = ("Difference in 'compiler' field:\n"
+ "Value before change:\t'first-compiler'\n"
+ "Value after change:\t'second-compiler'\n")
+ error_abi_version = ("Difference in 'abi_version' field:\n"
+ "Value before change:\t'first-abi'\n"
+ "Value after change:\t'second-abi'\n")
+ error_abi_libc_version = ("Difference in 'abi_libc_version' field:\n"
+ "Value before change:\t'first-abi-libc'\n"
+ "Value after change:\t'second-abi-libc'\n")
+ error_builtin_sysroot = ("Difference in 'builtin_sysroot' field:\n"
+ "Value before change is set to 'sysroot'\n"
+ "Value after change is not set\n")
+ error_cc_target_os = ("Difference in 'cc_target_os' field:\n"
+ "Value before change is not set\n"
+ "Value after change is set to 'os'\n")
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn(error_toolchain_identifier, mock_stdout.getvalue())
+ self.assertIn(error_host_system_name, mock_stdout.getvalue())
+ self.assertIn(error_target_system_name, mock_stdout.getvalue())
+ self.assertIn(error_target_cpu, mock_stdout.getvalue())
+ self.assertIn(error_target_libc, mock_stdout.getvalue())
+ self.assertIn(error_compiler, mock_stdout.getvalue())
+ self.assertIn(error_abi_version, mock_stdout.getvalue())
+ self.assertIn(error_abi_libc_version, mock_stdout.getvalue())
+ self.assertIn(error_builtin_sysroot, mock_stdout.getvalue())
+ self.assertIn(error_cc_target_os, mock_stdout.getvalue())
+
+ def test_tool_path(self):
+ first = make_toolchain("""
+ tool_path {
+ name: "only_first"
+ path: "/a/b/c"
+ }
+ tool_path {
+ name: "paths_differ"
+ path: "/path/first"
+ }
+ """)
+ second = make_toolchain("""
+ tool_path {
+ name: "paths_differ"
+ path: "/path/second"
+ }
+ tool_path {
+ name: "only_second_1"
+ path: "/a/b/c"
+ }
+ tool_path {
+ name: "only_second_2"
+ path: "/a/b/c"
+ }
+ """)
+ error_only_first = ("* List before change contains entries for the "
+ "following tools that the list after the change "
+ "doesn't:\n[only_first]\n")
+ error_only_second = ("* List after change contains entries for the "
+ "following tools that the list before the change "
+ "doesn't:\n"
+ "[\n"
+ "\tonly_second_1\n"
+ "\tonly_second_2\n"
+ "]\n")
+ error_paths_differ = ("* Path for tool 'paths_differ' differs before and "
+ "after the change:\n"
+ "Value before change:\t'/path/first'\n"
+ "Value after change:\t'/path/second'\n")
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn(error_only_first, mock_stdout.getvalue())
+ self.assertIn(error_only_second, mock_stdout.getvalue())
+ self.assertIn(error_paths_differ, mock_stdout.getvalue())
+
+ def test_make_variable(self):
+ first = make_toolchain("""
+ make_variable {
+ name: "only_first"
+ value: "val"
+ }
+ make_variable {
+ name: "value_differs"
+ value: "first_value"
+ }
+ """)
+ second = make_toolchain("""
+ make_variable {
+ name: "value_differs"
+ value: "second_value"
+ }
+ make_variable {
+ name: "only_second_1"
+ value: "val"
+ }
+ make_variable {
+ name: "only_second_2"
+ value: "val"
+ }
+ """)
+ error_only_first = ("* List before change contains entries for the "
+ "following variables that the list after the "
+ "change doesn't:\n[only_first]\n")
+ error_only_second = ("* List after change contains entries for the "
+ "following variables that the list before the "
+ "change doesn't:\n"
+ "[\n"
+ "\tonly_second_1\n"
+ "\tonly_second_2\n"
+ "]\n")
+ error_value_differs = ("* Value for variable 'value_differs' differs before"
+ " and after the change:\n"
+ "Value before change:\t'first_value'\n"
+ "Value after change:\t'second_value'\n")
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn(error_only_first, mock_stdout.getvalue())
+ self.assertIn(error_only_second, mock_stdout.getvalue())
+ self.assertIn(error_value_differs, mock_stdout.getvalue())
+
+ def test_cxx_builtin_include_directories(self):
+ first = make_toolchain("""
+ cxx_builtin_include_directory: "a/b/c"
+ cxx_builtin_include_directory: "d/e/f"
+ """)
+ second = make_toolchain("""
+ cxx_builtin_include_directory: "d/e/f"
+ cxx_builtin_include_directory: "a/b/c"
+ """)
+ expect_error = ("Difference in 'cxx_builtin_include_directory' field:\n"
+ "List of elements before change:\n"
+ "[\n"
+ "\ta/b/c\n"
+ "\td/e/f\n"
+ "]\n"
+ "List of elements after change:\n"
+ "[\n"
+ "\td/e/f\n"
+ "\ta/b/c\n"
+ "]\n")
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn(expect_error, mock_stdout.getvalue())
+
+ def test_artifact_name_pattern(self):
+ first = make_toolchain("""
+ artifact_name_pattern {
+ category_name: 'object_file'
+ prefix: ''
+ extension: '.obj1'
+ }
+ artifact_name_pattern {
+ category_name: 'executable'
+ prefix: 'first'
+ extension: '.exe'
+ }
+ artifact_name_pattern {
+ category_name: 'dynamic_library'
+ prefix: ''
+ extension: '.dll'
+ }
+ """)
+ second = make_toolchain("""
+ artifact_name_pattern {
+ category_name: 'object_file'
+ prefix: ''
+ extension: '.obj2'
+ }
+ artifact_name_pattern {
+ category_name: 'static_library'
+ prefix: ''
+ extension: '.lib'
+ }
+ artifact_name_pattern {
+ category_name: 'executable'
+ prefix: 'second'
+ extension: '.exe'
+ }
+ artifact_name_pattern {
+ category_name: 'interface_library'
+ prefix: ''
+ extension: '.if.lib'
+ }
+ """)
+ error_only_first = ("* List before change contains entries for the "
+ "following categories that the list after the "
+ "change doesn't:\n[dynamic_library]\n")
+ error_only_second = ("* List after change contains entries for the "
+ "following categories that the list before the "
+ "change doesn't:\n"
+ "[\n"
+ "\tinterface_library\n"
+ "\tstatic_library\n"
+ "]\n")
+ error_extension_differs = ("* Value for category 'object_file' differs "
+ "before and after the change:\n"
+ "Value before change:"
+ "\tprefix:''"
+ "\textension:'.obj1'\n"
+ "Value after change:"
+ "\tprefix:''"
+ "\textension:'.obj2'\n")
+ error_prefix_differs = ("* Value for category 'executable' differs "
+ "before and after the change:\n"
+ "Value before change:"
+ "\tprefix:'first'"
+ "\textension:'.exe'\n"
+ "Value after change:"
+ "\tprefix:'second'"
+ "\textension:'.exe'\n")
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn(error_only_first, mock_stdout.getvalue())
+ self.assertIn(error_only_second, mock_stdout.getvalue())
+ self.assertIn(error_extension_differs, mock_stdout.getvalue())
+ self.assertIn(error_prefix_differs, mock_stdout.getvalue())
+
+ def test_features_not_ordered(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature1'
+ }
+ feature {
+ name: 'feature2'
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature2'
+ }
+ feature {
+ name: 'feature1'
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("Features not in right order", mock_stdout.getvalue())
+
+ def test_features_missing(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature1'
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature2'
+ }
+ """)
+ error_only_first = ("* List before change contains entries for the "
+ "following features that the list after the "
+ "change doesn't:\n[feature1]\n")
+ error_only_second = ("* List after change contains entries for the "
+ "following features that the list before the "
+ "change doesn't:\n[feature2]\n")
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn(error_only_first, mock_stdout.getvalue())
+ self.assertIn(error_only_second, mock_stdout.getvalue())
+
+ def test_feature_enabled(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ enabled: true
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ enabled: false
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_feature_provides(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ provides: 'a'
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ provides: 'b'
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_feature_provides_preserves_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ provides: 'a'
+ provides: 'b'
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ provides: 'b'
+ provides: 'a'
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_feature_implies(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ implies: 'a'
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_feature_implies_preserves_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ implies: 'a'
+ implies: 'b'
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ implies: 'b'
+ implies: 'a'
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_feature_requires_preserves_list_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ requires: {
+ feature: 'feature1'
+ }
+ requires: {
+ feature: 'feature2'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ requires: {
+ feature: 'feature2'
+ }
+ requires: {
+ feature: 'feature1'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_feature_requires_ignores_required_features_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ requires: {
+ feature: 'feature1'
+ feature: 'feature2'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ requires: {
+ feature: 'feature2'
+ feature: 'feature1'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_feature_requires_differs(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ requires: {
+ feature: 'feature1'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ requires: {
+ feature: 'feature2'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_action_config_ignores_requires(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ requires: {
+ feature: 'feature1'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ requires: {
+ feature: 'feature2'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_env_set_actions_differ(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set {
+ action: 'a1'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set: {
+ action: 'a1'
+ action: 'a2'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_env_set_ignores_actions_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set {
+ action: 'a2'
+ action: 'a1'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set: {
+ action: 'a1'
+ action: 'a2'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_env_set_env_entries_not_ordered(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set {
+ env_entry {
+ key: 'k1'
+ value: 'v1'
+ }
+ env_entry {
+ key: 'k2'
+ value: 'v2'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set {
+ env_entry {
+ key: 'k2'
+ value: 'v2'
+ }
+ env_entry {
+ key: 'k1'
+ value: 'v1'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_env_set_env_entries_differ(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set {
+ env_entry {
+ key: 'k1'
+ value: 'value_first'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set {
+ env_entry {
+ key: 'k1'
+ value: 'value_second'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_feature_preserves_env_set_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set {
+ env_entry {
+ key: 'first'
+ value: 'first'
+ }
+ }
+ env_set {
+ env_entry {
+ key: 'second'
+ value: 'second'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set {
+ env_entry {
+ key: 'second'
+ value: 'second'
+ }
+ }
+ env_set {
+ env_entry {
+ key: 'first'
+ value: 'first'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after the change:",
+ mock_stdout.getvalue())
+
+ def test_action_config_ignores_env_set(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ env_set {
+ env_entry {
+ key: 'k1'
+ value: 'value_first'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ env_set {
+ env_entry {
+ key: 'k1'
+ value: 'value_second'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_env_set_ignores_with_feature_set_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set{
+ with_feature {
+ feature: 'feature1'
+ }
+ with_feature {
+ not_feature: 'feature2'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set {
+ with_feature {
+ not_feature: 'feature2'
+ }
+ with_feature {
+ feature: 'feature1'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_env_set_ignores_with_feature_set_lists_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set{
+ with_feature {
+ feature: 'feature1'
+ feature: 'feature2'
+ not_feature: 'not_feature1'
+ not_feature: 'not_feature2'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ env_set{
+ with_feature {
+ feature: 'feature2'
+ feature: 'feature1'
+ not_feature: 'not_feature2'
+ not_feature: 'not_feature1'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_flag_set_ignores_actions_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set {
+ action: 'a1'
+ action: 'a2'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set {
+ action: 'a2'
+ action: 'a1'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_action_config_flag_set_actions_ignored(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ flag_set {
+ action: 'a1'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ flag_set {
+ action: 'a2'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_flag_set_ignores_with_feature_set_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set {
+ with_feature {
+ feature: 'feature1'
+ }
+ with_feature {
+ not_feature: 'feature2'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set {
+ with_feature {
+ feature: 'feature1'
+ }
+ with_feature {
+ not_feature: 'feature2'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set {
+ with_feature {
+ not_feature: 'feature2'
+ }
+ with_feature {
+ feature: 'feature1'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set {
+ with_feature {
+ not_feature: 'feature2'
+ }
+ with_feature {
+ feature: 'feature1'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_flag_set_ignores_with_feature_set_lists_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ with_feature {
+ feature: 'feature1'
+ feature: 'feature2'
+ not_feature: 'not_feature1'
+ not_feature: 'not_feature2'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ with_feature {
+ feature: 'feature1'
+ feature: 'feature2'
+ not_feature: 'not_feature1'
+ not_feature: 'not_feature2'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ with_feature {
+ feature: 'feature2'
+ feature: 'feature1'
+ not_feature: 'not_feature2'
+ not_feature: 'not_feature1'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ with_feature {
+ feature: 'feature2'
+ feature: 'feature1'
+ not_feature: 'not_feature2'
+ not_feature: 'not_feature1'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_flag_set_preserves_flag_group_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set {
+ flag_group {
+ flag: 'a'
+ }
+ flag_group {
+ flag: 'b'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set {
+ flag_group {
+ flag: 'a'
+ }
+ flag_group {
+ flag: 'b'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set {
+ flag_group {
+ flag: 'b'
+ }
+ flag_group {
+ flag: 'a'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set {
+ flag_group {
+ flag: 'b'
+ }
+ flag_group {
+ flag: 'a'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_flag_group_preserves_flags_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ flag: 'flag1'
+ flag: 'flag2'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ flag: 'flag1'
+ flag: 'flag2'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ flag: 'flag2'
+ flag: 'flag1'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ flag: 'flag2'
+ flag: 'flag1'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_flag_group_iterate_over_differs(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ iterate_over: 'a'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ iterate_over: 'a'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ iterate_over: 'b'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ iterate_over: 'b'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_flag_group_expand_if_true_differs(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_true: 'a'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_true: 'a'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_true: 'b'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_true: 'b'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_flag_group_expand_if_false_differs(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_false: 'a'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_false: 'a'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_false: 'b'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_false: 'b'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_flag_group_expand_if_all_available_differs(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_all_available: 'a'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_all_available: 'a'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_all_available: 'b'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_all_available: 'b'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_flag_group_expand_if_none_available_differs(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_none_available: 'a'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_none_available: 'a'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_none_available: 'b'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_none_available: 'b'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_flag_group_expand_if_all_available_ignores_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_all_available: 'a'
+ expand_if_all_available: 'b'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_all_available: 'a'
+ expand_if_all_available: 'b'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_all_available: 'b'
+ expand_if_all_available: 'a'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_all_available: 'b'
+ expand_if_all_available: 'a'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_flag_group_expand_if_none_available_ignores_order(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_none_available: 'a'
+ expand_if_none_available: 'b'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_none_available: 'a'
+ expand_if_none_available: 'b'
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_none_available: 'b'
+ expand_if_none_available: 'a'
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_none_available: 'b'
+ expand_if_none_available: 'a'
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_flag_group_expand_if_equal_differs(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_equal {
+ variable: 'first'
+ value: 'val'
+ }
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_equal {
+ variable: 'first'
+ value: 'val'
+ }
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ expand_if_equal {
+ variable: 'second'
+ value: 'val'
+ }
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ expand_if_equal {
+ variable: 'second'
+ value: 'val'
+ }
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_flag_group_flag_groups_differ(self):
+ first = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ flag_group {
+ flag: 'a'
+ flag: 'b'
+ }
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ flag_group {
+ flag: 'a'
+ flag: 'b'
+ }
+ }
+ }
+ }
+ """)
+ second = make_toolchain("""
+ feature {
+ name: 'feature'
+ flag_set{
+ flag_group {
+ flag_group {
+ flag: 'b'
+ flag: 'a'
+ }
+ }
+ }
+ }
+ action_config {
+ config_name: 'config'
+ flag_set{
+ flag_group {
+ flag_group {
+ flag: 'b'
+ flag: 'a'
+ }
+ }
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Feature 'feature' differs before and after",
+ mock_stdout.getvalue())
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_action_configs_not_ordered(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'action1'
+ }
+ action_config {
+ config_name: 'action2'
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'action2'
+ }
+ action_config {
+ config_name: 'action1'
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("Action configs not in right order", mock_stdout.getvalue())
+
+ def test_action_configs_missing(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'action1'
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'action2'
+ }
+ """)
+ error_only_first = ("* List before change contains entries for the "
+ "following action_configs that the list after the "
+ "change doesn't:\n[action1]\n")
+ error_only_second = ("* List after change contains entries for the "
+ "following action_configs that the list before the "
+ "change doesn't:\n[action2]\n")
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn(error_only_first, mock_stdout.getvalue())
+ self.assertIn(error_only_second, mock_stdout.getvalue())
+
+ def test_action_config_enabled(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ enabled: true
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ enabled: false
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_action_config_action_name(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ action_name: 'config1'
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ action_name: 'config2'
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_action_config_tool_tool_path_differs(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ tool {
+ tool_path: 'path1'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ tool {
+ tool_path: 'path2'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_action_config_tool_execution_requirements_differ(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ tool {
+ execution_requirement: 'a'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ tool {
+ execution_requirement: 'b'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_action_config_tool_execution_requirements_ignores_order(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ tool {
+ execution_requirement: 'a'
+ execution_requirement: 'b'
+ }
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ tool {
+ execution_requirement: 'b'
+ execution_requirement: 'a'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_action_config_implies_differs(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ implies: 'a'
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ implies: 'b'
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_action_config_implies_preserves_order(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ implies: 'a'
+ implies: 'b'
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ implies: 'b'
+ implies: 'a'
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("* Action config 'config' differs before and after",
+ mock_stdout.getvalue())
+
+ def test_unused_tool_path(self):
+ first = make_toolchain("""
+ tool_path {
+ name: "empty"
+ path: ""
+ }
+ """)
+ second = make_toolchain("""
+ tool_path {
+ name: "empty"
+ path: "NOT_USED"
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+ def test_unused_tool_path_in_tool(self):
+ first = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ tool {
+ tool_path: ''
+ }
+ }
+ """)
+ second = make_toolchain("""
+ action_config {
+ config_name: 'config'
+ tool {
+ tool_path: 'NOT_USED'
+ }
+ }
+ """)
+ mock_stdout = StringIO()
+ with mock.patch("sys.stdout", mock_stdout):
+ compare_ctoolchains(first, second)
+ self.assertIn("No difference", mock_stdout.getvalue())
+
+if __name__ == "__main__":
+ unittest.main()