arm-tabular-parser/api/tests/fixtures/test_statements_property.py
2026-10-18 21:41:54 +04:00

84 lines
4.4 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.

"""Инварианты форм на всех `../fixtures/statements-xlsx/**` по манифесту (spec «Словари форм, координаты, golden»)."""
import time
from pathlib import Path
from typing import cast
import pytest
from fixtures_helpers import statement_files
from result_contract import assert_valid_result
from statement_helpers import load_manifest, relative_key
from src.contract import FileType, ResultStatus, StatementDocument
from src.parser import get_parser
pytestmark = pytest.mark.fixtures
EXPECTED_FILES = 18
MAX_PARSE_SECONDS = 5
def explained_needs_check(document: StatementDocument) -> bool:
"""Причина needs_check видна в результате: предупреждение error, нарушенное соотношение, пометка проверки
у строки, значения или шапки, нечитаемая или пропущенная строка."""
checks = document.checks
return bool(
any(warning.severity == "error" for warning in document.warnings)
or (checks is not None and checks.relations_failed)
or document.header.needs_review_fields
or any(
line.needs_review
or line.line_status in ("unreadable", "missing")
or any(value.needs_review for value in line.values)
for line in document.lines
)
)
def test_manifest_covers_every_file(fixtures_dir: Path) -> None:
files = statement_files(fixtures_dir)
assert len(files) == EXPECTED_FILES
assert {relative_key(fixtures_dir, path) for path in files} == set(load_manifest())
def test_statement_file_matches_manifest(fixtures_dir: Path, statement_file: Path) -> None:
expectation = load_manifest()[relative_key(fixtures_dir, statement_file)]
started = time.monotonic()
file_type = cast(FileType, statement_file.suffix.lstrip(".").upper())
outcome = get_parser().parse(statement_file.read_bytes(), file_type)
assert time.monotonic() - started < MAX_PARSE_SECONDS
assert outcome.error is None, outcome.error
documents = [document for document in outcome.documents if isinstance(document, StatementDocument)]
assert [document.document_type for document in documents] == [item.type for item in expectation.documents]
all_done = all(item.status == "done" for item in expectation.documents)
assert outcome.status is (ResultStatus.DONE if all_done else ResultStatus.NEEDS_CHECK)
for document, item in zip(documents, expectation.documents, strict=True):
# повторы кодов строк законны (v2.0); ссылки на строки уникальны, значения ссылаются на колонки документа
refs = [line.ref for line in document.lines]
assert len(refs) == len(set(refs)), "ref уникальны"
column_indexes = {column.column_index for column in document.columns}
assert all(value.column_index in column_indexes for line in document.lines for value in line.values)
if item.sheets:
assert document.locator.count(",") == item.sheets - 1
failed = {relation.relation for relation in document.checks.relations_failed} if document.checks else set()
if item.failed_relations is not None:
assert failed == set(item.failed_relations)
if item.error_warnings is not None:
errors = {warning.code for warning in document.warnings if warning.severity == "error"}
assert errors == set(item.error_warnings)
if item.complete:
assert document.checks is not None
assert document.checks.relations_failed == [], document.checks
assert document.columns
assert all(column.period_date is not None for column in document.columns)
assert document.status == item.status, (item, document.header)
if item.status == "needs_check":
assert explained_needs_check(document), "needs_check должен объясняться полями результата"
if expectation.organization:
assert document.header.organization_name == expectation.organization
if expectation.inn:
if document.document_type in expectation.inn_optional_for:
assert document.header.inn in {None, expectation.inn}
else:
assert document.header.inn == expectation.inn
assert_valid_result(outcome)