Files
ai-agent-admin/backend-fastapi/online_dev/report_manager/engine/test_golden.py
T

98 lines
3.2 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Golden Test:用 JSON fixture 回归报表 transform 流水线关键输出。
后续可追加 JNPF 导出的样例 fixture 做对比。
"""
from __future__ import annotations
import json
import math
from pathlib import Path
from typing import Any, Dict, List
from online_dev.report_manager.engine.convert import transform
from online_dev.report_manager.engine.dataset_transform import transform_dataset_rows
_FIXTURES_DIR = Path(__file__).parent / "fixtures"
def _load_fixture(name: str) -> dict:
path = _FIXTURES_DIR / name
with open(path, encoding="utf-8") as f:
return json.load(f)
def _cell_v(snapshot: dict, sheet_id: str, row: int, col: int) -> str:
sheet = (snapshot.get("sheets") or {}).get(sheet_id) or {}
cell = (sheet.get("cellData") or {}).get(str(row), {}).get(str(col), {})
v = cell.get("v")
return "" if v is None else str(v)
def _prepare_datasets(fixture: dict) -> Dict[str, List[Any]]:
raw = fixture.get("datasets") or {}
field_mapping_root = fixture.get("field_mapping") or {}
version_convert = fixture.get("convert_config")
out: Dict[str, List[Any]] = {}
for alias, rows in raw.items():
mapping = field_mapping_root.get(alias) if isinstance(field_mapping_root, dict) else field_mapping_root
out[alias] = transform_dataset_rows(
rows,
field_mapping=mapping,
version_convert=version_convert,
alias=alias,
)
return out
def _values_match(expected: Any, actual: str, *, tolerance: float = 1e-6) -> bool:
if expected == actual:
return True
try:
exp_f = float(expected)
act_f = float(actual)
return math.isclose(exp_f, act_f, rel_tol=tolerance, abs_tol=tolerance)
except (TypeError, ValueError):
return False
def _run_golden_fixture(fixture: dict) -> None:
datasets = _prepare_datasets(fixture)
out = transform(
fixture["snapshot"],
fixture.get("cells") or {},
datasets,
fixture.get("params") or {},
column_list=fixture.get("column_list"),
fence_list=fixture.get("fence_list"),
)
failures: List[str] = []
for sheet_id, cells in (fixture.get("expect") or {}).items():
for addr, expected in cells.items():
row_s, col_s = addr.split(",", 1)
actual = _cell_v(out, sheet_id, int(row_s), int(col_s))
exp_str = "" if expected is None else str(expected)
if not _values_match(exp_str, actual):
failures.append(
f" {sheet_id}!{addr}: expected {exp_str!r}, got {actual!r}"
)
if failures:
name = fixture.get("name") or "unnamed"
msg = f"{name} failed ({len(failures)} cell(s)):\n" + "\n".join(failures)
raise AssertionError(msg)
def test_golden_list_down():
_run_golden_fixture(_load_fixture("golden_list_down.json"))
def test_all_golden_fixtures():
for path in sorted(_FIXTURES_DIR.glob("golden_*.json")):
_run_golden_fixture(_load_fixture(path.name))
if __name__ == "__main__":
test_all_golden_fixtures()
print(f"ok ({len(list(_FIXTURES_DIR.glob('golden_*.json')))} fixtures)")