Files
Aislo/resources/tester/test_192_1_moved_pipe_station.py
T
eomsangdonandClaude Opus 5.5 6f2136f592 fix(B05·B06): 옮긴 관 측점의 숨은 계획선 꼭짓점 제거(192-1)
- 측점 있음 판정 폭 0.5m → 0.005m(측점 스냅 폭) — 0.1m 옮긴 관도 측점 없음으로 셈
- 비정규 측점 병합 때 사라진 측점의 base_pvi · 편집을 지움(0.006m 안 반올림은 옮김) · 계획선 다시 셈 · DB 등급 요약 갱신
- 시험 test_192_1(검증_랩탑메인 사본 재현) · missing_stations 판정 폭

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
2026-10-10 13:36:21 +09:00

129 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""192-1 — 종단 계획선 숨은 꺾임(검증_랩탑메인 226fc805 · No.38+9).
까닭: 관을 769.28 → 769.38(0.1m) 옮김 → 「측점 있음」 판정 폭이 0.5m 라 측점이 옛 자리
769.28 에 남음 → B06(측점 769.28)과 B05(관 769.38) 두 자리에 계획고 편집이 남아 0.1m 사이
−465% 계단 · 769.38 은 측점선 없는 꼭짓점.
고침: 판정 폭 0.005m(측점 스냅 폭) · 측점을 다시 뜨면 사라진 측점의 꼭짓점 · 편집을 지움
(반올림 차이 0.006m 안은 옮김). 사용자 storage 는 읽기만 — 사본(tmp_path)으로 재현.
"""
from __future__ import annotations
import copy
import json
import shutil
import sys
from pathlib import Path
import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
import B05_Profile.B05_Profile_Engine_Sections as sections # noqa: E402
from B05_Profile.B05_Profile_Router_Confirm import _merge_irregular_into_longitudinal # noqa: E402
from B06_Section.B06_Section_Router_Stations import _missing_marks # noqa: E402
SOURCE = (
PROJECT_ROOT
/ "storage/1/3/226fc805-26c8-4f5a-9956-bacb200e10a5/B06_Section/longitudinal/longitudinal.json"
)
REL = "B06_Section/longitudinal/longitudinal.json"
needs_copy = pytest.mark.skipif(not SOURCE.is_file(), reason="검증_랩탑메인 storage 없음")
def _copy(tmp_path: Path) -> Path:
target = tmp_path / REL
target.parent.mkdir(parents=True)
shutil.copyfile(SOURCE, target)
return target
def _load(path: Path) -> dict:
return json.loads(path.read_text(encoding="utf-8"))
def _irregular(data: dict, old: float, new: float) -> list[dict]:
"""다시 뜬 비정규 측점 목록 흉내 — `old` 측점만 `new` 로 옮김."""
result = []
for station in data["stations"]:
if station.get("kind") != "irregular":
continue
item = copy.deepcopy(station)
if abs(item["chainage_m"] - old) < 1e-6:
item["chainage_m"] = new
result.append(item)
return result
@needs_copy
def test_원본_자료가_숨은_꼭짓점을_가짐() -> None:
"""까닭 근거 — 769.38 꼭짓점은 측점 목록에 없고 두 편집 사이 −465%."""
data = _load(SOURCE)
alignment = data["profile_alignment"]
stations = [s["chainage_m"] for s in data["stations"]]
pvis = [p["chainage_m"] for p in alignment["pvi"]]
assert 769.38 in pvis and 769.38 not in stations and 769.28 in stations
assert set(alignment["edits"]["station_offsets"]) == {"769.280", "769.380"}
step = next(s for s in alignment["segments"] if s["from_m"] == 769.28)
assert step["to_m"] == 769.38 and step["grade_percent"] < -400
@needs_copy
def test_관_옮긴_측점_다시_뜨면_숨은_꼭짓점_사라짐(tmp_path: Path) -> None:
path = _copy(tmp_path)
data = _load(path)
summary = _merge_irregular_into_longitudinal(tmp_path, REL, _irregular(data, 769.28, 769.38))
after = _load(path)
alignment = after["profile_alignment"]
stations = {round(s["chainage_m"], 3) for s in after["stations"]}
near = [p for p in alignment["pvi"] if 760 < p["chainage_m"] < 780]
assert [p["chainage_m"] for p in near] == [769.38] # 꼭짓점 하나 · 측점선 있음
assert 769.38 in stations and 769.28 not in stations
assert alignment["edits"]["station_offsets"] == {"769.380": pytest.approx(0.051428)}
assert all(abs(b["chainage_m"] - 769.28) > 1e-6 for b in alignment["base_pvi"])
grades = [s["grade_percent"] for s in alignment["segments"] if 760 <= s["from_m"] < 780]
assert max(abs(g) for g in grades) < 20
assert summary is not None and summary["max_grade_pct"] < 20
assert after["design_profiles"][0]["summary"]["max_grade_pct"] == summary["max_grade_pct"]
@needs_copy
def test_반올림_차이만_다르면_편집을_옮김(tmp_path: Path) -> None:
path = _copy(tmp_path)
data = _load(path)
data["profile_alignment"]["edits"]["station_offsets"]["484.210"] = 0.3
path.write_text(json.dumps(data), encoding="utf-8")
_merge_irregular_into_longitudinal(tmp_path, REL, _irregular(data, 484.21, 484.213))
offsets = _load(path)["profile_alignment"]["edits"]["station_offsets"]
assert "484.210" not in offsets and offsets["484.213"] == pytest.approx(0.3)
@needs_copy
def test_측점이_그대로면_계획선을_건드리지_않음(tmp_path: Path) -> None:
path = _copy(tmp_path)
data = _load(path)
before = data["profile_alignment"]
assert _merge_irregular_into_longitudinal(tmp_path, REL, _irregular(data, -1, -1)) is None
assert _load(path)["profile_alignment"] == before
def test_조금_옮긴_관도_측점_없음으로_셈(tmp_path: Path, monkeypatch) -> None:
"""0.1m 옮긴 관 — 옛 판정(0.5m)은 「측점 있음」으로 놓쳤음."""
target = tmp_path / REL
target.parent.mkdir(parents=True)
target.write_text(
json.dumps({"stations": [{"chainage_m": 760.0}, {"chainage_m": 769.28}]}),
encoding="utf-8",
)
monkeypatch.setattr(sections, "_load_route_polyline", lambda *_: [])
monkeypatch.setattr(sections, "_load_pipe_points", lambda *_: [])
monkeypatch.setattr(
sections, "resolve_extra_stations", lambda *_: [(769.38, "파형강관 D800"), (760.0, "옹벽")]
)
assert _missing_marks(tmp_path, "route.csv") == [
{"chainage_m": 769.38, "label": "파형강관 D800"}
]