- 암 경계 · 암 절토 경사 저장소(`B06_Section_UI_Page_Persist`) = 세션 칸이 주인 — 읽을 때마다 측점 열쇠 칸(`readCells`) · 고칠 때 지금 칸을 읽어 그 측점만 바꿔 씀(`putCell`) · 메모리 맵 · load · 갈아끼움 다시 읽기(keyedStores · reloadKeyedStores) 걷음 · ↶ 뒤 다음 조작이 되돌림을 덮던 흠(N5) 고침 - 저장 재료 = `offsets()` · `ratios()`(새 Map) · ↶ ↷ 가 rockb · cutslope 칸을 바꾸면 조정창과 같은 onRestore 로 카드 · 면적 다시 - B05 상단측 메모리 맵(uphillOverrides · load/saveUphillOverrides) 걷음 — 읽는 곳 없이 저장 뒤 비우기만 하던 사본 · 값 주인 = 세션 칸 `uphill` · 상단측 차례 = 기본 조각 그대로 - 노선 바뀐 [저장] 성공 뒤(페이지 다시 세운 뒤) 옛 노선 번호의 노선 범위 초안(`clearRouteDrafts`) · `route-draft-hold` 비움 · 넘김 규칙 그대로 · 같은 번호면 노선 칸 안 지움 · 실패면 그대로 - 시험 test_472_5r_rock_owner 7(옛 코드 빨강 5) · 옛 단언 고침(176_3 · 271 · 443 상단측 조각 · 344_3 저장소 load) - 위키 암선 · 암 경사 · ↶ ↷ 규칙 · 노선 저장 뒤 정리 줄 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
143 lines
5.3 KiB
Python
143 lines
5.3 KiB
Python
"""PLAN 472-5 남음 (요구 272 · 273) — 암 경계 · 암 절토 경사 값 주인 = 세션 칸 하나 · 메모리 맵 걷음(N5) ·
|
|
노선 저장 뒤 옛 노선 칸만 비움.
|
|
|
|
못박는 것
|
|
- 암 경계(▲▼ · ↺) · 암 경사를 고친 뒤 ↶ 하고 다른 측점을 고쳐도 되돌린 값이 되살아나지 않음 — 옛 코드는 메모리
|
|
맵(`offsets` · `ratios`)이 옛 값을 쥐고 다음 조작이 칸을 통째로 다시 써 ↶ 를 덮었음(옛 코드 실패).
|
|
- ↶ 뒤 카드 읽기 = 조작 전 값(저장분 그대로) · ↷ = 다시 그 값 · 저장 재료(`offsets()` · `ratios()`)도 세션 칸 그대로.
|
|
- `clearRouteDrafts` = 그 노선 번호의 노선 범위 초안만 비움(다른 노선 · 다른 프로젝트 · 프로젝트 칸 그대로).
|
|
- 노선 바뀐 [저장] 성공 뒤 옛 노선 칸 · 초안 전 hold 비움 · 실패면 그대로(`design_save.ts`).
|
|
|
|
./venv/Scripts/python.exe -m pytest resources/tester/test_472_5r_rock_owner.py -q
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
ROOT = HERE.parents[1]
|
|
|
|
pytestmark = pytest.mark.skipif(
|
|
not (ROOT / "config" / "node_modules" / "vite").is_dir(),
|
|
reason="프론트엔드 의존성 미설치",
|
|
)
|
|
|
|
P = "p4725rock"
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def out(tmp_path_factory) -> dict:
|
|
work = tmp_path_factory.mktemp("s4725r")
|
|
subprocess.run( # noqa: S603 — 고정 실행 파일
|
|
[
|
|
"node",
|
|
str(ROOT / "config" / "node_modules" / "vite" / "bin" / "vite.js"),
|
|
"build",
|
|
"--configLoader",
|
|
"runner",
|
|
"--ssr",
|
|
"../resources/tester/helper_472_5r_rock_entry.ts",
|
|
"--outDir",
|
|
str(work),
|
|
"--logLevel",
|
|
"error",
|
|
],
|
|
cwd=ROOT,
|
|
check=True,
|
|
capture_output=True,
|
|
timeout=300,
|
|
)
|
|
bundle = work / "bundle.mjs"
|
|
shutil.copy(work / "helper_472_5r_rock_entry.js", bundle)
|
|
proc = subprocess.run( # noqa: S603
|
|
["node", str(HERE / "helper_472_5r_rock.mjs"), str(bundle)],
|
|
cwd=ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=120,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def test_조작_A_는_세션_칸에(out) -> None:
|
|
a = out["afterA"]
|
|
assert a["rockb"] == {"100.00": -0.9, "120.00": -0.4}
|
|
assert a["cutslope"] == {"140.00": 0.7}
|
|
r = out["readsA"]
|
|
assert r["100"]["rock"] == -0.9 and r["120"]["rock"] == -0.4 and r["140"]["cut"] == 0.7
|
|
|
|
|
|
def test_되돌리면_칸이_비고_카드도_조작_전(out) -> None:
|
|
assert out["afterUndo"] == {"rockb": {}, "cutslope": {}}
|
|
r = out["readsUndo"]
|
|
assert r["100"] == {"rock": -0.8, "cut": 0.4} # 저장분 그대로
|
|
assert r["120"] == {"rock": -0.5, "cut": 0.4}
|
|
assert r["140"] == {"rock": -0.5, "cut": 0.4}
|
|
|
|
|
|
def test_되돌린_뒤_다른_조작이_되돌림을_안_덮음(out) -> None:
|
|
"""N5 — 옛 코드는 메모리 맵이 A 값을 쥐고 B 를 쓸 때 통째로 다시 씀(옛 코드 실패)."""
|
|
assert out["afterB"] == {"rockb": {"140.00": -0.6}, "cutslope": {"100.00": 0.5}}
|
|
assert out["payloadB"] == {"rock": {"140.00": -0.6}, "cut": {"100.00": 0.5}}
|
|
|
|
|
|
def test_다시하기_뒤_값_같음(out) -> None:
|
|
assert out["afterUndo2"] == {"rockb": {}, "cutslope": {}}
|
|
assert out["afterRedo"] == out["afterB"]
|
|
r = out["readsRedo"]
|
|
assert r["100"] == {"rock": -0.8, "cut": 0.5}
|
|
assert r["140"] == {"rock": -0.6, "cut": 0.4}
|
|
|
|
|
|
def test_되돌림_단추_기본값_표준(out) -> None:
|
|
assert out["afterReset"] == {"rockb": {"140.00": -0.5}, "cutslope": {"100.00": 0}}
|
|
r = out["readsReset"]
|
|
assert r["140"]["rock"] == -0.5 and r["100"]["cut"] == 0.4
|
|
|
|
|
|
def test_옛_노선_칸만_비움(out) -> None:
|
|
before, after = set(out["keysBefore"]), set(out["keysAfter"])
|
|
gone = before - after
|
|
assert gone == {
|
|
f"aislo:draft:rockb:{P}:7",
|
|
f"aislo:draft:cutslope:{P}:7",
|
|
f"aislo:draft:crossw:{P}:7",
|
|
}
|
|
assert f"aislo:draft:rockb:{P}:8" in after
|
|
assert "aislo:draft:rockb:other:7" in after
|
|
assert f"aislo:draft:uphill:{P}" in after
|
|
|
|
|
|
def test_노선_저장_뒤_옛_노선_칸_비움(tmp_path) -> None:
|
|
proc = subprocess.run( # noqa: S603
|
|
["node", str(HERE / "helper_472_5r_route_save.cjs")],
|
|
cwd=ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=120,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
got = json.loads(proc.stdout)
|
|
# 새 노선 번호(9) ≠ 옛(3) — 다 저장하고 페이지를 다시 세운 뒤 옛 노선 칸 · hold 비움
|
|
assert got["moved"]["done"] is True
|
|
assert got["moved"]["calls"][-3:] == [
|
|
"rebuild",
|
|
"clearRouteDrafts:p1:3",
|
|
"clearState:route-draft-hold:p1",
|
|
]
|
|
# 같은 번호면 노선 칸은 안 지움(새 노선 칸일 수 있음) · hold 만
|
|
assert "clearRouteDrafts:p1:3" not in got["same"]["calls"]
|
|
assert got["same"]["calls"][-1] == "clearState:route-draft-hold:p1"
|
|
# 서버 실패 = 초안 그대로
|
|
assert got["failed"]["done"] is False
|
|
assert not [c for c in got["failed"]["calls"] if c.startswith("clear")]
|