- 마커 = 종단 알약과 같은 목록(laneStructures) · 노선 위 알약 꼴(종류 색) · 스냅 · 간격과 무관 - 고름 = 알약 고름과 같은 길(onStructureSelect · 공용 고름) · 알약 벌룬 그대로 · 좌우 20 m 법선 - 끌기 · 방향키 = 노선 따라 정수 m 1 m 씩 · 시점 · 종점 밖 안 감 · 놓을 때 알약 끌기와 같은 길로 한 번 - 집기 차례 = 교각점 · 곡선 손잡이 다음 · 옛 마름모 지움 - 시험 test_399_plan_structure_marks · test_391 마름모 줄 고침 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
129 lines
5.3 KiB
Python
129 lines
5.3 KiB
Python
"""399 B05 평면 구조물 측점 마커(요구 250-2) — 알약과 같은 목록 · 고름 = 공용 고름 · 정보 창(알약 벌룬) ·
|
||
20 m 법선 · 끌기 · 방향키 = 노선 따라 정수 m 1 m 씩 · 시점 · 종점 밖 안 감 · 놓을 때 한 번 옮김(알약과 같은 길).
|
||
|
||
TS 셈은 `helper_399_plan_structure_marks.cjs`(Node · 노선 셈 · 법선 · 걸음은 진짜).
|
||
|
||
./venv/Scripts/python.exe -m pytest resources/tester/test_399_plan_structure_marks.py -q
|
||
"""
|
||
|
||
import json
|
||
import subprocess
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
HELPER = Path(__file__).with_name("helper_399_plan_structure_marks.cjs")
|
||
|
||
|
||
def _read(*parts: str) -> str:
|
||
return (ROOT.joinpath(*parts)).read_text(encoding="utf-8")
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def got() -> dict:
|
||
run = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||
["node", str(HELPER)],
|
||
capture_output=True,
|
||
text=True,
|
||
encoding="utf-8",
|
||
timeout=120,
|
||
)
|
||
assert run.returncode == 0, run.stderr
|
||
return json.loads(run.stdout)
|
||
|
||
|
||
def test_마커_목록은_알약_목록(got) -> None:
|
||
assert got["laneGotSource"] is True # 알약 레인과 같은 `laneStructures`
|
||
assert got["plain"]["marks"] == [
|
||
{"color": "#e11d48", "at": [80, 0]}, # 40 m × 2 px · 종류 색
|
||
{"color": "#2563eb", "at": [160.34, 0]},
|
||
]
|
||
assert got["plain"]["normals"] == 0 and got["balloonsAfterPlain"] == 0
|
||
lane = _read("B05_Profile", "B05_Profile_UI_Structures_Marks.ts")
|
||
assert "const structures = laneStructures(options.structures);" in lane
|
||
marks = _read("B05_Profile", "B05_Profile_UI_RouteEdit_StructureMarks.ts")
|
||
assert "laneStructures(source.marks())" in marks
|
||
bridge = _read("B05_Profile", "B05_Profile_UI_Page_Structures.ts")
|
||
assert "setStructures([...ownStructures, ...pipeMarks]);" in bridge
|
||
assert "marks: (): StructureInstance[] => [...ownStructures, ...pipeMarks]," in bridge
|
||
assert "planMarksChanged(deps.projectId);" in bridge
|
||
|
||
|
||
def test_고름_정보_창_법선(got) -> None:
|
||
pipe = got["pickedPipe"]
|
||
assert pipe["ringAt"] == [[160.34, 0]] # 관 고름(누가거리만)도 그 마커
|
||
assert pipe["normal"] == [[160.34, -40], [160.34, 40]] # 좌우 20 m
|
||
assert pipe["balloon"]["lines"] == ["이름 pipe pos 80.17", "옵션 배수관"] # 알약 벌룬 줄
|
||
assert pipe["balloon"]["color"] == "#2563eb"
|
||
assert got["pickedStructureBalloon"] == ["이름 box pos 40", "옵션 BOX"]
|
||
assert got["balloonsAfterRelease"] == 0
|
||
|
||
|
||
def test_공용_고름과_같은_길() -> None:
|
||
view = _read("A00_Common", "design", "design_view_profile.ts")
|
||
assert " onStructureSelect,\n onStructureMarkMove,\n" in view # 알약 콜백 = 같은 함수
|
||
assert "select: onStructureSelect," in view and "move: onStructureMarkMove," in view
|
||
render = _read("B05_Profile", "B05_Profile_UI_RouteEdit_Render.ts")
|
||
labels = render.index("drawContourLabels(context, scene, band, style);\n drawStructureMarks")
|
||
nodes = render.index("scene.planned.forEach((vertex, index) => {")
|
||
assert labels < nodes # 라벨 위 · 교각점 아래
|
||
|
||
|
||
def test_집기_차례는_교각점_손잡이_다음() -> None:
|
||
pointer = _read("B05_Profile", "B05_Profile_UI_RouteEdit_Pointer.ts")
|
||
node = pointer.index("if (hitNode >= 0) {")
|
||
handle = pointer.index("} else if (dragHandle) {")
|
||
mark = pointer.index("} else if (marks.press(px, py)) {")
|
||
tick = pointer.index('if (!pick || !("chainage" in pick)) return false;')
|
||
assert node < handle < mark < tick
|
||
|
||
|
||
def test_끌기_1m_정수_놓을_때_한_번(got) -> None:
|
||
assert got["pressMiss"] is False and got["pressA"] is True
|
||
assert got["selects"] == ["A"]
|
||
assert got["movesBeforeRelease"] == 0 # 끄는 동안은 미리보기만
|
||
assert got["dragMove"] == ["A", 43] # 3 m
|
||
assert "2+0 → 2+3(+3 m) 옮김" in got["dragDoneStatus"]
|
||
assert got["oldDecimalStay"] is True # 옛 소수 자리 눌렀다 떼기 = 안 옮김
|
||
assert got["oldDecimalMoved"] == ["pipe-80.17", 81]
|
||
|
||
|
||
def test_노선_밖_안_감(got) -> None:
|
||
assert got["pastEnd"] == ["A", 200]
|
||
assert got["beforeStart"] == ["A", 0]
|
||
assert got["logic"]["clamp"] == [0, 199] # 종점 199.6 → 199(정수 m 안쪽)
|
||
assert got["logic"]["step"] == [81, 0, 199]
|
||
|
||
|
||
def test_방향키_노선_따라_1m(got) -> None:
|
||
assert got["keyRight"] == ["A", 41]
|
||
assert got["keyLeft"] == ["A", 39]
|
||
assert got["keyUpPerpendicular"] == ["A", 41] # 직각 = → · ↑ 가 +
|
||
assert got["keyRightWestward"] == ["A", 39] # 노선이 서쪽으로 가면 → = 뒤로
|
||
assert got["keyWithNodePicked"] == 0 # 교각점 고름 = 교각점 방향키 몫
|
||
assert got["keyNoPick"] == 0
|
||
|
||
|
||
def test_고른_마커_찾기(got) -> None:
|
||
logic = got["logic"]
|
||
assert logic["round"] == [41, 42]
|
||
assert (logic["pickId"], logic["pickNear"], logic["pickFar"], logic["pickOther"]) == (
|
||
"A",
|
||
"A",
|
||
None,
|
||
None,
|
||
)
|
||
assert got["redrawnOnChange"] == 1
|
||
|
||
|
||
def test_편집기_줄_수_그대로() -> None:
|
||
edit = _read("B05_Profile", "B05_Profile_UI_RouteEdit.ts")
|
||
assert edit.count("\n") <= 695
|
||
for name in (
|
||
"B05_Profile_UI_RouteEdit_StructureMarks.ts",
|
||
"B05_Profile_UI_RouteEdit_Render.ts",
|
||
"B05_Profile_UI_RouteEdit_Pointer.ts",
|
||
):
|
||
assert _read("B05_Profile", name).count("\n") <= 700
|