- ④ 노선 저장 뒤 횡단 저장 = 고침 없어도 한 번(뒤에 나간 계획고 초안이 횡단 설계 높이에 실림) - ⑤ 상단측 다시 셈 = 깎기 경사 · 소단을 기하 입력으로 · 사용자 조작값 목록째 승계 · 측구 끔(None) 저장분 셈 - ⑨ 추가 측점 = 묶음 입력 plusStations(stations 부터) · 가게 초안 · 되돌리기 → 묶음 - ⑨ [저장] 차례 실패 = 그 차례에서 멈춤 · 차례 이름째 알림(뒤 차례 안 보냄) - 시험 test_429_save_path · test_design_store_save 멈춤 규칙으로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
145 lines
6.2 KiB
Python
145 lines
6.2 KiB
Python
"""PLAN 429 — [저장] 길 정합(분석 424 9장 ④⑤⑧⑨).
|
|
|
|
- ④ 노선 [저장] 뒤 횡단 저장 = 고침이 없어도 한 번(서버가 지금 종단으로 횡단을 다시 셈 · 뒤에
|
|
나간 계획고 초안이 횡단 설계 높이에 실림) · 서버 [저장]이 횡단 설계 높이를 저장 종단에서 냄.
|
|
- ⑤ 상단측 차례(`sync_uphill_overrides_into_designs`)가 소단 · 깎기 경사 · 조절 값을 남김.
|
|
- ⑨ 추가 측점 = 계산 묶음 입력(stations 부터 다시) · 가게 초안 바뀜 · 되돌리기 → 묶음에 넣음.
|
|
[저장] 차례 실패 = 그 차례에서 멈춤(`test_design_store_save.py`).
|
|
Node 헬퍼 = `helper_429_save_path.cjs`.
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from B06_Section.B06_Section_Engine_Design import compute_cross_design
|
|
from B06_Section.B06_Section_Router_Design import enforce_design_lines
|
|
from config.config_system import STANDARD_CROSS_SECTION
|
|
|
|
HERE = Path(__file__).parent
|
|
ROOT = HERE.parents[1]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def out():
|
|
proc = subprocess.run(
|
|
["node", str(HERE / "helper_429_save_path.cjs")],
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=60,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def _ground() -> list[dict]:
|
|
"""왼쪽이 높은 비탈 — 왼쪽 깎기 · 오른쪽 쌓기(편절)."""
|
|
return [
|
|
{"offset_m": o / 2, "elevation_m": round(100.0 + 0.25 * o / 2, 4), "valid": True}
|
|
for o in range(-40, 41)
|
|
]
|
|
|
|
|
|
# ── ④ ────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
def test_노선_저장_뒤_고침이_없어도_횡단_저장_한_번(out):
|
|
assert out["noPatchSent"] == [["p1", 9, None, None]] # 본문 없이 = 서버가 다시 셈만
|
|
assert out["noPatchReturn"] == 0
|
|
|
|
|
|
def test_서버_저장이_횡단_높이를_저장_종단에서(tmp_path):
|
|
"""초안 계획고(101.2)가 종단 정본에 나간 뒤 [저장] 다시 셈 = 그 높이 · 옛 설계(100.0) 아님."""
|
|
old = compute_cross_design(
|
|
_ground(), 100.0, standard=STANDARD_CROSS_SECTION, ground_type="soil",
|
|
section_mode="left_cut", ditch_side="left",
|
|
) # fmt: skip
|
|
longitudinal = {
|
|
"design_profiles": [
|
|
{"samples": [{"chainage_m": 0.0, "elevation_m": 101.2},
|
|
{"chainage_m": 40.0, "elevation_m": 101.2}]}
|
|
]
|
|
} # fmt: skip
|
|
sections = [{"chainage_m": 20.0, "samples": _ground(), "design": old}]
|
|
assert enforce_design_lines(longitudinal, sections, tmp_path, STANDARD_CROSS_SECTION) == 1
|
|
assert sections[0]["design"]["design_elevation_m"] == pytest.approx(101.2, abs=1e-6)
|
|
|
|
|
|
# ── ⑤ ────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
def test_상단측_차례가_소단_깎기경사_조절값_남김(tmp_path, monkeypatch):
|
|
import B05_Profile.B05_Profile_Router_Confirm as confirm
|
|
import B06_Section.B06_Section_Repository as repo
|
|
import B06_Section.B06_Section_Repository_Bulk as bulk
|
|
import B06_Section.B06_Section_Router_Design as design_mod
|
|
|
|
user = {
|
|
"cut_slope_ratio_user": 0.7,
|
|
"berm": {"width_m": 1.0, "interval_m": 3.0, "slope_deg": 0.0, "depth_m": 1.0},
|
|
"berm_depth_left_m": 2.0,
|
|
"basin_adjust": {"w": 1.5},
|
|
"structure_note": "글",
|
|
"shoulder_extend_right_m": 0.3,
|
|
}
|
|
before = compute_cross_design(
|
|
_ground(), 100.0, standard=STANDARD_CROSS_SECTION, ground_type="soil",
|
|
section_mode="right_cut", ditch_side="right",
|
|
) # fmt: skip
|
|
stored = {**before, **user}
|
|
long_file = tmp_path / "long.json"
|
|
long_file.write_text("{}", encoding="utf-8")
|
|
|
|
async def designs(_connection, _route_id):
|
|
return [{"chainage_m": 20.0, "design": stored}]
|
|
|
|
async def longitudinal(*_args):
|
|
return {"data": {"options": {"standard_cross_section": STANDARD_CROSS_SECTION}}}
|
|
|
|
written: list = []
|
|
|
|
async def merge(_connection, *, route_id, entries, replace, project_id=None):
|
|
written.extend(entries)
|
|
|
|
monkeypatch.setattr(repo, "get_cross_section_designs", designs)
|
|
monkeypatch.setattr(confirm, "get_longitudinal_section", longitudinal)
|
|
monkeypatch.setattr(bulk, "merge_cross_section_designs", merge)
|
|
monkeypatch.setattr(design_mod, "resolve_longitudinal_path", lambda *_: long_file)
|
|
monkeypatch.setattr(
|
|
design_mod, "read_cross_design_inputs", lambda *_a: (_ground(), 100.0, False, {})
|
|
)
|
|
monkeypatch.setattr(design_mod, "ford_surface_drops", lambda _root: [])
|
|
|
|
asyncio.run(
|
|
confirm.sync_uphill_overrides_into_designs(
|
|
None, "p", 1, tmp_path, "long.json", [{"chainage_m": 20.0, "side": "left"}]
|
|
)
|
|
)
|
|
assert len(written) == 1
|
|
chainage, after = written[0]
|
|
assert chainage == 20.0 and before["ditch_type"] is None # 측구 끔 저장분도 셈
|
|
for key, value in user.items():
|
|
assert after[key] == value, key # 값 남음
|
|
assert after["cut_slope_ratio"] == pytest.approx(0.7) # 깎기 경사가 기하에 실림(키만 아님)
|
|
assert after["shoulder_extend_right_m"] == pytest.approx(0.3)
|
|
|
|
|
|
# ── ⑨ ────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
def test_추가_측점이_묶음_입력(out):
|
|
assert "input.plusStations" in out["stationsDeps"]
|
|
assert out["plusRan"][0] == "stations" and "route" not in out["plusRan"] # stations 부터
|
|
assert "cross" in out["plusRan"] # 뒤 단계까지 이어짐
|
|
assert out["plusSeen"] == [40]
|
|
assert out["sameValue"] is None and out["sameRan"] == [] # 같은 값은 안 셈
|
|
|
|
|
|
def test_가게_추가_측점_초안이_묶음에(out):
|
|
assert out["fed"] == [["plus", [12, 30]], ["plus", [12]]] # 초안 · 비우면 저장분
|
|
assert out["restoreFed"] == [["plus", [12, 55]]] # 되돌리기 = 입력과 다르면 넣음
|