"""PLAN 294-7 — 물넘이 콘크리트 누름 고침(브레인 검증 297). - 기본 배율 콘크리트(약 4 px) = 보라 노면선 판정 띠(위아래 5 px)에 덮였음 → 형상 판정면을 아래쪽으로 최소 두께(12 px)까지 늘림 · 노면선 바로 아래 누름 = 콘크리트 · 노면선 위는 보라 선 그대로(185 끌기) - 콘크리트 누름 = 그 물넘이(자기 id 누가거리) 고름 — 카드에 걸친 연동 관(95 m) · 자기 다른 관으로 안 감 · 자기 관 없는 카드의 「관」 되살림도 물넘이 · 관 몸통 누름은 자기 관 그대로 · 다시 누름 = 풂 - 맹암거 형상 = 알림(목록이 id 로 고름) 그대로 - 294-8 · 295-4 안 골라진 카드 첫 누름 = 눌린 대상 — 카드 고름이 연동 관으로 폼을 옮기지 않음 · 폼을 열 때 두 번 그림(기본값 → 시설 값)에 선 도수로 상자를 「새 상자」로 골라 덮지 않음(Esc 뒤 · 다른 카드 고른 뒤) 실제 TS 를 `helper_294_7_ford_slab_pick.cjs` 가 Node 로 돌린다. """ from __future__ import annotations import json import os import subprocess import pytest HERE = os.path.dirname(__file__) ROOT = os.path.join(HERE, "..", "..") B06 = os.path.join(ROOT, "B06_Section") pytestmark = pytest.mark.skipif( not os.path.isdir(os.path.join(ROOT, "config", "node_modules")), reason="프론트엔드 의존성 미설치", ) def _read(name: str) -> str: with open(os.path.join(B06, name), encoding="utf-8") as f: return f.read().replace(chr(13), "") @pytest.fixture(scope="module") def out() -> dict: proc = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", os.path.join(HERE, "helper_294_7_ford_slab_pick.cjs")], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def test_기본_배율_노면선_바로_아래_누름은_콘크리트(out): s = out["slab"] assert s["thick"] == "100,100 200,96 200,108 100,112" # 아랫변만 8 내림(평균 두께 4 → 12) assert s["bottomAt150"] == 110 assert s["justBelowOld"] is None and s["justBelow"] == "slab" # 노면선 6 px 아래 assert s["insideOld"] == "road" # 옛 판정면은 통째로 보라 띠 안 assert s["onLine"] == "road" # 노면선 위 = 보라 선 그대로(끌기 · 185) assert s["order"] == ["slab", "road"] assert s["tallUnchanged"] is True # 두꺼운 형상(맹암거 등)은 그대로 def test_형상_누름_길(out): assert out["routed"] == [["pipe", 90], ["event", "ud-1"]] def test_연동_관_있는_카드에서도_자기_물넘이(out): o = out["owner"] assert o["slabOwnCard"] == [["remember", 90, "pipe"], ["form", 90]] # 옛 = 연동 관 95 assert o["slabHint"] == [["remember", 90, "pipe"], ["form", 90]] assert o["slabLinkedCard"] == [["remember", 90, "pipe"], ["form", 90]] assert o["pipeBody"] == [["remember", 80, "pipe"], ["form", 80]] assert o["chute"] == [["remember", 90, "chute"], ["form", 90]] def test_다시_누름은_풂(out): assert out["owner"]["release"] == [["remember", 90, ""], ["release"]] def test_배선_경사각도_상자(): view = _read("B06_Section_UI_Cross_View.ts") assert 'shapePickRoute(svg, (at) => toggleRevet("pipe", at))' in view assert "revetOffset?.select(section.chainage_m, activeRevet, ownerM);" in view # 「관」 = 관 그림 · 콘크리트 하나만(307) assert "splitPipePick(setRevetActive, setShapeActive, shapePicked)" in view assert len(view.splitlines()) <= 700 shape = _read("B06_Section_UI_Cross_Shape_Pick.ts") assert 'thickenDown(shape.getAttribute("points") ?? "")' in shape # 폼에 물넘이(관 상자 없음) = 「경사각도」 상자(294-2 그대로) dock = _read("B06_Section_UI_Adjust_Dock.ts") assert 'side === "pipe" && (!own || own.closest("[hidden]")) ? visibleBox(SLOPE_BOX)' in dock def test_안_골라진_카드_콘크리트_첫_누름_294_8(out): f = out["first"] want = [["select", 90, "pipe"], ["remember", 90, "pipe"], ["form", 90], ["form", 90]] assert f["slabAfterEsc"] == want # 옛 = 폼 95 · {at:95, key:"chute"} assert f["slabAfterOther"] == want # 4+15 배관 고른 뒤도 def test_안_골라진_카드_보라_선_첫_누름_295_4(out): f = out["first"] want = [["select", 110, None], ["remember", 110, ""], ["release"], ["form", 110]] assert f["lineAfterEsc"] == want # 옛 = {at:110, key:"chute"} · 선 풀림 assert f["lineAfterOther"] == want def test_폼_안_새_상자는_그대로_고름(out): assert out["first"]["addBox"] == [ ["select", 95, "extra0"], ["remember", 95, "extra0"], ["form", 95], ] def test_배선_카드_고름_리스너(): with open( os.path.join(ROOT, "A00_Common", "design", "design_view_cross.ts"), encoding="utf-8" ) as f: raw = f.read() cross = " ".join(raw.split()) assert "structuresPanel.showAtChainage(structureSelection.formChainageOf(target))" in cross assert len(raw.splitlines()) <= 685 # 233-2 · 233-3 · 298 한도 sel = _read("B06_Section_UI_Page_Structures_Selection.ts") assert "(wallOwner ?? stationControls.structureSpan.ownerOf(target)?.chainage_m)" in " ".join( sel.split() ) assert "if (!born || chainageM === null || opening) return;" in sel