Some checks failed
CI / changes (push) Successful in 7s
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 7s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 7m42s
CI / backend-tests (pull_request) Successful in 7m40s
Deploy / changes (push) Has been cancelled
Deploy / build-backend (push) Has been cancelled
Deploy / build-worker (push) Has been cancelled
Deploy / build-frontend (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
#41: per-category routing-radius decay через reusable ORS /matrix client (foot-walk время + per-category пороги + decay-curves), opt-in ?decay=routing, graceful straight-line fallback (analyze не 500 при ORS down) + length-guard durations==destinations. #44: +5 OSM-категорий (transformer/gas/water/sewerage/heat) via Overpass nwr; nearest_{water_main,substation,gas,heat}_m в analyze.utilities. #255bk: ST_AsGeoJSON(CAST(geom AS geometry)) в _get_cad_zouit_overlaps → geom_geojson. Closes #41 Closes #44
100 lines
4 KiB
Python
100 lines
4 KiB
Python
"""Unit tests для noise_loader — OSM-источники шума + инж.сети (#44).
|
||
|
||
Mock-based / pure — без Overpass и БД. Покрывает:
|
||
- расширенный набор инж.-сетевых категорий (#44: gas/water/sewerage/transformer/
|
||
heat_substation)
|
||
- _build_overpass_query: node / way / nwr варианты
|
||
- el_type dispatch для point-like utility (nwr) vs линейных (way)
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from app.services.site_finder.noise_loader import (
|
||
_NOISE_QUERIES,
|
||
_UTILITY_POINT_VALUES,
|
||
_build_overpass_query,
|
||
_way_to_linestring_wkt,
|
||
)
|
||
|
||
# ── расширенные инж.-сетевые категории (#44) ─────────────────────────────────
|
||
|
||
|
||
def _road_classes() -> set[str | None]:
|
||
return {road_class for _k, _v, src, road_class in _NOISE_QUERIES if src == "utility"}
|
||
|
||
|
||
def test_new_utility_categories_present() -> None:
|
||
"""#44: добавлены недостающие инж.сети — газ/вода/канализация/трансформатор/ЦТП."""
|
||
classes = _road_classes()
|
||
for expected in (
|
||
"gas_pipeline",
|
||
"water_main",
|
||
"sewerage",
|
||
"transformer",
|
||
"heat_substation",
|
||
):
|
||
assert expected in classes, f"road_class {expected!r} должен быть в _NOISE_QUERIES"
|
||
|
||
|
||
def test_existing_utility_categories_retained() -> None:
|
||
"""Старые категории не потеряны при расширении (regression guard)."""
|
||
classes = _road_classes()
|
||
for kept in ("power_line", "pipeline", "water_works", "wastewater_plant", "substation"):
|
||
assert kept in classes
|
||
|
||
|
||
def test_pipeline_queries_use_pipeline_key() -> None:
|
||
"""pipeline=gas/water/sewerage маппится на OSM tag `pipeline`, не man_made."""
|
||
pipeline_entries = [(k, v) for k, v, src, _rc in _NOISE_QUERIES if k == "pipeline"]
|
||
values = {v for _k, v in pipeline_entries}
|
||
assert values == {"gas", "water", "sewerage"}
|
||
|
||
|
||
def test_utility_point_values_cover_new_nodes() -> None:
|
||
"""Точечные/площадные инж.объекты помечены для nwr-запроса."""
|
||
for v in ("substation", "transformer", "heat_substation", "water_works"):
|
||
assert v in _UTILITY_POINT_VALUES
|
||
|
||
|
||
# ── _build_overpass_query ─────────────────────────────────────────────────────
|
||
|
||
|
||
def test_build_query_node() -> None:
|
||
q = _build_overpass_query("aeroway", "aerodrome", "node")
|
||
assert q.startswith("[out:json][timeout:30];")
|
||
assert 'node["aeroway"="aerodrome"]' in q
|
||
assert "out body;" in q
|
||
|
||
|
||
def test_build_query_way_uses_out_geom() -> None:
|
||
"""way → out geom (нужны координаты узлов для LineString)."""
|
||
q = _build_overpass_query("highway", "motorway", "way")
|
||
assert 'way["highway"="motorway"]' in q
|
||
assert "out geom;" in q
|
||
|
||
|
||
def test_build_query_nwr_for_utility_points() -> None:
|
||
"""nwr ловит и node, и way (точка/площадка), с out geom."""
|
||
q = _build_overpass_query("power", "transformer", "nwr")
|
||
assert 'nwr["power"="transformer"]' in q
|
||
assert "out geom;" in q
|
||
|
||
|
||
def test_build_query_bbox_present() -> None:
|
||
"""Bbox ЕКБ присутствует во всех вариантах запроса."""
|
||
q = _build_overpass_query("power", "substation", "nwr")
|
||
# south,west,north,east из EKB_BBOX
|
||
assert "(56.7,60.5,56.95,60.75)" in q
|
||
|
||
|
||
# ── _way_to_linestring_wkt (используется для way-результатов nwr) ────────────
|
||
|
||
|
||
def test_way_to_linestring_valid() -> None:
|
||
nodes = [{"lat": 56.8, "lon": 60.6}, {"lat": 56.81, "lon": 60.61}]
|
||
wkt = _way_to_linestring_wkt(nodes)
|
||
assert wkt == "LINESTRING(60.6 56.8, 60.61 56.81)"
|
||
|
||
|
||
def test_way_to_linestring_too_few_points() -> None:
|
||
assert _way_to_linestring_wkt([{"lat": 56.8, "lon": 60.6}]) is None
|