| # Copyright 2025 The Pigweed Authors |
| # |
| # 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 |
| # |
| # https://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. |
| """Tests for cmake_converter_common.py.""" |
| |
| from pathlib import Path |
| from typing import Any |
| import unittest |
| |
| import cmake_converter_common as common |
| |
| |
| class CmakeConverterCommonTest(unittest.TestCase): |
| """Tests for cmake_converter_common.py.""" |
| |
| def test_translate_relative_path(self): |
| output = common.translate_relative_path( |
| Path('/a/b/c'), Path('/a'), Path('/x') |
| ) |
| self.assertEqual(output, Path('/x/b/c')) |
| |
| with self.assertRaises(ValueError) as e: |
| common.translate_relative_path( |
| Path('/xxx/b/c'), Path('/a'), Path('/x') |
| ) |
| self.assertEqual(str(e.exception), '/xxx/b/c is not inside /a') |
| |
| def test_parse_if_block_ast_node_simple_condition(self): |
| def recursive_callback( |
| ast: list[dict[str, Any]], |
| target_name: str, |
| ) -> list[str]: |
| return [f"""cc_library( |
| name = "{target_name}", |
| )"""] |
| |
| node = { |
| 'type': 'if_block', |
| 'branches': [ |
| { |
| 'condition': 'CONFIG_FEATURE', |
| 'body': [], |
| }, |
| ], |
| 'else_body': None, |
| } |
| |
| rules, deps_selects = common.parse_if_block_ast_node( |
| node, 'target', recursive_callback |
| ) |
| self.assertEqual(len(rules), 1) |
| self.assertEqual( |
| deps_selects, |
| '\n'.join([ |
| ' + select({', |
| ( |
| ' "@zephyr_kconfig//:CONFIG_FEATURE=true":' |
| ' [":target_config_feature_deps"],' |
| ), |
| ' "//conditions:default": [],', |
| ' })', |
| ]), |
| ) |
| |
| def test_parse_if_block_ast_node_not_condition(self): |
| def recursive_callback( |
| ast: list[dict[str, Any]], |
| target_name: str, |
| ) -> list[str]: |
| return [f"""cc_library( |
| name = "{target_name}", |
| )"""] |
| |
| node = { |
| 'type': 'if_block', |
| 'branches': [ |
| { |
| 'condition': 'NOT CONFIG_FEATURE', |
| 'body': [ |
| { |
| 'type': 'unconditional_source', |
| 'srcs': ['no_feature.c'], |
| }, |
| ], |
| }, |
| ], |
| 'else_body': None, |
| } |
| |
| rules, deps_selects = common.parse_if_block_ast_node( |
| node, 'target', recursive_callback |
| ) |
| self.assertEqual(len(rules), 1) |
| self.assertEqual( |
| deps_selects, |
| '\n'.join([ |
| ' + select({', |
| ( |
| ' "//conditions:default":' |
| ' [":target_not_config_feature_deps"],' |
| ), |
| ' "@zephyr_kconfig//:CONFIG_FEATURE=true": [],', |
| ' })', |
| ]), |
| ) |
| |
| def test_parse_if_block_ast_node_or_condition(self): |
| def recursive_callback( |
| ast: list[dict[str, Any]], |
| target_name: str, |
| ) -> list[str]: |
| return [f"""cc_library( |
| name = "{target_name}", |
| )"""] |
| |
| node = { |
| 'type': 'if_block', |
| 'branches': [ |
| { |
| 'condition': 'CONFIG_A OR CONFIG_B', |
| 'body': [ |
| {'type': 'unconditional_source', 'srcs': ['feature.c']}, |
| ], |
| }, |
| ], |
| 'else_body': None, |
| } |
| |
| rules, deps_selects = common.parse_if_block_ast_node( |
| node, 'target', recursive_callback |
| ) |
| self.assertEqual( |
| rules, |
| [ |
| """selects.config_setting_group( |
| name = "config_a_or_config_b", |
| match_any = ['@zephyr_kconfig//:CONFIG_A=true', '@zephyr_kconfig//:CONFIG_B=true'], |
| )""", |
| """cc_library( |
| name = "target_config_a_or_config_b_deps", |
| )""", |
| ], |
| ) |
| self.assertEqual( |
| deps_selects, |
| '\n'.join([ |
| ' + select({', |
| ( |
| ' ":config_a_or_config_b":' |
| ' [":target_config_a_or_config_b_deps"],' |
| ), |
| ' "//conditions:default": [],', |
| ' })', |
| ]), |
| ) |
| |
| def test_parse_if_block_ast_node_and_condition(self): |
| def recursive_callback( |
| ast: list[dict[str, Any]], |
| target_name: str, |
| ) -> list[str]: |
| return [f"""cc_library( |
| name = "{target_name}", |
| )"""] |
| |
| node = { |
| 'type': 'if_block', |
| 'branches': [ |
| { |
| 'condition': 'CONFIG_A AND CONFIG_B', |
| 'body': [ |
| {'type': 'unconditional_source', 'srcs': ['feature.c']}, |
| ], |
| }, |
| ], |
| 'else_body': None, |
| } |
| |
| rules, deps_selects = common.parse_if_block_ast_node( |
| node, 'target', recursive_callback |
| ) |
| self.assertEqual( |
| rules, |
| [ |
| """selects.config_setting_group( |
| name = "config_a_and_config_b", |
| match_all = ['@zephyr_kconfig//:CONFIG_A=true', '@zephyr_kconfig//:CONFIG_B=true'], |
| )""", |
| """cc_library( |
| name = "target_config_a_and_config_b_deps", |
| )""", |
| ], |
| ) |
| self.assertEqual( |
| deps_selects, |
| '\n'.join([ |
| ' + select({', |
| ( |
| ' ":config_a_and_config_b":' |
| ' [":target_config_a_and_config_b_deps"],' |
| ), |
| ' "//conditions:default": [],', |
| ' })', |
| ]), |
| ) |
| |
| def test_parse_if_block_ast_node_or_not_condition(self): |
| def recursive_callback( |
| ast: list[dict[str, Any]], |
| target_name: str, |
| ) -> list[str]: |
| return [f"""cc_library( |
| name = "{target_name}", |
| )"""] |
| |
| node = { |
| 'type': 'if_block', |
| 'branches': [ |
| { |
| 'condition': 'CONFIG_A OR NOT CONFIG_B', |
| 'body': [], |
| }, |
| ], |
| 'else_body': None, |
| } |
| |
| rules, deps_selects = common.parse_if_block_ast_node( |
| node, 'target', recursive_callback |
| ) |
| self.assertEqual( |
| rules, |
| [ |
| """config_setting( |
| name = "not_config_b", |
| flag_values = { |
| "@zephyr_kconfig//:CONFIG_B": "false", |
| }, |
| )""", |
| """selects.config_setting_group( |
| name = "config_a_or_not_config_b", |
| match_any = ['@zephyr_kconfig//:CONFIG_A=true', ':not_config_b'], |
| )""", |
| """cc_library( |
| name = "target_config_a_or_not_config_b_deps", |
| )""", |
| ], |
| ) |
| self.assertEqual( |
| deps_selects, |
| '\n'.join([ |
| ' + select({', |
| ( |
| ' ":config_a_or_not_config_b":' |
| ' [":target_config_a_or_not_config_b_deps"],' |
| ), |
| ' "//conditions:default": [],', |
| ' })', |
| ]), |
| ) |
| |
| def test_parse_if_block_ast_node_and_not_condition(self): |
| def recursive_callback( |
| ast: list[dict[str, Any]], |
| target_name: str, |
| ) -> list[str]: |
| return [f"""cc_library( |
| name = "{target_name}", |
| )"""] |
| |
| node = { |
| 'type': 'if_block', |
| 'branches': [ |
| { |
| 'condition': 'CONFIG_A AND NOT CONFIG_B', |
| 'body': [], |
| }, |
| ], |
| 'else_body': None, |
| } |
| |
| rules, deps_selects = common.parse_if_block_ast_node( |
| node, 'target', recursive_callback |
| ) |
| self.assertEqual( |
| rules, |
| [ |
| """config_setting( |
| name = "not_config_b", |
| flag_values = { |
| "@zephyr_kconfig//:CONFIG_B": "false", |
| }, |
| )""", |
| """selects.config_setting_group( |
| name = "config_a_and_not_config_b", |
| match_all = ['@zephyr_kconfig//:CONFIG_A=true', ':not_config_b'], |
| )""", |
| """cc_library( |
| name = "target_config_a_and_not_config_b_deps", |
| )""", |
| ], |
| ) |
| self.assertEqual( |
| deps_selects, |
| '\n'.join([ |
| ' + select({', |
| ( |
| ' ":config_a_and_not_config_b":' |
| ' [":target_config_a_and_not_config_b_deps"],' |
| ), |
| ' "//conditions:default": [],', |
| ' })', |
| ]), |
| ) |
| |
| def test_process_zephyr_cmake_functions_uart_native(self): |
| output = common._process_zephyr_cmake_functions( |
| 'zephyr_library_sources(uart_native_pty.c)' |
| ) |
| self.assertEqual( |
| output, |
| { |
| 'type': 'unconditional_source', |
| 'srcs': ['uart_native_pty.c', 'uart_native_pty_bottom.c'], |
| }, |
| ) |
| |
| output = common._process_zephyr_cmake_functions( |
| 'zephyr_library_sources_ifdef(CONFIG_UART_NATIVE_TTY uart_native_tty.c)' |
| ) |
| self.assertEqual( |
| output, |
| { |
| 'type': 'conditional_source', |
| 'config': 'CONFIG_UART_NATIVE_TTY', |
| 'srcs': ['uart_native_tty.c', 'uart_native_tty_bottom.c'], |
| }, |
| ) |
| |
| def test_traverse_ast_uart_native(self): |
| def update_rules_fn( |
| rules: list[str], |
| target_name: str, |
| srcs_content: str, |
| unconditional_deps: list[str], |
| deps_selects: list[str], |
| is_root: bool, |
| ) -> list[str]: |
| rules.append(f"srcs_content: {srcs_content}") |
| return rules |
| |
| ast = [{'type': 'unconditional_source', 'srcs': ['uart_native_pty.c']}] |
| |
| rules = common.traverse_ast(ast, 'uart_native_pty', update_rules_fn) |
| self.assertEqual(len(rules), 1) |
| self.assertIn('defines = ["_POSIX_C_SOURCE=200809L"]', rules[0]) |
| |
| if __name__ == '__main__': |
| unittest.main() |