Files
Aislo/resources/tester/test_415_page_split.py
T
eomsangdonandClaude Opus 5.5 1ee4febad7 fix(B05·B06 한 페이지): 측점 갈아끼움 뒤 누가거리 조절 세션 칸 바로 옮김 — 조정창 맵이 안 선 페이지도 초안 카드로 (415-3)
- 관 측점 열쇠 갈림(세션 pipe-s1 ↔ 계산 줄 pipe:p35100) = 415-1 로 풀림 · B06 연 길은 초안 카드 조절 그대로(화면)
- B05 만 연 길(새로고침 · 조정창 맵 없음) · 세월 · BOX · 연동 칸은 안 옮겨짐 → 갈아끼움 알림 뒤 Station_Keys 가
  ROUTE_CARRY_STATES(측점 열쇠 칸 빼고) 세션 칸을 바로 새 자리로 · 조정창 맵이 옮긴 칸은 그대로(Swap_Bus afterAnySwap)
- 시험: test_415 누가거리 조절 · 노선 바뀜 대조 = 417 넘김 규칙(사면 쉬프트 · 소단 깊이 넘김)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
2026-10-18 13:34:28 +09:00

163 lines
6.9 KiB
Python

# -*- coding: utf-8 -*-
"""PLAN 415 — 한 페이지 끊김 ① (분석 412 3장 H1 · H2 · M4).
못박는 것
- H1 관 · 구조물만 옮김 = 「노선 바뀜」 넘김 규칙 안 탐 — 측점 열쇠째 옮김(단면 유형 · 사면 쉬프트 ·
소단 깊이 · 관 측점 고침 그대로 · 두 번 옮겨도) · 노선 입력이 바뀐 때만 넘김 규칙(대조).
- H2 [저장] 도중 계산 줄 먹이기 멈춤 — 관 초안이 비어도 열 때 읽은 옛 관 목록으로 안 돎 · 맞춤 고리도 쉼 ·
저장 끝 = 저장 목록 다시 읽음 · 새 자리 그대로(다시 셈 0).
- 415-3 누가거리 조절(옹벽 · 세월 · BOX · 집수 · 연동)도 관 새 자리로 — 조정창 맵이 안 선 페이지도.
- 415-2 관 옮김 → 되돌리기 = 묶음 입력 · 공용 측점도 원래 · 다시하기 = 옮긴 자리.
- M4 새 시설 측점 서버 미리보기 걷음 — 미리보기 요청 0(`test_273_2` · `test_318` 이 맡음) · 여기는 코드 자리.
짝: `helper_415_swap.mjs`(346-2 진입점 묶음 · 진짜 상세 가게) · `helper_415_h2.cjs`(진짜 계산 묶음 · 365 틀).
"""
from __future__ import annotations
import json
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
import pytest
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[1]
if str(HERE) not in sys.path:
sys.path.insert(0, str(HERE))
import test_365_page_pipeline as t365 # noqa: E402
pytestmark = t365.pytestmark
@pytest.fixture(scope="module")
def h1(tmp_path_factory) -> dict:
work = tmp_path_factory.mktemp("b415")
build = subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
str(ROOT / "config" / "node_modules" / "vite" / "bin" / "vite.js"),
"build",
"--configLoader",
"runner",
"--ssr",
"../resources/tester/helper_346_2_swap_entry.ts",
"--outDir",
str(work),
"--logLevel",
"error",
],
cwd=ROOT,
capture_output=True,
text=True,
encoding="utf-8",
timeout=300,
)
assert build.returncode == 0, build.stderr
bundle = work / "bundle.mjs"
shutil.copy(work / "helper_346_2_swap_entry.js", bundle)
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", str(HERE / "helper_415_swap.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)
@pytest.fixture(scope="module")
def h2() -> dict:
with tempfile.TemporaryDirectory() as folder:
path, grid = t365._job(Path(folder))
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", str(HERE / "helper_415_h2.cjs"), str(path), str(grid)],
capture_output=True,
text=True,
encoding="utf-8",
timeout=180,
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
def test_H1_순수_관만_옮김은_노선_바뀜_아님(h1):
assert h1["pure"] == {"pipeOnly": False, "route": True}
def test_H1_관_옮김_뒤_고침_그대로(h1):
before = h1["before"]
assert before["choices"] == [[40, "soil", "right_cut"], [45.05, "soil", "left_cut"]]
assert before["shoulder"] == [["grid:1", {"left": 0.7}]]
assert before["berm"] == [["grid:3", {"right": 0.4}]]
moved = h1["pipeMoved"]
# 관 측점 고침은 새 자리(50 m)로 · 격자 고침 그대로 · 「노선 밖 고침」 알림 없음
assert moved["choices"] == [[40, "soil", "right_cut"], [50, "soil", "left_cut"]]
assert moved["shoulder"] == before["shoulder"] and moved["berm"] == before["berm"]
assert moved["toasts"] == 0
again = h1["pipeMovedAgain"]
assert again["choices"] == [[40, "soil", "right_cut"], [55, "soil", "left_cut"]]
assert again["shoulder"] == before["shoulder"] and again["berm"] == before["berm"]
def test_H1_노선이_바뀌면_넘김_규칙(h1):
routed = h1["routeMoved"]
# 대조 — 노선 입력이 바뀐 때 = 넘김 규칙(단면 유형 버림 · 지반 유형 · 사면 쉬프트 · 소단 깊이 넘김 = 417)
assert routed["choices"] == [[40, "soil", None], [55, "soil", None]]
assert routed["shoulder"] == [["grid:1", {"left": 0.7}]]
assert routed["berm"] == [["grid:3", {"right": 0.4}]]
def test_H2_저장_도중_먹이기_멈춤(h2):
opened = h2["open"]
assert h2["moved"]["input"] == [c + 5 for c in opened]
during = h2["during"]
assert during["runs"] == 0 and during["rounds"] == 0 # 옛 관 목록으로 안 돎 · 고리도 쉼
assert during["input"] == h2["moved"]["input"]
assert during["stations"] == h2["moved"]["stations"]
assert during["reads"] == 0
def test_H2_저장_끝_저장_목록_다시_읽음(h2):
after = h2["after"]
assert after["reads"] >= 1 # 저장 목록 다시 읽음
assert after["input"] == h2["moved"]["input"] # 새 자리 그대로
assert after["stations"] == h2["moved"]["stations"]
# 관 · 구조물 다시 먹이기 없음(옛 목록으로 안 돎) — 저장 측점 기준이 새 자리라 횡단만 한 번
assert all(source == ["cross"] for source in after["sources"]) and after["runs"] <= 1
assert h2["reconcile"] == 0
def test_M4_새_시설_측점_미리보기_걷음():
drafts = (ROOT / "B06_Section/B06_Section_Section_Drafts.ts").read_text(encoding="utf-8")
assert "previewStructureSections" not in drafts
page = (ROOT / "A00_Common/design/design_pipeline_page.ts").read_text(encoding="utf-8")
guard = (ROOT / "A00_Common/design/design_pipeline_facilities.ts").read_text(encoding="utf-8")
# 저장 창구는 늦게 불러옴 — 묶음(시험 · 화면)이 저장 모듈을 맨 위에서 안 끎
assert 'from "./design_save"' not in page and 'import("./design_save")' in guard
def test_415_2_관_옮김_되돌리기_측점_원래(h2):
undo = h2["undo"]
base = h2["moved"]["input"] # 저장 뒤 저장분 = 옮긴 자리
assert undo["movedAgain"]["input"] == [c + 5 for c in base]
# 되돌리기 = 세션만 되씀(가게 알림 없음) → 묶음 입력 · 공용 측점도 원래
assert undo["undone"]["draft"] is None
assert undo["undone"]["input"] == base and undo["undone"]["stations"] == base
assert undo["redone"]["input"] == undo["movedAgain"]["input"]
assert undo["redone"]["stations"] == undo["movedAgain"]["stations"]
def test_415_3_누가거리_조절_관_새_자리로(h1):
# 조정창 맵이 안 선 페이지(B05 만 · 새로고침)도 관 측점 누가거리 조절이 새 자리로 · 격자 값 그대로
adjusts = h1["adjusts"]
assert adjusts["revetx"] == {"50.00:outlet": {"x": 0.3}, "20.00:inlet": {"x": 0.1}}
assert adjusts["fordadjust"] == {"50.00": {"w": 1}}
assert adjusts["revetlink"] == {"detached": {"50.00": True}, "grade": {}}