mirror of
https://git.pumpin.online/funkpower/typikon.git
synced 2026-10-22 18:57:13 +00:00
There is one engine and nine doors into it, and nothing until now checked that the doors agree. CI tested each binding against itself: the Python wheel imported, the C demo compiled, the npm package type-checked. None of that would have caught a field that crosses one boundary wrong, which is the failure this library is most exposed to, because a wrong answer about a fast day looks exactly like a right one. So: twelve days, chosen where the bindings could plausibly differ, and all twenty-two fields compared against what the command line says. The days are Pascha itself, the Nativity on both calendars, a Wednesday of the Great Fast under Byzantine Catholic law and again at the Typikon, a weekday of the Nativity Fast where Greek and Slavic usage part, the one Orthodox church on the Gregorian Paschalion, and a day with no feast. A release now runs what a push runs. It had been gated on cargo test alone, so the C ABI, the Lua binding, the Python parity check and the README examples were checked on the branch that led to a release and not on the release. Neither registry will reuse a version, so the gate belongs before the upload. Writing it found three things. The npm exports map did not expose the wasm by package path, so a bundler asked for typikon/web/typikon_bg.wasm was told no such path exists and had to reach into node_modules; the documented init() call was never affected. The suite could hang instead of fail, because the test web server was backgrounded inside a subshell and killed by job spec, leaving bash in do_wait forever. And pointing XDG_CONFIG_HOME at a path that does not exist isolates typikon and breaks every other program that keeps state under it, a browser included. A surface whose toolchain is missing is named as skipped, and fewer than three surfaces running is a failure rather than a pass, so a container with nothing installed cannot come out green.
30 lines
1008 B
Python
30 lines
1008 B
Python
"""One surface's answers against the oracle's.
|
|
|
|
A surface need not expose every field; it must not disagree about one it does.
|
|
"""
|
|
import json
|
|
import sys
|
|
|
|
name, oracle_path, got_path = sys.argv[1:4]
|
|
oracle = json.load(open(oracle_path))
|
|
got = json.load(open(got_path))
|
|
|
|
bad = []
|
|
for key in sorted(set(oracle) - set(got)):
|
|
bad.append(f"missing probe {key}")
|
|
for key in sorted(set(got) - set(oracle)):
|
|
bad.append(f"unexpected probe {key}")
|
|
for key in sorted(set(oracle) & set(got)):
|
|
for field, expected in sorted(oracle[key].items()):
|
|
if field in got[key] and got[key][field] != expected:
|
|
bad.append(f"{key} {field}: {got[key][field]!r} != {expected!r}")
|
|
|
|
fields = sorted({f for v in got.values() for f in v})
|
|
for line in bad[:20]:
|
|
print(f" {line}")
|
|
if len(bad) > 20:
|
|
print(f" ... and {len(bad) - 20} more")
|
|
print(f" {'ok ' if not bad else 'FAIL'} {name}: "
|
|
f"{len(got)} probes, {len(fields)} fields, {len(bad)} differences")
|
|
sys.exit(1 if bad else 0)
|