Compute a hash of all test file metadata (path + mtime + size). This provides a fast way to detect if any test files have been added, deleted, or modified without re-parsing all test files. Args: tests_dir: Root directory containing test files Returns: SHA256
(tests_dir: Path)
| 32 | |
| 33 | |
| 34 | def compute_test_files_hash(tests_dir: Path) -> str: |
| 35 | """ |
| 36 | Compute a hash of all test file metadata (path + mtime + size). |
| 37 | |
| 38 | This provides a fast way to detect if any test files have been added, |
| 39 | deleted, or modified without re-parsing all test files. |
| 40 | |
| 41 | Args: |
| 42 | tests_dir: Root directory containing test files |
| 43 | |
| 44 | Returns: |
| 45 | SHA256 hash of all test file metadata |
| 46 | """ |
| 47 | # Find all *.cpp / *.ino files recursively, same logic as discover_tests.py |
| 48 | from discover_tests import TEST_SOURCE_GLOBS |
| 49 | from test_config import EXCLUDED_TEST_DIRS, EXCLUDED_TEST_FILES |
| 50 | |
| 51 | test_files: list[Path] = [] |
| 52 | |
| 53 | for f in sorted(chain.from_iterable(tests_dir.rglob(g) for g in TEST_SOURCE_GLOBS)): |
| 54 | resolved = f.resolve() |
| 55 | |
| 56 | # Skip excluded files |
| 57 | if resolved in EXCLUDED_TEST_FILES: |
| 58 | continue |
| 59 | |
| 60 | # Skip files inside excluded directories |
| 61 | if any(resolved.is_relative_to(d) for d in EXCLUDED_TEST_DIRS): |
| 62 | continue |
| 63 | |
| 64 | # Skip hidden directories and .dir directories |
| 65 | rel = f.relative_to(tests_dir) |
| 66 | parent_parts = rel.parts[:-1] |
| 67 | if any(part.startswith(".") or part.endswith(".dir") for part in parent_parts): |
| 68 | continue |
| 69 | test_files.append(f) |
| 70 | |
| 71 | unique_files = test_files # already deduplicated by rglob + sorted |
| 72 | |
| 73 | # Create hash input from file metadata |
| 74 | hash_input = [] |
| 75 | for f in unique_files: |
| 76 | if f.is_file(): |
| 77 | stat = f.stat() |
| 78 | rel_path = f.relative_to(tests_dir).as_posix() |
| 79 | # Include path, mtime, and size in hash |
| 80 | hash_input.append(f"{rel_path}:{stat.st_mtime:.6f}:{stat.st_size}") |
| 81 | |
| 82 | # Compute SHA256 hash |
| 83 | hash_str = "\n".join(hash_input) |
| 84 | return hashlib.sha256(hash_str.encode()).hexdigest() |
| 85 | |
| 86 | |
| 87 | def load_cache(build_dir: Path) -> dict | None: |
no test coverage detected