90 lines
2.8 KiB
Python
90 lines
2.8 KiB
Python
import json
|
|
|
|
import pytest
|
|
|
|
from app.core.geo import PathPoint
|
|
from app.models.buildings import BuildingsQueryRequest
|
|
from app.models.terrain import TerrainProfileRequest
|
|
from app.services import buildings as buildings_service
|
|
from app.services import terrain as terrain_service
|
|
|
|
|
|
class FakeResult:
|
|
def __init__(self, rows: list[dict[str, object]]) -> None:
|
|
self._rows = rows
|
|
|
|
def mappings(self) -> "FakeResult":
|
|
return self
|
|
|
|
def all(self) -> list[dict[str, object]]:
|
|
return self._rows
|
|
|
|
|
|
class FakeSession:
|
|
def __init__(self, rows: list[dict[str, object]]) -> None:
|
|
self.rows = rows
|
|
self.calls: list[dict[str, object]] = []
|
|
|
|
def execute(self, statement: object, params: dict[str, object]) -> FakeResult:
|
|
self.calls.append({"statement": str(statement), "params": params})
|
|
return FakeResult(self.rows)
|
|
|
|
|
|
def test_buildings_query_bbox_returns_feature_collection() -> None:
|
|
feature = {
|
|
"type": "Feature",
|
|
"id": 123,
|
|
"geometry": {"type": "Polygon", "coordinates": []},
|
|
"properties": {
|
|
"height_m": 12.0,
|
|
"levels": 4,
|
|
"building_type": "apartments",
|
|
"source": "estimated",
|
|
},
|
|
}
|
|
db = FakeSession(rows=[{"feature": json.dumps(feature)}])
|
|
request = BuildingsQueryRequest(bbox=(30.0, 59.0, 31.0, 60.0))
|
|
|
|
response = buildings_service.query_buildings(request, db, limit=10)
|
|
|
|
assert response.type == "FeatureCollection"
|
|
assert response.features == [feature]
|
|
assert db.calls[0]["params"]["limit"] == 10
|
|
|
|
|
|
def test_building_heights_along_returns_height_per_point() -> None:
|
|
db = FakeSession(rows=[{"i": 0, "height_m": 15.0}, {"i": 1, "height_m": 0.0}])
|
|
points = [
|
|
PathPoint(lat=59.0, lon=30.0, distance_m=0),
|
|
PathPoint(lat=59.1, lon=30.1, distance_m=1),
|
|
]
|
|
|
|
heights = buildings_service.building_heights_along(points, db)
|
|
|
|
assert heights == [15.0, 0.0]
|
|
assert "jsonb_to_recordset" in db.calls[0]["statement"]
|
|
|
|
|
|
def test_buildings_query_rejects_invalid_bbox() -> None:
|
|
with pytest.raises(ValueError, match="bbox"):
|
|
BuildingsQueryRequest(bbox=(31.0, 59.0, 30.0, 60.0))
|
|
|
|
|
|
def test_terrain_profile_applies_building_heights(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
def fake_heights(points: list[PathPoint], db: object) -> list[float]:
|
|
return [12.0] + [0.0] * (len(points) - 1)
|
|
|
|
monkeypatch.setattr(buildings_service, "building_heights_along", fake_heights)
|
|
request = TerrainProfileRequest(
|
|
start={"lat": 59.0, "lon": 30.0},
|
|
end={"lat": 59.1, "lon": 30.1},
|
|
samples=2,
|
|
include_buildings=True,
|
|
include_canopy=False,
|
|
)
|
|
|
|
response = terrain_service.terrain_profile(request, db=object())
|
|
|
|
assert response.samples[0].building_m == 12.0
|
|
assert response.samples[0].surface_m == response.samples[0].ground_m + 12.0
|