"""PLAN 472-8 (요구 409) — 단면 유형이 없는 (옛) 설계의 기본 = 상단측 깎기 하나 (지형이 정함 · 모르면 좌). 못박는 것 - 서버 [저장] 파이썬 길(`stored_section_mode`) = Node 길(TS `B06_Section_Cross_Save` storedOptions). - 브라우저 다시 셈(TS `B06_Section_Cross_Refresh_Calc`) = 같은 규칙. - 셋 다 「단면 유형 없음」 = 「상단측 깎기를 적어 넣음」과 0 차 · 우 상단측 측점은 옛 좌 깎기와 다름. - 묶음 cross 단계(`B06_Section_Cross_Stage`) 기본도 상단측 (`uphillSide` 다시 씀 · 좌 고정 폴백 없음). ./venv/Scripts/python.exe -m pytest resources/tester/test_472_8_section_mode_default.py -q """ from __future__ import annotations import copy import json import subprocess import sys from pathlib import Path import pytest HERE = Path(__file__).resolve().parent ROOT = HERE.parents[1] for path in (ROOT, HERE): if str(path) not in sys.path: sys.path.insert(0, str(path)) from test_511_b4_cross_save_mirror import SURFACE, _facilities, _npz, _plan, _sections # noqa: E402 from B06_Section import B06_Section_Server_Calc_Prebuild as prebuild # noqa: E402 from B06_Section.B06_Section_Engine_Design_Node import full_standard # noqa: E402 from config.config_system import STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M # noqa: E402 pytestmark = pytest.mark.skipif( not (ROOT / "config" / "node_modules" / "vite").is_dir(), reason="프론트엔드 의존성 미설치" ) def _uphill(index: int) -> str | None: return None if index == 3 else ("right" if index % 2 else "left") def _expected(index: int) -> str: return f"{_uphill(index) or 'left'}_cut" def _stripped(sections: list[dict], mode=None) -> list[dict]: """단면 유형을 지운 옛 설계 · `mode(index)` 가 오면 그 값을 적어 넣은 짝.""" out = copy.deepcopy(sections) for index, section in enumerate(out): section["uphill_side"] = _uphill(index) section["design"].pop("section_mode", None) if mode: section["design"]["section_mode"] = mode(index) return out def _server(root: Path, longitudinal: dict, sections: list[dict]) -> tuple[list, list]: py, node = copy.deepcopy(sections), copy.deepcopy(sections) prebuild._enforce_on_python(longitudinal, py, root, None, SURFACE) grid = prebuild.design_grid_file(root, SURFACE) assert prebuild._enforce_on_node(longitudinal, node, root, None, grid) return [s["design"] for s in py], [s["design"] for s in node] def _browser(tmp_path: Path, sections: list[dict]) -> list[dict]: job = tmp_path / "job.json" plan = [[s["chainage_m"], _plan(s["chainage_m"])] for s in sections] job.write_text( json.dumps( { "sections": sections, "plan": plan, "standard": full_standard(None), "rockDefault": STANDARD_ROCK_BOUNDARY_DEFAULT_OFFSET_M, } ), encoding="utf-8", ) proc = subprocess.run( ["node", str(HERE / "helper_472_8_section_mode.cjs"), str(job)], capture_output=True, text=True, encoding="utf-8", timeout=120, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def test_단면_유형_없음_상단측_서버_두_길_브라우저_같음(tmp_path, monkeypatch): root = tmp_path / "p" _npz(root) _facilities(monkeypatch) longitudinal, sections = _sections(root) bare = _stripped(sections) py, node = _server(root, longitudinal, bare) assert py == node # 파이썬 길 = Node 길(TS Cross_Save) py_set, _ = _server(root, longitudinal, _stripped(sections, _expected)) assert py == py_set # 없음 = 상단측 적어 넣음 py_left, _ = _server(root, longitudinal, _stripped(sections, lambda _i: "left_cut")) assert any(a != b for a, b in zip(py, py_left)) # 옛 좌 고정과 다름(우 상단측 측점) browser = _browser(tmp_path, bare) assert browser == _browser(tmp_path, _stripped(sections, _expected)) assert [d["section_mode"] for d in browser] == [d["section_mode"] for d in py] assert browser != _browser(tmp_path, _stripped(sections, lambda _i: "left_cut")) def test_묶음_cross_단계_기본은_상단측(): stage = (ROOT / "B06_Section/logic/B06_Section_Cross_Stage.ts").read_text(encoding="utf-8") assert 'sectionMode: `${uphillSide(station) ?? "left"}_cut`' in stage assert '"left_cut"' not in stage