Files
Aislo/resources/tester/test_384_7_section_canon.py
T
eomsangdonandClaude Opus 5.5 eedafe8db9 fix(451 B06 세션 캐시 판): 세션 상세 뒤에서 서버 판 확인 · 다르면 서버 값 위 내 칸만 · 숨은 종단 보기 관 id 장부 · 384_3 단언 427 의도
- 433-16: 새로고침 · 새 탭 = 세션 상세로 먼저 섬 · 뒤에서 상세 GET(ETag 304) · 판이 다르면 서버 값 위에 이 탭에서 고친 사용자 칸만 · [저장] patch 바탕도 새 판 · 노선 초안 hold 는 버릴 때 새 판
- 440-3: 숨은 종단 보기도 관 세션 id 장부 돌림(평면 마커 누름 = 초안 자리) · 그리기는 보일 때
- 384_3: pvi 단언 = 저장 꼭짓점 + 심은 측점마다 세운 꼭짓점(427)
- 384_7: 세션 쓰기 = 받을 때 · 판 확인 새 판 둘

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

105 lines
3.8 KiB
Python

"""387-7(384 단계 7) 결과 층 — 세션 상세 = 저장 정본만 · 열 때 세션 상세 JSON.parse 한 번.
· 상세 가게(새로고침)와 묶음 cross 입력이 어느 쪽이 먼저 읽어도 세션 글은 한 번만 풂(`_Section_Canon`)
· 정본 사본은 캐시 객체와 따로 — 다시 셈 · 초안 얹기가 캐시를 고쳐도 묶음 입력의 정본은 그대로
· 갈아끼움 · 되돌림은 세션 상세를 안 씀(`test_365_page_pipeline` 365-1 · 이 파일은 소스로)
./venv/Scripts/python.exe -m pytest resources/tester/test_384_7_section_canon.py -q
"""
from __future__ import annotations
import json
import re
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
LOADER = Path(__file__).resolve().parent / "helper_ts_cjs_load.cjs"
DRIVER = r"""
const data = new Map();
const fake = {
get length() { return data.size; },
key: (i) => [...data.keys()][i] ?? null,
getItem: (k) => (data.has(k) ? data.get(k) : null),
setItem: (k, v) => data.set(k, String(v)),
removeItem: (k) => data.delete(k),
};
globalThis.window = { sessionStorage: fake, localStorage: fake };
const { loadTs } = require(process.argv[1]);
const canon = loadTs(process.argv[2]);
const state = loadTs(process.argv[3]);
const detail = {
longitudinal: {},
cross_sections: [
{ chainage_m: 0, design: { ground_type: "soil", cut_area_m2: 1 } },
{ chainage_m: 20, design: { ground_type: "rock", cut_area_m2: 2 } },
],
};
let parses = 0;
const parse = JSON.parse;
JSON.parse = (text, ...rest) => {
if (typeof text === "string" && text.includes("cross_sections")) parses += 1;
return parse(text, ...rest);
};
const out = {};
// 묶음 입력이 먼저 → 상세 가게
state.writeState("section-detail", detail, "p", 1);
const rows = canon.savedDesigns("p", 1);
const shown = canon.sessionDetail("p", 1);
out.cross = { parses, rows: rows.length };
// 정본 사본 = 캐시 객체와 따로
shown.cross_sections[0].design.cut_area_m2 = 99;
out.canonKept = canon.savedDesigns("p", 1)[0].design.cut_area_m2;
// 상세 가게가 먼저 → 묶음 입력
parses = 0;
state.writeState("section-detail", detail, "p", 2);
canon.sessionDetail("p", 2);
canon.savedDesigns("p", 2);
out.storeFirst = parses;
// 버림 → 다시 받기 전엔 정본 없음
canon.forgetCanon("p");
state.writeState("section-detail", null, "p", 1);
out.forgot = canon.savedDesigns("p", 1);
process.stdout.write(JSON.stringify(out));
"""
def _run() -> dict:
done = subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
"-e",
DRIVER,
str(LOADER),
str(ROOT / "B06_Section" / "B06_Section_Section_Canon.ts"),
str(ROOT / "A00_Common" / "b_page_state.ts"),
],
capture_output=True,
text=True,
encoding="utf-8",
cwd=str(ROOT),
)
assert done.returncode == 0, done.stderr
return json.loads(done.stdout)
def test_열_때_세션_상세_한_번만_풂() -> None:
out = _run()
assert out["cross"] == {"parses": 1, "rows": 2}
assert out["storeFirst"] == 1
assert out["canonKept"] == 1 # 캐시를 고쳐도 정본 사본 그대로
assert out["forgot"] is None
def test_세션_상세_쓰는_곳_받을_때_하나() -> None:
store = (ROOT / "B06_Section" / "B06_Section_Section_Store.ts").read_text(encoding="utf-8")
code = re.sub(r"/\*.*?\*/|//[^\n]*", "", store, flags=re.S)
# 서버에서 받은 정본만 — 받을 때 · 세션 판 확인(451 · 433-16)이 받은 새 판
assert re.findall(r'writeState\("section-detail", (\w+),', code) == ["detail", "fresh"]
cross = (ROOT / "A00_Common" / "design" / "design_pipeline_cross.ts").read_text(
encoding="utf-8"
)
assert "section-detail" not in re.sub(r"/\*.*?\*/|//[^\n]*", "", cross, flags=re.S)