- 반폭 재생성 = 옛 횡단 행 data · 상태를 측점 열쇠(0.01 m)로 새 행에 · 옛 종단 data 사용자 키(표준 횡단면 · 유토 · 계획 입력 · 상태) — 같은 트랜잭션 - 계획고 편집 = 옛 계획선 통째(_carry_profile 같은 노선 갈래) · 실패면 종 · 횡단 파일 되돌림 - 넓힌 지반 위 [저장]과 같은 서버 재계산 - 화면 = 다시 만들기 전 확인창 · 취소면 재생성 없음 · 오버레이 셈 짝 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Se7ytqbohmBQnfYpwYFnYf
107 lines
4.6 KiB
Python
107 lines
4.6 KiB
Python
"""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") # 요청 폭 · 표본 폭이 글에 들어감
|