93 lines
2.8 KiB
Python
Executable File
93 lines
2.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Independent verification of checkin-inventory.csv.
|
|
|
|
Two independent implementations of the same extraction spec:
|
|
build : os.listdir() + open/read + re.match() + str.count()
|
|
verify: os.scandir() + Path.read_text() + re.fullmatch() + str.count()
|
|
|
|
Exits 0 only if the CSV's rows equal a fresh recomputation from the source files.
|
|
"""
|
|
import os
|
|
import re
|
|
import sys
|
|
import csv
|
|
|
|
SRC = "/root/troupe-standup/checkins"
|
|
CSV_PATH = "/root/troupe-standup/wizard-work/ledger/checkin-inventory.csv"
|
|
PAT = re.compile(r"^(\d{4}-\d{2}-\d{2})-(.+)$")
|
|
FIELDS = ["date", "wizard", "filename", "n_lines", "n_did", "n_blocked", "n_next", "n_ask"]
|
|
|
|
|
|
def build_expected():
|
|
rows = []
|
|
with os.scandir(SRC) as it:
|
|
for entry in it:
|
|
if not entry.is_file():
|
|
continue
|
|
name = entry.name
|
|
if not name.endswith(".md"):
|
|
continue
|
|
m = PAT.fullmatch(name)
|
|
if not m:
|
|
continue
|
|
date, wizard = m.group(1), m.group(2)
|
|
with open(entry.path, encoding="utf-8", errors="replace") as fh:
|
|
data = fh.read()
|
|
rows.append((date, wizard, name, data.count("\n"),
|
|
data.count("Did"), data.count("Blocked"),
|
|
data.count("Next"), data.count("Ask")))
|
|
rows.sort(key=lambda r: (r[0], r[1]))
|
|
return rows
|
|
|
|
|
|
|
|
|
|
|
|
def _norm(row):
|
|
d = dict(row)
|
|
for k in ("n_lines", "n_did", "n_blocked", "n_next", "n_ask"):
|
|
d[k] = int(d[k])
|
|
return tuple(d[h] for h in FIELDS)
|
|
|
|
|
|
def read_csv():
|
|
with open(CSV_PATH, newline="", encoding="utf-8") as fh:
|
|
reader = csv.DictReader(fh)
|
|
assert reader.fieldnames == FIELDS, f"header mismatch: {reader.fieldnames}"
|
|
return [_norm(r) for r in reader]
|
|
|
|
|
|
def main():
|
|
ok = True
|
|
try:
|
|
expected = build_expected()
|
|
actual = read_csv()
|
|
except Exception as exc: # noqa: BLE001
|
|
print("FAIL: could not load source or artifact:", exc)
|
|
return 1
|
|
|
|
if len(expected) != len(actual):
|
|
ok = False
|
|
print(f"FAIL: row count mismatch: expected {len(expected)}, actual {len(actual)}")
|
|
|
|
diff = 0
|
|
for i in range(max(len(expected), len(actual))):
|
|
exp = expected[i] if i < len(expected) else None
|
|
act = actual[i] if i < len(actual) else None
|
|
if exp != act:
|
|
ok = False
|
|
diff += 1
|
|
print(f"FAIL row {i + 1}: expected={exp} actual={act}")
|
|
|
|
if ok:
|
|
print(f"PASS: {len(actual)} check-in rows match the source files "
|
|
f"({len(set(r[0] for r in actual))} distinct dates, "
|
|
f"{sorted(set(r[1] for r in actual))})")
|
|
else:
|
|
print(f"FAIL: {diff} differing rows")
|
|
return 0 if ok else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|