94 lines
3.7 KiB
Python
94 lines
3.7 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 "Некорректное имя XML-файла" 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"
|
|
|
|
|
|
def test_parse_xml_with_numeric_suffix_file_name_is_valid() -> None:
|
|
xml = _base_xml(
|
|
"<Операция><ИдентификаторЗаписи>OP4</ИдентификаторЗаписи><СуммаОпер>100</СуммаОпер></Операция>"
|
|
)
|
|
result = parse_xml_content("SKO115FZ_01_044525111_20251224_000051.xml", xml)
|
|
assert not result.is_fatal
|
|
assert len(result.rows) == 1
|