Co-authored-by: lekss361 <lekss361@gendsgn.local> Co-committed-by: lekss361 <lekss361@gendsgn.local>
98 lines
3.2 KiB
Python
98 lines
3.2 KiB
Python
"""Тесты parcel_functional_zones (#1058) — read-side lookup функциональных зон генплана."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
from sqlalchemy.exc import OperationalError, ProgrammingError
|
||
|
||
from app.services.site_finder.functional_zone_lookup import parcel_functional_zones
|
||
|
||
|
||
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)
|
||
|
||
|
||
_WKT = "POLYGON((60.5 56.8, 60.6 56.8, 60.6 56.9, 60.5 56.9, 60.5 56.8))"
|
||
|
||
|
||
def test_returns_zones_for_parcel() -> None:
|
||
"""Обычный случай: строки из БД → список dict с нужными ключами."""
|
||
rows = [
|
||
{
|
||
"zone_type": "Жилые зоны",
|
||
"status": "Существующий",
|
||
"area_ha": 15.3,
|
||
"zone_class_code": "Ж",
|
||
},
|
||
{
|
||
"zone_type": "Общественные зоны",
|
||
"status": "Планируемый",
|
||
"area_ha": None,
|
||
"zone_class_code": "О",
|
||
},
|
||
]
|
||
result = parcel_functional_zones(_FakeDB(rows), _WKT)
|
||
|
||
assert len(result) == 2
|
||
first = result[0]
|
||
assert first["zone_type"] == "Жилые зоны"
|
||
assert first["status"] == "Существующий"
|
||
assert first["area_ha"] == 15.3
|
||
assert first["zone_class_code"] == "Ж"
|
||
second = result[1]
|
||
assert second["area_ha"] is None # NULL → None (не падает)
|
||
|
||
|
||
def test_empty_when_no_wkt() -> None:
|
||
"""parcel_wkt=None → пустой список без запроса к БД."""
|
||
result = parcel_functional_zones(_FakeDB([{"zone_type": "Жилые зоны"}]), None)
|
||
assert result == []
|
||
|
||
|
||
def test_empty_when_no_overlap() -> None:
|
||
"""БД вернула 0 строк → пустой список."""
|
||
result = parcel_functional_zones(_FakeDB([]), _WKT)
|
||
assert result == []
|
||
|
||
|
||
def test_graceful_when_table_missing_operational_error() -> None:
|
||
"""OperationalError (таблица не задеплоена) → [] без падения."""
|
||
db = _FakeDB(raise_exc=OperationalError("stmt", {}, Exception("no such table")))
|
||
result = parcel_functional_zones(db, _WKT)
|
||
assert result == []
|
||
|
||
|
||
def test_graceful_when_table_missing_programming_error() -> None:
|
||
"""ProgrammingError (e.g. relation не существует) → [] без падения."""
|
||
db = _FakeDB(raise_exc=ProgrammingError("stmt", {}, Exception("relation does not exist")))
|
||
result = parcel_functional_zones(db, _WKT)
|
||
assert result == []
|
||
|
||
|
||
def test_empty_string_wkt_treated_as_falsy() -> None:
|
||
"""Пустая строка wkt → пустой список (falsy guard)."""
|
||
result = parcel_functional_zones(_FakeDB([]), "")
|
||
assert result == []
|