r"""子程序 gcov 行号不得并入主程序 gcov 字典的回归测试。 Bug:`generate_coverage_report` 用 `gcov_data.update(sub_merged)` 把子程序 (SUB*.cbl) 的 gcov 行计数并入主程序行号字典。主程序与子程序的行号都是纯 整数,直接碰撞——SUB04CHK 的第 167 行(count=0)覆盖了 SHA02MNC 主程序 第 167 行(count=25,主循环 PERFORM 已进入),导致 #10 Enter 分支被误判为 未覆盖(SHA02MNC 覆盖率从应有的水平被拉低)。 修复:子程序 gcov 按子程序名独立保存(`_sub_gcov_data`),不并入主程序 `gcov_data`。`_merge_run_dirs_gcov` 对单个程序跨 run 目录合并。 """ import sys, os sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from pathlib import Path from cobol_testgen.gcov import parse_cbl_gcov from orchestrator_db import _merge_run_dirs_gcov def _write_fake_gcov(dirpath: Path, name: str, counts: dict[int, int]): lines = [] for ln in sorted(counts): cnt = counts[ln] marker = "#####" if cnt == 0 else f"{cnt}*" lines.append(f"{marker}:{ln}: dummy source line\n") (dirpath / f"{name}.cbl.gcov").write_text("".join(lines), encoding="utf-8") def _fake_gcov_func(name: str, d: str): return parse_cbl_gcov(os.path.join(d, f"{name}.cbl.gcov")) def test_sub_gcov_line_collision_does_not_corrupt_main(tmp_path): run_normal = tmp_path / "run_normal"; run_normal.mkdir() run_fail = tmp_path / "run_fail"; run_fail.mkdir() # 主程序:line 167 在 normal 场景执行 25 次(主循环进入) _write_fake_gcov(run_normal, "MAIN", {167: 25, 265: 1}) _write_fake_gcov(run_fail, "MAIN", {167: 0, 265: 1}) # 子程序:line 167 从未执行(count=0)——与主程序行号碰撞 _write_fake_gcov(run_normal, "SUB", {167: 0, 10: 1}) _write_fake_gcov(run_fail, "SUB", {167: 0, 10: 1}) main = _merge_run_dirs_gcov(tmp_path, "MAIN", gcov_func=_fake_gcov_func) sub = _merge_run_dirs_gcov(tmp_path, "SUB", gcov_func=_fake_gcov_func) # 合并后主程序 167 必须保持 25 assert main[167] == 25, f"main line 167 corrupted: {main[167]}" assert sub[167] == 0 # 旧 bug 行为演示:若把子程序并入主程序字典,167 会被覆盖为 0 buggy = dict(main) buggy.update(sub) assert buggy[167] == 0, "demonstrates the corruption the fix avoids" # 修复不变量:子程序数据独立保存,主程序字典完好 assert main[167] == 25 def test_merge_run_dirs_takes_max_count(tmp_path): r1 = tmp_path / "run_a"; r1.mkdir() r2 = tmp_path / "run_b"; r2.mkdir() _write_fake_gcov(r1, "MAIN", {167: 25}) _write_fake_gcov(r2, "MAIN", {167: 3}) merged = _merge_run_dirs_gcov(tmp_path, "MAIN", gcov_func=_fake_gcov_func) assert merged[167] == 25