"""446 카드 폭 넘김 다시 만들기 — 표본 폭을 넘겨 종 · 횡단을 다시 만들어도 사용자 값 그대로. - 횡단 행: 측점 열쇠(0.01 m 안)로 옛 data(설계 · 메모 · CAD · 상세 표 · 조절) · 상태 · 새 요약 이김 - 종단 행: 생성 요약 · 생성 옵션은 새것 · 표준 횡단면 · 유토(풍선) · 계획 입력은 옛것 - 화면: 다시 만들기 전 확인창 · 취소 = 재생성 없음(`helper_446_widen_confirm.cjs`) """ import json import subprocess from pathlib import Path import pytest from B06_Section.B06_Section_Router_Widen import carried_cross_rows, carried_longitudinal_data HERE = Path(__file__).parent ROOT = HERE.parents[1] DESIGN = { "ground_type": "soil", "section_mode": "right_cut", "structure_note": "메모", "structure_note_cad": {"lines": [1]}, "detail_table": {"rows": 2}, "display_half_width_m": 21, "basin_adjust": {"d": 0.3}, } def _old(row_id: int, at: float, design: dict | None = None, status: str = "CONFIRMED") -> dict: data = {"sample_count": 41, "center_z": 100.0, "design": design or DESIGN} return {"id": row_id, "chainage_m": at, "data": json.dumps(data), "status": status} def _new(row_id: int, at: float) -> dict: return {"id": row_id, "chainage_m": at, "data": json.dumps({"sample_count": 43})} def test_횡단_행은_측점_열쇠로_설계_상태_그대로() -> None: old = [_old(1, 0.0), _old(2, 20.0), _old(3, 33.456)] new = [_new(11, 0.0), _new(12, 20.0), _new(13, 33.46), _new(14, 40.0)] updates, dropped = carried_cross_rows(old, new) assert dropped == 0 by_id = {row_id: (json.loads(data), status) for data, status, row_id in updates} assert set(by_id) == {11, 12, 13} # 40 m = 새 측점 · 옛 값 없음 data, status = by_id[13] # 0.004 m 어긋남도 같은 측점 assert data["design"] == DESIGN and status == "CONFIRMED" assert data["sample_count"] == 43 and data["center_z"] == 100.0 # 새 요약이 이김 · 옛 칸 남김 def test_같은_측점_둘이면_최신_행_못_옮긴_행은_셈() -> None: newer = {**DESIGN, "structure_note": "새 메모"} old = [_old(1, 20.0), _old(5, 20.0, newer, "DRAFT"), _old(6, 55.0)] updates, dropped = carried_cross_rows(old, [_new(12, 20.0)]) data, status, _ = updates[0] assert json.loads(data)["design"]["structure_note"] == "새 메모" and status == "DRAFT" assert dropped == 1 # 55 m — 새 측점에 없음(로그로 알림) def test_종단_data_는_사용자_키를_옛것으로() -> None: old = { "length_m": 500.0, "options": {"cross_half_width_m": 20, "standard_cross_section": {"road_width_m": 3}}, "grade_overrides": {"max_grade_pct": 12}, "grade_summary": {"old": 1}, "mass_haul": {"balloon_offsets": {"0": [3.0, -4.0]}}, } new = { "length_m": 500.0, "options": {"cross_half_width_m": 21, "station_interval_m": 20}, "grade_overrides": {}, "grade_summary": {"new": 1}, } merged = carried_longitudinal_data(old, new) assert merged["options"] == { "cross_half_width_m": 21, "station_interval_m": 20, "standard_cross_section": {"road_width_m": 3}, } assert merged["grade_overrides"] == {"max_grade_pct": 12} assert merged["mass_haul"] == {"balloon_offsets": {"0": [3.0, -4.0]}} assert merged["grade_summary"] == {"new": 1} # 계획고 옮김이 다시 씀 def test_반폭_요청은_옮겨_담는_길로() -> None: router = (ROOT / "B06_Section" / "B06_Section_Router.py").read_text(encoding="utf-8") at = router.index("async def regenerate_sections(") body = router[at : router.index("async def regenerate_route_sections(", at)] assert "widen_route_sections(" in body and "regenerate_route_sections(" not in body assert "await carry(connection)" in router # 같은 트랜잭션 안 @pytest.mark.skipif(not (ROOT / "config" / "node_modules").is_dir(), reason="의존성 미설치") def test_다시_만들기_전_확인창_취소면_재생성_없음() -> None: done = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", str(HERE / "helper_446_widen_confirm.cjs")], capture_output=True, text=True, encoding="utf-8", ) assert done.returncode == 0, done.stderr out = json.loads(done.stdout) assert out["within"] is True and out["withinAsked"] == 0 assert out["cancel"] is False and out["cancelCalls"] == 0 and out["cancelOverlay"] == 0 assert out["ok"] is True and out["okCalls"] == [21] and out["okOverlay"] == 0 assert out["asked"][0].endswith("21/20") # 요청 폭 · 표본 폭이 글에 들어감