98 lines
3.2 KiB
Python
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)")
|