diff --git a/tools/test_build_system/MIGRATION.md b/tools/test_build_system/MIGRATION.md index 26f3a8d45b..3fbb5a1760 100644 --- a/tools/test_build_system/MIGRATION.md +++ b/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 | | diff --git a/tools/test_build_system/test_build.py b/tools/test_build_system/test_build.py index f9e0f3758a..104e0d34f8 100644 --- a/tools/test_build_system/test_build.py +++ b/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) diff --git a/tools/test_build_system/test_build_system_helpers/__init__.py b/tools/test_build_system/test_build_system_helpers/__init__.py index b5ee5fbe3c..e8f8794167 100644 --- a/tools/test_build_system/test_build_system_helpers/__init__.py +++ b/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' ] diff --git a/tools/test_build_system/test_build_system_helpers/idf_utils.py b/tools/test_build_system/test_build_system_helpers/idf_utils.py index 7578c17ee0..201c5a899c 100644 --- a/tools/test_build_system/test_build_system_helpers/idf_utils.py +++ b/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 diff --git a/tools/test_build_system/test_cmake.py b/tools/test_build_system/test_cmake.py new file mode 100644 index 0000000000..d7af9500c1 --- /dev/null +++ b/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() diff --git a/tools/test_build_system/test_common.py b/tools/test_build_system/test_common.py index 88454ae852..e2ac7ff32c 100644 --- a/tools/test_build_system/test_common.py +++ b/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) diff --git a/tools/test_build_system/test_components.py b/tools/test_build_system/test_components.py new file mode 100644 index 0000000000..06856735d5 --- /dev/null +++ b/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"') diff --git a/tools/test_build_system/test_kconfig.py b/tools/test_build_system/test_kconfig.py new file mode 100644 index 0000000000..ddcdba2132 --- /dev/null +++ b/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']]) diff --git a/tools/test_build_system/test_non_default_target.py b/tools/test_build_system/test_non_default_target.py index 2655c65f20..0760cac91f 100644 --- a/tools/test_build_system/test_non_default_target.py +++ b/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,44 +113,44 @@ 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, default_idf_env: EnvDict) -> 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)) logging.info('Can set target if IDF_TARGET env is set and old sdkconfig exists') default_idf_env.update({'IDF_TARGET': ESP32_TARGET}) @@ -163,8 +163,8 @@ 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: @@ -177,8 +177,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') @@ -186,20 +186,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))