98 lines
3.6 KiB
Python
98 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Verify the UN member-states extraction artifact.
|
|
|
|
Exit code 0 = correct, 1 = any check failed.
|
|
Pure assertions on the artifacts; no network, no external data.
|
|
"""
|
|
import csv
|
|
import json
|
|
import sys
|
|
from datetime import datetime
|
|
|
|
OUT = "/root/.hermes/wizard-outputs/ledger"
|
|
csv_path = f"{OUT}/un_member_states.csv"
|
|
json_path = f"{OUT}/un_member_states.json"
|
|
|
|
failures = []
|
|
|
|
|
|
def check(name, cond, msg=None):
|
|
if not cond:
|
|
failures.append((name, msg or ""))
|
|
|
|
|
|
def parse_date(s):
|
|
return datetime.strptime(s.strip(), "%d %B %Y")
|
|
|
|
|
|
# --- CSV -------------------------------------------------------------------
|
|
with open(csv_path, encoding="utf-8", newline="") as fh:
|
|
reader = csv.DictReader(fh)
|
|
rows = list(reader)
|
|
headers = reader.fieldnames
|
|
|
|
check("csv.exists", True)
|
|
check("csv.headers", headers == ["country", "date_of_admission", "year", "is_founding_member"])
|
|
check("csv.rowcount", len(rows) == 193, f"got {len(rows)} rows, expected 193")
|
|
check("csv.no_empty_cells", all(
|
|
r.get("country", "").strip() and r.get("date_of_admission", "").strip() for r in rows
|
|
))
|
|
|
|
# rows are chronologically sorted (verified below); first is a 1945 admission,
|
|
# last is the 2011 admission.
|
|
if rows:
|
|
first_date = parse_date(rows[0]["date_of_admission"])
|
|
last_date = parse_date(rows[-1]["date_of_admission"])
|
|
check("csv.first_year", first_date.year == 1945, rows[0]["date_of_admission"])
|
|
check("csv.last_year", last_date.year == 2011, rows[-1]["date_of_admission"])
|
|
|
|
# chronological order + date/year/founding consistency
|
|
prev = None
|
|
for r in rows:
|
|
d = parse_date(r["date_of_admission"])
|
|
y = d.year
|
|
check("csv.year.match." + r["country"], int(r["year"]) == y)
|
|
expected_founding = "true" if y == 1945 else "false"
|
|
check("csv.founding.match." + r["country"],
|
|
r["is_founding_member"].strip().lower() == expected_founding)
|
|
if prev is not None:
|
|
check("csv.sorted." + r["country"], d >= prev)
|
|
prev = d
|
|
|
|
# --- JSON ------------------------------------------------------------------
|
|
with open(json_path, encoding="utf-8") as fh:
|
|
jrows = json.load(fh)
|
|
check("json.exists", True)
|
|
check("json.rowcount", len(jrows) == 193)
|
|
check("json.keys", all(list(r.keys()) == ["country", "date_of_admission", "year", "is_founding_member"] for r in jrows))
|
|
|
|
canonical = []
|
|
for r in rows:
|
|
d = parse_date(r["date_of_admission"])
|
|
canonical.append({
|
|
"country": r["country"],
|
|
"date_of_admission": r["date_of_admission"],
|
|
"year": d.year,
|
|
"is_founding_member": r["is_founding_member"].strip().lower() == "true",
|
|
})
|
|
check("json.match_csv", jrows == canonical)
|
|
|
|
# --- Cross-check -----------------------------------------------------------
|
|
check("csv.founding_count", sum(1 for r in rows if r["is_founding_member"].strip().lower() == "true") == 49,
|
|
"expected 49 founding members (admitted 1945)")
|
|
|
|
# presence spot-checks
|
|
by_country = {r["country"]: r for r in rows}
|
|
check("csv.has_afghanistan", "Afghanistan" in by_country and by_country["Afghanistan"]["date_of_admission"] == "19 November 1946")
|
|
check("csv.has_zimbabwe", "Zimbabwe" in by_country and by_country["Zimbabwe"]["date_of_admission"] == "25 August 1980")
|
|
|
|
print("member_states:", len(rows))
|
|
print("founding_1945:", sum(1 for r in rows if r["is_founding_member"].strip().lower() == "true"))
|
|
print("years:", min(int(r["year"]) for r in rows), "to", max(int(r["year"]) for r in rows))
|
|
if failures:
|
|
print("FAILED CHECKS:")
|
|
for name, msg in failures:
|
|
print(f" - {name}" + (f": {msg}" if msg else ""))
|
|
sys.exit(1)
|
|
print("ALL CHECKS PASSED")
|