| # SPDX-License-Identifier: GPL-2.0 | |
| # Copyright (c) 2023 Tobias Deiminger <tdmg@linutronix.de> | |
| """Test for unexpected leftovers after make clean""" | |
| import itertools | |
| import os | |
| import pathlib | |
| import shutil | |
| import sys | |
| import pytest | |
| # pylint: disable=redefined-outer-name | |
| @pytest.fixture | |
| def tmp_copy_of_builddir(u_boot_config, tmp_path): | |
| """For each test, provide a temporary copy of the initial build directory.""" | |
| if os.path.realpath(u_boot_config.source_dir) == os.path.realpath( | |
| u_boot_config.build_dir | |
| ): | |
| pytest.skip("Leftover detection requires out of tree build.") | |
| return None | |
| shutil.copytree( | |
| u_boot_config.build_dir, | |
| tmp_path, | |
| symlinks=True, | |
| dirs_exist_ok=True, | |
| ) | |
| return tmp_path | |
| @pytest.fixture(scope="module") | |
| def run_make(u_boot_log): | |
| """Provide function to run and log make without connecting to u-boot console.""" | |
| runner = u_boot_log.get_runner("make", sys.stdout) | |
| def _run_make(build_dir, target): | |
| cmd = ["make", f"O={build_dir}", target] | |
| runner.run(cmd) | |
| yield _run_make | |
| runner.close() | |
| @pytest.fixture(scope="module") | |
| def most_generated_files(): | |
| """Path.glob style patterns to describe what should be removed by 'make clean'.""" | |
| return ( | |
| "**/*.c", | |
| "**/*.dtb", | |
| "**/*.dtbo", | |
| "**/*.o", | |
| "**/*.py", | |
| "**/*.pyc", | |
| "**/*.so", | |
| "**/*.srec", | |
| "u-boot*", | |
| "[svt]pl/u-boot*", | |
| ) | |
| @pytest.fixture(scope="module") | |
| def all_generated_files(most_generated_files): | |
| """Path.glob style patterns to describe what should be removed by 'make mrproper'.""" | |
| return most_generated_files + (".config", "**/*.h") | |
| def find_files(search_dir, include_patterns, exclude_dirs=None): | |
| """Find files matching include_patterns, unless it's in one of exclude_dirs. | |
| include_patterns -- Path.glob style pattern relative to search dir | |
| exclude_dir -- directories to exclude, expected relative to search dir | |
| """ | |
| matches = [] | |
| exclude_dirs = [] if exclude_dirs is None else exclude_dirs | |
| for abs_path in itertools.chain.from_iterable( | |
| pathlib.Path(search_dir).glob(pattern) for pattern in include_patterns | |
| ): | |
| if abs_path.is_dir(): | |
| continue | |
| rel_path = pathlib.Path(os.path.relpath(abs_path, search_dir)) | |
| if not any( | |
| rel_path.is_relative_to(exclude_dir) for exclude_dir in exclude_dirs | |
| ): | |
| matches.append(rel_path) | |
| return matches | |
| def test_clean(run_make, tmp_copy_of_builddir, most_generated_files): | |
| """Test if 'make clean' deletes most generated files.""" | |
| run_make(tmp_copy_of_builddir, "clean") | |
| leftovers = find_files( | |
| tmp_copy_of_builddir, | |
| most_generated_files, | |
| exclude_dirs=["scripts", "test/overlay"], | |
| ) | |
| assert not leftovers, f"leftovers: {', '.join(map(str, leftovers))}" | |
| def test_mrproper(run_make, tmp_copy_of_builddir, all_generated_files): | |
| """Test if 'make mrproper' deletes current configuration and all generated files.""" | |
| run_make(tmp_copy_of_builddir, "mrproper") | |
| leftovers = find_files( | |
| tmp_copy_of_builddir, | |
| all_generated_files, | |
| exclude_dirs=["test/overlay"], | |
| ) | |
| assert not leftovers, f"leftovers: {', '.join(map(str, leftovers))}" |