Browse Source

Tools: Rewrite build system unit tests to python - cmake libraries and Kconfig

Marek Fiala 3 years ago
parent
commit
b4446e1748

+ 14 - 12
tools/test_build_system/MIGRATION.md

@@ -47,20 +47,22 @@ Can guess target from sdkconfig, if CMakeCache does not exist | test_non_default
 Can set the default target using sdkconfig.defaults | test_non_default_target.py::test_target_using_sdkconfig |
 IDF_TARGET takes precedence over the value of CONFIG_IDF_TARGET in sdkconfig.defaults | test_non_default_target.py::test_target_precedence |
 idf.py fails if IDF_TARGET settings don't match in sdkconfig, CMakeCache.txt, and the environment | test_non_default_target.py::test_target_from_environment_idf_py |
-Setting EXTRA_COMPONENT_DIRS works | |
-Non-existent paths in EXTRA_COMPONENT_DIRS are not allowed | |
-Component names may contain spaces | |
+Setting EXTRA_COMPONENT_DIRS works | test_components.py::test_component_extra_dirs |
+Non-existent paths in EXTRA_COMPONENT_DIRS are not allowed | test_components.py::test_component_nonexistent_extra_dirs_not_allowed |
+Component names may contain spaces | test_components.py::test_component_names_contain_spaces |
 sdkconfig should have contents of all files: sdkconfig, sdkconfig.defaults, sdkconfig.defaults.IDF_TARGET | |
 Test if it can build the example to run on host | |
-Test build ESP-IDF as a library to a custom CMake projects for all targets | |
-Building a project with CMake library imported and PSRAM workaround, all files compile with workaround | |
-Test for external libraries in custom CMake projects with ESP-IDF components linked | |
-Test for external libraries in custom CMake projects with PSRAM strategy $strat | |
-Cleaning Python bytecode | |
-Displays partition table when executing target partition_table | |
-Make sure a full build never runs '/usr/bin/env python' or similar | |
-Handling deprecated Kconfig options | |
-Handling deprecated Kconfig options in sdkconfig.defaults | |
+Test build ESP-IDF as a library to a custom CMake projects for all targets | test_cmake.py::test_build_custom_cmake_project |
+Building a project with CMake library imported and PSRAM workaround, all files compile with workaround | test_cmake.py::test_build_cmake_library_psram_workaround |
+Test for external libraries in custom CMake projects with ESP-IDF components linked | test_cmake.py::test_build_custom_cmake_project |
+Test for external libraries in custom CMake projects with PSRAM strategy $strat | test_cmake.py::test_build_cmake_library_psram_strategies |
+Cleaning Python bytecode | test_common.py::test_python_clean |
+Displays partition table when executing target partition_table | test_common.py::test_partition_table |
+Make sure a full build never runs '/usr/bin/env python' or similar | test_common.py::test_python_interpreter_unix, test_common.py::test_python_interpreter_win |
+Handling deprecated Kconfig options | test_kconfig.py::test_kconfig_deprecated_options |
+Handling deprecated Kconfig options in sdkconfig.defaults | test_kconfig.py::test_kconfig_deprecated_options |
+Can have multiple deprecated Kconfig options map to a single new option | test_kconfig.py::test_kconfig_multiple_and_target_specific_options |
+Can have target specific deprecated Kconfig options | test_kconfig.py::test_kconfig_multiple_and_target_specific_options |
 Confserver can be invoked by idf.py | |
 Check ccache is used to build | |
 Custom bootloader overrides original | |

+ 4 - 15
tools/test_build_system/test_build.py

@@ -5,23 +5,12 @@ import logging
 import os
 import sys
 import textwrap
-import typing
 from pathlib import Path
 from typing import List, Union
 
 import pytest
-from test_build_system_helpers import (APP_BINS, BOOTLOADER_BINS, PARTITION_BIN, EnvDict, IdfPyFunc, append_to_file,
-                                       check_file_contains, get_idf_build_env, replace_in_file, run_cmake)
-
-
-def run_cmake_and_build(*cmake_args: str, env: typing.Optional[EnvDict] = None) -> None:
-    """
-    Run cmake command with given arguments and build afterwards, raise an exception on failure
-    :param cmake_args: arguments to pass cmake
-    :param env: environment variables to run the cmake with; if not set, the default environment is used
-    """
-    run_cmake(*cmake_args, env=env)
-    run_cmake('--build', '.')
+from test_build_system_helpers import (APP_BINS, BOOTLOADER_BINS, PARTITION_BIN, IdfPyFunc, append_to_file,
+                                       file_contains, get_idf_build_env, replace_in_file, run_cmake_and_build)
 
 
 def assert_built(paths: Union[List[str], List[Path]]) -> None:
@@ -65,7 +54,7 @@ def test_build_with_generator_ninja(idf_py: IdfPyFunc) -> None:
     idf_py('-G', 'Ninja', 'build')
     cmake_cache_file = Path('build', 'CMakeCache.txt')
     assert_built([cmake_cache_file])
-    check_file_contains(cmake_cache_file, 'CMAKE_GENERATOR:INTERNAL=Ninja')
+    assert file_contains(cmake_cache_file, 'CMAKE_GENERATOR:INTERNAL=Ninja')
     assert_built(BOOTLOADER_BINS + APP_BINS + PARTITION_BIN)
 
 
@@ -76,7 +65,7 @@ def test_build_with_generator_makefile(idf_py: IdfPyFunc) -> None:
     idf_py('-G', 'Unix Makefiles', 'build')
     cmake_cache_file = Path('build', 'CMakeCache.txt')
     assert_built([cmake_cache_file])
-    check_file_contains(cmake_cache_file, 'CMAKE_GENERATOR:INTERNAL=Unix Makefiles')
+    assert file_contains(cmake_cache_file, 'CMAKE_GENERATOR:INTERNAL=Unix Makefiles')
     assert_built(BOOTLOADER_BINS + APP_BINS + PARTITION_BIN)
 
 

+ 4 - 2
tools/test_build_system/test_build_system_helpers/__init__.py

@@ -2,12 +2,14 @@
 # SPDX-License-Identifier: Apache-2.0
 from .build_constants import ALL_ARTIFACTS, APP_BINS, BOOTLOADER_BINS, JSON_METADATA, PARTITION_BIN
 from .editing import append_to_file, replace_in_file
-from .idf_utils import EXT_IDF_PATH, EnvDict, IdfPyFunc, check_file_contains, get_idf_build_env, run_cmake, run_idf_py
+from .idf_utils import (EXT_IDF_PATH, EnvDict, IdfPyFunc, file_contains, find_python, get_idf_build_env, run_cmake,
+                        run_cmake_and_build, run_idf_py)
 from .snapshot import Snapshot, get_snapshot
 
 __all__ = [
     'append_to_file', 'replace_in_file',
     'get_idf_build_env', 'run_idf_py', 'EXT_IDF_PATH', 'EnvDict', 'IdfPyFunc',
     'Snapshot', 'get_snapshot', 'run_cmake', 'APP_BINS', 'BOOTLOADER_BINS',
-    'PARTITION_BIN', 'JSON_METADATA', 'ALL_ARTIFACTS', 'check_file_contains'
+    'PARTITION_BIN', 'JSON_METADATA', 'ALL_ARTIFACTS',
+    'run_cmake_and_build', 'find_python', 'file_contains'
 ]

+ 23 - 6
tools/test_build_system/test_build_system_helpers/idf_utils.py

@@ -60,7 +60,8 @@ def run_idf_py(*args: str,
                env: typing.Optional[EnvDict] = None,
                idf_path: typing.Optional[typing.Union[str,Path]] = None,
                workdir: typing.Optional[str] = None,
-               check: bool = True) -> subprocess.CompletedProcess:
+               check: bool = True,
+               python: typing.Optional[str] = None) -> subprocess.CompletedProcess:
     """
     Run idf.py command with given arguments, raise an exception on failure
     :param args: arguments to pass to idf.py
@@ -68,6 +69,7 @@ def run_idf_py(*args: str,
     :param idf_path: path to the IDF copy to use; if not set, IDF_PATH from the 'env' argument is used
     :param workdir: directory where to run the build; if not set, the current directory is used
     :param check: check process exits with a zero exit code, if false all retvals are accepted without failing the test
+    :param python: absolute path to python interpreter
     """
     env_dict = dict(**os.environ)
     if env is not None:
@@ -79,8 +81,8 @@ def run_idf_py(*args: str,
         idf_path = env_dict.get('IDF_PATH')
         if not idf_path:
             raise ValueError('IDF_PATH must be set in the env array if idf_path argument is not set')
-
-    python = find_python(env_dict['PATH'])
+    if python is None:
+        python = find_python(env_dict['PATH'])
 
     cmd = [
         python,
@@ -115,10 +117,25 @@ def run_cmake(*cmake_args: str, env: typing.Optional[EnvDict] = None,
         text=True, encoding='utf-8', errors='backslashreplace')
 
 
-def check_file_contains(filename: Union[str, Path], what: Union[str, Pattern]) -> None:
+def run_cmake_and_build(*cmake_args: str, env: typing.Optional[EnvDict] = None) -> None:
+    """
+    Run cmake command with given arguments and build afterwards, raise an exception on failure
+    :param cmake_args: arguments to pass cmake
+    :param env: environment variables to run the cmake with; if not set, the default environment is used
+    """
+    run_cmake(*cmake_args, env=env)
+    run_cmake('--build', '.')
+
+
+def file_contains(filename: Union[str, Path], what: Union[str, Pattern]) -> bool:
+    """
+    Returns true if file contains required object
+    :param filename: path to file where lookup is executed
+    :param what: searched substring or regex object
+    """
     with open(filename, 'r', encoding='utf-8') as f:
         data = f.read()
         if isinstance(what, str):
-            assert what in data
+            return what in data
         else:
-            assert re.search(what, data) is not None
+            return re.search(what, data) is not None

+ 49 - 0
tools/test_build_system/test_cmake.py

@@ -0,0 +1,49 @@
+# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: Apache-2.0
+import logging
+import os
+import re
+import shutil
+from pathlib import Path
+
+from test_build_system_helpers import IdfPyFunc, file_contains, run_cmake, run_cmake_and_build
+
+
+def test_build_custom_cmake_project(test_app_copy: Path) -> None:
+    for target in ['esp32', 'esp32s3', 'esp32c6', 'esp32h4']:
+        logging.info(f'Test build ESP-IDF as a library to a custom CMake projects for {target}')
+        idf_path = Path(os.environ['IDF_PATH'])
+        run_cmake_and_build(str(idf_path / 'examples' / 'build_system' / 'cmake' / 'idf_as_lib'),
+                            '-DCMAKE_TOOLCHAIN_FILE={}'.format(idf_path / 'tools' / 'cmake' / f'toolchain-{target}.cmake'), f'-DTARGET={target}')
+        assert file_contains((test_app_copy / 'build' / 'compile_commands.json'), '"command"')
+        shutil.rmtree(test_app_copy / 'build')
+
+
+def test_build_cmake_library_psram_workaround(test_app_copy: Path) -> None:
+    logging.info('Building a project with CMake library imported and PSRAM workaround, all files compile with workaround')
+    idf_path = Path(os.environ['IDF_PATH'])
+    (test_app_copy / 'sdkconfig.defaults').write_text('\n'.join(['CONFIG_SPIRAM=y',
+                                                                 'CONFIG_SPIRAM_CACHE_WORKAROUND=y']))
+    run_cmake('-G', 'Ninja', '-DSDKCONFIG_DEFAULTS={}'.format(test_app_copy / 'sdkconfig.defaults'),
+              str(idf_path / 'examples' / 'build_system' / 'cmake' / 'import_lib'))
+    with open((test_app_copy / 'build' / 'compile_commands.json'), 'r', encoding='utf-8') as f:
+        data = f.read()
+        res = re.findall(r'.*\"command\".*', data)
+        for r in res:
+            assert 'mfix-esp32-psram-cache-issue' in r, 'All commands in compile_commands.json should use PSRAM cache workaround'
+
+
+def test_build_cmake_library_psram_strategies(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
+    for strategy in ['DUPLDST', 'NOPS', 'MEMW']:
+        logging.info(f'Test for external libraries in custom CMake projects with PSRAM strategy {strategy}')
+        (test_app_copy / 'sdkconfig.defaults').write_text('\n'.join(['CONFIG_SPIRAM=y',
+                                                                    f'CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_{strategy}=y',
+                                                                     'CONFIG_SPIRAM_CACHE_WORKAROUND=y']))
+        idf_py('reconfigure')
+        with open((test_app_copy / 'build' / 'compile_commands.json'), 'r', encoding='utf-8') as f:
+            data = f.read()
+            res = re.findall(r'.*\"command\".*', data)
+            for r in res:
+                assert f'mfix-esp32-psram-cache-strategy={strategy.lower()}' in r, ('All commands in compile_commands.json '
+                                                                                    'should use PSRAM cache workaround strategy')
+        (test_app_copy / 'sdkconfig').unlink()

+ 71 - 1
tools/test_build_system/test_common.py

@@ -1,12 +1,30 @@
 # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
 # SPDX-License-Identifier: Apache-2.0
+import logging
+import os
+import re
 import shutil
+import stat
 import subprocess
+import sys
+import textwrap
 from pathlib import Path
+from typing import List
 
 import pytest
 from _pytest.monkeypatch import MonkeyPatch
-from test_build_system_helpers import IdfPyFunc, get_snapshot, replace_in_file
+from test_build_system_helpers import IdfPyFunc, find_python, get_snapshot, replace_in_file, run_idf_py
+
+
+def get_subdirs_absolute_paths(path: Path) -> List[str]:
+    """
+    Get a list of files with absolute path in a given `path` folder
+    """
+    return [
+        '{}/{}'.format(dir_path, file_name)
+        for dir_path, _, file_names in os.walk(path)
+        for file_name in file_names
+    ]
 
 
 @pytest.mark.usefixtures('test_app_copy')
@@ -88,3 +106,55 @@ def test_efuse_symmary_cmake_functions(
 def test_custom_build_folder(test_app_copy: Path, idf_py: IdfPyFunc) -> None:
     idf_py('-BBuiLDdiR', 'build')
     assert (test_app_copy / 'BuiLDdiR').is_dir()
+
+
+def test_python_clean(idf_py: IdfPyFunc) -> None:
+    logging.info('Cleaning Python bytecode')
+    idf_path = Path(os.environ['IDF_PATH'])
+    abs_paths = get_subdirs_absolute_paths(idf_path)
+    abs_paths_suffix = [path for path in abs_paths if path.endswith(('.pyc', '.pyo'))]
+    assert len(abs_paths_suffix) != 0
+    idf_py('python-clean')
+    abs_paths = get_subdirs_absolute_paths(idf_path)
+    abs_paths_suffix = [path for path in abs_paths if path.endswith(('.pyc', '.pyo'))]
+    assert len(abs_paths_suffix) == 0
+
+
+@pytest.mark.usefixtures('test_app_copy')
+def test_partition_table(idf_py: IdfPyFunc) -> None:
+    logging.info('Displays partition table when executing target partition_table')
+    output = idf_py('partition-table')
+    assert re.search('# ESP-IDF.+Partition Table', output.stdout)
+
+
+@pytest.mark.skipif(sys.platform == 'win32', reason='Windows does not support executing bash script')
+def test_python_interpreter_unix(test_app_copy: Path) -> None:
+    logging.info("Make sure idf.py never runs '/usr/bin/env python' or similar")
+    env_dict = dict(**os.environ)
+    python = find_python(env_dict['PATH'])
+    (test_app_copy / 'python').write_text(textwrap.dedent("""#!/bin/sh
+                                                          echo "idf.py has executed '/usr/bin/env python' or similar"
+                                                          exit 1
+                                                          """))
+    st = os.stat(test_app_copy / 'python')
+    # equivalent to 'chmod +x ./python'
+    os.chmod((test_app_copy / 'python'), st.st_mode | stat.S_IEXEC)
+
+    env_dict['PATH'] = str(test_app_copy) + os.pathsep + env_dict['PATH']
+    # python is loaded from env:$PATH, but since false interpreter is provided there, python needs to be specified as argument
+    # if idf.py is reconfigured during it's execution, it would load a false interpreter
+    run_idf_py('reconfigure', env=env_dict, python=python)
+
+
+@pytest.mark.skipif(sys.platform != 'win32', reason='Linux does not support executing .exe files')
+def test_python_interpreter_win(test_app_copy: Path) -> None:
+    logging.info('Make sure idf.py never runs false python interpreter')
+    env_dict = dict(**os.environ)
+    python = find_python(env_dict['PATH'])
+
+    # on windows python interpreter has compiled code '.exe' format, so this false file can be empty
+    (test_app_copy / 'python.exe').write_text('')
+    env_dict['PATH'] = str(test_app_copy) + os.pathsep + env_dict['PATH']
+    # python is loaded from env:$PATH, but since false interpreter is provided there, python needs to be specified as argument
+    # if idf.py is reconfigured during it's execution, it would load a false interpreter
+    run_idf_py('reconfigure', env=env_dict, python=python)

+ 32 - 0
tools/test_build_system/test_components.py

@@ -0,0 +1,32 @@
+# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: Apache-2.0
+
+import logging
+import shutil
+from pathlib import Path
+
+import pytest
+from test_build_system_helpers import IdfPyFunc, replace_in_file
+
+
+def test_component_extra_dirs(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
+    logging.info('Setting EXTRA_COMPONENT_DIRS works')
+    shutil.move(test_app_copy / 'main', test_app_copy / 'different_main' / 'main')
+    replace_in_file((test_app_copy / 'CMakeLists.txt'), '# placeholder_before_include_project_cmake',
+                    'set(EXTRA_COMPONENT_DIRS {})'.format(Path('different_main', 'main')))
+    ret = idf_py('reconfigure')
+    assert str(test_app_copy / 'different_main' / 'main') in ret.stdout
+    assert str(test_app_copy / 'main') not in ret.stdout
+
+
+@pytest.mark.usefixtures('test_app_copy')
+def test_component_nonexistent_extra_dirs_not_allowed(idf_py: IdfPyFunc) -> None:
+    ret = idf_py('reconfigure', '-DEXTRA_COMPONENT_DIRS="nonexistent_dir"', check=False)
+    assert ret.returncode != 0
+
+
+def test_component_names_contain_spaces(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
+    logging.info('Component names may contain spaces')
+    (test_app_copy / 'extra component').mkdir()
+    (test_app_copy / 'extra component' / 'CMakeLists.txt').write_text('idf_component_register')
+    idf_py('-DEXTRA_COMPONENT_DIRS="extra component;main"')

+ 126 - 0
tools/test_build_system/test_kconfig.py

@@ -0,0 +1,126 @@
+# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: Apache-2.0
+import logging
+import os
+import shutil
+import textwrap
+from contextlib import contextmanager
+from pathlib import Path
+from typing import Iterator
+
+import pytest
+from test_build_system_helpers import IdfPyFunc, append_to_file, file_contains
+
+
+@contextmanager
+def backup_required_files(test_app_copy: Path) -> Iterator[None]:
+    idf_path = Path(os.environ['IDF_PATH'])
+
+    sdk_rename_backup = (idf_path / 'sdkconfig.rename').read_text()
+    kconfig_backup = (idf_path / 'Kconfig').read_text()
+    try:
+        yield
+    finally:
+        (idf_path / 'sdkconfig.rename').write_text(sdk_rename_backup)
+        (idf_path / 'Kconfig').write_text(kconfig_backup)
+        shutil.rmtree(test_app_copy / 'build', ignore_errors=True)
+        if (test_app_copy / 'sdkconfig').exists():
+            (test_app_copy / 'sdkconfig').unlink()
+
+
+# For this and the following test function, there are actually two logical
+# tests in one test function. It would be better to have every check in a separate
+# test case, but that would mean doing idf_copy each time, and copying takes most of the time
+@pytest.mark.usefixtures('idf_copy')
+def test_kconfig_deprecated_options(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
+    idf_path = Path(os.environ['IDF_PATH'])
+
+    with backup_required_files(test_app_copy):
+        logging.info('Handling deprecated Kconfig options')
+        (idf_path / 'sdkconfig.rename').write_text('')
+        idf_py('reconfigure')
+        append_to_file((test_app_copy / 'sdkconfig'), 'CONFIG_TEST_OLD_OPTION=y')
+        (idf_path / 'sdkconfig.rename').write_text('CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION')
+        append_to_file((idf_path / 'Kconfig'), textwrap.dedent("""
+                                                               menu "test"
+                                                                   config TEST_NEW_OPTION
+                                                                       bool "test"
+                                                                       default "n"
+                                                                       help
+                                                                           TEST_NEW_OPTION description
+                                                               endmenu
+                                                               """))
+        idf_py('reconfigure')
+        assert all([file_contains((test_app_copy / 'sdkconfig'), x) for x in ['CONFIG_TEST_OLD_OPTION=y',
+                                                                              'CONFIG_TEST_NEW_OPTION=y']])
+        assert all([file_contains((test_app_copy / 'build' / 'config' / 'sdkconfig.h'), x) for x in ['#define CONFIG_TEST_NEW_OPTION 1',
+                                                                                                     '#define CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION']])
+        assert all([file_contains((test_app_copy / 'build' / 'config' / 'sdkconfig.cmake'), x) for x in ['set(CONFIG_TEST_OLD_OPTION "y")',
+                                                                                                         'set(CONFIG_TEST_NEW_OPTION "y")']])
+
+    logging.info('Handling deprecated Kconfig options in sdkconfig.defaults')
+    (test_app_copy / 'sdkconfig.defaults').write_text('CONFIG_TEST_OLD_OPTION=7')
+    (idf_path / 'sdkconfig.rename').write_text('CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION')
+    append_to_file((idf_path / 'Kconfig'), textwrap.dedent("""
+                                                           menu "test"
+                                                               config TEST_NEW_OPTION
+                                                                   int "TEST_NEW_OPTION"
+                                                                   range 0 10
+                                                                   default 5
+                                                                   help
+                                                                       TEST_NEW_OPTION description
+                                                           endmenu
+                                                           """))
+    idf_py('reconfigure')
+    assert all([file_contains((test_app_copy / 'sdkconfig'), x) for x in ['CONFIG_TEST_OLD_OPTION=7',
+                                                                          'CONFIG_TEST_NEW_OPTION=7']])
+
+
+@pytest.mark.usefixtures('idf_copy')
+def test_kconfig_multiple_and_target_specific_options(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
+    idf_path = Path(os.environ['IDF_PATH'])
+
+    with backup_required_files(test_app_copy):
+        logging.info('Can have multiple deprecated Kconfig options map to a single new option')
+        (idf_path / 'sdkconfig.rename').write_text('')
+        idf_py('reconfigure')
+        append_to_file((test_app_copy / 'sdkconfig'), 'CONFIG_TEST_NEW_OPTION=y')
+        append_to_file((idf_path / 'sdkconfig.rename'), '\n'.join(['CONFIG_TEST_OLD_OPTION_1 CONFIG_TEST_NEW_OPTION',
+                                                                   'CONFIG_TEST_OLD_OPTION_2 CONFIG_TEST_NEW_OPTION']))
+        append_to_file((idf_path / 'Kconfig'), textwrap.dedent("""
+                                                               menu "test"
+                                                               config TEST_NEW_OPTION
+                                                                   bool "test"
+                                                                   default "n"
+                                                                   help
+                                                                       TEST_NEW_OPTION description
+                                                               endmenu
+                                                               """))
+        idf_py('reconfigure')
+        assert all([file_contains((test_app_copy / 'sdkconfig'), x) for x in ['CONFIG_TEST_OLD_OPTION_1=y',
+                                                                              'CONFIG_TEST_OLD_OPTION_2=y']])
+        assert all([file_contains((test_app_copy / 'build' / 'config' / 'sdkconfig.h'), x) for x in ['#define CONFIG_TEST_OLD_OPTION_1 CONFIG_TEST_NEW_OPTION',
+                                                                                                     '#define CONFIG_TEST_OLD_OPTION_2 CONFIG_TEST_NEW_OPTION'
+                                                                                                     ]])
+        assert all([file_contains((test_app_copy / 'build' / 'config' / 'sdkconfig.cmake'), x) for x in ['set(CONFIG_TEST_OLD_OPTION_1 "y")',
+                                                                                                         'set(CONFIG_TEST_OLD_OPTION_2 "y")']])
+
+    logging.info('Can have target specific deprecated Kconfig options')
+    (test_app_copy / 'sdkconfig').write_text('CONFIG_TEST_OLD_OPTION=y')
+    append_to_file((idf_path / 'components' / 'esp_system' / 'sdkconfig.rename.esp32s2'), 'CONFIG_TEST_OLD_OPTION CONFIG_TEST_NEW_OPTION')
+    append_to_file((idf_path / 'Kconfig'), textwrap.dedent("""
+                                                           menu "test"
+                                                           config TEST_NEW_OPTION
+                                                               bool "TEST_NEW_OPTION"
+                                                               default y
+                                                               help
+                                                                   TEST_NEW_OPTION description
+                                                           endmenu
+                                                           """))
+    idf_py('set-target', 'esp32')
+    assert not file_contains((test_app_copy / 'sdkconfig'), 'CONFIG_TEST_OLD_OPTION=y')
+    assert file_contains((test_app_copy / 'sdkconfig'), 'CONFIG_TEST_NEW_OPTION=y')
+    (test_app_copy / 'sdkconfig').unlink()
+    idf_py('set-target', 'esp32s2')
+    assert all([file_contains((test_app_copy / 'sdkconfig'), x) for x in ['CONFIG_TEST_NEW_OPTION=y',
+                                                                          'CONFIG_TEST_OLD_OPTION=y']])

+ 26 - 26
tools/test_build_system/test_non_default_target.py

@@ -7,7 +7,7 @@ from pathlib import Path
 from typing import List, Optional
 
 import pytest
-from test_build_system_helpers import EnvDict, IdfPyFunc, check_file_contains, run_cmake
+from test_build_system_helpers import EnvDict, IdfPyFunc, file_contains, run_cmake
 
 ESP32C3_TARGET = 'esp32c3'
 ESP32C2_TARGET = 'esp32c2'
@@ -27,8 +27,8 @@ def test_target_from_environment_cmake(default_idf_env: EnvDict) -> None:
     env = default_idf_env
     env.update({'IDF_TARGET': ESP32S2_TARGET})
     run_cmake('-G', 'Ninja', '..', env=env)
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
 
 
 def test_target_from_environment_idf_py(idf_py: IdfPyFunc, default_idf_env: EnvDict, test_app_copy: Path) -> None:
@@ -113,52 +113,52 @@ def test_target_precedence(idf_py: IdfPyFunc, default_idf_env: EnvDict, test_app
     (test_app_copy / 'sdkconfig.defaults').write_text('CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
     default_idf_env.update({'IDF_TARGET': ESP32_TARGET})
     idf_py('reconfigure')
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32_TARGET))
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET_{}=y'.format(ESP32_TARGET.upper()))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET_{}=y'.format(ESP32_TARGET.upper()))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32_TARGET))
 
 
 def test_target_using_D_parameter(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
     logging.info('Can set target using idf.py -D')
     idf_py('-DIDF_TARGET={}'.format(ESP32S2_TARGET), 'reconfigure')
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
 
     logging.info('Can set target using -D as subcommand parameter for idf.py')
     clean_app(test_app_copy)
     idf_py('reconfigure', '-DIDF_TARGET={}'.format(ESP32S2_TARGET))
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
 
 
 @pytest.mark.usefixtures('test_app_copy')
 def test_target_using_settarget_parameter_alternative_name(idf_py: IdfPyFunc) -> None:
     logging.info('idf.py understands alternative target names')
     idf_py('set-target', ESP32S2_TARGET.upper())
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
 
 
 @pytest.mark.usefixtures('test_app_copy')
 def test_target_using_settarget_parameter(idf_py: IdfPyFunc) -> None:
     logging.info('Can set target using idf.py set-target')
     idf_py('set-target', ESP32S2_TARGET)
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
 
     logging.info('Can guess target from sdkconfig, if CMakeCache does not exist')
     idf_py('fullclean')
     idf_py('reconfigure')
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
 
 
 def test_target_using_sdkconfig(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
     logging.info('Can set the default target using sdkconfig.defaults')
     (test_app_copy / 'sdkconfig.defaults').write_text('CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
     idf_py('reconfigure')
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET_{}=y'.format(ESP32S2_TARGET.upper()))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET_{}=y'.format(ESP32S2_TARGET.upper()))
 
 
 def test_target_guessing(idf_py: IdfPyFunc, test_app_copy: Path, default_idf_env: EnvDict) -> None:
@@ -171,8 +171,8 @@ def test_target_guessing(idf_py: IdfPyFunc, test_app_copy: Path, default_idf_env
     logging.info('Can guess target from sdkconfig.defaults')
     (test_app_copy / 'sdkconfig.defaults').write_text('CONFIG_IDF_TARGET="{}"'.format(ESP32_TARGET))
     idf_py('reconfigure')
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32_TARGET))
 
     logging.info('Can guess target from SDKCONFIG_DEFAULTS environment variable')
     (test_app_copy / 'sdkconfig1').write_text('NOTHING HERE')
@@ -180,20 +180,20 @@ def test_target_guessing(idf_py: IdfPyFunc, test_app_copy: Path, default_idf_env
     clean_app(test_app_copy)
     default_idf_env.update({'SDKCONFIG_DEFAULTS': 'sdkconfig1;sdkconfig2'})
     idf_py('reconfigure')
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S2_TARGET))
 
     logging.info('Can guess target from SDKCONFIG_DEFAULTS using -D')
     (test_app_copy / 'sdkconfig3').write_text('CONFIG_IDF_TARGET="{}"'.format(ESP32S2_TARGET))
     (test_app_copy / 'sdkconfig4').write_text('CONFIG_IDF_TARGET="{}"'.format(ESP32S3_TARGET))
     clean_app(test_app_copy)
     idf_py('-D', 'SDKCONFIG_DEFAULTS=sdkconfig4;sdkconfig3', 'reconfigure')
-    check_file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S3_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S3_TARGET))
+    assert file_contains('sdkconfig', 'CONFIG_IDF_TARGET="{}"'.format(ESP32S3_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32S3_TARGET))
 
     logging.info('Can guess target from custom sdkconfig')
     (test_app_copy / 'sdkconfig5').write_text('CONFIG_IDF_TARGET="{}"'.format(ESP32C3_TARGET))
     clean_app(test_app_copy)
     idf_py('-D', 'SDKCONFIG=sdkconfig5', '-D', 'SDKCONFIG_DEFAULTS=sdkconfig4;sdkconfig3', 'reconfigure')
-    check_file_contains('sdkconfig5', 'CONFIG_IDF_TARGET="{}"'.format(ESP32C3_TARGET))
-    check_file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32C3_TARGET))
+    assert file_contains('sdkconfig5', 'CONFIG_IDF_TARGET="{}"'.format(ESP32C3_TARGET))
+    assert file_contains('build/CMakeCache.txt', 'IDF_TARGET:STRING={}'.format(ESP32C3_TARGET))