from __future__ import annotations import json from pathlib import Path from types import SimpleNamespace from uuid import uuid4 from app.core.errors import AppError from app.services import geojson_service from app.services.dataset_service import DatasetService def test_parse_geojson_payload_extracts_metadata() -> None: payload = { "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Point", "coordinates": [4.5, 51.3], }, } ], } metadata = geojson_service.parse_geojson_payload(payload) assert metadata["feature_count"] == 1 assert metadata["feature_geometry_count"] == 1 assert metadata["bounds_json"] == { "min_x": 4.5, "min_y": 51.3, "max_x": 4.5, "max_y": 51.3, } assert metadata["geometry_types"] == ["Point"] def test_parse_geojson_payload_rejects_non_feature_collection() -> None: payload = {"type": "Feature", "features": []} try: geojson_service.parse_geojson_payload(payload) except ValueError as exc: assert "FeatureCollection" in str(exc) else: raise AssertionError("Invalid GeoJSON should raise ValueError") def test_get_dataset_geojson_reads_stored_payload(tmp_path, monkeypatch) -> None: file_path = tmp_path / "dataset.geojson" file_path.write_text( json.dumps({"type": "FeatureCollection", "features": []}), encoding="utf-8", ) dataset = SimpleNamespace(dataset_type="vector", storage_path=str(file_path)) monkeypatch.setattr(DatasetService, "get_dataset", lambda _db, _id: dataset) payload = DatasetService.get_dataset_geojson(Path("."), uuid4()) assert payload["type"] == "FeatureCollection" def test_get_dataset_geojson_rejects_invalid_stored_json(tmp_path, monkeypatch) -> None: file_path = tmp_path / "invalid.geojson" file_path.write_text("not-json", encoding="utf-8") dataset = SimpleNamespace(dataset_type="vector", storage_path=str(file_path)) monkeypatch.setattr(DatasetService, "get_dataset", lambda _db, _id: dataset) try: DatasetService.get_dataset_geojson(Path("."), uuid4()) except AppError as exc: assert exc.code == "INVALID_GEOJSON" else: raise AssertionError("Invalid stored payload should raise AppError") def test_parse_geojson_payload_returns_vector_metadata() -> None: payload = { "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [ [ [4.3, 51.2], [4.4, 51.2], [4.4, 51.3], [4.3, 51.3], [4.3, 51.2], ] ], }, } ], "crs": {"type": "name", "properties": {"name": "EPSG:31370"}}, } metadata = geojson_service.parse_geojson_payload(payload) assert metadata["feature_count"] == 1 assert metadata["feature_geometry_count"] == 1 assert metadata["geometry_types"] == ["Polygon"] assert metadata["bounds_json"] == { "min_x": 4.3, "min_y": 51.2, "max_x": 4.4, "max_y": 51.3, } assert metadata["crs"] == "EPSG:31370" assert metadata["approximate_area_m2"] is not None assert metadata["approximate_area_m2"] >= 0.0 def test_parse_geojson_payload_reports_z_dimension_for_canonical_2d_storage() -> None: metadata = geojson_service.parse_geojson_payload( { "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": {"type": "Point", "coordinates": [5.08, 51.18, 0.0]}, "properties": {}, } ], } ) assert metadata["z_dimension_feature_count"] == 1 assert metadata["canonical_storage_dimension"] == "2D" def test_parse_geojson_payload_rejects_invalid_geometry() -> None: payload = { "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Polygon", "coordinates": "invalid", }, } ], } try: geojson_service.parse_geojson_payload(payload) except ValueError as exc: assert "Invalid feature geometry" in str(exc) else: raise AssertionError("Invalid geometry should raise ValueError") def test_get_dataset_geojson_accepts_legacy_geojson_type(tmp_path, monkeypatch) -> None: file_path = tmp_path / "legacy.geojson" file_path.write_text( json.dumps({"type": "FeatureCollection", "features": []}), encoding="utf-8", ) dataset = SimpleNamespace(dataset_type="geojson", storage_path=str(file_path)) monkeypatch.setattr(DatasetService, "get_dataset", lambda _db, _id: dataset) payload = DatasetService.get_dataset_geojson(Path("."), uuid4()) assert payload["type"] == "FeatureCollection" def test_vector_summary_supports_legacy_geojson_type(monkeypatch) -> None: dataset = SimpleNamespace( dataset_type="geojson", metadata_json={ "feature_count": 7, "geometry_types": ["Point"], "bounds_json": {"min_x": 0.0, "min_y": 0.0, "max_x": 1.0, "max_y": 1.0}, }, storage_path="", ) monkeypatch.setattr(DatasetService, "get_dataset", lambda _db, _id: dataset) summary = DatasetService.vector_summary(Path("."), uuid4()) assert summary["feature_count"] == 7 assert summary["geometry_types"] == ["Point"]