change(tools): Fix pre-commit checks for test_components.py

This commit is contained in:
Roland Dobai
2025-08-22 12:20:28 +02:00
parent 7cf02797d9
commit c3729929a8

View File

@@ -1,16 +1,16 @@
# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2023-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
import os import os
import shutil import shutil
from collections.abc import Generator
from pathlib import Path from pathlib import Path
from typing import Generator
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 IdfPyFunc
from test_build_system_helpers import append_to_file
from test_build_system_helpers import replace_in_file from test_build_system_helpers import replace_in_file
@@ -42,8 +42,11 @@ def create_idf_components(request: pytest.FixtureRequest) -> Generator:
def test_component_extra_dirs(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_component_extra_dirs(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('Setting EXTRA_COMPONENT_DIRS works') logging.info('Setting EXTRA_COMPONENT_DIRS works')
shutil.move(test_app_copy / 'main', test_app_copy / 'different_main' / 'main') 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', replace_in_file(
'set(EXTRA_COMPONENT_DIRS {})'.format(Path('different_main', 'main').as_posix())) (test_app_copy / 'CMakeLists.txt'),
'# placeholder_before_include_project_cmake',
'set(EXTRA_COMPONENT_DIRS {})'.format(Path('different_main', 'main').as_posix()),
)
ret = idf_py('reconfigure') ret = idf_py('reconfigure')
assert str((test_app_copy / 'different_main' / 'main').as_posix()) in ret.stdout assert str((test_app_copy / 'different_main' / 'main').as_posix()) in ret.stdout
assert str((test_app_copy / 'main').as_posix()) not in ret.stdout assert str((test_app_copy / 'main').as_posix()) not in ret.stdout
@@ -64,10 +67,10 @@ def test_component_names_contain_spaces(idf_py: IdfPyFunc, test_app_copy: Path)
def test_component_can_not_be_empty_dir(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_component_can_not_be_empty_dir(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('Empty directory not treated as a component') logging.info('Empty directory not treated as a component')
empty_component_dir = (test_app_copy / 'components' / 'esp32') empty_component_dir = test_app_copy / 'components' / 'esp32'
empty_component_dir.mkdir(parents=True) empty_component_dir.mkdir(parents=True)
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 str(empty_component_dir) not in data.get('build_component_paths') assert str(empty_component_dir) not in data.get('build_component_paths')
@@ -76,14 +79,14 @@ def test_component_subdirs_not_added_to_component_dirs(idf_py: IdfPyFunc, test_a
(test_app_copy / 'main' / 'test').mkdir(parents=True) (test_app_copy / 'main' / 'test').mkdir(parents=True)
(test_app_copy / 'main' / 'test' / 'CMakeLists.txt').write_text('idf_component_register()') (test_app_copy / 'main' / 'test' / 'CMakeLists.txt').write_text('idf_component_register()')
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 str((test_app_copy / 'main' / 'test').as_posix()) not in data.get('build_component_paths') assert str((test_app_copy / 'main' / 'test').as_posix()) not in data.get('build_component_paths')
assert str((test_app_copy / 'main').as_posix()) in data.get('build_component_paths') assert str((test_app_copy / 'main').as_posix()) in data.get('build_component_paths')
def test_component_sibling_dirs_not_added_to_component_dirs(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_component_sibling_dirs_not_added_to_component_dirs(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('If a component directory is added to COMPONENT_DIRS, its sibling directories are not added') logging.info('If a component directory is added to COMPONENT_DIRS, its sibling directories are not added')
mycomponents_subdir = (test_app_copy / 'mycomponents') mycomponents_subdir = test_app_copy / 'mycomponents'
(mycomponents_subdir / 'mycomponent').mkdir(parents=True) (mycomponents_subdir / 'mycomponent').mkdir(parents=True)
(mycomponents_subdir / 'mycomponent' / 'CMakeLists.txt').write_text('idf_component_register()') (mycomponents_subdir / 'mycomponent' / 'CMakeLists.txt').write_text('idf_component_register()')
@@ -91,7 +94,7 @@ def test_component_sibling_dirs_not_added_to_component_dirs(idf_py: IdfPyFunc, t
(mycomponents_subdir / 'esp32').mkdir(parents=True) (mycomponents_subdir / 'esp32').mkdir(parents=True)
(mycomponents_subdir / 'esp32' / 'CMakeLists.txt').write_text('idf_component_register()') (mycomponents_subdir / 'esp32' / 'CMakeLists.txt').write_text('idf_component_register()')
idf_py('-DEXTRA_COMPONENT_DIRS={}'.format(str(mycomponents_subdir / 'mycomponent')), 'reconfigure') idf_py('-DEXTRA_COMPONENT_DIRS={}'.format(str(mycomponents_subdir / 'mycomponent')), '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 str((mycomponents_subdir / 'esp32').as_posix()) not in data.get('build_component_paths') assert str((mycomponents_subdir / 'esp32').as_posix()) not in data.get('build_component_paths')
assert str((mycomponents_subdir / 'mycomponent').as_posix()) in data.get('build_component_paths') assert str((mycomponents_subdir / 'mycomponent').as_posix()) in data.get('build_component_paths')
shutil.rmtree(mycomponents_subdir / 'esp32') shutil.rmtree(mycomponents_subdir / 'esp32')
@@ -99,74 +102,95 @@ def test_component_sibling_dirs_not_added_to_component_dirs(idf_py: IdfPyFunc, t
# now the same thing, but add a components directory # now the same thing, but add a components directory
(test_app_copy / 'esp32').mkdir() (test_app_copy / 'esp32').mkdir()
(test_app_copy / 'esp32' / 'CMakeLists.txt').write_text('idf_component_register()') (test_app_copy / 'esp32' / 'CMakeLists.txt').write_text('idf_component_register()')
idf_py('-DEXTRA_COMPONENT_DIRS={}'.format(str(mycomponents_subdir)), 'reconfigure') idf_py(f'-DEXTRA_COMPONENT_DIRS={str(mycomponents_subdir)}', '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 str((test_app_copy / 'esp32').as_posix()) not in data.get('build_component_paths') assert str((test_app_copy / 'esp32').as_posix()) not in data.get('build_component_paths')
assert str((mycomponents_subdir / 'mycomponent').as_posix()) in data.get('build_component_paths') assert str((mycomponents_subdir / 'mycomponent').as_posix()) in data.get('build_component_paths')
def test_component_properties_are_set(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_component_properties_are_set(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('Component properties are set') logging.info('Component properties are set')
append_to_file(test_app_copy / 'CMakeLists.txt', '\n'.join(['', append_to_file(
'idf_component_get_property(srcs main SRCS)', test_app_copy / 'CMakeLists.txt',
'message(STATUS SRCS:${srcs})'])) '\n'.join(['', 'idf_component_get_property(srcs main SRCS)', 'message(STATUS SRCS:${srcs})']),
)
ret = idf_py('reconfigure') ret = idf_py('reconfigure')
assert 'SRCS:{}'.format((test_app_copy / 'main' / 'build_test_app.c').as_posix()) in ret.stdout, 'Component properties should be set' assert 'SRCS:{}'.format((test_app_copy / 'main' / 'build_test_app.c').as_posix()) in ret.stdout, (
'Component properties should be set'
)
def test_get_property_for_unknown_component(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_get_property_for_unknown_component(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('Getting property of unknown component fails gracefully') logging.info('Getting property of unknown component fails gracefully')
append_to_file(test_app_copy / 'CMakeLists.txt', '\n'.join(['', append_to_file(test_app_copy / 'CMakeLists.txt', '\n'.join(['', 'idf_component_get_property(VAR UNKNOWN PROP)']))
'idf_component_get_property(VAR UNKNOWN PROP)']))
ret = idf_py('reconfigure', check=False) ret = idf_py('reconfigure', check=False)
assert "Failed to resolve component 'UNKNOWN'" in ret.stderr, ('idf_component_get_property ' assert "Failed to resolve component 'UNKNOWN'" in ret.stderr, (
'for unknown component should fail gracefully') 'idf_component_get_property for unknown component should fail gracefully'
)
def test_set_property_for_unknown_component(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_set_property_for_unknown_component(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('Setting property of unknown component fails gracefully') logging.info('Setting property of unknown component fails gracefully')
append_to_file(test_app_copy / 'CMakeLists.txt', '\n'.join(['', append_to_file(test_app_copy / 'CMakeLists.txt', '\n'.join(['', 'idf_component_set_property(UNKNOWN PROP VAL)']))
'idf_component_set_property(UNKNOWN PROP VAL)']))
ret = idf_py('reconfigure', check=False) ret = idf_py('reconfigure', check=False)
assert "Failed to resolve component 'UNKNOWN'" in ret.stderr, ('idf_component_set_property ' assert "Failed to resolve component 'UNKNOWN'" in ret.stderr, (
'for unknown component should fail gracefully') 'idf_component_set_property for unknown component should fail gracefully'
)
def test_component_overridden_dir(idf_py: IdfPyFunc, test_app_copy: Path, default_idf_env: EnvDict) -> None: def test_component_overridden_dir(idf_py: IdfPyFunc, test_app_copy: Path, default_idf_env: EnvDict) -> None:
logging.info('Getting component overridden dir') logging.info('Getting component overridden dir')
(test_app_copy / 'components' / 'hal').mkdir(parents=True) (test_app_copy / 'components' / 'hal').mkdir(parents=True)
(test_app_copy / 'components' / 'hal' / 'CMakeLists.txt').write_text('\n'.join([ (test_app_copy / 'components' / 'hal' / 'CMakeLists.txt').write_text(
'idf_component_get_property(overridden_dir ${COMPONENT_NAME} COMPONENT_OVERRIDEN_DIR)', '\n'.join(
'message(STATUS overridden_dir:${overridden_dir})', 'idf_component_register()'])) [
'idf_component_get_property(overridden_dir ${COMPONENT_NAME} COMPONENT_OVERRIDEN_DIR)',
'message(STATUS overridden_dir:${overridden_dir})',
'idf_component_register()',
]
)
)
ret = idf_py('reconfigure') ret = idf_py('reconfigure')
idf_path = Path(default_idf_env.get('IDF_PATH')) idf_path = Path(default_idf_env.get('IDF_PATH'))
# no registration, overrides registration as well # no registration, overrides registration as well
assert 'overridden_dir:{}'.format((idf_path / 'components' / 'hal').as_posix()) in ret.stdout, 'Failed to get overridden dir' assert 'overridden_dir:{}'.format((idf_path / 'components' / 'hal').as_posix()) in ret.stdout, (
append_to_file((test_app_copy / 'components' / 'hal' / 'CMakeLists.txt'), '\n'.join([ 'Failed to get overridden dir'
'', )
'idf_component_register(KCONFIG ${overridden_dir}/Kconfig)', append_to_file(
'idf_component_get_property(kconfig ${COMPONENT_NAME} KCONFIG)', (test_app_copy / 'components' / 'hal' / 'CMakeLists.txt'),
'message(STATUS kconfig:${overridden_dir}/Kconfig)'])) '\n'.join(
[
'',
'idf_component_register(KCONFIG ${overridden_dir}/Kconfig)',
'idf_component_get_property(kconfig ${COMPONENT_NAME} KCONFIG)',
'message(STATUS kconfig:${overridden_dir}/Kconfig)',
]
),
)
ret = idf_py('reconfigure', check=False) ret = idf_py('reconfigure', check=False)
assert 'kconfig:{}'.format((idf_path / 'components' / 'hal').as_posix()) in ret.stdout, 'Failed to verify original `main` directory' assert 'kconfig:{}'.format((idf_path / 'components' / 'hal').as_posix()) in ret.stdout, (
'Failed to verify original `main` directory'
)
def test_project_components_overrides_extra_components(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_project_components_overrides_extra_components(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('Project components override components defined in EXTRA_COMPONENT_DIRS') logging.info('Project components override components defined in EXTRA_COMPONENT_DIRS')
(test_app_copy / 'extra_dir' / 'my_component').mkdir(parents=True) (test_app_copy / 'extra_dir' / 'my_component').mkdir(parents=True)
(test_app_copy / 'extra_dir' / 'my_component' / 'CMakeLists.txt').write_text('idf_component_register()') (test_app_copy / 'extra_dir' / 'my_component' / 'CMakeLists.txt').write_text('idf_component_register()')
replace_in_file(test_app_copy / 'CMakeLists.txt', replace_in_file(
'# placeholder_before_include_project_cmake', test_app_copy / 'CMakeLists.txt',
'set(EXTRA_COMPONENT_DIRS extra_dir)') '# placeholder_before_include_project_cmake',
'set(EXTRA_COMPONENT_DIRS extra_dir)',
)
idf_py('reconfigure') idf_py('reconfigure')
with open(test_app_copy / 'build' / 'project_description.json', 'r') as f: with open(test_app_copy / 'build' / 'project_description.json') as f:
data = json.load(f) data = json.load(f)
assert str((test_app_copy / 'extra_dir' / 'my_component').as_posix()) in data.get('build_component_paths') assert str((test_app_copy / 'extra_dir' / 'my_component').as_posix()) in data.get('build_component_paths')
(test_app_copy / 'components' / 'my_component').mkdir(parents=True) (test_app_copy / 'components' / 'my_component').mkdir(parents=True)
(test_app_copy / 'components' / 'my_component' / 'CMakeLists.txt').write_text('idf_component_register()') (test_app_copy / 'components' / 'my_component' / 'CMakeLists.txt').write_text('idf_component_register()')
idf_py('reconfigure') idf_py('reconfigure')
with open(test_app_copy / 'build' / 'project_description.json', 'r') as f: with open(test_app_copy / 'build' / 'project_description.json') as f:
data = json.load(f) data = json.load(f)
assert str((test_app_copy / 'components' / 'my_component').as_posix()) in data.get('build_component_paths') assert str((test_app_copy / 'components' / 'my_component').as_posix()) in data.get('build_component_paths')
assert str((test_app_copy / 'extra_dir' / 'my_component').as_posix()) not in data.get('build_component_paths') assert str((test_app_copy / 'extra_dir' / 'my_component').as_posix()) not in data.get('build_component_paths')
@@ -179,22 +203,24 @@ def test_extra_components_overrides_managed_components(idf_py: IdfPyFunc, test_a
example/cmp: "*" example/cmp: "*"
""") """)
idf_py('reconfigure') idf_py('reconfigure')
with open(test_app_copy / 'build' / 'project_description.json', 'r') as f: with open(test_app_copy / 'build' / 'project_description.json') as f:
data = json.load(f) data = json.load(f)
assert str((test_app_copy / 'managed_components' / 'example__cmp').as_posix()) in data.get( assert str((test_app_copy / 'managed_components' / 'example__cmp').as_posix()) in data.get('build_component_paths')
'build_component_paths')
(test_app_copy / 'extra_dir' / 'cmp').mkdir(parents=True) (test_app_copy / 'extra_dir' / 'cmp').mkdir(parents=True)
(test_app_copy / 'extra_dir' / 'cmp' / 'CMakeLists.txt').write_text('idf_component_register()') (test_app_copy / 'extra_dir' / 'cmp' / 'CMakeLists.txt').write_text('idf_component_register()')
replace_in_file(test_app_copy / 'CMakeLists.txt', replace_in_file(
'# placeholder_before_include_project_cmake', test_app_copy / 'CMakeLists.txt',
'set(EXTRA_COMPONENT_DIRS extra_dir)') '# placeholder_before_include_project_cmake',
'set(EXTRA_COMPONENT_DIRS extra_dir)',
)
idf_py('reconfigure') idf_py('reconfigure')
with open(test_app_copy / 'build' / 'project_description.json', 'r') as f: with open(test_app_copy / 'build' / 'project_description.json') as f:
data = json.load(f) data = json.load(f)
assert str((test_app_copy / 'extra_dir' / 'cmp').as_posix()) in data.get('build_component_paths') assert str((test_app_copy / 'extra_dir' / 'cmp').as_posix()) in data.get('build_component_paths')
assert str((test_app_copy / 'managed_components' / 'example__cmp').as_posix()) not in data.get( assert str((test_app_copy / 'managed_components' / 'example__cmp').as_posix()) not in data.get(
'build_component_paths') 'build_component_paths'
)
@pytest.mark.with_idf_components(['cmp']) @pytest.mark.with_idf_components(['cmp'])
@@ -203,32 +229,31 @@ def test_managed_components_overrides_idf_components(idf_py: IdfPyFunc, test_app
# created idf component 'cmp' in marker # created idf component 'cmp' in marker
idf_path = Path(os.environ['IDF_PATH']) idf_path = Path(os.environ['IDF_PATH'])
idf_py('reconfigure') idf_py('reconfigure')
with open(test_app_copy / 'build' / 'project_description.json', 'r') as f: with open(test_app_copy / 'build' / 'project_description.json') as f:
data = json.load(f) data = json.load(f)
assert str((idf_path / 'components' / 'cmp').as_posix()) in data.get( assert str((idf_path / 'components' / 'cmp').as_posix()) in data.get('build_component_paths')
'build_component_paths')
(test_app_copy / 'main' / 'idf_component.yml').write_text(""" (test_app_copy / 'main' / 'idf_component.yml').write_text("""
dependencies: dependencies:
example/cmp: "*" example/cmp: "*"
""") """)
idf_py('reconfigure') idf_py('reconfigure')
with open(test_app_copy / 'build' / 'project_description.json', 'r') as f: with open(test_app_copy / 'build' / 'project_description.json') as f:
data = json.load(f) data = json.load(f)
assert str((test_app_copy / 'managed_components' / 'example__cmp').as_posix()) in data.get( assert str((test_app_copy / 'managed_components' / 'example__cmp').as_posix()) in data.get('build_component_paths')
'build_component_paths') assert str((idf_path / 'components' / 'cmp').as_posix()) not in data.get('build_component_paths')
assert str((idf_path / 'components' / 'cmp').as_posix()) not in data.get(
'build_component_paths')
def test_manifest_local_source_overrides_extra_components(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_manifest_local_source_overrides_extra_components(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
(test_app_copy / '..' / 'extra_dir' / 'cmp').mkdir(parents=True) (test_app_copy / '..' / 'extra_dir' / 'cmp').mkdir(parents=True)
(test_app_copy / '..' / 'extra_dir' / 'cmp' / 'CMakeLists.txt').write_text('idf_component_register()') (test_app_copy / '..' / 'extra_dir' / 'cmp' / 'CMakeLists.txt').write_text('idf_component_register()')
replace_in_file(test_app_copy / 'CMakeLists.txt', replace_in_file(
'# placeholder_before_include_project_cmake', test_app_copy / 'CMakeLists.txt',
'set(EXTRA_COMPONENT_DIRS ../extra_dir)') '# placeholder_before_include_project_cmake',
'set(EXTRA_COMPONENT_DIRS ../extra_dir)',
)
idf_py('reconfigure') idf_py('reconfigure')
with open(test_app_copy / 'build' / 'project_description.json', 'r') as f: with open(test_app_copy / 'build' / 'project_description.json') as f:
data = json.load(f) data = json.load(f)
assert str((test_app_copy / '..' / 'extra_dir' / 'cmp').resolve().as_posix()) in data.get('build_component_paths') assert str((test_app_copy / '..' / 'extra_dir' / 'cmp').resolve().as_posix()) in data.get('build_component_paths')
@@ -241,10 +266,12 @@ dependencies:
path: '../../cmp' path: '../../cmp'
""") """)
idf_py('reconfigure') idf_py('reconfigure')
with open(test_app_copy / 'build' / 'project_description.json', 'r') as f: with open(test_app_copy / 'build' / 'project_description.json') as f:
data = json.load(f) data = json.load(f)
assert str((test_app_copy / '..' / 'cmp').resolve().as_posix()) in data.get('build_component_paths') assert str((test_app_copy / '..' / 'cmp').resolve().as_posix()) in data.get('build_component_paths')
assert str((test_app_copy / '..' / 'extra_dir' / 'cmp').resolve().as_posix()) not in data.get('build_component_paths') assert str((test_app_copy / '..' / 'extra_dir' / 'cmp').resolve().as_posix()) not in data.get(
'build_component_paths'
)
def test_exclude_components_not_passed(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_exclude_components_not_passed(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
@@ -258,8 +285,11 @@ def test_exclude_components_not_passed(idf_py: IdfPyFunc, test_app_copy: Path) -
def test_version_in_component_cmakelist(idf_py: IdfPyFunc, test_app_copy: Path) -> None: def test_version_in_component_cmakelist(idf_py: IdfPyFunc, test_app_copy: Path) -> None:
logging.info('Use IDF version variables in component CMakeLists.txt file') logging.info('Use IDF version variables in component CMakeLists.txt file')
replace_in_file((test_app_copy / 'main' / 'CMakeLists.txt'), '# placeholder_before_idf_component_register', replace_in_file(
'\n'.join(['if (NOT IDF_VERSION_MAJOR)', ' message(FATAL_ERROR "IDF version not set")', 'endif()'])) (test_app_copy / 'main' / 'CMakeLists.txt'),
'# placeholder_before_idf_component_register',
'\n'.join(['if (NOT IDF_VERSION_MAJOR)', ' message(FATAL_ERROR "IDF version not set")', 'endif()']),
)
idf_py('reconfigure') idf_py('reconfigure')
@@ -271,4 +301,4 @@ def test_unknown_component_error(idf_py: IdfPyFunc, test_app_copy: Path) -> None
replace='REQUIRES unknown', replace='REQUIRES unknown',
) )
ret = idf_py('reconfigure', check=False) ret = idf_py('reconfigure', check=False)
assert 'Failed to resolve component \'unknown\' required by component \'main\'' in ret.stderr assert "Failed to resolve component 'unknown' required by component 'main'" in ret.stderr