"""Tests du journal d'événements de progression (file de génération).""" def test_report_and_read_events(tmp_path): """Les événements s'écrivent en JSONL et se relisent dans l'ordre.""" from lidar_pipeline.progress import read_events, report_event, reset_events reset_events(tmp_path) report_event(tmp_path, "LHD_FXX_1054_6882_PTS_LAMB93_IGN69", "download", "start") report_event(tmp_path, "LHD_FXX_1054_6882_PTS_LAMB93_IGN69", "download", "ok") events = read_events(tmp_path) assert len(events) == 2 assert events[0]["phase"] == "download" and events[0]["state"] == "start" assert events[1]["state"] == "ok" assert events[1]["tile"] == "LHD_FXX_1054_6882_PTS_LAMB93_IGN69" def test_reset_clears_previous_run(tmp_path): """reset_events tronque le journal : un nouveau run repart de zéro.""" from lidar_pipeline.progress import read_events, report_event, reset_events reset_events(tmp_path) report_event(tmp_path, "X", "tile", "ok") reset_events(tmp_path) assert read_events(tmp_path) == [] def test_read_events_missing_or_partial(tmp_path): """Dossier sans journal → liste vide ; ligne partielle → ignorée.""" from lidar_pipeline.progress import events_path, read_events assert read_events(tmp_path) == [] events_path(tmp_path).write_text( '{"tile": "X", "phase": "tile", "state": "ok"}\n' '{"tile": "X", "phase": "vi', encoding="utf-8") events = read_events(tmp_path) assert len(events) == 1 and events[0]["state"] == "ok" def test_short_name(): """Le nom court extrait col-row du nom de dalle IGN.""" from lidar_pipeline.progress import tile_short_name assert tile_short_name("LHD_FXX_1054_6882_PTS_LAMB93_IGN69") == "1054-6882" assert tile_short_name("LHD_FXX_1054_6882_PTS_LAMB93_IGN69.copc.laz") == "1054-6882" assert tile_short_name("autre.tif") == "autre.tif" assert tile_short_name("") == "" def test_aggregate_full_run(tmp_path): """Run complet : étapes ordonnées avec libellés français, tuile terminée.""" from lidar_pipeline.progress import aggregate_tiles, read_events, report_event, reset_events reset_events(tmp_path) b = "LHD_FXX_1054_6882_PTS_LAMB93_IGN69" report_event(tmp_path, b, "download", "skip", "déjà dans input/") report_event(tmp_path, b, "classif", "start") report_event(tmp_path, b, "classif", "ok") report_event(tmp_path, b, "dtm", "ok", res=0.5) report_event(tmp_path, b, "viz", "start", "aspect", res=0.5) report_event(tmp_path, b, "viz", "ok", "aspect", res=0.5) report_event(tmp_path, b, "tile", "ok", "123s") tiles = aggregate_tiles(read_events(tmp_path), viz_labels={"aspect": "Exposition"}) assert len(tiles) == 1 t = tiles[0] assert t["short"] == "1054-6882" and t["state"] == "done" assert [s["label"] for s in t["steps"]] == [ "Téléchargement", "Classification", "DTM 0,5 m", "Exposition"] assert [s["state"] for s in t["steps"]] == ["skip", "ok", "ok", "ok"] def test_aggregate_running_step(tmp_path): """Une étape démarrée non terminée laisse la tuile « running ».""" from lidar_pipeline.progress import aggregate_tiles, read_events, report_event, reset_events reset_events(tmp_path) b = "LHD_FXX_1054_6882_PTS_LAMB93_IGN69" report_event(tmp_path, b, "download", "ok") report_event(tmp_path, b, "classif", "ok") report_event(tmp_path, b, "dtm", "ok", res=0.5) report_event(tmp_path, b, "viz", "start", "aspect", res=0.5) tiles = aggregate_tiles(read_events(tmp_path)) assert tiles[0]["state"] == "running" assert tiles[0]["steps"][-1]["state"] == "running" def test_aggregate_failure_marks_tile_failed(): """Une viz en échec marque la tuile failed même sans événement tuile.""" from lidar_pipeline.progress import aggregate_tiles b = "LHD_FXX_1054_6882_PTS_LAMB93_IGN69" tiles = aggregate_tiles([ {"tile": b, "phase": "classif", "state": "ok"}, {"tile": b, "phase": "dtm", "state": "ok", "res": 0.5}, {"tile": b, "phase": "viz", "state": "start", "detail": "aspect", "res": 0.5}, {"tile": b, "phase": "viz", "state": "fail", "detail": "aspect", "res": 0.5}, ]) assert tiles[0]["state"] == "failed" aspect = [s for s in tiles[0]["steps"] if s["detail"] == "aspect"][0] assert aspect["state"] == "fail" def test_aggregate_multi_resolution_and_bad_input(): """Deux résolutions → deux étapes DTM/viz distinctes ; entrées invalides ignorées.""" from lidar_pipeline.progress import aggregate_tiles b = "LHD_FXX_1054_6882_PTS_LAMB93_IGN69" tiles = aggregate_tiles([ "pas du tout du json", None, {"tile": b, "phase": "inconnu", "state": "ok"}, {"tile": b, "phase": "dtm", "state": "ok", "res": 0.5}, {"tile": b, "phase": "dtm", "state": "ok", "res": 0.2}, {"tile": b, "phase": "viz", "state": "ok", "detail": "aspect", "res": 0.2}, {"tile": b, "phase": "tile", "state": "ok"}, ], viz_labels={"aspect": "Exposition"}) assert len(tiles) == 1 labels = [s["label"] for s in tiles[0]["steps"]] assert labels == ["DTM 0,5 m", "DTM 0,2 m", "Exposition 0,2 m"] # La résolution secondaire (0,2 m) est suffixée, la primaire (0,5 m) non def test_aggregate_multiple_tiles_ordered(): """Une entrée par tuile, dans l'ordre de première apparition.""" from lidar_pipeline.progress import aggregate_tiles a = "LHD_FXX_1054_6882_PTS_LAMB93_IGN69" b = "LHD_FXX_1055_6882_PTS_LAMB93_IGN69" tiles = aggregate_tiles([ {"tile": a, "phase": "download", "state": "ok"}, {"tile": b, "phase": "download", "state": "start", "detail": "catalogue IGN"}, {"tile": a, "phase": "tile", "state": "ok"}, ]) assert [t["short"] for t in tiles] == ["1054-6882", "1055-6882"] assert tiles[0]["state"] == "done" assert tiles[1]["state"] == "running"