"""PLAN 356-4 sub7 — 되돌리기 · 다시하기 = 그 걸음 사진(노선 + 계획고 편집) 그대로. · 노선 바뀜 규칙(바뀐 구간 첫 계획선 맞춤 · 계획고 옮김)은 새 조작 때만 — 되살림 때는 안 탐 · 끌기 → 계획고 ▲(측점 C) → 다시 끌기(새 조작 = ▲ 버림) → 되돌리기 = ▲ 그대로 · 다시하기 = 다시 끌기 값 · 중심점 좌우 꼴(끌기 + C 높이 보정 한 걸음) → 되돌리기 = 조작 전 계획고 · 편집 · 다시하기 = 보정 값 · 고침을 끈 판(옛 동작)은 되돌리기에서 ▲ · 보정이 사라짐 — 시험이 흠을 실제로 잡음 짝: `helper_356_4_undo_grade.cjs`(판 = 349-0q · 실제 TS 를 Node 로 · 화면 부품 · 서버 창구만 가짜). """ from __future__ import annotations import json import subprocess import tempfile from pathlib import Path import pytest import test_349_0q_undo_echo as base HERE = Path(__file__).resolve().parent def _run(job: dict, mode: str) -> dict: with tempfile.TemporaryDirectory() as folder: path = Path(folder) / "job.json" path.write_text(json.dumps(job), encoding="utf-8") grid = Path(folder) / "grid.bin" grid.write_bytes(base.dtm_grid_bytes(base.GRID)) proc = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", str(HERE / "helper_356_4_undo_grade.cjs"), str(path), str(grid), mode], capture_output=True, text=True, encoding="utf-8", timeout=300, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) @pytest.fixture(scope="module") def job() -> dict: return base.build_job() # 349-0q 판 입력(검증_sub7) @pytest.fixture(scope="module") def r(job) -> dict: return _run(job, "on") @pytest.fixture(scope="module") def off(job) -> dict: return _run(job, "off") def test_새_조작은_바뀐_구간_계획고_편집을_버림(r): c = f"{r['C']:.3f}" assert c in json.loads(r["lift"]["offs"]) # ▲ 가 C 에 assert c not in json.loads(r["drag2"]["offs"]) # 다시 끌기(새 조작) = 버림 assert r["drag2"]["route"] != r["lift"]["route"] def test_되돌리기_다시하기_그_걸음_사진(r): assert r["undo1"]["route"] == r["lift"]["route"] assert r["undo1"]["offs"] == r["lift"]["offs"] # ▲ 그대로 assert r["undo1"]["z"] == pytest.approx(r["lift"]["z"], abs=1e-4) assert r["redo1"]["route"] == r["drag2"]["route"] assert r["redo1"]["offs"] == r["drag2"]["offs"] assert r["redo1"]["z"] == pytest.approx(r["drag2"]["z"], abs=1e-4) def test_중심점_좌우_보정_되돌리기(r): pinned = r["pinned"] assert pinned["z"] == pytest.approx(pinned["zBefore"], abs=1e-3) # 높이 보정 assert pinned["offs"] != r["redo1"]["offs"] assert r["undo2"]["route"] == r["redo1"]["route"] assert r["undo2"]["offs"] == r["redo1"]["offs"] # 조작 전 편집 assert r["undo2"]["z"] == pytest.approx(pinned["zBefore"], abs=1e-4) # 조작 전 계획고 assert r["redo2"]["route"] == pinned["route"] assert r["redo2"]["offs"] == pinned["offs"] # 보정 값 assert r["home"]["route"] is None and r["home"]["offs"] == r["open"]["offs"] assert r["blocked"] == 0 def test_옛_동작은_되돌리기에서_편집이_사라짐(off): c = f"{off['C']:.3f}" assert c not in json.loads(off["undo1"]["offs"]) # ▲ 사라짐(고친 흠) assert off["redo2"]["offs"] != off["pinned"]["offs"] # 다시하기에서 보정 사라짐