- ☰ [설정] 마우스 탭 = 휠 방향 + 옮기기 버튼 라디오 · 규칙 글 = 고른 버튼 끌기 옮김(가운데는 늘) - 끌면 옮김 · 덜 끌고 떼면 그 버튼 제 몫(고름 · 메뉴 · CAD Enter) · 오른쪽 끌기 뒤 메뉴 안 뜸 - 왼쪽 옮김은 페이지가 잡은 누름(B05 노드 · 손잡이 · 마커 · 재기 · D03 겹 · 그림 안 도형)에선 비킴 - 자리: B05 · B06 · D03 노선 지도 · CAD · 공용 SVG 확대 · B04 지도 · 3D(오른쪽만) · B05 배수 · 종단 가로 · B08 이정표 · M02 흐름도 · 노임 - 시험: CAD 오른쪽 끌기 옮김 · 옮기기 자리 배선 대조 · 낡은 헬퍼 둘 새 import 대응 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
153 lines
5.6 KiB
Python
153 lines
5.6 KiB
Python
"""PLAN 588 — 단축키 등록부 · 겹침 판정 · CAD 리본 묶음 · 찾기 (요구 445 C2 · C3).
|
||
|
||
· 등록부 = `A00_Common/key_registry.ts` — ☰ [설정] 표가 여기서 그려짐 · 바꿀 수 있는 줄은 코드가 부름
|
||
· 키 글 = 한글 자판에서도 자판 자리로(Ctrl+ㅋ = Ctrl+Z) · 바꾼 키만 먹음 · 못 바꾸는 줄은 바꾼 값 무시
|
||
· 겹침 = 같은 화면 자리끼리 · 「모든 화면」과 · 브라우저 몫 · CAD 글자 단독 — 다른 화면끼리는 같은 키 됨
|
||
· CAD 묶음 = 리본 탭 › 패널 · 154 명령이 꼭 한 묶음 · 기타 여섯(리본에 없음)
|
||
짝: `helper_588_key_registry.cjs`(실제 TS 를 Node 로 돌림).
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import os
|
||
import subprocess
|
||
|
||
import pytest
|
||
|
||
HERE = os.path.dirname(__file__)
|
||
ROOT = os.path.join(HERE, "..", "..")
|
||
|
||
pytestmark = pytest.mark.skipif(
|
||
not os.path.isdir(os.path.join(ROOT, "config", "node_modules")),
|
||
reason="프론트엔드 의존성 미설치",
|
||
)
|
||
|
||
|
||
def _read(rel: str) -> str:
|
||
with open(os.path.join(ROOT, rel), encoding="utf-8") as f:
|
||
return f.read()
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def r() -> dict:
|
||
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||
["node", os.path.join(HERE, "helper_588_key_registry.cjs")],
|
||
capture_output=True,
|
||
text=True,
|
||
encoding="utf-8",
|
||
timeout=60,
|
||
)
|
||
assert proc.returncode == 0, proc.stderr
|
||
return json.loads(proc.stdout)
|
||
|
||
|
||
def test_CAD_154_명령_꼭_한_묶음_기타_여섯(r):
|
||
ids = r["groupIds"]
|
||
assert len(ids) == 154 and len(set(ids)) == 154
|
||
assert sorted(r["other"]) == ["LAYER", "PLACETABLE", "RECOVER", "REDO", "TOAREA", "UNDO"]
|
||
assert r["groups"][0]["label"] == "홈 › 그리기"
|
||
assert r["groups"][-1]["label"] == "" # 기타 이름은 화면 글(locale)
|
||
|
||
|
||
def test_찾기_낱말_모두_대소문자_무시(r):
|
||
f = r["find"]
|
||
assert {"LINE", "PLINE"} <= set(f["sun"]) and {"LINE", "PLINE"} <= set(f["L"])
|
||
assert "PLINE" in f["sunPl"] and "LINE" not in f["sunPl"] # 낱말 모두
|
||
assert f["blank"] == 154 and f["none"] == []
|
||
|
||
|
||
def test_키_글_한글_자판_안전(r):
|
||
c = r["chord"]
|
||
assert c["hangulCtrlZ"] == "Ctrl+Z"
|
||
assert c["ctrlShiftZ"] == "Ctrl+Shift+Z"
|
||
assert c["meta"] == "Ctrl+Z"
|
||
assert c["space"] == "Space"
|
||
assert c["shiftOnly"] == "" and c["process"] == ""
|
||
assert c["f3"] == "F3"
|
||
assert c["shiftDigit"] == "Ctrl+Shift+1"
|
||
assert c["arrow"] == "Shift+ArrowUp" and c["label"] == "Shift+↑"
|
||
|
||
|
||
def test_바꾼_키만_먹음_못_바꾸는_줄은_무시(r):
|
||
k = r["keyIs"]
|
||
assert k["delDefault"] is True and k["hangulUndo"] is True
|
||
assert k["delAfter"] is False and k["ctrlDAfter"] is True
|
||
assert k["fixedIgnored"] == ["Escape"]
|
||
assert k["cadAction"] == "cad.grid"
|
||
|
||
|
||
def test_겹침_판정(r):
|
||
c = r["check"]
|
||
assert c["none"] == {}
|
||
assert c["sameScope"] == {"plan.delete": "dup"}
|
||
assert c["withAll"] == {"plan.delete": "dup"}
|
||
assert c["withLoupe"] == {"plan.delete": "dup"}
|
||
assert c["otherPage"] == {} # D03 과 CAD 는 다른 화면
|
||
assert c["reserved"] == {"plan.delete": "reserved"}
|
||
assert c["cadLetter"] == {"cad.snap": "letter"}
|
||
assert c["cadShiftLetter"] == {"cad.snap": "letter"}
|
||
assert c["cadCtrl"] == {}
|
||
assert c["samePage"] == {"b05.undo": "dup"} # B05 · B06 한 페이지 — 횡단 Enter 와 겹침
|
||
assert c["swap"] == {} # 서로 바꿈은 됨
|
||
assert c["both"] == {"plan.drawFinish": "dup", "plan.drawBack": "dup"}
|
||
|
||
|
||
def test_등록부_꼴(r):
|
||
ids = [a["id"] for a in r["actions"]]
|
||
assert len(ids) == len(set(ids))
|
||
for a in r["actions"]:
|
||
assert a["scope"] in r["scopes"] and a["keys"]
|
||
assert a["id"].startswith(a["scope"] + ".")
|
||
|
||
|
||
# 바꿀 수 있는 줄 = 코드가 실제로 부름(등록부에만 있고 안 먹는 키 없음)
|
||
WIRED = {
|
||
"b05": "B05_Profile/B05_Profile_UI_Profile_Panel_Tools.ts",
|
||
"profile": "B05_Profile/B05_Profile_UI_Profile_Panel_Tools.ts",
|
||
"plan": "D03_PlanAnalysis",
|
||
"cad": "B07_DesignDetail/openwebcad/src/inputController",
|
||
}
|
||
|
||
|
||
def _sources(rel: str) -> str:
|
||
full = os.path.join(ROOT, rel)
|
||
if os.path.isfile(full):
|
||
return _read(rel)
|
||
names = sorted(n for n in os.listdir(full) if n.endswith(".ts"))
|
||
return "\n".join(_read(os.path.join(rel, n)) for n in names)
|
||
|
||
|
||
def test_바꿀_수_있는_줄은_배선됨(r):
|
||
for a in r["actions"]:
|
||
if a["fixed"]:
|
||
continue
|
||
src = _sources(WIRED[a["scope"]])
|
||
assert f'"{a["id"]}"' in src or f"'{a['id']}'" in src, a["id"]
|
||
|
||
|
||
def test_손글_안내_지움_표는_등록부():
|
||
assert "App_Settings_Keys_" not in _read("ui_template/ui_template_locale_common.ts")
|
||
assert "App_Settings_Keys_" not in _read("A00_Common/app_settings.ts")
|
||
|
||
|
||
# 588-4 — 화면 옮기기 자리는 모두 설정 버튼을 따름(가운데 고정 판정이 남지 않음)
|
||
PAN_SITES = [
|
||
"B05_Profile/B05_Profile_UI_RouteEdit_Input.ts", # B05 · B06 겹침 평면 · D03 지도
|
||
"B07_DesignDetail/openwebcad/src/inputController/input-controller.ts",
|
||
"A00_Common/b_svg_zoom_pan.ts",
|
||
"B04_PreProcess/B04_PreProcess_UI_MapViewer.ts",
|
||
"B04_PreProcess/B04_PreProcess_UI_Camera.ts",
|
||
"B05_Profile/B05_Profile_UI_Drainage_Interact.ts",
|
||
"B05_Profile/B05_Profile_UI_Profile_Wheel.ts",
|
||
"B08_Quantity/B08_Quantity_UI_Milestone_Diagram.ts",
|
||
"M02_MasterTemplete/DataFlow/M02_DF_Diagram.ts",
|
||
"M02_MasterTemplete/M02_MasterTemplete_Labor_Diagram.ts",
|
||
]
|
||
|
||
|
||
@pytest.mark.parametrize("rel", PAN_SITES)
|
||
def test_옮기기_자리는_설정_버튼(rel):
|
||
src = _read(rel)
|
||
assert "isPanButton(" in src or "isAuxPanButton(" in src, rel
|