"""Граница «пакет arm_statements → модели контракта шлюза»: `dict` пакета проходит модели и схему v2.0. Правила перевода проверяет пакет; здесь — что его результат принимают модели шлюза и JSON Schema `result`. """ import json import uuid import pytest from arm_statements import WarningCode, default_rules, make_warning, warning_to_contract import src.normalizer.ocr as ocr_module 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="не определена версия библиотеки.*make install"): OcrNormalizer(default_rules())