refactor(tools): Updated tests to corespond with massage changes

This commit is contained in:
Jakub Kocka
2025-08-12 10:55:05 +02:00
parent 7b65c5e0b7
commit 2affbb9509
2 changed files with 73 additions and 49 deletions

View File

@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
import json import json
import logging import logging
@@ -9,28 +9,23 @@ import subprocess
import sys import sys
import textwrap import textwrap
from pathlib import Path from pathlib import Path
from typing import List
import pytest import pytest
from test_build_system_helpers import append_to_file
from test_build_system_helpers import EnvDict from test_build_system_helpers import EnvDict
from test_build_system_helpers import IdfPyFunc
from test_build_system_helpers import append_to_file
from test_build_system_helpers import file_contains from test_build_system_helpers import file_contains
from test_build_system_helpers import find_python from test_build_system_helpers import find_python
from test_build_system_helpers import get_snapshot from test_build_system_helpers import get_snapshot
from test_build_system_helpers import IdfPyFunc
from test_build_system_helpers import replace_in_file from test_build_system_helpers import replace_in_file
from test_build_system_helpers import run_idf_py from test_build_system_helpers import run_idf_py
def get_subdirs_absolute_paths(path: Path) -> List[str]: def get_subdirs_absolute_paths(path: Path) -> list[str]:
""" """
Get a list of files with absolute path in a given `path` folder Get a list of files with absolute path in a given `path` folder
""" """
return [ return [f'{dir_path}/{file_name}' for dir_path, _, file_names in os.walk(path) for file_name in file_names]
'{}/{}'.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')
@@ -51,10 +46,11 @@ def test_hints_no_color_output_when_noninteractive(idf_py: IdfPyFunc) -> None:
"""Check that idf.py hints don't include color escape codes in non-interactive builds""" """Check that idf.py hints don't include color escape codes in non-interactive builds"""
# make the build fail in such a way that idf.py shows a hint # make the build fail in such a way that idf.py shows a hint
replace_in_file('main/build_test_app.c', '// placeholder_inside_main', replace_in_file(
'esp_chip_info_t chip_info; esp_chip_info(&chip_info);') 'main/build_test_app.c', '// placeholder_inside_main', 'esp_chip_info_t chip_info; esp_chip_info(&chip_info);'
)
with (pytest.raises(subprocess.CalledProcessError)) as exc_info: with pytest.raises(subprocess.CalledProcessError) as exc_info:
idf_py('build') idf_py('build')
# Should not actually include a color escape sequence! # Should not actually include a color escape sequence!
@@ -70,10 +66,7 @@ def test_idf_copy(idf_copy: Path, idf_py: IdfPyFunc) -> None:
idf_py('build') idf_py('build')
def test_idf_build_with_env_var_sdkconfig_defaults( def test_idf_build_with_env_var_sdkconfig_defaults(test_app_copy: Path, default_idf_env: EnvDict) -> None:
test_app_copy: Path,
default_idf_env: EnvDict
) -> None:
with open(test_app_copy / 'sdkconfig.test', 'w') as fw: with open(test_app_copy / 'sdkconfig.test', 'w') as fw:
fw.write('CONFIG_BT_ENABLED=y') fw.write('CONFIG_BT_ENABLED=y')
@@ -86,9 +79,7 @@ def test_idf_build_with_env_var_sdkconfig_defaults(
@pytest.mark.usefixtures('test_app_copy') @pytest.mark.usefixtures('test_app_copy')
@pytest.mark.test_app_copy('examples/system/efuse') @pytest.mark.test_app_copy('examples/system/efuse')
def test_efuse_summary_cmake_functions( def test_efuse_summary_cmake_functions(default_idf_env: EnvDict) -> None:
default_idf_env: EnvDict
) -> None:
default_idf_env['IDF_CI_BUILD'] = '1' default_idf_env['IDF_CI_BUILD'] = '1'
output = run_idf_py('efuse-filter', env=default_idf_env) output = run_idf_py('efuse-filter', env=default_idf_env)
assert 'FROM_CMAKE: MAC: 00:00:00:00:00:00' in output.stdout assert 'FROM_CMAKE: MAC: 00:00:00:00:00:00' in output.stdout
@@ -117,16 +108,22 @@ def test_python_interpreter_unix(test_app_copy: Path) -> None:
logging.info("Make sure idf.py never runs '/usr/bin/env python' or similar") logging.info("Make sure idf.py never runs '/usr/bin/env python' or similar")
env_dict = dict(**os.environ) env_dict = dict(**os.environ)
python = find_python(env_dict['PATH']) python = find_python(env_dict['PATH'])
(test_app_copy / 'python').write_text(textwrap.dedent("""#!/bin/sh (test_app_copy / 'python').write_text(
textwrap.dedent(
"""
#!/bin/sh
echo "idf.py has executed '/usr/bin/env python' or similar" echo "idf.py has executed '/usr/bin/env python' or similar"
exit 1 exit 1
""")) """
)
)
st = os.stat(test_app_copy / 'python') st = os.stat(test_app_copy / 'python')
# equivalent to 'chmod +x ./python' # equivalent to 'chmod +x ./python'
os.chmod((test_app_copy / 'python'), st.st_mode | stat.S_IEXEC) os.chmod((test_app_copy / 'python'), st.st_mode | stat.S_IEXEC)
env_dict['PATH'] = str(test_app_copy) + os.pathsep + env_dict['PATH'] 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 # 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 # if idf.py is reconfigured during it's execution, it would load a false interpreter
run_idf_py('reconfigure', env=env_dict, python=python) run_idf_py('reconfigure', env=env_dict, python=python)
@@ -140,7 +137,8 @@ def test_python_interpreter_win(test_app_copy: Path) -> None:
# on windows python interpreter has compiled code '.exe' format, so this false file can be empty # on windows python interpreter has compiled code '.exe' format, so this false file can be empty
(test_app_copy / 'python.exe').write_text('') (test_app_copy / 'python.exe').write_text('')
env_dict['PATH'] = str(test_app_copy) + os.pathsep + env_dict['PATH'] 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 # 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 # if idf.py is reconfigured during it's execution, it would load a false interpreter
run_idf_py('reconfigure', env=env_dict, python=python) run_idf_py('reconfigure', env=env_dict, python=python)
@@ -172,7 +170,7 @@ def test_ccache_used_to_build(test_app_copy: Path) -> None:
def test_toolchain_prefix_in_description_file(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_toolchain_prefix_in_description_file(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('Toolchain prefix is set in project description file') logging.info('Toolchain prefix is set in project description file')
idf_py('reconfigure') idf_py('reconfigure')
data = json.load(open(test_app_copy / 'build' / 'project_description.json', 'r')) data = json.load(open(test_app_copy / 'build' / 'project_description.json'))
assert 'monitor_toolprefix' in data assert 'monitor_toolprefix' in data
@@ -195,8 +193,10 @@ def test_subcommands_with_options(idf_py: IdfPyFunc, default_idf_env: EnvDict) -
def test_fallback_to_build_system_target(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_fallback_to_build_system_target(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('idf.py fallback to build system target') logging.info('idf.py fallback to build system target')
msg = 'Custom target is running' msg = 'Custom target is running'
append_to_file(test_app_copy / 'CMakeLists.txt', append_to_file(
'add_custom_target(custom_target COMMAND ${{CMAKE_COMMAND}} -E echo "{}")'.format(msg)) test_app_copy / 'CMakeLists.txt',
f'add_custom_target(custom_target COMMAND ${{CMAKE_COMMAND}} -E echo "{msg}")',
)
ret = idf_py('custom_target') ret = idf_py('custom_target')
assert msg in ret.stdout, 'Custom target did not produce expected output' assert msg in ret.stdout, 'Custom target did not produce expected output'
@@ -205,10 +205,16 @@ def test_create_component_project(idf_copy: Path) -> None:
logging.info('Create project and component using idf.py and build it') logging.info('Create project and component using idf.py and build it')
run_idf_py('-C', 'projects', 'create-project', 'temp_test_project', workdir=idf_copy) run_idf_py('-C', 'projects', 'create-project', 'temp_test_project', workdir=idf_copy)
run_idf_py('-C', 'components', 'create-component', 'temp_test_component', workdir=idf_copy) run_idf_py('-C', 'components', 'create-component', 'temp_test_component', workdir=idf_copy)
replace_in_file(idf_copy / 'projects' / 'temp_test_project' / 'main' / 'temp_test_project.c', '{\n\n}', replace_in_file(
'\n'.join(['{', '\tfunc();', '}'])) idf_copy / 'projects' / 'temp_test_project' / 'main' / 'temp_test_project.c',
replace_in_file(idf_copy / 'projects' / 'temp_test_project' / 'main' / 'temp_test_project.c', '#include <stdio.h>', '{\n\n}',
'\n'.join(['#include <stdio.h>', '#include "temp_test_component.h"'])) '\n'.join(['{', '\tfunc();', '}']),
)
replace_in_file(
idf_copy / 'projects' / 'temp_test_project' / 'main' / 'temp_test_project.c',
'#include <stdio.h>',
'\n'.join(['#include <stdio.h>', '#include "temp_test_component.h"']),
)
run_idf_py('build', workdir=(idf_copy / 'projects' / 'temp_test_project')) run_idf_py('build', workdir=(idf_copy / 'projects' / 'temp_test_project'))
@@ -244,6 +250,7 @@ def test_create_project_with_idf_readonly(idf_copy: Path) -> None:
if '/bin/' in path: if '/bin/' in path:
continue # skip executables continue # skip executables
os.chmod(os.path.join(root, name), file_permission) os.chmod(os.path.join(root, name), file_permission)
logging.info('Check that command for creating new project will success if the IDF itself is readonly.') logging.info('Check that command for creating new project will success if the IDF itself is readonly.')
change_file_permissions(idf_copy, write_permission=False) change_file_permissions(idf_copy, write_permission=False)
try: try:
@@ -267,7 +274,18 @@ def test_docs_command(idf_py: IdfPyFunc) -> None:
assert 'https://docs.espressif.com/projects/esp-idf/en/v4.2.1' in ret.stdout assert 'https://docs.espressif.com/projects/esp-idf/en/v4.2.1' in ret.stdout
ret = idf_py('docs', '--no-browser', '--language', 'en', '--version', 'v4.2.1', '--target', 'esp32') ret = idf_py('docs', '--no-browser', '--language', 'en', '--version', 'v4.2.1', '--target', 'esp32')
assert 'https://docs.espressif.com/projects/esp-idf/en/v4.2.1/esp32' in ret.stdout assert 'https://docs.espressif.com/projects/esp-idf/en/v4.2.1/esp32' in ret.stdout
ret = idf_py('docs', '--no-browser', '--language', 'en', '--version', 'v4.2.1', '--target', 'esp32', '--starting-page', 'get-started') ret = idf_py(
'docs',
'--no-browser',
'--language',
'en',
'--version',
'v4.2.1',
'--target',
'esp32',
'--starting-page',
'get-started',
)
assert 'https://docs.espressif.com/projects/esp-idf/en/v4.2.1/esp32/get-started' in ret.stdout assert 'https://docs.espressif.com/projects/esp-idf/en/v4.2.1/esp32/get-started' in ret.stdout
@@ -285,25 +303,31 @@ def test_deprecation_warning(idf_py: IdfPyFunc) -> None:
def test_save_defconfig_check(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_save_defconfig_check(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('Save-defconfig checks') logging.info('Save-defconfig checks')
(test_app_copy / 'sdkconfig').write_text('\n'.join(['CONFIG_COMPILER_OPTIMIZATION_SIZE=y', (test_app_copy / 'sdkconfig').write_text(
'CONFIG_ESPTOOLPY_FLASHFREQ_80M=y'])) '\n'.join(['CONFIG_COMPILER_OPTIMIZATION_SIZE=y', 'CONFIG_ESPTOOLPY_FLASHFREQ_80M=y'])
)
idf_py('save-defconfig') idf_py('save-defconfig')
assert not file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_IDF_TARGET'), \ assert not file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_IDF_TARGET'), (
'CONFIG_IDF_TARGET should not be in sdkconfig.defaults' 'CONFIG_IDF_TARGET should not be in sdkconfig.defaults'
assert file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_COMPILER_OPTIMIZATION_SIZE=y'), \ )
assert file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_COMPILER_OPTIMIZATION_SIZE=y'), (
'Missing CONFIG_COMPILER_OPTIMIZATION_SIZE=y in sdkconfig.defaults' 'Missing CONFIG_COMPILER_OPTIMIZATION_SIZE=y in sdkconfig.defaults'
assert file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_ESPTOOLPY_FLASHFREQ_80M=y'), \ )
assert file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_ESPTOOLPY_FLASHFREQ_80M=y'), (
'Missing CONFIG_ESPTOOLPY_FLASHFREQ_80M=y in sdkconfig.defaults' 'Missing CONFIG_ESPTOOLPY_FLASHFREQ_80M=y in sdkconfig.defaults'
)
idf_py('fullclean') idf_py('fullclean')
(test_app_copy / 'sdkconfig').unlink() (test_app_copy / 'sdkconfig').unlink()
(test_app_copy / 'sdkconfig.defaults').unlink() (test_app_copy / 'sdkconfig.defaults').unlink()
idf_py('set-target', 'esp32c3') idf_py('set-target', 'esp32c3')
(test_app_copy / 'sdkconfig').write_text('CONFIG_PARTITION_TABLE_OFFSET=0x8001') (test_app_copy / 'sdkconfig').write_text('CONFIG_PARTITION_TABLE_OFFSET=0x8001')
idf_py('save-defconfig') idf_py('save-defconfig')
assert file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_IDF_TARGET="esp32c3"'), \ assert file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_IDF_TARGET="esp32c3"'), (
'Missing CONFIG_IDF_TARGET="esp32c3" in sdkconfig.defaults' 'Missing CONFIG_IDF_TARGET="esp32c3" in sdkconfig.defaults'
assert file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_PARTITION_TABLE_OFFSET=0x8001'), \ )
assert file_contains(test_app_copy / 'sdkconfig.defaults', 'CONFIG_PARTITION_TABLE_OFFSET=0x8001'), (
'Missing CONFIG_PARTITION_TABLE_OFFSET=0x8001 in sdkconfig.defaults' 'Missing CONFIG_PARTITION_TABLE_OFFSET=0x8001 in sdkconfig.defaults'
)
def test_merge_bin_cmd(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_merge_bin_cmd(idf_py: IdfPyFunc, test_app_copy: Path) -> None:

View File

@@ -204,7 +204,8 @@ class TestDeprecations(TestWithoutExtensions):
[sys.executable, idf_py_path, '-C', current_dir, 'test-2'], env=os.environ, stderr=subprocess.STDOUT [sys.executable, idf_py_path, '-C', current_dir, 'test-2'], env=os.environ, stderr=subprocess.STDOUT
) )
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
self.assertIn('Error: Command "test-2" is deprecated and was removed.', e.output.decode('utf-8', 'ignore')) output = e.output.decode('utf-8', 'ignore').replace('\r\n', '\n')
self.assertIn('Error: Command "test-2" is deprecated and was removed\n', output)
def test_exit_with_error_for_option(self): def test_exit_with_error_for_option(self):
try: try:
@@ -239,7 +240,6 @@ class TestDeprecations(TestWithoutExtensions):
env=os.environ, env=os.environ,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
).decode('utf-8', 'ignore') ).decode('utf-8', 'ignore')
self.assertIn('Warning: Option "test_sub_1" is deprecated and will be removed in future versions.', output) self.assertIn('Warning: Option "test_sub_1" is deprecated and will be removed in future versions.', output)
self.assertIn( self.assertIn(
'Warning: Command "test-1" is deprecated and will be removed in future versions. ' 'Warning: Command "test-1" is deprecated and will be removed in future versions. '
@@ -374,8 +374,8 @@ class TestWrapperCommands(TestCase):
class TestEFuseCommands(TestWrapperCommands): class TestEFuseCommands(TestWrapperCommands):
""" """
Test if wrapper commands for espefuse.py are working as expected. Test if wrapper commands for espefuse.py are working as expected.
The goal is NOT to test the functionality of espefuse.py, but to test if the wrapper commands The goal is NOT to test the functionality of espefuse.py
are working as expected. but to test if the wrapper commands are working as expected.
""" """
def test_efuse_summary(self): def test_efuse_summary(self):
@@ -438,8 +438,8 @@ class TestEFuseCommands(TestWrapperCommands):
class TestSecureCommands(TestWrapperCommands): class TestSecureCommands(TestWrapperCommands):
""" """
Test if wrapper commands for espsecure.py are working as expected. Test if wrapper commands for espsecure.py are working as expected.
The goal is NOT to test the functionality of espsecure.py, but to test if the wrapper commands are The goal is NOT to test the functionality of espsecure.py
working as expected. but to test if the wrapper commands are working as expected.
""" """
@classmethod @classmethod
@@ -577,8 +577,8 @@ class TestSecureCommands(TestWrapperCommands):
class TestMergeBinCommands(TestWrapperCommands): class TestMergeBinCommands(TestWrapperCommands):
""" """
Test if merge-bin command is invoked as expected. Test if merge-bin command is invoked as expected.
This test is not testing the functionality of esptool.py merge_bin command, but the invocation of This test is not testing the functionality of esptool.py merge_bin command
the command from idf.py. but the invocation of the command from idf.py.
""" """
def test_merge_bin(self): def test_merge_bin(self):