Merge branch 'feature/rewrite_build_sys_tests_v3' into 'master'

Rewrite build system unit tests to python v3

Closes IDF-6842

See merge request espressif/esp-idf!22280
This commit is contained in:
Roland Dobai
2023-04-06 15:21:32 +08:00
9 changed files with 349 additions and 62 deletions

View File

@@ -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 | 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_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 | 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 | | Setting EXTRA_COMPONENT_DIRS works | test_components.py::test_component_extra_dirs |
Non-existent paths in EXTRA_COMPONENT_DIRS are not allowed | | 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 | | 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 | | 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 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 | | 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 | | 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 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 for external libraries in custom CMake projects with PSRAM strategy $strat | test_cmake.py::test_build_cmake_library_psram_strategies |
Cleaning Python bytecode | | Cleaning Python bytecode | test_common.py::test_python_clean |
Displays partition table when executing target partition_table | | 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 | | 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 | | Handling deprecated Kconfig options | test_kconfig.py::test_kconfig_deprecated_options |
Handling deprecated Kconfig options in sdkconfig.defaults | | 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 | | Confserver can be invoked by idf.py | |
Check ccache is used to build | | Check ccache is used to build | |
Custom bootloader overrides original | | Custom bootloader overrides original | |

View File

@@ -5,23 +5,12 @@ import logging
import os import os
import sys import sys
import textwrap import textwrap
import typing
from pathlib import Path from pathlib import Path
from typing import List, Union from typing import List, Union
import pytest import pytest
from test_build_system_helpers import (APP_BINS, BOOTLOADER_BINS, PARTITION_BIN, EnvDict, IdfPyFunc, append_to_file, from test_build_system_helpers import (APP_BINS, BOOTLOADER_BINS, PARTITION_BIN, IdfPyFunc, append_to_file,
check_file_contains, get_idf_build_env, replace_in_file, run_cmake) file_contains, get_idf_build_env, replace_in_file, run_cmake_and_build)
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 assert_built(paths: Union[List[str], List[Path]]) -> None: 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') idf_py('-G', 'Ninja', 'build')
cmake_cache_file = Path('build', 'CMakeCache.txt') cmake_cache_file = Path('build', 'CMakeCache.txt')
assert_built([cmake_cache_file]) 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) 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') idf_py('-G', 'Unix Makefiles', 'build')
cmake_cache_file = Path('build', 'CMakeCache.txt') cmake_cache_file = Path('build', 'CMakeCache.txt')
assert_built([cmake_cache_file]) 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) assert_built(BOOTLOADER_BINS + APP_BINS + PARTITION_BIN)

View File

@@ -2,12 +2,14 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
from .build_constants import ALL_ARTIFACTS, APP_BINS, BOOTLOADER_BINS, JSON_METADATA, PARTITION_BIN from .build_constants import ALL_ARTIFACTS, APP_BINS, BOOTLOADER_BINS, JSON_METADATA, PARTITION_BIN
from .editing import append_to_file, replace_in_file 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 from .snapshot import Snapshot, get_snapshot
__all__ = [ __all__ = [
'append_to_file', 'replace_in_file', 'append_to_file', 'replace_in_file',
'get_idf_build_env', 'run_idf_py', 'EXT_IDF_PATH', 'EnvDict', 'IdfPyFunc', 'get_idf_build_env', 'run_idf_py', 'EXT_IDF_PATH', 'EnvDict', 'IdfPyFunc',
'Snapshot', 'get_snapshot', 'run_cmake', 'APP_BINS', 'BOOTLOADER_BINS', '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'
] ]

View File

@@ -60,7 +60,8 @@ def run_idf_py(*args: str,
env: typing.Optional[EnvDict] = None, env: typing.Optional[EnvDict] = None,
idf_path: typing.Optional[typing.Union[str,Path]] = None, idf_path: typing.Optional[typing.Union[str,Path]] = None,
workdir: typing.Optional[str] = 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 Run idf.py command with given arguments, raise an exception on failure
:param args: arguments to pass to idf.py :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 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 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 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) env_dict = dict(**os.environ)
if env is not None: if env is not None:
@@ -79,8 +81,8 @@ def run_idf_py(*args: str,
idf_path = env_dict.get('IDF_PATH') idf_path = env_dict.get('IDF_PATH')
if not idf_path: if not idf_path:
raise ValueError('IDF_PATH must be set in the env array if idf_path argument is not set') raise ValueError('IDF_PATH must be set in the env array if idf_path argument is not set')
if python is None:
python = find_python(env_dict['PATH']) python = find_python(env_dict['PATH'])
cmd = [ cmd = [
python, python,
@@ -115,10 +117,25 @@ def run_cmake(*cmake_args: str, env: typing.Optional[EnvDict] = None,
text=True, encoding='utf-8', errors='backslashreplace') 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: with open(filename, 'r', encoding='utf-8') as f:
data = f.read() data = f.read()
if isinstance(what, str): if isinstance(what, str):
assert what in data return what in data
else: else:
assert re.search(what, data) is not None return re.search(what, data) is not None

View File

@@ -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()

View File

@@ -1,12 +1,30 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
import logging
import os
import re
import shutil import shutil
import stat
import subprocess import subprocess
import sys
import textwrap
from pathlib import Path from pathlib import Path
from typing import List
import pytest import pytest
from _pytest.monkeypatch import MonkeyPatch 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') @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: def test_custom_build_folder(test_app_copy: Path, idf_py: IdfPyFunc) -> None:
idf_py('-BBuiLDdiR', 'build') idf_py('-BBuiLDdiR', 'build')
assert (test_app_copy / 'BuiLDdiR').is_dir() 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)

View File

@@ -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"')

View File

@@ -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']])

View File

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