Files
Aislo/resources/tester/test_415_page_split.py
T
eomsangdonandClaude Opus 5.5 d9fec937aa fix(B05·B06 한 페이지): 시설 옮김 = 횡단 편집 열쇠째 · [저장] 중 먹이기 멈춤 · 새 시설 측점 미리보기 걷음 · 되돌리기 뒤 다시 견줌 (415-1 · 415-2)
- H1: 관 · 구조물 밖 측점이 움직인 때만 「노선 바뀜」 넘김 규칙 · 시설만 옮기면 열쇠째 옮김
  (사면 쉬프트 · 소단 깊이 · 단면 유형 · 관 측점 고침 그대로)
- H1 덧: 초안 없을 때도 저장분 계획으로 열쇠 주인(관 = 저장 id · 계산 묶음 열쇠와 같음 · 첫 옮김도 열쇠째)
  · 묶음이 세운 열쇠 목록을 같은 측점이면 주인 규칙으로 다시 세지 않음 · 갈아끼운 옛 상세 맞춤 끝냄
- H2: [저장] 도중 관 · 구조물 먹이기 · 맞춤 고리 쉼 · 끝나면 저장 목록 다시 읽고 맞춤(design_pipeline_facilities)
- M4: 새 시설 측점 서버 미리보기(preview-stations) 걷음 · 새 자리 = 계산 묶음 갈아끼움 · 카드 이름만 얹음
  · 종류 바뀐 자리 = 구조물 없는 사본
- 415-2: 되돌리기 · 다시하기(세션만 되씀) 뒤 관 · 구조물을 묶음 입력과 견줘 다시 넣음
- 시험: test_415_page_split 새로 · 미리보기 전제 시험(273-2 · 298 · 317 · 318 · 322-0 · 322-3)을 새 규칙으로

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

153 lines
6.3 KiB
Python

# -*- coding: utf-8 -*-
"""PLAN 415 — 한 페이지 끊김 ① (분석 412 3장 H1 · H2 · M4).
못박는 것
- H1 관 · 구조물만 옮김 = 「노선 바뀜」 넘김 규칙 안 탐 — 측점 열쇠째 옮김(단면 유형 · 사면 쉬프트 ·
소단 깊이 · 관 측점 고침 그대로 · 두 번 옮겨도) · 노선 입력이 바뀐 때만 넘김 규칙(대조).
- H2 [저장] 도중 계산 줄 먹이기 멈춤 — 관 초안이 비어도 열 때 읽은 옛 관 목록으로 안 돎 · 맞춤 고리도 쉼 ·
저장 끝 = 저장 목록 다시 읽음 · 새 자리 그대로(다시 셈 0).
- 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"]
# 대조 — 노선 입력이 바뀐 때 = 지반 유형만 넘기고 단면 유형 · 사면 쉬프트 · 소단 깊이 버림
assert routed["choices"] == [[40, "soil", None], [55, "soil", None]]
assert routed["shoulder"] == [] and routed["berm"] == []
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"]