요구 651 · 653 — 계산 공식 참고용 흐름도(① M01 로직 상세 오른쪽 접는 패널)를 걷음. ② M02 일위대가 다이어그램은 그대로.
지움(64 파일 · 18,666 줄 · 되돌릴 길 = git 이력)
- M01 6 파일 1,064 줄 — Store_Flow.py · UI_LogicLab_Flow.ts/.css · FlowRows.ts · FlowView.ts/.css
- M02_MasterTemplete/DataFlow 43 파일 12,799 줄 — 흐름도 화면 · 셈(Compute · Convert · Lookup · Model · Eval …)
- 시험 15 파일 4,803 줄 — test_m01_logic_flow{view,_engine,_project,_save} · test_m02_df_*(값 찾기 values_old 뺌) — 지운 흐름 코드만 지키던 것
남김(바닥) — DataFlow M02_DF_UnitPick(일위대가 셋) · M02_DF_Values(M02_Item_Prices) · M02_DF_Round · _standard 표 ·
M02_DF_Router = GET /api/m02/df/standards 하나 · M02_DF_Api = cfStandards 하나 · CfRound 꼴은 Round 안으로
고침
- M01 Router — /save = Store_Make.save(개정 확인 · 자체 파일 새 줄 GX · added 그대로) · /calc /text /logic/auto = 옛 셈만 · /logic/flow 둘 지움
- master_formula — 흐름 훅 지움 · 줄에 「흐름」 이 남으면 「흐름도 로직은 걷음」 까닭 오류(저장된 흐름 로직 0 — 마스터 · storage 다시 확인)
- Sangeun_Calc._defaults = 옛 자동값 · M02_Logic_Lib_Read /logic/flow 지움 · main.py 주석
- 화면 — LogicLab(startFlow · scheduleFlow · 예시값 잇기 지움 · [신규 로직] 줄 = 입력 · 중간 · 호표 빈 목록 + 끝수 null) ·
Side(원문 패널 하나) · Source(머리 칸 이름 m01lab-src__top/__title · DF_Panel.css 안 씀) · Detail · View(nowInputs 지움) · Sheet(흐름 갈래 지움) · 글
- 시험 — 지운 파일을 가리키던 목록 넷(spreadsheet_size · 208_1 · 588 · input_prefs) · 717_1 흐름 길 두 줄 · values_old 흐름 셈 부분 지움
- test_713_3_list 기대 — 로직 1,461 → 1,515 · 묶음 307 → 335 · 작업량 21 → 65 · 부르는 506 → 512(782-1 · 2 · 3 건설 기초 로직 54 더함 ·
옛 키만 세면 307 · 21 · 506 그대로)
- 새 지킴 test_794_1b_flow_gone — 흐름 길 404 · 표준 표 남음 · 신규 로직 자체 GX · 흐름 남은 줄 까닭 오류
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
152 lines
5.6 KiB
Python
152 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/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
|