Files
Aislo/resources/tester/test_383_2_route_keys.py
T
eomsangdonandClaude Opus 5.5 5555be5e42 fix(498-1 메모리): 평면 편집 키 듣개 둘을 캔버스 수명에 묶음 — 요구 298-3
- B05_Profile_UI_RouteEdit_StructureMarks · B05_Profile_UI_RouteEdit_Keys 의 창 keydown · keyup · blur 듣개를 listenWhileAlive 로 · 다음 키 누름 때만 떨어지던 detach 걷음
- 시험: test_298_3_page_dispose 두 칸 더함 · test_383_2 · helper_399 가 @ui 듣기 틀을 읽음
- 확인: 키 누름 없이 [저장] 다섯 번 GC 뒤 힙 39 → 123 → 205 → 205 → 206 → 206 MB(둘째부터 평탄)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 23:32:28 +09:00

84 lines
3.6 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 (
'listenWhileAlive(window, "keydown", canvas, onKeyDown, true)' in keys
) # 앞서 받음(capture)
# 마지막 누름이 평면 안 — B06 겹침 평면도 같음(436)
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