"""Tests pour la carte globale interactive (index.py).""" import json from pathlib import Path def test_parse_basename_coords_valid(): """Parse les coordonnées d'un basename LHD valide.""" from lidar_pipeline.index import parse_basename_coords assert parse_basename_coords("LHD_FXX_1000_6881_PTS_LAMB93_IGN69") == (1000, 6881) assert parse_basename_coords("LHD_FXX_1049_6895_PTS_LAMB93_IGN69") == (1049, 6895) def test_parse_basename_coords_with_res_suffix(): """Les noms de dossier avec suffixe résolution sont aussi parsables.""" from lidar_pipeline.index import parse_basename_coords assert parse_basename_coords("LHD_FXX_1000_6881_PTS_LAMB93_IGN69_r0p2") == (1000, 6881) def test_parse_basename_coords_invalid(): """Les noms non-LHD retournent None.""" from lidar_pipeline.index import parse_basename_coords assert parse_basename_coords("random_dir") is None assert parse_basename_coords("DTM") is None assert parse_basename_coords("") is None def test_strip_res_suffix_primary(): """Dossier sans suffixe = résolution primaire (0.5).""" from lidar_pipeline.index import _strip_res_suffix base, res = _strip_res_suffix("LHD_FXX_1000_6881_PTS_LAMB93_IGN69") assert base == "LHD_FXX_1000_6881_PTS_LAMB93_IGN69" assert res == 0.5 def test_strip_res_suffix_multi(): """Dossier avec suffixe _r0p2 = résolution 0.2.""" from lidar_pipeline.index import _strip_res_suffix base, res = _strip_res_suffix("LHD_FXX_1000_6881_PTS_LAMB93_IGN69_r0p2") assert base == "LHD_FXX_1000_6881_PTS_LAMB93_IGN69" assert res == 0.2 def test_compute_bbox(): """Calcule la bounding box d'un ensemble de tuiles.""" from lidar_pipeline.index import compute_bbox tiles = [ {'col': 1000, 'row': 6881}, {'col': 1001, 'row': 6882}, {'col': 1002, 'row': 6880}, ] bbox = compute_bbox(tiles) assert bbox == {'min_col': 1000, 'max_col': 1002, 'min_row': 6880, 'max_row': 6882} def test_compute_bbox_empty(): """Aucune tuile → None.""" from lidar_pipeline.index import compute_bbox assert compute_bbox([]) is None def _make_fake_viz_dir(vis_dir, basename, col, row, viz_keys=('hillshade_multi', 'svf'), ext='webp', res_suffix=''): """Crée un faux dossier de visualisations avec de petites images.""" from PIL import Image as PILImage import numpy as np dir_name = f"LHD_FXX_{col}_{row}_PTS_LAMB93_IGN69{res_suffix}" tile_dir = Path(vis_dir) / dir_name tile_dir.mkdir(parents=True, exist_ok=True) for v in viz_keys: arr = np.random.randint(0, 255, (50, 50, 3), dtype=np.uint8) img = PILImage.fromarray(arr) fname = f"LHD_FXX_{col}_{row}_PTS_LAMB93_IGN69{res_suffix}_{v}.{ext}" img.save(str(tile_dir / fname), format='WEBP', quality=80) return tile_dir def test_scan_tiles(tmp_path): """scan_tiles détecte les dossiers de tuiles et leurs visualisations.""" from lidar_pipeline.index import scan_tiles vis_dir = tmp_path / "visualisations" vis_dir.mkdir() _make_fake_viz_dir(vis_dir, "a", 1000, 6881, ('hillshade_multi', 'svf')) _make_fake_viz_dir(vis_dir, "b", 1001, 6881, ('hillshade_multi',)) tiles = scan_tiles(vis_dir) assert len(tiles) == 2 names = sorted(t['dir_name'] for t in tiles) assert "LHD_FXX_1000_6881_PTS_LAMB93_IGN69" in names assert "LHD_FXX_1001_6881_PTS_LAMB93_IGN69" in names # Vérifie que les viz sont détectées t0 = next(t for t in tiles if t['col'] == 1000) assert 'hillshade_multi' in t0['viz'] assert 'svf' in t0['viz'] def test_scan_tiles_ignores_non_lhd(tmp_path): """Les dossiers non-LHD (ex: temp, DTM) sont ignorés.""" from lidar_pipeline.index import scan_tiles vis_dir = tmp_path / "visualisations" vis_dir.mkdir() (vis_dir / "random_folder").mkdir() _make_fake_viz_dir(vis_dir, "a", 1000, 6881) tiles = scan_tiles(vis_dir) assert len(tiles) == 1 assert tiles[0]['col'] == 1000 def test_scan_tiles_multi_resolution(tmp_path): """Les dossiers avec suffixe résolution sont correctement décodés.""" from lidar_pipeline.index import scan_tiles vis_dir = tmp_path / "visualisations" vis_dir.mkdir() _make_fake_viz_dir(vis_dir, "a", 1000, 6881, res_suffix='') _make_fake_viz_dir(vis_dir, "a", 1000, 6881, res_suffix='_r0p2') tiles = scan_tiles(vis_dir) assert len(tiles) == 2 resolutions = sorted(t['resolution'] for t in tiles) assert resolutions == [0.2, 0.5] def test_build_index_generates_html(tmp_path): """build_index génère index.html et les vignettes.""" from lidar_pipeline.index import build_index output_dir = tmp_path / "output" vis_dir = output_dir / "visualisations" vis_dir.mkdir(parents=True) _make_fake_viz_dir(vis_dir, "a", 1000, 6881, ('hillshade_multi', 'svf')) _make_fake_viz_dir(vis_dir, "b", 1001, 6881, ('hillshade_multi',)) result = build_index(output_dir) assert result is not None html_path = Path(result) assert html_path.exists() assert html_path.name == "index.html" content = html_path.read_text(encoding='utf-8') # Vérifie la présence des éléments clés assert "Carte continue LiDAR" in content assert "LHD_FXX_1000_6881" in content assert "LHD_FXX_1001_6881" in content # Vérifie que le JSON intégré est valide assert "const DATA" in content # Vérifie les vignettes générées thumb_dir = output_dir / "index_thumbs" assert thumb_dir.is_dir() thumbs = list(thumb_dir.glob("*.jpg")) assert len(thumbs) >= 2 # au moins hillshade pour chaque tuile def test_build_index_empty_returns_none(tmp_path): """Aucune tuile → build_index retourne None sans crash.""" from lidar_pipeline.index import build_index output_dir = tmp_path / "output" (output_dir / "visualisations").mkdir(parents=True) result = build_index(output_dir) assert result is None def test_build_index_embeds_valid_json(tmp_path): """Le JSON embarqué dans le HTML est valide et contient les tuiles.""" from lidar_pipeline.index import build_index output_dir = tmp_path / "output" vis_dir = output_dir / "visualisations" vis_dir.mkdir(parents=True) _make_fake_viz_dir(vis_dir, "a", 1000, 6881, ('hillshade_multi',)) build_index(output_dir) content = (output_dir / "index.html").read_text(encoding='utf-8') # Extrait le JSON entre "const DATA = " et ";" start = content.index("const DATA = ") + len("const DATA = ") # Trouve le ; de fin de déclaration depth = 0 end = start for i, ch in enumerate(content[start:], start): if ch == '{': depth += 1 elif ch == '}': depth -= 1 if depth == 0: end = i + 1 break data = json.loads(content[start:end]) assert 'tiles' in data assert 'bbox' in data assert 'vizList' in data assert len(data['tiles']) == 1 assert data['tiles'][0]['col'] == 1000 assert data['tiles'][0]['row'] == 6881 def test_pick_display_viz_prefers_hillshade(): """Le choix de viz par défaut privilégie hillshade_multi.""" from lidar_pipeline.index import _pick_display_viz assert _pick_display_viz(['svf', 'hillshade_multi', 'slope']) == 'hillshade_multi' assert _pick_display_viz(['svf', 'slope']) == 'svf' assert _pick_display_viz(['topo']) == 'topo'