import unittest from unittest.mock import patch, MagicMock import numpy as np from geodata_pipeline.buildings import export_buildings from geodata_pipeline.config import Config class TestBuildingsMemory(unittest.TestCase): @patch("geodata_pipeline.buildings.gdal.Open") @patch("geodata_pipeline.buildings._ensure_cityjson_for_tile") @patch("geodata_pipeline.buildings._load_cityjson") @patch("geodata_pipeline.buildings._collect_faces") @patch("geodata_pipeline.buildings._load_ortho") @patch("geodata_pipeline.buildings._compose_glb") @patch("geodata_pipeline.buildings.ensure_dir") @patch("os.path.exists") @patch("builtins.open") def test_ground_snapping_windowed_read(self, mock_open_file, mock_exists, mock_ensure_dir, mock_compose, mock_load_ortho, mock_collect, mock_load_cj, mock_ensure_cj, mock_gdal_open): # Setup mocks mock_exists.return_value = True # Mock file handle for manifest CSV mock_handle = MagicMock() mock_open_file.return_value.__enter__.return_value = mock_handle mock_handle.__iter__.return_value = [ "tile_id,xmin,ymin,xmax,ymax,global_min,global_max,out_res,tile_key,tile_min,tile_max\n", "tile1,1000,1000,2000,2000,0,100,1025,1_1,0,100\n" ] mock_ensure_cj.return_value = "dummy.json" mock_load_cj.return_value = {"CityObjects": {}} mock_collect.return_value = ( [[10.0, 10.0, 5.0]], # vertices (local to tile) [([0, 0, 0], "WallSurface")] # faces ) mock_load_ortho.return_value = None # Mock GDAL for heightmap mock_ds = MagicMock() mock_gdal_open.return_value = mock_ds mock_ds.GetGeoTransform.return_value = (0, 1, 0, 3000, 0, -1) # Origin (0, 3000), 1m resolution mock_ds.RasterXSize = 5000 mock_ds.RasterYSize = 5000 mock_band = MagicMock() mock_ds.GetRasterBand.return_value = mock_band mock_band.GetNoDataValue.return_value = -9999 mock_band.ReadAsArray.return_value = np.array([[50.0, 50.0], [50.0, 50.0]]) # Return 2x2 array cfg = Config.default() cfg.work.heightmap_vrt = "dgm.vrt" cfg.export.manifest_path = "manifest.csv" export_buildings(cfg) # Verify ReadAsArray was called with a window args, kwargs = mock_band.ReadAsArray.call_args # ReadAsArray(xoff, yoff, xsize, ysize) self.assertEqual(len(args), 4) xoff, yoff, xsize, ysize = args # tile1 starts at 1000, 1000 (xmin, ymin) -> (xmin, ymax) = (1000, 2000) for GDAL # xoff = (1000 - 0) / 1 = 1000 # yoff = (2000 - 3000) / -1 = 1000 self.assertEqual(xoff, 1000) self.assertEqual(yoff, 1000) if __name__ == "__main__": unittest.main()