Co-authored-by: bot-backend <bot-backend@gendsgn.local> Co-committed-by: bot-backend <bot-backend@gendsgn.local>
181 lines
7 KiB
Python
181 lines
7 KiB
Python
"""Тесты granddoc_lookup (#1061) — read-side lookup граддокументации из planning_projects."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from datetime import date
|
||
from typing import Any
|
||
|
||
from sqlalchemy.exc import OperationalError, ProgrammingError
|
||
|
||
from app.services.site_finder.granddoc_lookup import parcel_granddoc
|
||
|
||
# ── Моки БД (аналог test_reservation_lookup.py) ────────────────────────────
|
||
|
||
|
||
class _Result:
|
||
def __init__(self, rows: list[dict[str, Any]]) -> None:
|
||
self._rows = rows
|
||
|
||
def mappings(self) -> _Result:
|
||
return self
|
||
|
||
def all(self) -> list[dict[str, Any]]:
|
||
return self._rows
|
||
|
||
|
||
class _FakeDB:
|
||
def __init__(
|
||
self,
|
||
rows: list[dict[str, Any]] | None = None,
|
||
raise_exc: Exception | None = None,
|
||
) -> None:
|
||
self._rows = rows or []
|
||
self._raise = raise_exc
|
||
|
||
def execute(self, sql: Any, params: dict[str, Any] | None = None) -> _Result:
|
||
if self._raise is not None:
|
||
raise self._raise
|
||
return _Result(self._rows)
|
||
|
||
|
||
# ── Фикстура строк ────────────────────────────────────────────────────────────
|
||
|
||
_ROW_PAGA = {
|
||
"project_type": "ppt",
|
||
"doc_status_name": "Действующий",
|
||
"full_name": "ПАГЕ № 2792 от 16.12.2021\nРеконструкция ул. Декабристов",
|
||
"doc_full_name": "Проект планировки территории ул. Декабристов",
|
||
}
|
||
|
||
_ROW_NO_PAGA = {
|
||
"project_type": "pmt",
|
||
"doc_status_name": "Недействующий",
|
||
"full_name": "Проект межевания без реквизитов ПАГЕ",
|
||
"doc_full_name": "ПМТ квартал 24",
|
||
}
|
||
|
||
_ROW_INACTIVE = {
|
||
"project_type": "ppt",
|
||
"doc_status_name": "Недействующий",
|
||
"full_name": "ПАГЕ № 111 от 01.03.2015\nПрежний проект",
|
||
"doc_full_name": "Старый ППТ",
|
||
}
|
||
|
||
_ROW_ACTIVE_NEWER = {
|
||
"project_type": "ppt",
|
||
"doc_status_name": "Действующий",
|
||
"full_name": "ПАГЕ № 3500 от 20.06.2023\nНовый квартал",
|
||
"doc_full_name": "ППТ 2023",
|
||
}
|
||
|
||
# ── Тесты: парсинг ПАГЕ ───────────────────────────────────────────────────────
|
||
|
||
|
||
def test_paga_number_and_date_parsed() -> None:
|
||
"""full_name с «ПАГЕ № 2792 от 16.12.2021» → paga_number='2792', paga_date=date(2021,12,16)."""
|
||
result = parcel_granddoc(_FakeDB([_ROW_PAGA]), "POINT(60 56)")
|
||
assert len(result) == 1
|
||
row = result[0]
|
||
assert row["paga_number"] == "2792"
|
||
assert row["paga_date"] == date(2021, 12, 16)
|
||
|
||
|
||
def test_paga_subject_extracted() -> None:
|
||
"""Предмет (текст после реквизитов ПАГЕ) извлекается как subject."""
|
||
result = parcel_granddoc(_FakeDB([_ROW_PAGA]), "POINT(60 56)")
|
||
assert result[0]["subject"] == "Реконструкция ул. Декабристов"
|
||
|
||
|
||
def test_is_active_true_for_dejstvuyushiy() -> None:
|
||
"""doc_status_name='Действующий' → is_active=True."""
|
||
result = parcel_granddoc(_FakeDB([_ROW_PAGA]), "POINT(60 56)")
|
||
assert result[0]["is_active"] is True
|
||
|
||
|
||
def test_is_active_false_for_nedejstvuyushiy() -> None:
|
||
"""doc_status_name='Недействующий' → is_active=False."""
|
||
result = parcel_granddoc(_FakeDB([_ROW_INACTIVE]), "POINT(60 56)")
|
||
assert result[0]["is_active"] is False
|
||
|
||
|
||
def test_no_paga_in_full_name_returns_none_graceful() -> None:
|
||
"""full_name без «ПАГЕ № …» → paga_number=None, paga_date=None, subject=None (graceful)."""
|
||
result = parcel_granddoc(_FakeDB([_ROW_NO_PAGA]), "POINT(60 56)")
|
||
assert len(result) == 1
|
||
row = result[0]
|
||
assert row["paga_number"] is None
|
||
assert row["paga_date"] is None
|
||
assert row["subject"] is None
|
||
|
||
|
||
def test_all_expected_keys_present() -> None:
|
||
"""Каждый элемент содержит все ожидаемые ключи."""
|
||
result = parcel_granddoc(_FakeDB([_ROW_PAGA, _ROW_NO_PAGA]), "POINT(60 56)")
|
||
expected = {
|
||
"project_type",
|
||
"doc_status_name",
|
||
"is_active",
|
||
"paga_number",
|
||
"paga_date",
|
||
"subject",
|
||
"doc_full_name",
|
||
}
|
||
for item in result:
|
||
assert set(item.keys()) == expected
|
||
|
||
|
||
# ── Тесты: сортировка ────────────────────────────────────────────────────────
|
||
|
||
|
||
def test_active_first_sorting() -> None:
|
||
"""Действующие документы идут первыми независимо от порядка в БД."""
|
||
rows = [_ROW_INACTIVE, _ROW_PAGA] # inactive первый в БД
|
||
result = parcel_granddoc(_FakeDB(rows), "POINT(60 56)")
|
||
assert result[0]["is_active"] is True
|
||
assert result[1]["is_active"] is False
|
||
|
||
|
||
def test_active_sorted_by_date_desc() -> None:
|
||
"""Среди действующих: более новая дата идёт раньше (desc)."""
|
||
rows = [_ROW_PAGA, _ROW_ACTIVE_NEWER] # 2021 первый в БД, 2023 второй
|
||
result = parcel_granddoc(_FakeDB(rows), "POINT(60 56)")
|
||
# Оба active; 2023 > 2021 → 2023 должен быть первым
|
||
active_results = [r for r in result if r["is_active"]]
|
||
assert len(active_results) == 2
|
||
assert active_results[0]["paga_date"] == date(2023, 6, 20)
|
||
assert active_results[1]["paga_date"] == date(2021, 12, 16)
|
||
|
||
|
||
# ── Тесты: graceful ──────────────────────────────────────────────────────────
|
||
|
||
|
||
def test_empty_when_parcel_wkt_none() -> None:
|
||
"""parcel_wkt=None → пустой список, БД не вызывается."""
|
||
result = parcel_granddoc(_FakeDB([_ROW_PAGA]), None)
|
||
assert result == []
|
||
|
||
|
||
def test_empty_when_parcel_wkt_empty_string() -> None:
|
||
"""parcel_wkt='' → пустой список (falsy guard)."""
|
||
result = parcel_granddoc(_FakeDB([_ROW_PAGA]), "")
|
||
assert result == []
|
||
|
||
|
||
def test_empty_when_no_rows() -> None:
|
||
"""Нет пересечений в БД → пустой список."""
|
||
result = parcel_granddoc(_FakeDB([]), "POINT(60 56)")
|
||
assert result == []
|
||
|
||
|
||
def test_graceful_on_operational_error() -> None:
|
||
"""OperationalError (таблица не задеплоена) → [] без падения."""
|
||
db = _FakeDB(raise_exc=OperationalError("stmt", {}, Exception("no such table")))
|
||
result = parcel_granddoc(db, "POINT(60 56)")
|
||
assert result == []
|
||
|
||
|
||
def test_graceful_on_programming_error() -> None:
|
||
"""ProgrammingError → [] без падения."""
|
||
db = _FakeDB(raise_exc=ProgrammingError("stmt", {}, Exception("column not found")))
|
||
result = parcel_granddoc(db, "POINT(60 56)")
|
||
assert result == []
|