from __future__ import annotations from pathlib import Path from uuid import uuid4 from app.models import Dataset from app.schemas.operations import VectorSelectionSummary from app.services.vector_feature_service import VectorFeatureService from tests.frontend_contract import read_feature ROOT = Path(__file__).parents[2] BBOX = {"min_x": 5.0, "min_y": 51.1, "max_x": 5.2, "max_y": 51.3, "crs": "EPSG:4326"} class ScalarQuery: def __init__(self, value: float): self.value = value def filter(self, *args): # noqa: ANN002, ARG002 return self def scalar(self): return self.value class SequenceScalarSession: """Answers scalar queries in the order the summary issues them. The first query is the fully-covered feature count that produces the selection-edge disclosure; ``covered_count`` defaults to the full population, i.e. a selection that cuts nothing. """ def __init__(self, values: list[float], covered_count: float | None = None): self.values = iter(([covered_count] if covered_count is not None else []) + values) def query(self, *args): # noqa: ANN002, ARG002 return ScalarQuery(next(self.values)) def themed_dataset(theme: str, *, method: str = "feature_count") -> Dataset: return Dataset( id=uuid4(), project_id=uuid4(), name=f"regional-{theme}.geojson", dataset_type="vector", dataset_role="reference", source_name="grb", reference_layer_name=theme, source_metadata={ "theme": theme, "selection_aggregation": { "method": method, "label": theme.title(), "unit": "objecten", }, }, ) def test_building_selection_promotes_footprint_area_and_retains_object_count() -> None: result = VectorFeatureService.summarize_features_by_bbox( SequenceScalarSession([125_000.0], covered_count=40), dataset=themed_dataset("buildings"), bbox=BBOX, total_feature_count=40, ) assert result["primary_metric_key"] == "footprint_area" assert result["metric_label"] == "Bebouwde grondoppervlakte" assert result["metric_value"] == 12.5 assert result["metric_unit"] == "ha" assert [(item["metric_key"], item["metric_value"]) for item in result["metrics"]] == [ ("footprint_area", 12.5), ("feature_count", 40.0), ] assert "niet de totale vloeroppervlakte" in result["warning"] VectorSelectionSummary(**result) def test_water_selection_reports_surface_length_and_honest_volume_limitation() -> None: result = VectorFeatureService.summarize_features_by_bbox( SequenceScalarSession([52_500.0, 12_750.0], covered_count=23), dataset=themed_dataset("water"), bbox=BBOX, total_feature_count=23, ) assert result["metric_value"] == 5.25 assert result["metric_unit"] == "ha" assert [(item["metric_key"], item["metric_value"], item["metric_unit"]) for item in result["metrics"]] == [ ("water_area", 5.25, "ha"), ("watercourse_length", 12.75, "km"), ("feature_count", 23.0, "objecten"), ] assert "Watervolume is niet berekenbaar" in result["warning"] def test_population_keeps_configured_metric_and_adds_sector_count() -> None: dataset = themed_dataset("population", method="sum") dataset.source_metadata["selection_aggregation"].update( {"metric_key": "population", "property": "population_total", "label": "Inwoners", "unit": "inwoners"} ) result = VectorFeatureService.summarize_features_by_bbox( SequenceScalarSession([86_458.0], covered_count=733), dataset=dataset, bbox=BBOX, total_feature_count=733, ) assert result["primary_metric_key"] == "population" assert result["metric_value"] == 86_458.0 assert result["metrics"][1] == { "metric_key": "feature_count", "metric_label": "Statistische sectoren", "metric_value": 733.0, "metric_unit": "objecten", "aggregation_method": "feature_count", "is_estimate": False, "warning": None, } def test_station_measurement_uses_numeric_mean_without_area_extrapolation() -> None: dataset = themed_dataset("water", method="mean") dataset.source_name = "waterinfo" dataset.source_metadata.update( { "semantic_metrics": False, "selection_aggregation": { "metric_key": "water_level", "method": "mean", "property": "annual_mean_water_level_m", "label": "Jaargemiddelde waterstand", "unit": "m", "warning": "Puntmeting; geen gebiedsdekkend watervolume.", }, } ) result = VectorFeatureService.summarize_features_by_bbox( SequenceScalarSession([30.455], covered_count=1), dataset=dataset, bbox=BBOX, total_feature_count=1, ) assert result["metric_value"] == 30.455 assert result["aggregation_method"] == "mean" assert result["metric_unit"] == "m" assert result["warning"] == "Puntmeting; geen gebiedsdekkend watervolume." def test_regional_historical_polygons_do_not_emit_irrelevant_line_metrics() -> None: dataset = themed_dataset("water", method="intersection_area") dataset.source_metadata["selection_aggregation"].update( {"metric_key": "water_area", "label": "Historische wateroppervlakte", "unit": "ha"} ) dataset.provenance_metadata = {"operator_tool": "provision_regional_historical_landuse.py"} result = VectorFeatureService.summarize_features_by_bbox( SequenceScalarSession([52_500.0], covered_count=23), dataset=dataset, bbox=BBOX, total_feature_count=23, ) assert [(item["metric_key"], item["metric_unit"]) for item in result["metrics"]] == [ ("water_area", "ha"), ("feature_count", "objecten"), ] def test_future_regional_imports_persist_semantic_aggregation_configuration() -> None: buildings = (ROOT / "scripts/provision_regional_grb_buildings.py").read_text(encoding="utf-8") context = (ROOT / "scripts/provision_regional_grb_context.py").read_text(encoding="utf-8") frontend = read_feature("map_workspace") assert '"method": "intersection_area"' in buildings assert '"label": "Bebouwde grondoppervlakte"' in buildings assert 'metric_method="intersection_length"' in context assert 'metric_label="Wateroppervlakte"' in context assert 'metric_label="Perceeloppervlakte"' in context assert 'aria-label="Aanvullende gebiedsmetingen"' in frontend assert "activeSelectionResult.summary.warning" in frontend