Files
Aislo/resources/tester/test_383_2_route_keys.py
T
eomsangdonandClaude Opus 5.5 e0abf8c5bf feat(383-2): 평면 교각점 방향키 — 화면 축 0.1 m · Shift ×10 · 뗄 때 한 걸음(스냅이면 맞춤 + 실제 이동 · 함께 밀린 IP)
- 새 파일 B05_Profile_UI_RouteEdit_Keys.ts(창 keydown 가로채기 · 마지막 누름 평면 안 · 고정 · 입력칸 제외 · 하한 검사) + logic/KeyNudge
- 평면을 누른 뒤 방향키는 평면이 삼킴 — 종단 ▲▼ · 횡단 조정창으로 안 샘
- B06 Panel_Base lastPointerWithin 넓힘 · Pointer.ts 걸기 한 줄

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
2026-10-17 15:11:46 +09:00

81 lines
3.5 KiB
Python

"""383-2 교각점 방향키 — `logic/B05_Profile_RouteEdit_KeyNudge.ts` 를
Node(`helper_383_2_key_nudge.cjs`)로 돌려 판정(화면 축 0.1 m · Shift ×10 · 돌린 지도 · 스냅 뒤
실제 이동 · 함께 밀린 IP · 제자리 안내) + 이음(`_RouteEdit_Keys` · 끌기 걸기 한 줄 · 평면이
삼킴 → 종단 ▲▼ 비킴).
./venv/Scripts/python.exe -m pytest resources/tester/test_383_2_route_keys.py -q
"""
import json
import math
import subprocess
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
B05 = ROOT / "B05_Profile"
HELPER = Path(__file__).with_name("helper_383_2_key_nudge.cjs")
@pytest.fixture(scope="module")
def got() -> dict:
run = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", str(HELPER)], capture_output=True, text=True, encoding="utf-8", timeout=60
)
assert run.returncode == 0, run.stderr
return json.loads(run.stdout)
def _read(name: str) -> str:
return (B05 / name).read_text(encoding="utf-8")
def test_화면_축_0_1m_Shift_10배(got) -> None:
plain = got["plain"]
assert plain["ArrowUp"] == pytest.approx([0, 0.1]) # 화면 위 = 도면 북쪽(뒤집힌 y)
assert plain["ArrowDown"] == pytest.approx([0, -0.1])
assert plain["ArrowLeft"] == pytest.approx([-0.1, 0])
assert plain["ArrowRight"] == pytest.approx([0.1, 0])
assert got["shift"]["ArrowRight"] == pytest.approx([1.0, 0])
assert got["arrows"] == [True, True, True, True, False]
def test_돌린_지도도_화면_위(got) -> None:
up = got["rotated"]["ArrowUp"]
turn = math.radians(30)
assert math.hypot(*up) == pytest.approx(0.1)
assert up == pytest.approx([-0.1 * math.sin(turn), 0.1 * math.cos(turn)])
def test_스냅_뒤_실제_이동_함께_밀린_IP(got) -> None:
assert got["snapped"]["movedM"] == pytest.approx(0.8)
assert got["snapped"]["pushed"] == 1
assert got["stayed"]["movedM"] == pytest.approx(0.02) and got["stayed"]["pushed"] == 0
assert got["merged"]["movedM"] == pytest.approx(0.4) and got["merged"]["pushed"] == 0
messages = got["messages"]
assert "실제 이동 0.8 m" in messages["snapped"] and "함께 밀린 IP 1곳" in messages["snapped"]
assert "같은 측점 — 스냅 끄고 미세 조정" in messages["stayed"]
assert "0.3 m 옮겼습니다" in messages["free"]
def test_이음_끌기_걸기_한_줄_창_가로채기() -> None:
pointer = _read("B05_Profile_UI_RouteEdit_Pointer.ts")
assert pointer.count("bindRouteEditKeys(") == 1
keys = _read("B05_Profile_UI_RouteEdit_Keys.ts")
assert 'window.addEventListener("keydown", onKeyDown, true)' in keys # 앞서 받음(capture)
assert 'lastPointerWithin(".b05-routeedit")' in keys
assert "event.preventDefault();\n event.stopPropagation();" in keys
assert "state.apexLock[index] === true" in keys # 고정 IP 는 안 옮김
assert "shortfallCrossed(" in keys # 하한 검사 = 끌기와 같음
assert "params.commit();" in keys # 뗄 때 한 걸음(스냅이면 그때 맞춤)
# 종단 ▲▼ 는 앞선 preventDefault 를 보고 비킴
tools = _read("B05_Profile_UI_Profile_Panel_Tools.ts")
assert "if (event.defaultPrevented) return;" in tools
base = (ROOT / "B06_Section/B06_Section_UI_Cross_Panel_Base.ts").read_text(encoding="utf-8")
assert "export function lastPointerWithin(selector: string)" in base
def test_RouteEdit_본문_줄_안_늘림() -> None:
assert len(_read("B05_Profile_UI_RouteEdit.ts").splitlines()) <= 700