- 줌 [+ − ⤢] = 아이콘 단추 22 · 상세 [칸에 넣기] = 단추 22 · [여럿] = 켜기 칩 22 · 사이 금 지움 - 구조물 조정창 십자 · 9키 · 단 수 [-][+] = 아이콘 단추(선) 22 · ✕ = 고스트 · 옵션 연동 · 경사 = 켜기 칩 24(유입 · 유출 칸 꼴은 그대로) - 카드 머리 단면유형 = 배지(정보) 20 · 구조물 = 배지(강조) 20 - 알림 칩 = 단추(고스트) 20(색만 경고 / 정보) · 측점 목록 날 단추 = 단추(고스트) 20 - 날 details 넷(변수 위치 안내 · 상세값 · 다른 프로젝트 불러오기 · 횡단 조정) = 접이 구역(ui-collapsible) · 가이드 장면 선택자 `details.` 뗌 - 측점 없는 구조물 줄 · 표준 미반영 알림 = 띠 알림(경고) — 날 색 #fff8e6 · #e0b872 · #7a5a12 · #8a6a22 · 폴백 #d98324 지움 - 빈 그림 자리 = 빈 상태 · 선 치수 글 옛 보라 이름 → --color-accent - 흉내 DOM 시험 · 서버 Node 묶음이 끄는 파일이라 부품 함수 대신 클래스 · data-size 계약 + 부품 CSS 직접 실음(묶음 셋 빌드 정상) - 시험 넷 기대 고침 — 108(닫기 클래스) · 179-1(줌 사이 금 규칙 없음) · 196-1(칩 클래스) · 207-1(칩 반경 = 부품) - 그대로 둔 것 — 수량 산출표(b06-detail__qtable · B07 산출서 병합 칸 · 세로선 = 부품 표에 없는 꼴) · 조정창 고르기 · 암 절토 칸(작은 단 없음) · 조정창 · ⋯ · 측점 목록 떠 있는 판 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
133 lines
5.7 KiB
Python
133 lines
5.7 KiB
Python
"""PLAN 108 — 횡단도 안 조정창 끌기 두 축 · 패널 걸음 맞춤 · 미리 보기 = 결과 · BOX 끝 판정면.
|
|
|
|
짝: `B06_Section/B06_Section_UI_Cross_Panel_Base.ts`(`snapAxisDrag` · `bindDragHandle`) ·
|
|
`_Cross_Structure_Panel.ts` · `_Cross_View_Structure.ts`(벽 · 집수정 축 · 한계) · `_Cross_Box_Panel.ts` ·
|
|
`_Cross_Box.ts`(`boxHitBands`). 실제 TS 를 `helper_108_drag_box_hit.cjs` 가 Node 로 돌린다.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
HERE = os.path.dirname(__file__)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def out() -> dict:
|
|
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
|
|
["node", os.path.join(HERE, "helper_108_drag_box_hit.cjs")],
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=60,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
@pytest.mark.parametrize("side", ["diag1", "diag-1"])
|
|
def test_대각_끌기는_두_축이_함께_걸음_배수로(out, side) -> None:
|
|
"""배관 기준벽(0.1 m 걸음 · 225-1) — 사면 d · 수평 x 가 한 번에 · 값은 걸음 배수."""
|
|
case = out["wall"][side]
|
|
assert case["update"] == {"role": "outlet", "x": 1.3, "d": 4}
|
|
assert "◀" in case["snap"]["text"] or "▶" in case["snap"]["text"]
|
|
assert "▼ 2.0m" in case["snap"]["text"]
|
|
|
|
|
|
@pytest.mark.parametrize("side", ["diag1", "diag-1"])
|
|
def test_미리보기_자리는_놓은_뒤_자리와_같다(out, side) -> None:
|
|
"""미리 보기 이동 = `placePipeWall` 로 다시 푼 벽 자리 이동(화면 왼쪽 · 아래)."""
|
|
case = out["wall"][side]
|
|
assert case["snap"]["leftM"] == case["result"]["leftM"]
|
|
assert case["snap"]["downM"] == case["result"]["downM"]
|
|
|
|
|
|
def test_한계면_가장_가까운_허용_자리(out) -> None:
|
|
"""사면 위로 · 안쪽으로 넘겨 끌면 d 0 · x 0 에서 멈춤 — 원래 자리로 돌아가지 않음."""
|
|
case = out["wall"]["limit"]
|
|
assert case["update"] == {"role": "outlet", "x": 0, "d": 0}
|
|
assert case["snap"] == {"leftM": -1, "downM": -0.417, "text": "▶ 0.5m · ▲ 0.5m"}
|
|
|
|
|
|
def test_흙막이는_안쪽도_되고_10m_에서_멈춘다(out) -> None:
|
|
assert out["wall"]["guard"]["update"] == {"role": "outlet", "x": -10, "d": 0}
|
|
assert out["wall"]["guard"]["snap"]["leftM"] == -10
|
|
|
|
|
|
def test_다단_벽은_순수_수직_선반이_따라_나감(out) -> None:
|
|
"""다단 ▲▼ = 수직 하강 · x ≥ 1.2·d(선반) — 미리 보기도 그 자리."""
|
|
case = out["wall"]["extra"]
|
|
assert case["update"] == {"role": "extra0", "x": 1.2, "d": 1}
|
|
assert case["snap"]["leftM"] == 1.2 and case["snap"]["downM"] == 1
|
|
|
|
|
|
def test_집수정은_사면_축_0_1_걸음(out) -> None:
|
|
case = out["wall"]["basin"]
|
|
assert case["update"]["basin"]["lateralM"] == 0.9
|
|
assert case["update"]["basin"]["slopeM"] == 0.3
|
|
assert case["snap"] == {"leftM": -0.9, "downM": 0.25, "text": "▶ 0.6m · ▼ 0.3m"}
|
|
|
|
|
|
def test_걸음_반도_안_끌면_반영_없음(out) -> None:
|
|
assert out["wall"]["basinNone"] == {
|
|
"snap": {"leftM": 0, "downM": 0, "text": ""},
|
|
"update": None,
|
|
}
|
|
|
|
|
|
def test_BOX_끌기는_길이_표고_함께(out) -> None:
|
|
assert out["box"]["left"]["move"] == {"role": "left", "screen": 0.5, "rise": -0.3}
|
|
assert out["box"]["left"]["snap"]["leftM"] == 0.5
|
|
# 위로는 기본 자리(노면 − 복토)까지만(139-3) — 0 에서 0.2 올리기 = 그대로
|
|
assert out["box"]["right"]["move"] == {"role": "right", "screen": -0.5, "rise": 0}
|
|
|
|
|
|
def test_BOX_한계_길이_0_표고_0(out) -> None:
|
|
"""안으로 줄이면 길이 0 에서 · 표고는 0(기본 자리) 위로 못 감 — 옛 +9.9 는 0 으로 내려옴(139-3)."""
|
|
assert out["box"]["shorten"]["move"] == {"role": "left", "screen": -0.2, "rise": -9.9}
|
|
|
|
|
|
def test_세월교_끌기는_좌우_수직_함께(out) -> None:
|
|
"""좌우 0.5 · 바닥판 내림 0.3(수직 · 0.1 걸음 · 139-3) — 두 축이 따로."""
|
|
case = out["ford"]["diag"]
|
|
assert case["move"] == {"role": "inlet", "screen": 0.5, "slope": 0.3}
|
|
assert case["snap"] == {"leftM": 0.5, "downM": 0.3, "text": "◀ 0.5m · ▼ 0.3m"}
|
|
|
|
|
|
def test_세월교_기본_자리_위로는_못_감(out) -> None:
|
|
"""내림 0.2 에서 0.5 올려도 0(기본 자리)까지만(139-3)."""
|
|
case = out["ford"]["up"]
|
|
assert case["move"] == {"role": "inlet", "screen": 0, "slope": -0.2}
|
|
|
|
|
|
def test_세월교_노견_안쪽은_0_에서_멈춤(out) -> None:
|
|
"""좌우 0.2 에서 안쪽으로 0.9 끌어도 0 까지만(가장 가까운 허용 자리)."""
|
|
case = out["ford"]["inward"]
|
|
assert case["move"] == {"role": "inlet", "screen": 0.2, "slope": 0}
|
|
assert case["snap"]["leftM"] == 0.2
|
|
|
|
|
|
def test_조정창은_제목과_단추만(out) -> None:
|
|
"""머리줄 = 제목 · 닫기(집수정 ↺ 없음) · BOX 오버레이 읽기 줄 = 끄는 중 미리 보기 하나."""
|
|
assert out["wall"]["diag1"]["overlayHead"] == [
|
|
"b06-structure-panel__title",
|
|
# 553-2 — 닫기 = 부품 아이콘 단추(선) 22 + 고스트 덮음
|
|
"ui-icon-btn ui-icon-btn--outline b06-structure-panel__btn b06-structure-panel__close",
|
|
]
|
|
assert out["box"]["left"]["value"] == ["b06-structure-panel__drag"]
|
|
assert out["ford"]["diag"]["value"] == ["b06-structure-panel__drag"]
|
|
|
|
|
|
def test_BOX_끝_판정면은_본체로_안_넘어감(out) -> None:
|
|
"""본체 = 두 구체 끝 사이 · 끝 = 구체 끝 ~ 에이프런 바깥 · 날개벽 없는 끝 = 바깥 0.3 m 띠."""
|
|
hit = out["hit"]
|
|
assert hit["body"]["offsets"] == [-4, 4]
|
|
assert hit["left"]["offsets"] == [4, 6]
|
|
assert hit["right"]["offsets"] == [-4.3, -4]
|
|
for role in ("body", "left", "right"):
|
|
assert hit[role]["elevations"] == [96.5, 99]
|