Collect all files included by any ancestor aggregator. Walks up from the excluded dir, checking each ancestor's .cpp aggregator. Resolves include paths to actual file paths so we can match regardless of how the include path is written. Returns (primary_aggregator, set_of_included_a
(excluded_dir: Path)
| 95 | |
| 96 | |
| 97 | def _collect_included_files(excluded_dir: Path) -> tuple[Path | None, set[Path]]: |
| 98 | """Collect all files included by any ancestor aggregator. |
| 99 | |
| 100 | Walks up from the excluded dir, checking each ancestor's .cpp aggregator. |
| 101 | Resolves include paths to actual file paths so we can match regardless |
| 102 | of how the include path is written. |
| 103 | |
| 104 | Returns (primary_aggregator, set_of_included_absolute_file_paths). |
| 105 | """ |
| 106 | aggregator = _find_aggregator(excluded_dir) |
| 107 | included_files: set[Path] = set() |
| 108 | |
| 109 | # Check the direct aggregator and all ancestors |
| 110 | check_dir = excluded_dir |
| 111 | while check_dir.is_relative_to(TESTS_DIR) and check_dir != TESTS_DIR: |
| 112 | agg = check_dir.with_suffix(".cpp") |
| 113 | if agg.exists(): |
| 114 | agg_dir = agg.parent |
| 115 | for inc_path in _parse_includes(agg): |
| 116 | # Try resolving relative to the aggregator's directory first |
| 117 | resolved = (agg_dir / inc_path).resolve() |
| 118 | if resolved.exists(): |
| 119 | included_files.add(resolved) |
| 120 | else: |
| 121 | # Also try resolving relative to project root |
| 122 | # (for fully-qualified includes like "tests/fl/codec/gif.hpp") |
| 123 | resolved_root = (PROJECT_ROOT / inc_path).resolve() |
| 124 | if resolved_root.exists(): |
| 125 | included_files.add(resolved_root) |
| 126 | check_dir = check_dir.parent |
| 127 | |
| 128 | return aggregator, included_files |
| 129 | |
| 130 | |
| 131 | def check() -> tuple[bool, list[str]]: |
no test coverage detected