testprogram/ is local test data, not part of the tool: untracked and gitignored so it never comes back. verify.py now prints SKIP and exits 0 when the test pair is absent instead of blowing up. Adds config.NAME / config.VERSION (sab2sax 0.0.0.001). Every dialog title bar goes through config.title(), and the CLI prints the same line at startup, so it is clear which build produced a file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
112 lines
3.9 KiB
Python
112 lines
3.9 KiB
Python
"""Regression check: our output must be byte-identical to sedonac.exe's, both ways.
|
|
|
|
sax -> sab check_encode()
|
|
sab -> sax check_decode()
|
|
sab -> sax -> sab round trip
|
|
|
|
Usage: python verify.py [sedona_home]
|
|
|
|
Without an argument the home comes from system.properties (see config.py), which
|
|
pops a folder chooser the first time.
|
|
"""
|
|
import os, sys, subprocess, tempfile, shutil
|
|
import sab, sax, config
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
HOME = sys.argv[1] if len(sys.argv) > 1 else config.get_sedona_home()
|
|
TESTS = os.path.join(HERE, "testprogram")
|
|
|
|
|
|
def sedonac(src, tmp):
|
|
"""Run sedonac on a copy of `src`; return the file it produced (needs a JRE)."""
|
|
work = os.path.join(tmp, os.path.basename(src))
|
|
shutil.copy(src, work)
|
|
exe = os.path.join(HOME, "bin", "sedonac.exe")
|
|
r = subprocess.run([exe, work], capture_output=True, text=True)
|
|
if r.returncode != 0:
|
|
print(" sedonac failed:\n" + r.stdout + r.stderr)
|
|
return None
|
|
other = ".sax" if work.endswith(".sab") else ".sab"
|
|
return os.path.splitext(work)[0] + other
|
|
|
|
|
|
def compare(label, reference, mine, binary):
|
|
a = open(reference, "rb").read()
|
|
b = open(mine, "rb").read()
|
|
if a == b:
|
|
print(" PASS %-28s %d bytes identical" % (label, len(a)))
|
|
return True
|
|
|
|
diffs = [i for i in range(min(len(a), len(b))) if a[i] != b[i]]
|
|
print(" FAIL %-28s sedonac=%d ours=%d, %d byte diffs" % (label, len(a), len(b), len(diffs)))
|
|
if diffs:
|
|
i = diffs[0]
|
|
if binary:
|
|
lo, hi = max(0, i - 12), i + 12
|
|
print(" first diff at offset %d" % i)
|
|
print(" sedonac %s" % a[lo:hi].hex())
|
|
print(" ours %s" % b[lo:hi].hex())
|
|
else:
|
|
line = a[:i].count(b"\n") + 1
|
|
print(" first diff at line %d" % line)
|
|
print(" sedonac %s" % a.splitlines()[line - 1])
|
|
print(" ours %s" % b.splitlines()[line - 1])
|
|
return False
|
|
|
|
|
|
def check_encode(sax_file, reference=None):
|
|
"""sax -> sab, against `reference` or a fresh sedonac run."""
|
|
tmp = tempfile.mkdtemp()
|
|
try:
|
|
reference = reference or sedonac(sax_file, tmp)
|
|
if reference is None:
|
|
return False
|
|
mine = os.path.join(tmp, "mine.sab")
|
|
sab.encode(sax_file, HOME, mine)
|
|
return compare(os.path.basename(sax_file) + " -> sab", reference, mine, True)
|
|
finally:
|
|
shutil.rmtree(tmp, ignore_errors=True)
|
|
|
|
|
|
def check_decode(sab_file, reference=None):
|
|
"""sab -> sax, against `reference` or a fresh sedonac run."""
|
|
tmp = tempfile.mkdtemp()
|
|
try:
|
|
reference = reference or sedonac(sab_file, tmp)
|
|
if reference is None:
|
|
return False
|
|
mine = os.path.join(tmp, "mine.sax")
|
|
sax.decode(sab_file, HOME, mine)
|
|
return compare(os.path.basename(sab_file) + " -> sax", reference, mine, False)
|
|
finally:
|
|
shutil.rmtree(tmp, ignore_errors=True)
|
|
|
|
|
|
def check_round_trip(sab_file):
|
|
"""sab -> sax -> sab must come back to the same bytes."""
|
|
tmp = tempfile.mkdtemp()
|
|
try:
|
|
mid = os.path.join(tmp, "mid.sax")
|
|
back = os.path.join(tmp, "back.sab")
|
|
sax.decode(sab_file, HOME, mid)
|
|
sab.encode(mid, HOME, back)
|
|
return compare(os.path.basename(sab_file) + " round trip", sab_file, back, True)
|
|
finally:
|
|
shutil.rmtree(tmp, ignore_errors=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("sedona home: %s" % HOME)
|
|
saxf = os.path.join(TESTS, "test_normal.sax")
|
|
sabf = os.path.join(TESTS, "test_normal_sedonac.sab")
|
|
missing = [f for f in (saxf, sabf) if not os.path.isfile(f)]
|
|
if missing:
|
|
# testprogram/ is deliberately not in the repo -- put the pair back to run this
|
|
print(" SKIP no test files: %s" % ", ".join(os.path.basename(f) for f in missing))
|
|
sys.exit(0)
|
|
|
|
ok = check_encode(saxf, sabf)
|
|
ok &= check_decode(sabf, saxf)
|
|
ok &= check_round_trip(sabf)
|
|
sys.exit(0 if ok else 1)
|