import json import unittest from typing import Any from uuid import UUID from B04_wf1_Surface.B04_wf1_Surface_Repository import ( create_processed_point_cloud, create_surface_model, create_terrain_layer, list_surface_models, ) class FakeCursor: def __init__(self, *, lastrowid: int = 0, rows: list[tuple[Any, ...]] | None = None) -> None: self.query = "" self.arguments: tuple[Any, ...] = () self.lastrowid = lastrowid self._rows = rows or [] async def __aenter__(self) -> "FakeCursor": return self async def __aexit__(self, *_exc: Any) -> None: return None async def execute(self, query: str, arguments: tuple[Any, ...] | None = None) -> None: self.query = query self.arguments = arguments or () async def fetchall(self) -> list[tuple[Any, ...]]: return self._rows class FakeConnection: def __init__(self, cursor: FakeCursor) -> None: self._cursor = cursor def cursor(self) -> FakeCursor: return self._cursor PROJECT_ID = UUID("550e8400-e29b-41d4-a716-446655440000") class ProcessedPointCloudTest(unittest.IsolatedAsyncioTestCase): async def test_create(self) -> None: cursor = FakeCursor(lastrowid=11) new_id = await create_processed_point_cloud( # type: ignore[arg-type] FakeConnection(cursor), input_file_id=3, project_id=PROJECT_ID, process_type="filtered", processed_file_path="B04_wf1_Surface/processed/cloud.las", converted_format="ply", converted_file_path="B04_wf1_Surface/processed/cloud.ply", point_count=1000, bounds={"x_min": 0.0, "x_max": 10.0, "y_min": 0.0, "y_max": 10.0}, statistics={"min_z": 1.0, "max_z": 5.0, "mean_z": 3.0, "density_per_sqm": 10.0}, classification_summary={"ground": 800}, processing_params={"filter": "csf"}, ) self.assertEqual(new_id, 11) self.assertIn("INSERT INTO processed_point_cloud", cursor.query) self.assertEqual(cursor.arguments[1], str(PROJECT_ID)) self.assertEqual(cursor.arguments[6], 1000) self.assertEqual(json.loads(cursor.arguments[15]), {"ground": 800}) async def test_rejects_path_outside_stage(self) -> None: with self.assertRaises(ValueError): await create_processed_point_cloud( # type: ignore[arg-type] FakeConnection(FakeCursor(lastrowid=1)), input_file_id=3, project_id=PROJECT_ID, process_type="filtered", processed_file_path="B05_wf2_Route/x.las", converted_format=None, converted_file_path=None, point_count=None, bounds=None, statistics=None, classification_summary=None, processing_params=None, ) class SurfaceModelTest(unittest.IsolatedAsyncioTestCase): async def test_create(self) -> None: cursor = FakeCursor(lastrowid=22) new_id = await create_surface_model( # type: ignore[arg-type] FakeConnection(cursor), project_id=PROJECT_ID, model_type="dtm_grid", source_file_id=3, processed_cloud_id=11, crs_epsg=5178, resolution_m=1.0, model_file_path="B04_wf1_Surface/models/dtm.npz", generation_params={"algorithm": "dtm"}, ) self.assertEqual(new_id, 22) self.assertIn("INSERT INTO surface_models", cursor.query) self.assertEqual(cursor.arguments[7], "B04_wf1_Surface/models/dtm.npz") class TerrainLayerTest(unittest.IsolatedAsyncioTestCase): async def test_create(self) -> None: cursor = FakeCursor(lastrowid=33) new_id = await create_terrain_layer( # type: ignore[arg-type] FakeConnection(cursor), surface_model_id=22, layer_name="지표", geometry_type="GRID", layer_file_path="B04_wf1_Surface/models/layer_ground.geojson", file_format="geojson", file_size_mb=1.5, statistics={"point_count": 500}, ) self.assertEqual(new_id, 33) self.assertIn("INSERT INTO terrain_layers", cursor.query) class ListSurfaceModelsTest(unittest.IsolatedAsyncioTestCase): async def test_list(self) -> None: import datetime rows = [ ( 22, "dtm_grid", "COMPLETE", 1.0, "B04_wf1_Surface/models/dtm.npz", datetime.datetime(2026, 7, 5, 12, 0, 0), ), ] result = await list_surface_models( # type: ignore[arg-type] FakeConnection(FakeCursor(rows=rows)), PROJECT_ID ) self.assertEqual(len(result), 1) self.assertEqual(result[0]["id"], 22) self.assertEqual(result[0]["model_type"], "dtm_grid") self.assertTrue(result[0]["created_at"].startswith("2026-07-05"))