diff --git a/backend/tests/services/test_cadastre_bulk.py b/backend/tests/services/test_cadastre_bulk.py index 9cd3ddf7..f33513a7 100644 --- a/backend/tests/services/test_cadastre_bulk.py +++ b/backend/tests/services/test_cadastre_bulk.py @@ -18,7 +18,10 @@ from app.services.cadastre.bulk_harvest import ( _safe_numeric, upsert_features, ) -from app.services.cadastre.grid_geometry import generate_grid_click_points +from app.services.cadastre.grid_geometry import ( + generate_grid_click_points, + quarter_bbox_3857, +) # ── Фикстуры ───────────────────────────────────────────────────────────────── @@ -195,6 +198,52 @@ def test_generate_grid_click_points_custom_grid() -> None: assert cell_bbox[3] - cell_bbox[1] == pytest.approx(200.0) +# ── quarter_bbox_3857 sanity check ─────────────────────────────────────────── + + +def _mock_db_with_bbox( + xmin: float | None, ymin: float | None, xmax: float | None, ymax: float | None +) -> MagicMock: + """Mock SQLAlchemy session.execute().mappings().first() возвращает заданный bbox.""" + mock_db = MagicMock() + row = None if xmin is None else {"xmin": xmin, "ymin": ymin, "xmax": xmax, "ymax": ymax} + mock_db.execute.return_value.mappings.return_value.first.return_value = row + return mock_db + + +def test_quarter_bbox_3857_healthy_geom() -> None: + """Real ЕКБ-квартал ~750м — должен пройти sanity check.""" + db = _mock_db_with_bbox(6735845.0, 8329000.0, 6736595.0, 8329750.0) + bbox = quarter_bbox_3857(db, "66:41:0303161") + assert bbox is not None + assert bbox == (6735845.0, 8329000.0, 6736595.0, 8329750.0) + + +def test_quarter_bbox_3857_skips_broken_micro_geom() -> None: + """width < 100m — broken micro-precision geom (72% rows в cad_quarters_geom).""" + # width=60.7m — реальный broken quarter 66:41:0101005 после ST_Transform + db = _mock_db_with_bbox(60.0, 60.0, 120.7, 120.7) + assert quarter_bbox_3857(db, "66:41:0101005") is None + + +def test_quarter_bbox_3857_skips_oversized_geom() -> None: + """width > 10000m — broken/regional geom (не городской квартал).""" + db = _mock_db_with_bbox(0.0, 0.0, 15000.0, 15000.0) + assert quarter_bbox_3857(db, "66:41:9999999") is None + + +def test_quarter_bbox_3857_skips_zero_height() -> None: + """height < 100m — симметрия по другой оси.""" + db = _mock_db_with_bbox(0.0, 0.0, 500.0, 50.0) + assert quarter_bbox_3857(db, "66:41:0000001") is None + + +def test_quarter_bbox_3857_returns_none_when_quarter_missing() -> None: + """Квартал не найден в cad_quarters_geom → None (xmin IS NULL).""" + db = _mock_db_with_bbox(None, None, None, None) + assert quarter_bbox_3857(db, "66:99:0000000") is None + + # ── upsert_features routing ──────────────────────────────────────────────────