"""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") ok = check_encode(saxf, sabf) ok &= check_decode(sabf, saxf) ok &= check_round_trip(sabf) sys.exit(0 if ok else 1)