from __future__ import annotations
import re
import sys
from pathlib import Path
ROOTS: list[tuple[Path, list[Path]]] = [
(Path("tests"), [Path("src")]),
(Path("hegel-c/tests"), [Path("hegel-c/src")]),
(Path("hegel-macros/tests"), [Path("hegel-macros/src")]),
]
MOD_RE = re.compile(r"^\s*(?:pub\s+)?mod\s+(\w+)\s*;", re.MULTILINE)
PATH_ATTR_RE = re.compile(r'#\[path\s*=\s*"([^"]+)"\s*\]')
INCLUDE_RE = re.compile(r'include!\s*\(\s*"([^"]+)"\s*\)')
EMBEDDED_MARKER = "tests/embedded/"
def embedded_targets(src_roots: list[Path]) -> set[str]:
targets: set[str] = set()
scan_roots = list(src_roots)
for src_root in scan_roots:
if not src_root.is_dir():
continue
for f in src_root.rglob("*.rs"):
for p in PATH_ATTR_RE.findall(f.read_text()):
idx = p.find(EMBEDDED_MARKER)
if idx != -1:
targets.add(p[idx + len(EMBEDDED_MARKER) :])
return targets
def check_module_tree(directory: Path, module_file: Path, violations: list[str]) -> None:
declared = set(MOD_RE.findall(module_file.read_text()))
for entry in sorted(directory.iterdir()):
if entry.is_file() and entry.suffix == ".rs":
if entry == module_file or entry.name in ("main.rs", "mod.rs"):
continue
if entry.stem not in declared:
violations.append(
f" {entry}: not referenced from {module_file} "
f"(add `mod {entry.stem};` to {module_file})"
)
elif entry.is_dir():
sibling = directory / f"{entry.name}.rs"
nested = entry / "mod.rs"
if entry.name not in declared:
violations.append(
f" {entry}/: not referenced from {module_file} "
f"(add `mod {entry.name};` to {module_file})"
)
if sibling.exists():
check_module_tree(entry, sibling, violations)
elif nested.exists():
check_module_tree(entry, nested, violations)
else:
violations.append(
f" {entry}/: has no {entry.name}.rs or mod.rs module file, "
"so nothing inside it can be compiled"
)
def check_embedded(directory: Path, src_roots: list[Path], violations: list[str]) -> None:
targets = embedded_targets(src_roots + [directory])
included: set[str] = set()
for f in directory.rglob("*.rs"):
for inc in INCLUDE_RE.findall(f.read_text()):
target = (f.parent / inc).resolve()
if target.is_relative_to(directory.resolve()):
included.add(target.relative_to(directory.resolve()).as_posix())
for f in sorted(directory.rglob("*.rs")):
rel = f.relative_to(directory).as_posix()
if rel not in targets and rel not in included:
violations.append(
f" {f}: not the target of any `#[path = \"…{EMBEDDED_MARKER}{rel}\"]` "
f"or `include!` reference in {'/'.join(str(r) for r in src_roots)}"
)
def check() -> int:
violations: list[str] = []
for tests_root, src_roots in ROOTS:
if not tests_root.is_dir():
continue
for lib_dir in sorted(tests_root.iterdir()):
if not lib_dir.is_dir():
continue
if lib_dir.name == "embedded":
check_embedded(lib_dir, src_roots, violations)
continue
main_rs = lib_dir / "main.rs"
mod_rs = lib_dir / "mod.rs"
if main_rs.exists():
check_module_tree(lib_dir, main_rs, violations)
elif mod_rs.exists():
check_module_tree(lib_dir, mod_rs, violations)
else:
violations.append(
f" {lib_dir}/: has no main.rs (integration-test target) or "
"mod.rs (shared helper module), so nothing inside it is compiled"
)
if violations:
print("Orphan test files found:\n")
for v in violations:
print(v)
print(
"\nTest files are only compiled if something references them: a"
" `mod <name>;` chain from main.rs/mod.rs, or a `#[path]` include"
" from src/ for embedded tests. Add the reference, or delete the"
" file."
)
return 1
return 0
if __name__ == "__main__":
sys.exit(check())