chore: SETUP.md + 测试报告脚本 + 文档更新
- SETUP.md: 完整环境搭建指南(同事用) - SETUP_QUICK.md: 快速搭环境(4步) - s22~s26: TNA端到端、覆盖率报告、回归检查 - procedure_grammar.lark: 实验性Lark语法 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
"""S23: Per-program branch coverage + code coverage report"""
|
||||
import sys, os, re, subprocess, time
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
ROOT_BENCH = "D:/cobol-java/cobol-test-programs/"
|
||||
COPYBOOKS_BENCH = os.path.join(ROOT_BENCH, "common", "copybooks")
|
||||
ROOT_TNA = "D:/cobol-java/cobol-tna-system/"
|
||||
COPYBOOKS_TNA = os.path.join(ROOT_TNA, "cpy")
|
||||
|
||||
from cobol_testgen import extract_structure, generate_data
|
||||
from cobol_testgen.read import preprocess, resolve_copybooks, extract_data_division, extract_procedure_division, parse_data_division
|
||||
from cobol_testgen.design_mcdc import enum_paths
|
||||
from cobol_testgen.pipeline_bridge import build_branch_tree_fallback
|
||||
from cobol_testgen.flatfile import analyze_fd_layout
|
||||
|
||||
def find_main(d):
|
||||
cbls = [f for f in os.listdir(d) if f.endswith('.cbl')]
|
||||
ws = [f for f in cbls if re.match(r'main-\d{2}-', f, re.IGNORECASE)]
|
||||
if ws: return max(ws, key=lambda f: os.path.getsize(os.path.join(d, f)))
|
||||
return max(cbls, key=lambda f: os.path.getsize(os.path.join(d, f))) if cbls else None
|
||||
|
||||
def analyze_one(name, fpath, source_dir, copybook_dirs):
|
||||
"""Return dict: {branches, dpoints, paths, records, flat_files, lines, code_lines, compile, run, error}"""
|
||||
result = {"name": name, "branches": 0, "dpoints": 0, "paths": 0, "records": 0,
|
||||
"flat_files": 0, "lines": 0, "code_lines": 0, "compile": "-", "run": "-", "error": ""}
|
||||
try:
|
||||
src = open(fpath, encoding="utf-8-sig").read()
|
||||
result["lines"] = len(src.split("\n"))
|
||||
result["code_lines"] = sum(1 for l in src.split("\n") if l.strip() and not l.strip().startswith("*"))
|
||||
t0 = time.time()
|
||||
st = extract_structure(src)
|
||||
result["branches"] = st.get("total_branches", 0)
|
||||
result["dpoints"] = len(st.get("decision_points", []))
|
||||
pp = resolve_copybooks(src, source_dir, extra_search_paths=copybook_dirs)
|
||||
pp = preprocess(pp)
|
||||
recs = generate_data(pp, st)
|
||||
result["records"] = len(recs)
|
||||
# Coverage data from generate_data (mark_coverage result)
|
||||
cov = st.get('coverage', {})
|
||||
result["cov_total"] = cov.get('total', 0)
|
||||
result["cov_covered"] = cov.get('covered', 0)
|
||||
result["cov_pct"] = cov.get('pct', 0)
|
||||
# Path count
|
||||
dd = extract_data_division(pp)
|
||||
fields = parse_data_division(dd) if dd else []
|
||||
fdict = [{'name': f.name, 'pic_info': {'type': f.pic_info.type if f.pic_info else 'unknown'}} for f in fields]
|
||||
proc = extract_procedure_division(pp)
|
||||
tree, ass = build_branch_tree_fallback(proc, fdict)
|
||||
paths = enum_paths(tree, fdict)
|
||||
result["paths"] = len(paths)
|
||||
layouts = analyze_fd_layout(pp)
|
||||
result["flat_files"] = len(layouts)
|
||||
result["time_ms"] = int((time.time()-t0)*1000)
|
||||
except Exception as e:
|
||||
result["error"] = str(e)[:80]
|
||||
return result
|
||||
|
||||
def analyze_tna(name, fpath):
|
||||
"""Analyze TNA program"""
|
||||
return analyze_one(name, fpath, os.path.dirname(fpath), [COPYBOOKS_TNA])
|
||||
|
||||
def analyze_bench(name, fpath):
|
||||
"""Analyze benchmark program"""
|
||||
return analyze_one(name, fpath, os.path.dirname(fpath), [COPYBOOKS_BENCH])
|
||||
|
||||
# ── Run all benchmark programs ──
|
||||
print("=" * 110)
|
||||
print(f"{'Program':<28} {'Br':>4} {'DPs':>4} {'Paths':>5} {'Recs':>4} {'Flats':>4} {'CovBr':>5} {'Cov%':>5} {'Lines':>5} {'CodeL':>5} {'Time':>6}")
|
||||
print("-" * 110)
|
||||
|
||||
bench_results = []
|
||||
for d in sorted(os.listdir(ROOT_BENCH)):
|
||||
dp = os.path.join(ROOT_BENCH, d)
|
||||
if not os.path.isdir(dp) or d in ('common','docs','cross-cutting'): continue
|
||||
fn = find_main(dp)
|
||||
if not fn: continue
|
||||
r = analyze_bench(d, os.path.join(dp, fn))
|
||||
bench_results.append(r)
|
||||
br_pct = r["paths"] / r["branches"] * 100 if r["branches"] > 0 else 0
|
||||
cov_pct = r.get("cov_pct", 0)
|
||||
codel = r["code_lines"]
|
||||
status = r.get("error", "")[:8] if r.get("error") else ""
|
||||
print(f" {r['name']:<28} {r['branches']:>4} {r['dpoints']:>4} {r['paths']:>5} {r['records']:>4} {r['flat_files']:>4} {r.get('cov_covered',0):>5} {cov_pct:>4.0f}% {r['lines']:>5} {r['code_lines']:>5} {r.get('time_ms',0):>5}ms {status}")
|
||||
|
||||
# ── Run all TNA programs ──
|
||||
print("-" * 110)
|
||||
for f in ["ZAN01CHK", "ZAN02CHK", "ZAN03CHK", "ZAN04MAT", "ZAN05CAL", "ZAN06UPD"]:
|
||||
fpath = os.path.join(ROOT_TNA, "src", f + ".cbl")
|
||||
if not os.path.exists(fpath): continue
|
||||
r = analyze_tna(f, fpath)
|
||||
bench_results.append(r)
|
||||
cov_pct = r.get("cov_pct", 0)
|
||||
codel = r["code_lines"]
|
||||
status = r.get("error", "")[:8] if r.get("error") else ""
|
||||
print(f" {r['name']:<28} {r['branches']:>4} {r['dpoints']:>4} {r['paths']:>5} {r['records']:>4} {r['flat_files']:>4} {r.get('cov_covered',0):>5} {cov_pct:>4.0f}% {r['lines']:>5} {r['code_lines']:>5} {r.get('time_ms',0):>5}ms {status}")
|
||||
|
||||
print("=" * 110)
|
||||
|
||||
# ── Totals ──
|
||||
total_br = sum(r["branches"] for r in bench_results)
|
||||
total_paths = sum(r["paths"] for r in bench_results)
|
||||
total_recs = sum(r["records"] for r in bench_results)
|
||||
total_lines = sum(r["code_lines"] for r in bench_results)
|
||||
total_flats = sum(r["flat_files"] for r in bench_results)
|
||||
total_cov = sum(r.get("cov_covered", 0) for r in bench_results)
|
||||
total_cov_all = sum(r.get("cov_total", 0) for r in bench_results)
|
||||
with_br = sum(1 for r in bench_results if r["branches"] > 0)
|
||||
print(f"\n{'TOTAL':<28} {total_br:>4} {total_paths:>5} {total_recs:>4} {total_flats:>4} {total_cov:>5} {total_cov/max(total_cov_all,1)*100:>4.0f}%")
|
||||
print(f"Programs with branch detection: {with_br}/{len(bench_results)}")
|
||||
print(f"Total code lines (non-comment): {total_lines}")
|
||||
print(f"\n{'='*110}")
|
||||
print("NOTES:")
|
||||
print(" Br = Decision branches detected by static analysis")
|
||||
print(" DPs = Decision points (IF/EVAL/PERFORM)")
|
||||
print(" Paths = Generated test paths (O(N) linear)")
|
||||
print(" Recs = Generated data records")
|
||||
print(" CovBr = Branches actually covered by generated data")
|
||||
print(" Cov% = Real branch coverage via mark_coverage")
|
||||
print(" Time = Parse + generate time in ms")
|
||||
Reference in New Issue
Block a user