blob: aca90cb110739a79296796ab033f5a855071ac49 [file] [log] [blame]
Tobias Deiminger4d412fa2023-06-20 00:41:07 +02001# 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."""
Tobias Deiminger7184a092024-01-08 22:11:00 +010020 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
Tobias Deiminger4d412fa2023-06-20 00:41:07 +020025 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))}"