Files
typikon/tests/readme-examples.py
funkpower d4750ca814 the README examples must not depend on a fetched menaion
The checker isolated XDG_CONFIG_HOME and not XDG_DATA_HOME, so the two
Ruthenian examples were verified against the MCI menaion this machine has
fetched and CI does not. They passed here and failed there, which is the
checker working: a reader running them after a fresh install gets the common
menologion, and that is what the README now shows.

Both examples still make their point. The commemorations are worded
differently; the fast, the obligations and the contrast between them are
identical either way.
2026-09-18 14:03:46 -04:00

89 lines
3.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""Run every console example in the README and diff it against the real output.
A README whose examples have quietly stopped being true is worse than one with
no examples in it, and the output of this program changes shape often enough
that hand-checking does not hold. Every ```console block whose single command
is `typikon ...` is executed and compared line for line.
tests/readme-examples.py # against ./target/release/typikon
TYPIKON=/usr/bin/typikon tests/readme-examples.py
A block ending in a horizontal ellipsis is treated as a prefix, for listings
too long to paste whole.
"""
import difflib
import os
import re
import shlex
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
BINARY = os.environ.get("TYPIKON") or str(ROOT / "target" / "release" / "typikon")
def commands_and_body(block):
"""Split a console block into its commands and its expected output,
joining backslash continuations."""
out, buf = [], ""
for line in block.rstrip("\n").split("\n"):
if buf:
buf += " " + line.strip().rstrip("\\ ")
if not line.rstrip().endswith("\\"):
out.append("$ " + buf)
buf = ""
continue
if line.startswith("$ ") and line.rstrip().endswith("\\"):
buf = line[2:].rstrip("\\ ")
else:
out.append(line)
if buf:
out.append("$ " + buf)
cmds = [l[2:] for l in out if l.startswith("$ ")]
body = "\n".join(l for l in out if not l.startswith("$ ")).strip("\n")
return cmds, body
def main():
if not Path(BINARY).exists():
print(f" {BINARY} not built; run cargo build --release", file=sys.stderr)
return 77
env = dict(os.environ, COLUMNS="88")
# The examples must not depend on whatever this machine remembers, nor on
# a menaion this machine happens to have fetched. A reader running them
# after a fresh install has neither, and the README should show what they
# get: without this the Ruthenian examples passed here and failed in CI.
env.pop("TYPIKON_JURISDICTION", None)
env["XDG_CONFIG_HOME"] = str(ROOT / "target" / "readme-config")
env["XDG_DATA_HOME"] = str(ROOT / "target" / "readme-data")
text = (ROOT / "README.md").read_text(encoding="utf-8")
checked = bad = skipped = 0
for block in re.findall(r"```console\n(.*?)```", text, re.S):
cmds, expected = commands_and_body(block)
if len(cmds) != 1 or not cmds[0].startswith("typikon") or not expected:
skipped += 1
continue
argv = [BINARY] + shlex.split(cmds[0])[1:]
got = subprocess.run(argv, capture_output=True, text=True, env=env).stdout.strip("\n")
checked += 1
if expected.rstrip().endswith("…"):
ok = got.startswith(expected.rstrip()[:-1].rstrip("\n"))
else:
ok = got == expected
if not ok:
bad += 1
print(f" MISMATCH {cmds[0]}")
for line in difflib.unified_diff(
expected.split("\n"), got.split("\n"), "README", "actual", lineterm=""
):
print(" ", line)
print(f"\n {checked} README examples run, {bad} mismatched, {skipped} not executable")
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main())