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