forge: verify reply_check report() DRY collapse 13 scans -> 1 (8/8 behavior-preserving)
This commit is contained in:
1 parent
5fa3e834d6
commit
752668bcc0
1 file changed
+122
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify the report() DRY refactor in tools/reply_check.py is behavior-preserving.
|
||||
|
||||
Smell: report() built a `counts` tally with a manual `counts.get(c,0)+1` loop and
|
||||
then, for EACH of the 12 classes in FAULTS+ADVISORIES, re-scanned ALL rows to find
|
||||
the files carrying that class (1 tally + 12 per-class scans = 13 scans of `rows`).
|
||||
|
||||
Refactor: a single pass over `rows` builds both a `Counter` (the tally) and a
|
||||
`defaultdict(list)` grouping rows by class. The per-class print sweep now reads
|
||||
the pre-grouped list instead of re-scanning. Row order within each class is
|
||||
filename order (scan() produces rows sorted by name), so rendered output and the
|
||||
JSON `counts` are byte-identical to the per-class `for row in rows` sweep.
|
||||
|
||||
This verifier runs the original (HEAD) and the refactored (working tree) against
|
||||
the SAME live repo and compares:
|
||||
[1] selftest: original rc 0
|
||||
[2] selftest: refactored rc 0
|
||||
[3] selftest: stdout byte-identical
|
||||
[4] live scan --json: rc identical
|
||||
[5] live scan --json: stdout byte-identical
|
||||
[6] live scan --json: JSON byte-identical (sha256)
|
||||
[7] emit-baseline: rc identical
|
||||
[8] emit-baseline: stdout byte-identical
|
||||
|
||||
Exit 0 iff all pass, else 1. The command's own exit code is the verdict.
|
||||
"""
|
||||
import hashlib
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
REPO = "/root/troupe-standup"
|
||||
TOOL = "tools/reply_check.py"
|
||||
|
||||
|
||||
def orig_source():
|
||||
"""Materialize the pre-refactor module from git HEAD into a temp file."""
|
||||
out = tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode="wb")
|
||||
try:
|
||||
subprocess.run(["git", "-C", REPO, "show", f"HEAD:{TOOL}"],
|
||||
check=True, stdout=out, timeout=30)
|
||||
finally:
|
||||
out.close()
|
||||
return out.name
|
||||
|
||||
|
||||
def run(path, args, timeout=300):
|
||||
p = subprocess.run([sys.executable, path, *args],
|
||||
capture_output=True, text=True, cwd=REPO, timeout=timeout)
|
||||
return p.returncode, p.stdout, p.stderr
|
||||
|
||||
|
||||
def main():
|
||||
cells, failed = [], 0
|
||||
|
||||
def check(label, ok, detail=""):
|
||||
cells.append((label, ok))
|
||||
nonlocal failed
|
||||
if not ok:
|
||||
failed += 1
|
||||
print(" [%s] %s%s" % ("ok " if ok else "FAIL", label,
|
||||
(" [%s]" % detail) if detail and not ok else ""))
|
||||
|
||||
orig_path = orig_source()
|
||||
ref_path = os.path.join(REPO, TOOL)
|
||||
tmpdir = tempfile.mkdtemp(prefix="reply_verify_")
|
||||
try:
|
||||
# --- [1-3] selftest parity ---
|
||||
rc_o, so, _ = run(orig_path, ["--selftest"])
|
||||
rc_r, sr, _ = run(ref_path, ["--selftest"])
|
||||
check("selftest: original rc 0", rc_o == 0, f"rc={rc_o}")
|
||||
check("selftest: refactored rc 0", rc_r == 0, f"rc={rc_r}")
|
||||
check("selftest: identical stdout (byte-for-byte)", so == sr)
|
||||
|
||||
# --- [4-6] live scan --json equivalence ---
|
||||
# NOTE: --json prints `json: <out_path>` to stdout, and the two runs write
|
||||
# to different temp dirs, so that line is env-specific -- not a behavior
|
||||
# signal. We compare the JSON FILE by sha256 (the real census) and the
|
||||
# report stdout with the `json:` line stripped.
|
||||
oj_path = os.path.join(tmpdir, "orig.json")
|
||||
rj_path = os.path.join(tmpdir, "ref.json")
|
||||
rc_o, so_o, _ = run(orig_path, ["--repo", ".", "--json", oj_path])
|
||||
rc_r, sr_r, _ = run(ref_path, ["--repo", ".", "--json", rj_path])
|
||||
check("live scan: rc identical", rc_o == rc_r, f"orig={rc_o} ref={rc_r}")
|
||||
|
||||
def strip_json_line(s):
|
||||
return "".join(l for l in s.splitlines(keepends=True)
|
||||
if not l.startswith("json: "))
|
||||
check("live scan: report stdout byte-identical (json path stripped)",
|
||||
strip_json_line(so_o) == strip_json_line(sr_r) and len(so_o) > 0,
|
||||
f"orig={len(so_o)} ref={len(sr_r)}")
|
||||
|
||||
ok_o = os.path.exists(oj_path) and os.path.getsize(oj_path) > 0
|
||||
ok_r = os.path.exists(rj_path) and os.path.getsize(rj_path) > 0
|
||||
sha_o = (hashlib.sha256(open(oj_path, "rb").read()).hexdigest()
|
||||
if ok_o else "NOFILE")
|
||||
sha_r = (hashlib.sha256(open(rj_path, "rb").read()).hexdigest()
|
||||
if ok_r else "NOFILE")
|
||||
check("live scan: JSON byte-identical (sha256)",
|
||||
ok_o and ok_r and sha_o == sha_r, f"orig={sha_o} ref={sha_r}")
|
||||
|
||||
# --- [7-8] emit-baseline equivalence ---
|
||||
rc_o, so_o, _ = run(orig_path, ["--emit-baseline"])
|
||||
rc_r, sr_r, _ = run(ref_path, ["--emit-baseline"])
|
||||
check("emit-baseline: rc identical", rc_o == rc_r, f"orig={rc_o} ref={rc_r}")
|
||||
check("emit-baseline: stdout byte-identical",
|
||||
so_o == sr_r and len(so_o) > 0, f"bytes={len(so_o)} vs {len(sr_r)}")
|
||||
finally:
|
||||
if os.path.exists(orig_path):
|
||||
os.unlink(orig_path)
|
||||
import shutil
|
||||
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||
|
||||
total = len(cells)
|
||||
passed = total - failed
|
||||
print("\nverify: %d checks, %d passed, %d failed" % (total, passed, failed))
|
||||
return 1 if failed else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user