Files
Jyotisha/tests/run_golden_cases.py
T
2026-06-03 14:58:51 +08:00

90 lines
3.3 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Golden case regression runner for Jyotish full-reading output contracts."""
from __future__ import annotations
import argparse
import json
import os
import subprocess
import sys
from typing import Any, Dict, List
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ENGINE = os.path.join(ROOT_DIR, "scripts", "jyotish_engine.py")
DEFAULT_CASES = os.path.join(ROOT_DIR, "tests", "golden", "golden_cases.json")
def get_path(data: Dict[str, Any], dotted_path: str) -> Any:
cur: Any = data
for part in dotted_path.split("."):
if not isinstance(cur, dict) or part not in cur:
raise KeyError(dotted_path)
cur = cur[part]
return cur
def run_full_reading(py: str, case: Dict[str, Any]) -> Dict[str, Any]:
inp = case["input"]
cmd = [
py,
ENGINE,
"full-reading",
"--year", str(inp["year"]),
"--month", str(inp["month"]),
"--day", str(inp["day"]),
"--hour", str(inp["hour"]),
"--minute", str(inp["minute"]),
"--lat", str(inp["lat"]),
"--lon", str(inp["lon"]),
"--tz", str(inp["tz"]),
]
if inp.get("today"):
cmd.extend(["--today", inp["today"]])
out = subprocess.check_output(cmd, text=True)
return json.loads(out)
def run_cases(py: str, cases_path: str) -> Dict[str, Any]:
with open(cases_path, "r", encoding="utf-8") as f:
suite = json.load(f)
results: List[Dict[str, Any]] = []
for case in suite.get("cases", []):
case_result = {"id": case.get("id"), "passed": True, "failures": []}
try:
data = run_full_reading(py, case)
errors = data.get("errors", [])
if len(errors) > case.get("max_errors", 0):
case_result["passed"] = False
case_result["failures"].append(f"too many errors: {len(errors)} > {case.get('max_errors', 0)}; {errors[:5]}")
for path in case.get("expected_output_paths", []):
try:
value = get_path(data, path)
if value is None or value == {} or value == []:
case_result["passed"] = False
case_result["failures"].append(f"empty output path: {path}")
except KeyError:
case_result["passed"] = False
case_result["failures"].append(f"missing output path: {path}")
except Exception as exc:
case_result["passed"] = False
case_result["failures"].append(str(exc))
results.append(case_result)
failed = [r for r in results if not r["passed"]]
return {"valid": len(failed) == 0, "total": len(results), "failed": len(failed), "results": results}
def main() -> int:
parser = argparse.ArgumentParser(description="Run Jyotish golden case regressions")
parser.add_argument("--python", default=sys.executable, help="Python executable used to run jyotish_engine.py")
parser.add_argument("--cases", default=DEFAULT_CASES, help="Path to golden_cases.json")
args = parser.parse_args()
result = run_cases(args.python, args.cases)
print(json.dumps(result, ensure_ascii=False, indent=2))
return 0 if result["valid"] else 1
if __name__ == "__main__":
raise SystemExit(main())