SFM/tests/unit/test_parser.py
2026-06-22 07:25:27 +03:00

85 lines
3.3 KiB
Python

from __future__ import annotations
from app.pipeline.parser import parse_xml_content
def _base_xml(operations: str) -> str:
return f"""<?xml version="1.0" encoding="UTF-8"?>
<СообщОперКО xmlns="urn:test">
<СлужЧасть><ИдФайл>ID1</ИдФайл></СлужЧасть>
<ИнформЧасть>
<ИнфБанк><БИК>123</БИК></ИнфБанк>
<СведКО>
{operations}
</СведКО>
</ИнформЧасть>
</СообщОперКО>
"""
def test_parse_xml_with_invalid_name_returns_fatal() -> None:
result = parse_xml_content("broken.xml", "<СообщОперКО/>")
assert result.is_fatal
assert "Некорректное имя файла" in (result.fatal_error or "")
def test_parse_xml_with_malformed_xml_returns_fatal() -> None:
result = parse_xml_content("SKO115FZ_01_123456789_20260616_X00001.xml", "<broken")
assert result.is_fatal
assert "Ошибка XML" in (result.fatal_error or "")
def test_parse_xml_without_inform_part_returns_fatal() -> None:
xml = """<?xml version="1.0" encoding="UTF-8"?><СообщОперКО></СообщОперКО>"""
result = parse_xml_content("SKO115FZ_01_123456789_20260616_X00001.xml", xml)
assert result.is_fatal
assert "ИнформЧасть" in (result.fatal_error or "")
def test_parse_xml_without_participants_creates_single_row() -> None:
xml = _base_xml(
"<Операция><ИдентификаторЗаписи>OP1</ИдентификаторЗаписи><СуммаОпер>100</СуммаОпер></Операция>"
)
result = parse_xml_content("SKO115FZ_01_123456789_20260616_X00001.xml", xml)
assert not result.is_fatal
assert len(result.rows) == 1
assert result.rows[0].record_id == "OP1"
def test_parse_xml_with_namespace_and_two_participants() -> None:
xml = _base_xml(
"""
<Операция>
<ИдентификаторЗаписи>OP2</ИдентификаторЗаписи>
<УчастникОп><Тип>01</Тип></УчастникОп>
<УчастникОп><Тип>02</Тип></УчастникОп>
</Операция>
"""
)
result = parse_xml_content("SKO115FZ_01_123456789_20260616_X00001.xml", xml)
assert not result.is_fatal
assert len(result.rows) == 2
assert result.rows[0].participant_fields["Тип"] == "01"
assert result.rows[1].participant_fields["Тип"] == "02"
def test_parse_xml_operation_error_marks_partial(monkeypatch) -> None:
xml = _base_xml(
"<Операция><ИдентификаторЗаписи>OP3</ИдентификаторЗаписи><УчастникОп><Тип>01</Тип></УчастникОп></Операция>"
)
from app.pipeline import parser
original = parser._extract_direct_fields
def _boom(element, excluded_tags=None): # noqa: ANN001
tag_name = parser._normalize_tag(element.tag)
if tag_name == "УчастникОп":
raise ValueError("bad participant")
return original(element, excluded_tags=excluded_tags)
monkeypatch.setattr(parser, "_extract_direct_fields", _boom)
result = parse_xml_content("SKO115FZ_01_123456789_20260616_X00001.xml", xml)
assert not result.is_fatal
assert result.operation_errors
assert result.operation_errors[0].record_id == "OP3"