Tobias Deiminger | 4d412fa | 2023-06-20 00:41:07 +0200 | [diff] [blame] | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | # Copyright (c) 2023 Tobias Deiminger <tdmg@linutronix.de> |
| 3 | |
| 4 | """Test for unexpected leftovers after make clean""" |
| 5 | |
| 6 | import itertools |
| 7 | import os |
| 8 | import pathlib |
| 9 | import shutil |
| 10 | import sys |
| 11 | |
| 12 | import pytest |
| 13 | |
| 14 | # pylint: disable=redefined-outer-name |
| 15 | |
| 16 | |
| 17 | @pytest.fixture |
| 18 | def tmp_copy_of_builddir(u_boot_config, tmp_path): |
| 19 | """For each test, provide a temporary copy of the initial build directory.""" |
| 20 | shutil.copytree( |
| 21 | u_boot_config.build_dir, |
| 22 | tmp_path, |
| 23 | symlinks=True, |
| 24 | dirs_exist_ok=True, |
| 25 | ) |
| 26 | return tmp_path |
| 27 | |
| 28 | |
| 29 | @pytest.fixture(scope="module") |
| 30 | def run_make(u_boot_log): |
| 31 | """Provide function to run and log make without connecting to u-boot console.""" |
| 32 | runner = u_boot_log.get_runner("make", sys.stdout) |
| 33 | |
| 34 | def _run_make(build_dir, target): |
| 35 | cmd = ["make", f"O={build_dir}", target] |
| 36 | runner.run(cmd) |
| 37 | |
| 38 | yield _run_make |
| 39 | runner.close() |
| 40 | |
| 41 | |
| 42 | @pytest.fixture(scope="module") |
| 43 | def most_generated_files(): |
| 44 | """Path.glob style patterns to describe what should be removed by 'make clean'.""" |
| 45 | return ( |
| 46 | "**/*.c", |
| 47 | "**/*.dtb", |
| 48 | "**/*.dtbo", |
| 49 | "**/*.o", |
| 50 | "**/*.py", |
| 51 | "**/*.pyc", |
| 52 | "**/*.so", |
| 53 | "**/*.srec", |
| 54 | "u-boot*", |
| 55 | "[svt]pl/u-boot*", |
| 56 | ) |
| 57 | |
| 58 | |
| 59 | @pytest.fixture(scope="module") |
| 60 | def all_generated_files(most_generated_files): |
| 61 | """Path.glob style patterns to describe what should be removed by 'make mrproper'.""" |
| 62 | return most_generated_files + (".config", "**/*.h") |
| 63 | |
| 64 | |
| 65 | def find_files(search_dir, include_patterns, exclude_dirs=None): |
| 66 | """Find files matching include_patterns, unless it's in one of exclude_dirs. |
| 67 | |
| 68 | include_patterns -- Path.glob style pattern relative to search dir |
| 69 | exclude_dir -- directories to exclude, expected relative to search dir |
| 70 | """ |
| 71 | matches = [] |
| 72 | exclude_dirs = [] if exclude_dirs is None else exclude_dirs |
| 73 | for abs_path in itertools.chain.from_iterable( |
| 74 | pathlib.Path(search_dir).glob(pattern) for pattern in include_patterns |
| 75 | ): |
| 76 | if abs_path.is_dir(): |
| 77 | continue |
| 78 | rel_path = pathlib.Path(os.path.relpath(abs_path, search_dir)) |
| 79 | if not any( |
| 80 | rel_path.is_relative_to(exclude_dir) for exclude_dir in exclude_dirs |
| 81 | ): |
| 82 | matches.append(rel_path) |
| 83 | return matches |
| 84 | |
| 85 | |
| 86 | def test_clean(run_make, tmp_copy_of_builddir, most_generated_files): |
| 87 | """Test if 'make clean' deletes most generated files.""" |
| 88 | run_make(tmp_copy_of_builddir, "clean") |
| 89 | leftovers = find_files( |
| 90 | tmp_copy_of_builddir, |
| 91 | most_generated_files, |
| 92 | exclude_dirs=["scripts", "test/overlay"], |
| 93 | ) |
| 94 | assert not leftovers, f"leftovers: {', '.join(map(str, leftovers))}" |
| 95 | |
| 96 | |
| 97 | def test_mrproper(run_make, tmp_copy_of_builddir, all_generated_files): |
| 98 | """Test if 'make mrproper' deletes current configuration and all generated files.""" |
| 99 | run_make(tmp_copy_of_builddir, "mrproper") |
| 100 | leftovers = find_files( |
| 101 | tmp_copy_of_builddir, |
| 102 | all_generated_files, |
| 103 | exclude_dirs=["test/overlay"], |
| 104 | ) |
| 105 | assert not leftovers, f"leftovers: {', '.join(map(str, leftovers))}" |