"""Tests for visualization functions. Each test creates a small synthetic DEM and runs a visualization function, checking that it produces a valid output file. """ import numpy as np import pytest from pathlib import Path # --- Core terrain visualizations (no GPU required) --- class TestHillshade: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_hillshade result = generate_hillshade(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() assert result.suffix == ".tif" def test_output_values_valid(self, synthetic_dem, tmp_output_dir): import rasterio from lidar_pipeline.visualizations import generate_hillshade result = generate_hillshade(synthetic_dem, "test", tmp_output_dir, 5.0) with rasterio.open(result) as src: data = src.read(1) assert data.shape[0] > 0 assert np.nanmin(data) >= 0 assert np.nanmax(data) <= 1 class TestSlope: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_slope result = generate_slope(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() def test_slope_values_degrees(self, synthetic_dem, tmp_output_dir): import rasterio from lidar_pipeline.visualizations import generate_slope result = generate_slope(synthetic_dem, "test", tmp_output_dir, 5.0) with rasterio.open(result) as src: data = src.read(1) assert np.nanmin(data) >= 0 assert np.nanmax(data) <= 90 class TestAspect: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_aspect result = generate_aspect(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() def test_aspect_values_0_360(self, synthetic_dem, tmp_output_dir): import rasterio from lidar_pipeline.visualizations import generate_aspect result = generate_aspect(synthetic_dem, "test", tmp_output_dir, 5.0) with rasterio.open(result) as src: data = src.read(1) valid = data[~np.isnan(data)] assert np.nanmin(valid) >= 0 assert np.nanmax(valid) <= 360 class TestCurvature: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_curvature result = generate_curvature(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() # --- GPU-accelerated visualizations --- class TestLRM: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_lrm result = generate_lrm(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() def test_lrm_has_positive_negative(self, synthetic_dem, tmp_output_dir): import rasterio from lidar_pipeline.visualizations import generate_lrm result = generate_lrm(synthetic_dem, "test", tmp_output_dir, 5.0) with rasterio.open(result) as src: data = src.read(1) # LRM should have both positive and negative values assert np.nanmax(data) > 0 assert np.nanmin(data) < 0 class TestSVF: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_svf result = generate_svf(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() def test_svf_values_0_1(self, synthetic_dem, tmp_output_dir): import rasterio from lidar_pipeline.visualizations import generate_svf result = generate_svf(synthetic_dem, "test", tmp_output_dir, 5.0) with rasterio.open(result) as src: data = src.read(1) valid = data[~np.isnan(data)] assert np.nanmin(valid) >= 0 assert np.nanmax(valid) <= 1 class TestOpenness: def test_positive_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_openness result = generate_openness(synthetic_dem, "test", tmp_output_dir, 5.0, positive=True) assert result is not None assert result.exists() def test_negative_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_openness result = generate_openness(synthetic_dem, "test", tmp_output_dir, 5.0, positive=False) assert result is not None assert result.exists() class TestMSLRM: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_mslrm result = generate_mslrm(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() class TestTPI: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_tpi result = generate_tpi(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() class TestSAILORE: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_sailore result = generate_sailore(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() class TestRoughness: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_roughness result = generate_roughness(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() def test_roughness_non_negative(self, synthetic_dem, tmp_output_dir): import rasterio from lidar_pipeline.visualizations import generate_roughness result = generate_roughness(synthetic_dem, "test", tmp_output_dir, 5.0) with rasterio.open(result) as src: data = src.read(1) # Standard deviation is always >= 0 assert np.nanmin(data) >= 0 class TestAnomalies: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_anomalies result = generate_anomalies(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() class TestWavelet: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_wavelet result = generate_wavelet(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() class TestFlow: def test_generates_tif(self, synthetic_dem, tmp_output_dir): from lidar_pipeline.visualizations import generate_flow result = generate_flow(synthetic_dem, "test", tmp_output_dir, 5.0) assert result is not None assert result.exists() def test_flow_log_values(self, synthetic_dem, tmp_output_dir): import rasterio from lidar_pipeline.visualizations import generate_flow result = generate_flow(synthetic_dem, "test", tmp_output_dir, 5.0) with rasterio.open(result) as src: data = src.read(1) # log1p(x) >= 0 for x >= 0 valid = data[~np.isnan(data)] assert np.nanmin(valid) >= 0