arm-scan-gateway/api/tests/unit/normalizer/test_contract_boundary.py

89 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Граница «пакет arm_statements → модели контракта шлюза»: `dict` пакета проходит модели и схему v2.0.
Правила перевода проверяет пакет; здесь — что его результат принимают модели шлюза и JSON Schema `result`.
"""
import json
import uuid
import pytest
import src.normalizer.ocr as ocr_module
from arm_statements import WarningCode, default_rules, make_warning, warning_to_contract
from src.contract import ErrorCode, FileWarning, ServiceInfo, ServiceName
from src.core.worker import build_result
from src.normalizer import NullNormalizer, OcrNormalizer
from tests.unit.normalizer.ocr_builders import BAD, BALANCE, INCOME, merged, ocr_table, response
from tests.unit.test_contract import VALIDATORS
SERVICE = ServiceInfo(name=ServiceName.SCAN_GATEWAY, version="test")
def test_mapped_document_passes_schema_v2() -> None:
outcome = OcrNormalizer(default_rules(), version="abc1234").normalize(
merged(
(
"j.json",
response(
ocr_table("Бухгалтерский баланс", BALANCE), ocr_table("Отчет о финансовых результатах", INCOME)
),
)
)
)
result = build_result(
outcome, job_id=uuid.uuid4(), file_id=uuid.uuid4(), service=SERVICE, raw_s3_key="raw/x.json", metrics=None
)
payload = result.to_wire()
VALIDATORS["result"].validate(payload)
assert payload["schema_version"] == "2.0" and payload["service"]["statements_version"] == "abc1234"
head = payload["documents"][0]["header"]
assert (head["form_name"], head["inn"], head["inn_text"], head["inn_confidence"]) == (
"Бухгалтерский баланс",
"7700000000",
"7700000000",
100.0,
)
assert "column_key" not in json.dumps(payload)
def test_package_warning_fits_file_warning_model() -> None:
w = make_warning(WarningCode.ROW_SPLIT, "разлеплено", default_rules(), line_refs=("row:3#1", "row:3#2"))
assert FileWarning.model_validate(warning_to_contract(w, file_level=True)).to_wire() == {
"code": "ROW_SPLIT",
"severity": "info",
"message": "разлеплено",
"line_refs": ["row:3#1", "row:3#2"],
}
def test_empty_target_relation_passes_model() -> None:
rows = [
("Наименование показателя", "Код", "На 31 декабря 2024 г."),
("Запасы", "1210", "60"),
("Итого II", "1200", "60"),
]
outcome = OcrNormalizer(default_rules(), version="abc1234").normalize(
merged(("j.json", response(ocr_table("Бухгалтерский баланс", rows))))
)
failed = outcome.documents[0].checks.relations_failed # type: ignore[union-attr]
assert any(f.relation == "1600 = 1100 + 1200" and f.expected is None for f in failed)
def test_null_normalizer_structured_json_failed() -> None:
outcome = NullNormalizer().normalize(merged(("j.json", response()), ("j_ofr.json", response(error=BAD))))
assert outcome.error is not None and outcome.error.code is ErrorCode.NOT_IMPLEMENTED
assert [w.to_wire() for w in outcome.warnings] == [
{
"code": "JSON_FAILED",
"severity": "error",
"message": "INVALID_DOCUMENT: Не удалось определить тип документа.",
"locator": "file:j_ofr.json",
}
]
def test_normalizer_requires_statements_version(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(ocr_module, "statements_version", lambda path=None: None)
with pytest.raises(ValueError, match="без VERSION"):
OcrNormalizer(default_rules())