BL / tests /test_eval.py
youssefboutaleb's picture
Implement OCR pipeline enhancements: Pydantic schemas, validation gate, retry, and evaluation harness (excluding images)
497c3ef
Raw History Blame Contribute Delete
2.27 kB
from __future__ import annotations
import json
from pathlib import Path
from bl_ocr.domain.schema_validation import build_validator
from bl_ocr.eval.harness import evaluate_annotation, evaluate_directory
PROJECT_ROOT = Path(__file__).resolve().parents[1]
SCHEMA_PATH = PROJECT_ROOT / "schema.json"
def _validator():
return build_validator(json.loads(SCHEMA_PATH.read_text(encoding="utf-8")))
def _example() -> dict:
return json.loads((PROJECT_ROOT / "example.json").read_text(encoding="utf-8"))
def test_clean_example_passes_all_structural_checks():
result = evaluate_annotation("example", _example(), _validator())
assert result.parse_pass
assert result.schema_pass
assert result.schema_error_count == 0
assert result.row_count_pass
assert result.arithmetic_pass
assert not result.critical
def test_row_count_mismatch_is_flagged():
annotation = _example()
annotation["totals"]["line_count"]["value"] = 99
result = evaluate_annotation("mismatch", annotation, _validator())
assert not result.row_count_pass
def test_empty_products_with_line_count_is_critical():
annotation = _example()
annotation["products"] = []
result = evaluate_annotation("empty", annotation, _validator())
assert result.critical
assert result.critical_reason is not None
def test_none_annotation_fails_parse():
result = evaluate_annotation("broken", None, _validator(), parse_error="bad json")
assert not result.parse_pass
assert result.parse_error == "bad json"
def test_evaluate_directory_aggregates(tmp_path: Path):
# one clean file, one schema-invalid file (extra key)
clean = _example()
(tmp_path / "clean.json").write_text(
json.dumps({"document_annotation": json.dumps(clean)}), encoding="utf-8"
)
dirty = _example()
dirty["products"][0]["_repaired"] = "leak"
(tmp_path / "dirty.json").write_text(
json.dumps({"document_annotation": json.dumps(dirty)}), encoding="utf-8"
)
summary = evaluate_directory(tmp_path, SCHEMA_PATH)
assert summary.total == 2
assert summary.parse_pass == 2
assert summary.schema_pass == 1
data = summary.as_dict()
assert data["rates"]["schema_pass"] == 0.5
assert len(data["files"]) == 2