SniperGold_ML/tests/harness.py

76 lines
2.1 KiB
Python

"""Tiny deterministic test harness (no external test dependencies).
Each test registers a name + a callable returning (ok, detail). The harness
collects PASS/FAIL results and prints a summary. It deliberately provides no
assertion magic: every expectation is an explicit equality/condition check."""
import sys
import time
class Suite:
def __init__(self, name):
self.name = name
self.cases = []
def case(self, name):
def deco(fn):
self.cases.append((name, fn))
return fn
return deco
def run(self):
results = []
for name, fn in self.cases:
t0 = time.time()
try:
result = fn()
ok = result[0]
detail = result[1]
results.append((name, ok, detail, time.time() - t0))
except Exception as e:
results.append((name, False, "exception: %r" % e, time.time() - t0))
return results
def expect(cond, detail=""):
return (bool(cond), detail)
def eq(a, b, label=""):
return (a == b, "%s expected=%r actual=%r" % (label, b, a))
def summarize(results):
passed = sum(1 for r in results if r[1])
failed = [r for r in results if not r[1]]
out = "%s: %d/%d passed" % (results[0][0] if False else "", passed, len(results))
return passed, failed, out
def run_suites(suites):
"""Run many suites; return dict {suite: results} and overall verdict."""
flat = []
all_pass = True
for suite in suites:
results = suite.run()
flat.append((suite.name, results))
for name, ok, detail, _t in results:
if not ok:
all_pass = False
return flat, all_pass
def print_results(flat):
for sname, results in flat:
passed = sum(1 for r in results if r[1])
print("[%s] %d/%d passed" % (sname, passed, len(results)))
for name, ok, detail, t in results:
if not ok:
print(" FAIL %s :: %s" % (name, detail))
def assert_ok(result, label):
ok, detail = result
if not ok:
raise AssertionError("%s: %s" % (label, detail))
return ok