"""Unit tests for the deterministic regex prescreen extractor.""" from __future__ import annotations import pytest from contract_check.worker_prescreen.extractor import extract_contract_meta SIMPLE_SUPPLY = """\ ДОГОВОР ПОСТАВКИ № 42 г. Москва Общество с ограниченной ответственностью «Продавец», именуемое в дальнейшем «Поставщик», в лице директора Иванова И.И., с одной стороны, и Общество с ограниченной ответственностью «Покупатель», именуемое в дальнейшем «Покупатель», с другой стороны, заключили настоящий договор о нижеследующем. 1. Предмет договора Поставщик обязуется передать в собственность Покупателю товар. 2. Цена и порядок расчётов 2.1. Общая стоимость товара составляет 1 250 000 (один миллион двести пятьдесят тысяч) рублей. 3. Срок действия договора 3.1. Настоящий договор вступает в силу с 01.09.2025 и действует по 31.08.2026. 4. Ответственность сторон 4.1. За просрочку поставки Поставщик уплачивает неустойку в размере 0,1% от стоимости. 5. Порядок разрешения споров 5.1. Споры подлежат рассмотрению в Арбитражном суде г. Москвы. """ MINIMAL = """\ Договор оказания услуг между ИП Петров Петр Петрович и ООО «Клиент». Стоимость услуг составляет 50 000 рублей. """ def test_supply_extraction() -> None: meta = extract_contract_meta(SIMPLE_SUPPLY) assert meta.contract_type == "supply" assert "Продавец" in (meta.party_a or "") assert "Покупатель" in (meta.party_b or "") assert meta.total_amount == 1250000.0 assert meta.currency == "RUB" assert meta.start_date == "2025-09-01" assert meta.end_date == "2026-08-31" assert meta.has_penalty_clause is True assert meta.has_termination_clause is False assert meta.has_arbitration is True assert meta.confidence_score > 0.6 def test_minimal_extraction() -> None: meta = extract_contract_meta(MINIMAL) assert meta.contract_type == "services" assert "ИП Петров" in (meta.party_a or "") assert "ООО «Клиент»" in (meta.party_b or "") assert meta.total_amount == 50000.0 assert meta.currency == "RUB" def test_confidence_score_bounds() -> None: meta = extract_contract_meta("") assert meta.confidence_score == 0.0 assert 0.0 <= meta.confidence_score <= 1.0 def test_party_extraction_handles_whitespace() -> None: text = "Договор между ООО «Альфа» и ООО «Бета»" meta = extract_contract_meta(text) assert "Альфа" in (meta.party_a or "") assert "Бета" in (meta.party_b or "") @pytest.mark.parametrize( ("clause", "expected"), [ ("Стороны вправе расторгнуть договор в одностороннем порядке", "has_termination_clause"), ("В случае нарушения Покупатель уплачивает штраф", "has_penalty_clause"), ("Споры рассматриваются в Арбитражном суде", "has_arbitration"), ], ) def test_boolean_flags(clause: str, expected: str) -> None: meta = extract_contract_meta(f"Договор поставки. {clause}.") assert getattr(meta, expected) is True def test_shim_defaults_to_heuristic_v2() -> None: meta = extract_contract_meta(SIMPLE_SUPPLY) assert meta.confidence_score > 0.6 def test_keep_regex_flag_routes_to_regex_v1(monkeypatch: pytest.MonkeyPatch) -> None: """PRESCREEN_KEEP_REGEX=true keeps the legacy regex path alive (plan §5).""" from contract_check.worker_prescreen.extractor import _extract_contract_meta_regex monkeypatch.setenv("PRESCREEN_KEEP_REGEX", "true") meta = extract_contract_meta(SIMPLE_SUPPLY) legacy = _extract_contract_meta_regex(SIMPLE_SUPPLY.replace("\n", " ")) # Identical extraction semantics on the ported fixtures. assert meta.model_dump() == legacy.model_dump() monkeypatch.setenv("PRESCREEN_KEEP_REGEX", "false") assert extract_contract_meta(SIMPLE_SUPPLY).model_dump() == meta.model_dump()