Skip to content

Commit f6d6bd1

Browse files
committed
fix(coverage): broaden always-run-all and rung3 Fortran extension matching
Fix 3: ALWAYS_RUN_ALL_EXACT + prefixes enumerated only a handful of toolchain files, missing case.py, build.py, common.py, state.py, sched.py, etc. Any toolchain/mfc/*.py change (except cases.py) affects every test's generation or execution, so under-enumeration was unsound. Replace with a catch-all: any(f.startswith('toolchain/mfc/') and f.endswith('.py') and f != CASES_PY). Drop the now-redundant individual file entries and toolchain/mfc/params/ and toolchain/mfc/run/ prefixes (all subsumed). Keep CMakeLists.txt, toolchain/cmake/, toolchain/bootstrap/, and src include rules. Fix 4: rung 3 matched only .f90 and .f, missing .F90, .F95, .F03, .F08, .FOR and all other uppercase/mixed variants. Changed files ending in those extensions under src/ would fall through to per-test selection against a coverage map that only tracks .fpp, causing silent under-inclusion. Fix: case-insensitive match against the full tuple (.f90, .f, .f95, .f03, .f08, .for). Tests: add three new unit tests covering the above fixes.
1 parent 9f970d3 commit f6d6bd1

2 files changed

Lines changed: 31 additions & 9 deletions

File tree

toolchain/mfc/test/coverage.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,12 @@ def save_map(path: Path, entries: dict, *, n_tests: int, git_sha: str, gfortran_
4747
ALWAYS_RUN_ALL_EXACT = frozenset(
4848
[
4949
"CMakeLists.txt",
50-
# Toolchain infra that affects EVERY test's generation/execution -> run all.
51-
"toolchain/mfc/test/case.py", # TestCase: how a case runs
52-
"toolchain/mfc/test/test.py", # the test runner
53-
"toolchain/mfc/test/coverage.py", # the selector itself
54-
"toolchain/mfc/test/coverage_build.py", # the map collector
5550
]
5651
)
5752
ALWAYS_RUN_ALL_PREFIXES = (
5853
"src/common/include/", # GPU/Fypp macro & include files (CPU map can't line-attribute)
5954
"toolchain/cmake/", # build system
60-
"toolchain/mfc/params/", # parameter codegen -> emits Fortran broadly
6155
"toolchain/bootstrap/", # build/run scripts
62-
"toolchain/mfc/run/", # .inp generation / case dicts -> affects every test's input
6356
)
6457

6558

@@ -69,6 +62,14 @@ def is_always_run_all(changed_files: set) -> bool:
6962
return True
7063
if any(f.startswith(ALWAYS_RUN_ALL_PREFIXES) for f in changed_files):
7164
return True
65+
# Any toolchain/mfc/*.py change (params/, run/, test infra, case.py, common.py,
66+
# build.py, state.py, sched.py, …) affects EVERY test's generation or execution and
67+
# cannot be attributed to individual tests by the coverage map. Treat the entire
68+
# toolchain/mfc/ subtree as run-all EXCEPT cases.py, which is handled precisely by
69+
# rung 5 (new/modified tests have a fresh param_hash absent from the map and run
70+
# individually; unchanged tests have no .fpp overlap and are skipped).
71+
if any(f.startswith("toolchain/mfc/") and f.endswith(".py") and f != CASES_PY for f in changed_files):
72+
return True
7273
# gcov rolls #:include'd .fpp into the parent compilation unit, so include files
7374
# (inline_*.fpp, HardcodedIC, macros) are not reliably attributed in the map. Force a
7475
# full run for ANY src/**/include/ change so this attribution gap can never cause
@@ -112,8 +113,10 @@ def select_tests(cases, coverage_map, changed_files):
112113
if is_always_run_all(changed_files):
113114
return list(cases), [], "rung2: macro/codegen/build input changed"
114115

115-
# Rung 3: changed .f90/.f under src/ (map tracks .fpp only) -> run all.
116-
if any(f.startswith("src/") and f.endswith((".f90", ".f")) for f in changed_files):
116+
# Rung 3: changed hand-written Fortran source under src/ (map tracks .fpp only) -> run
117+
# all. Match case-insensitively to catch .F90, .F95, .FOR, etc.
118+
_FORTRAN_EXTS = (".f90", ".f", ".f95", ".f03", ".f08", ".for")
119+
if any(f.startswith("src/") and f.lower().endswith(_FORTRAN_EXTS) for f in changed_files):
117120
return list(cases), [], "rung3: hand-written .f90/.f changed"
118121

119122
changed_fpp = {f for f in changed_files if f.endswith(".fpp")}

toolchain/mfc/test/test_coverage_unit.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,22 @@ def test_docs_only_still_skips_all():
303303
cases = _cases("a")
304304
run, skip, reason = select_tests(cases, {"a": ["src/x.fpp"]}, {"README.md"})
305305
assert run == [] and len(skip) == 1 and "rung7" in reason
306+
307+
308+
def test_uppercase_fortran_extension_forces_all():
309+
cases = _cases("a")
310+
run, skip, reason = select_tests(cases, {"a": []}, {"src/common/m_x.F90"})
311+
assert len(run) == 1 and reason.startswith("rung3")
312+
313+
314+
def test_toolchain_py_change_forces_all_except_cases():
315+
assert is_always_run_all({"toolchain/mfc/case.py"})
316+
assert is_always_run_all({"toolchain/mfc/build.py"})
317+
assert is_always_run_all({"toolchain/mfc/common.py"})
318+
assert not is_always_run_all({"toolchain/mfc/test/cases.py"})
319+
320+
321+
def test_empty_map_with_fpp_change_runs_all_rung4():
322+
cases = _cases("a", "b")
323+
run, skip, reason = select_tests(cases, {}, {"src/simulation/m_rhs.fpp"})
324+
assert len(run) == 2 and reason.startswith("rung4")

0 commit comments

Comments
 (0)