# -*- coding: utf-8 -*- """PLAN 189-1 — 노면공(여러 측점 구간) 고름 세 갈래 · 종단 측점선(사용자 41번). 못박는 것 ① 좌측 목록 노면공 = 범위 카드 전부 테두리 + 포장층 강조 · 카드 하나 안 고름 · 종단 측점선 없음. ② 카드 안 노면공 형상 누름 = ① 과 같음(고른 카드도 풂 · 카드 고름 리스너 안 돎). ③ 카드 하나 누름(형상 밖) = 목록 고름 · 범위 강조 풂 · 그 카드 하나 · 종단 측점선 = 그 카드 · 세션 sid 없음. 같은 카드 재누름 = 풂 · 관 자리 카드 = 관. 상태는 `helper_165_pavement_flow.cjs`(진짜 SPN) · 형상 → 노면공 찾기는 `helper_189_1_pave_shape.cjs`. """ import json import os import re import subprocess import pytest HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.abspath(os.path.join(HERE, "..", "..")) pytestmark = pytest.mark.skipif( not os.path.isdir(os.path.join(ROOT, "config", "node_modules")), reason="프론트엔드 의존성 미설치", ) def _node(name: str) -> dict: proc = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", os.path.join(HERE, name)], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) @pytest.fixture(scope="module") def flow() -> dict: return _node("helper_165_pavement_flow.cjs") @pytest.fixture(scope="module") def shape() -> dict: return _node("helper_189_1_pave_shape.cjs") def _read(*parts: str) -> str: with open(os.path.join(ROOT, *parts), encoding="utf-8") as handle: return handle.read() PAVE = { "form": "pave", "pill": "pave", "paveLayer": "pave", "paveCards": 12, "card": None, "sid": "pave", "line": None, } def _card(at): return { "form": None, "pill": None, "paveLayer": None, "paveCards": 0, "card": at, "sid": None, "line": None if at is None else f"s{at}", } def test_1_목록_고름은_범위_카드_전부_종단_선_없음(flow) -> None: assert flow["r1"] == PAVE def test_2_형상_누름은_목록_고름과_같음(flow) -> None: assert flow["r2first"] == PAVE # 처음부터 형상 assert flow["r2"] == PAVE # 카드 하나 고른 뒤 형상 = 옛 카드 풂 assert flow["r2reveal"] == "s40" def test_3_카드_하나는_목록_고름과_범위_강조를_풂(flow) -> None: assert flow["r3"] == _card(140) assert flow["r3b"] == _card(100) assert flow["r3re"] == _card(None) # 같은 카드 재누름 = 풂 pipe = flow["r3pipe"] assert (pipe["form"], pipe["pill"], pipe["paveCards"], pipe["sid"]) == ( "pipe-80.17", "pipe-80.17", 0, None, ) def test_누른_포장층은_범위_표식으로_그_노면공(shape) -> None: assert shape["pave"] == "pave" assert shape["pave2"] == "pave2" # 겹친 노면공 = 누른 층 for key in ("plainLayer", "outside", "noTarget", "unknown"): assert shape[key] is None, key def test_배선() -> None: view = _read("B06_Section", "B06_Section_UI_Section_View.ts") # 형상 누름은 카드 고름보다 먼저 가로챔(잡기 단계 · 전파 멈춤) body = re.search( r"const pave = pavementAt\(event\.target, spanMarks\);(.*?)true,\n", view, re.S ) assert body, "형상 누름 배선 없음" assert "event.stopPropagation();" in body.group(1) assert "pavementSelectListener?.(pave.structure_id);" in body.group(1) cross = _read("A00_Common", "design", "design_view_cross.ts") assert ( "sectionView.setPavementSelectListener((id) => structuresPanel.selectStructure(id));" in cross ) # 카드 하나 고름 = 그 측점(구조물 id 는 목록 · 알약 · 넘김만) assert "const preferred = structuresPanel.preferred() !== null;" in cross assert ( "const picked = preferred ? opened : { chainageM: opened.chainageM, structureId: null };" in cross ) profile = _read("A00_Common", "design", "design_view_profile.ts") assert "const structurePick = !!readSelection(activeProjectId)?.structureId;" in profile