Files
Aislo/resources/tester/test_283_route_reset_confirm.py
T
eomsangdonandClaude Opus 5.5 d2bf68b598 feat(492-2 노선 바뀜 확인): 모양 바뀐 노선 초안 띠 · [저장] · 추천 [적용] 확인 창(지워질 수) · 저장 뒤 초기화 알림
- 판정 = 저장 노선 대 초안이 그릴 선 정점 1 mm(`routeShapeChanged` · 파이썬 `route_shape_changed` 짝) · 스냅 · 간격 · 지형만 = 아님
- 띠 = 평면(노선 편집) 위 한 줄 · B06 평면 패널로 같이 옮겨짐 · 저장 노선 = 페이지 자료 줄 `pageRoutePlan`(조작마다 안 물음)
- [저장] 확인 창 = 잠금 막 · 서버 요청 앞 · 구조물 · 관 · 추가 측점 · 종단 편집 수 · [취소] = 요청 0 · 추천 [적용] 같은 글 · 수
- 저장 뒤 = 응답 `steps.route.route_reset` 지운 수 한 줄 · 초기화면 세션 초안 통째 비움 → 서버 정본으로 다시 세움 · 옛 서버(칸 없음) = 알림 건너뜀
- 시험: 새 test_283_route_reset_confirm(띠 · 확인 창 수 · [취소] · 스냅만 · 거울) · 저장 헬퍼 셋 확인 창 가짜 · 476-2 확인 글 기대 고침

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

193 lines
7.1 KiB
Python

# -*- coding: utf-8 -*-
"""283 · 492-2 노선 모양 바뀐 [저장] = 초기화 — 브라우저 판정 · 띠 · 확인 창 · 저장 뒤 알림.
거울(파이썬 = 서버 정본 판정 · TS = 브라우저 띠 · 확인 창 · 같은 값):
`B05_Profile_Engine_Grade_Carry.route_shape_changed` ↔ `logic/B05_Profile_Grade_Carry.ts` routeShapeChanged.
판정 입력 = 저장 노선(그린 선) 대 초안이 그릴 선(`draftLine`) — 스냅 · 간격 · 지형만 바뀜 = 아님.
[취소] = 요청 0 — `design_save` 가 잠금 막 · 서버 요청보다 먼저 묻는지(소스 차례).
"""
from __future__ import annotations
import copy
import json
import subprocess
import sys
from pathlib import Path
import pytest
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from B05_Profile import B05_Profile_Engine_Grade_Carry as grade_carry # noqa: E402
pytestmark = pytest.mark.skipif(
not (ROOT / "config" / "node_modules" / "typescript").is_dir(),
reason="프론트엔드 의존성 미설치",
)
NODES = [[0.0, 0.0], [200.0, 0.0], [400.0, 150.0], [600.0, 150.0], [800.0, 0.0]]
def _draft(nodes=NODES, **over) -> dict:
n = len(nodes)
draft = {
"rev": 0,
"nodes": copy.deepcopy(nodes),
"curveOn": [True] * n,
"curveRadius": [None] * n,
"curveLock": [None] * n,
"curveArc": [None] * n,
"stationSnap": False,
"stationSnapStep": None,
"terrain": None,
}
draft.update(over)
return draft
def _moved(index: int, dx: float, dy: float = 0.0) -> list:
nodes = copy.deepcopy(NODES)
nodes[index] = [nodes[index][0] + dx, nodes[index][1] + dy]
return nodes
BASE = _draft()
SAME = { # 선이 그대로 — 띠 · 창 없음
"snap_on": _draft(stationSnap=True),
"snap_step": _draft(stationSnap=True, stationSnapStep=10),
"terrain": _draft(terrain="las"),
"rev": _draft(rev=7),
"tiny": _draft(_moved(2, 0.0004)), # 0.4 mm — 1 mm 안
}
CHANGED = { # 모양 바뀜 — 띠 · 창
"drag20": _draft(_moved(2, 20.0)),
"radius": _draft(curveRadius=[None, 80.0, None, None, None]),
"add": _draft(NODES[:1] + [[100.0, 30.0]] + NODES[1:]),
"remove": _draft(NODES[:3] + NODES[4:]),
"curve_off": _draft(curveOn=[True, False, True, True, True]),
"end_drag": _draft(_moved(4, 0.0, 5.0)),
}
COUNTS = {"structures": 1, "pipes": 3, "plusStations": 1, "profileEdits": 2}
RESET = {"reset": True, "dropped": {"structures": 1, "pipes": 3, "plus_stations": 1}}
@pytest.fixture(scope="module")
def ts(tmp_path_factory):
drafts = {**SAME, **CHANGED}
payload = {
"min_radius_m": 30.0,
"base": BASE,
"drafts": drafts,
"counts": COUNTS,
"reset": RESET,
"pairs": [],
}
source = tmp_path_factory.mktemp("s283") / "in.json"
source.write_text(json.dumps(payload), encoding="utf-8")
first = _run(source)
# 거울 짝 — 저장 선 대 각 초안 선 · 같은 선 · 2 mm 흔듦
saved = first["saved"]
jitter = [[x + (0.002 if i == 3 else 0.0), y] for i, (x, y) in enumerate(saved)]
pairs = [[saved, line] for line in first["lines"].values()] + [[saved, saved], [saved, jitter]]
payload["pairs"] = pairs
source.write_text(json.dumps(payload), encoding="utf-8")
out = _run(source)
out["pair_inputs"] = pairs
return out
def _run(source: Path) -> dict:
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", str(HERE / "helper_283_route_reset_confirm.cjs"), str(source)],
capture_output=True,
text=True,
encoding="utf-8",
timeout=120,
check=False,
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
# ── 판정 ─────────────────────────────────────────────────────────────────────
@pytest.mark.parametrize("name", list(SAME))
def test_스냅_간격_지형만_띠_창_없음(ts, name):
assert ts["changed"][name] is False
@pytest.mark.parametrize("name", list(CHANGED))
def test_모양_바뀐_초안_띠_창(ts, name):
assert ts["changed"][name] is True
def test_초안_없음_아님_저장선_모름_바뀜(ts):
assert ts["nullDraft"] is False
assert ts["unknownSaved"] is True
def test_거울_파이썬_판정_같은값(ts):
judge = getattr(grade_carry, "route_shape_changed", None)
if judge is None:
pytest.skip("서버 판정 route_shape_changed 아직 없음(492-1 sub4 합침 전)")
for (old, new), got in zip(ts["pair_inputs"], ts["pairs"]):
assert judge(old, new) is got
assert ts["pairs"][-2] is False # 같은 선
assert ts["pairs"][-1] is True # 2 mm
# ── 확인 창 · [취소] ──────────────────────────────────────────────────────────
def test_확인창_안바뀜_묻지않음(ts):
gate = ts["gate"][0]
assert gate["ok"] is True and gate["asked"] == [] and gate["counted"] == 0
def test_확인창_수_취소_false(ts):
cancel, accept = ts["gate"][1], ts["gate"][2]
assert cancel["ok"] is False and accept["ok"] is True
for gate in (cancel, accept):
assert len(gate["asked"]) == 1 and gate["counted"] == 1
text = gate["asked"][0]
assert text.startswith("노선이 바뀌어 [저장]하면 초기화")
for part in ("구조물 1", "관 3", "추가 측점 1", "종단 편집 2", "횡단 손 입력"):
assert part in text
assert text.endswith("저장할까요?")
def test_추천_적용_같은글_같은수(ts):
text = ts["applyText"]
assert text.startswith("추천 노선을 [적용]하면 초기화")
tail = ts["gate"][2]["asked"][0].split("초기화", 1)[1].replace("저장할까요?", "")
assert text.split("초기화", 1)[1].replace("적용할까요?", "") == tail
def test_취소_요청0_잠금막_서버요청_앞(ts):
src = (ROOT / "A00_Common" / "design" / "design_save.ts").read_text(encoding="utf-8")
body = src[src.index("export async function saveDesign(") :]
ask = body.index("confirmRouteReset(")
assert ask < body.index("showLoadingOverlay()") < body.index("postDesignSave(")
assert "return false" in body[ask : body.index("showLoadingOverlay()")]
def test_띠_글(ts):
assert ts["band"].startswith("노선이 바뀌어 [저장] 하면 초기화")
for part in ("구조물", "관", "추가 측점", "종단", "횡단 손 입력"):
assert part in ts["band"]
# ── 저장 뒤 알림 ─────────────────────────────────────────────────────────────
def test_저장뒤_알림_dropped(ts):
assert ts["notice"] == (
"노선이 바뀌어 초기화했습니다 — 지움: 구조물 1 · 관 3 · 추가 측점 1 · 새 교차 관 2"
)
assert ts["noticeNone"] == [None, None]