"""139-2 관보호공 연동 풀림 — 옆 측점 벽 0.1 m 걸음 · 푸는 순간 4축 굳힘 · 다시 연동 = 지움. 화면 TS 를 그 자리에서 돌린 값(`helper_139_2_link_freeze.cjs` · 73-4 픽스처 박스 352.14 흙막이 · 옆 측점 360). """ import json import subprocess from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] HELPER = Path(__file__).parent / "helper_139_2_link_freeze.cjs" NODE_MODULES = ROOT / "config" / "node_modules" pytestmark = pytest.mark.skipif(not NODE_MODULES.is_dir(), reason="프론트엔드 의존성 미설치") @pytest.fixture(scope="module") def out() -> dict: done = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", str(HELPER)], cwd=str(ROOT), capture_output=True, text=True, encoding="utf-8" ) assert done.returncode == 0, done.stderr return json.loads(done.stdout) def test_푸는_순간_4축이_차고_그림은_그대로(out: dict) -> None: assert set(out["frozen"]) == {"inlet", "outlet"} for adjust in out["frozen"].values(): assert isinstance(adjust["x"], (int, float)) assert isinstance(adjust["d"], (int, float)) # d 가 차서 자동 자리 · 정수 맞춤 안 탐 assert adjust["h"] > 0 and adjust["m"] assert out["frozen"]["outlet"]["h"] == pytest.approx(2.3) # 소유 측점 높이 그대로 assert out["detachedShape"] == out["linkedShape"] # 튐 없음 def test_푼_뒤엔_소유_측점_이동을_안_따라감(out: dict) -> None: assert out["afterOwnerMove"] == out["detachedShape"] assert out["linkedAfterMove"] != out["linkedShape"] # 대조 — 연동이면 따라감 def test_한_길_걸음_다시_연동_지움() -> None: stc = (ROOT / "B06_Section" / "B06_Section_UI_Page_Station_Controls.ts").read_text( encoding="utf-8" ) vs = (ROOT / "B06_Section" / "B06_Section_UI_Cross_View_Structure.ts").read_text( encoding="utf-8" ) # 카드 [연동] · 좌측 [연동] 모두 제어기 setLinked 로 — 풀면 굳힘 · 걸면 지움 assert "if (linked) dropLinkedAdjusts(chainageM);" in stc assert "freezeLinkedWalls(section" in stc assert "setLinked: (linked) => ctx.revetLink?.setLinked(ctx.section.chainage_m, linked)" in vs # 풀린 옆 측점 카드 = 0.1 m 걸음 assert "(ctx.isLinked && ctx.revetLink?.linkedFor(ctx.section) === false)" in vs