Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W
89 lines
3.7 KiB
Python
89 lines
3.7 KiB
Python
"""Граница «пакет 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())
|