"""624-4 화면 — 예정노선 지형 칩 라이다 · LAS 올리기(요구 530 · 531). · 칩 = 예정노선 지형 칸(`UI_LidarUpload`)이 만듦 · 공용 칩 안 그대로 · 지도는 넘겨받기만 · 라이다 없음 = 「라이다」 숨기고 [LAS 올리기](부품 단추 · 파일 고르기) · 진행 = 위치 칸 서클 하나 · 고른 원천 = 세션 등록부 `d03-terrain`(draft · project) · 겹 급경사 · 음영 · 0차곡 = `terrain=` · 높이 = 원천 격자 · 원천 바뀜 = 지형 겹 셋만 비우고 다시 ./venv/Scripts/python.exe -m pytest resources/tester/test_624_4b_plan_lidar_ui.py -q """ from __future__ import annotations from pathlib import Path ROOT = Path(__file__).resolve().parents[2] D03 = ROOT / "D03_PlanAnalysis" def _read(path: Path) -> str: return path.read_text(encoding="utf-8") def test_chip_made_by_plan_terrain() -> None: ui_map = _read(D03 / "D03_PlanAnalysis_UI_Map.ts") assert "createTerrainChip" not in ui_map and "terrain: events.terrain," in ui_map lidar = _read(D03 / "D03_PlanAnalysis_UI_LidarUpload.ts") assert "onChange: (next) => void choose(next)" in lidar assert 'chip.setHave(ready ? ["sheet", "lidar"] : ["sheet"])' in lidar chip = _read(ROOT / "A00_Common" / "map" / "map_terrain_chip.ts") assert "onChange?: (value: TerrainSource) => void;" in chip # 칩 꼴 그대로 def test_upload_uses_parts_and_one_circle() -> None: # 올리기 단추 · 보냄 · 1 초 묻기 = 공용 부품(637-3 · B05 같음) · 예정노선 = 주소 · 서클만 part = _read(ROOT / "A00_Common" / "map" / "map_lidar_upload.ts") assert 'label: "LAS 올리기"' in part and "createButton({" in part assert 'pickFiles({ accept: ".las,.laz,.prj", multiple: true }' in part assert "const POLL_MS = 1000;" in part and "button.disabled = on;" in part lidar = _read(D03 / "D03_PlanAnalysis_UI_LidarUpload.ts") for text in (lidar, part): assert 'createElement("button")' not in text and 'createElement("input")' not in text assert "createProgressCircle" not in text # 서클 = 위치 칸 하나(604-3) assert "path: `/projects/${projectId}/plan/lidar`" in lidar assert 'label: "라이다"' in lidar and "track: (job) => work.track(job)" in lidar assert "void lidarUpload.follow()" in lidar assert 'lidarItem.style.display = !ready && editable ? "none" : ""' in lidar api = _read(D03 / "D03_PlanAnalysis_Api.ts") assert "Promise<{ terrain: PlanJob; lidar: PlanJob }>" in api def test_source_session_only() -> None: lidar = _read(D03 / "D03_PlanAnalysis_UI_LidarUpload.ts") assert 'writeState("d03-terrain", source, projectId)' in lidar assert "sessionStorage" not in lidar and "localStorage" not in lidar state = _read(ROOT / "A00_Common" / "b_page_state.ts") assert '"d03-terrain": { bucket: "draft", scope: "project" },' in state page = _read(D03 / "D03_PlanAnalysis_UI_Page.ts") assert "d03-terrain" not in page # 저장 꼴(d03-plan) 그대로 def test_layers_and_heights_follow_source() -> None: api = _read(ROOT / "A00_Common" / "map" / "map_layer_api.ts") assert 'terrain ? `&terrain=${terrain}` : ""' in api assert "/layers/raster?kind=${kind}${terrainQuery(terrain)}" in api assert "/layers/zero-order?${terrainQuery(terrain).slice(1)}" in api layers = _read(D03 / "D03_PlanAnalysis_UI_Layers.ts") assert "fetchPlanRaster(projectId, key, terrain())" in layers assert 'key === "hillshade" ? terrain() : undefined' in layers # 산사태위험 = 원천 없음 assert "fetchPlanZeroOrder(projectId, terrain())" in layers body = layers.split("async function reterrain(): Promise {")[1].split("\n }\n")[0] assert 'for (const key of ["slope", "hillshade", "zeroOrder"] as const)' in body assert "areaTurn += 1;" in body and "pending.clear();" in body page = _read(D03 / "D03_PlanAnalysis_UI_Page.ts") assert "const heights = terrain.surface(surface);" in page assert "onChange: () => (void backdrop.reterrain(), refresh())," in page assert "await Promise.all([loadSurface(), terrain.load()]);" in page assert len(page.splitlines()) < 700 and len(layers.splitlines()) < 683