fix(532-1): E01 복사본 읽기 — 횡단 경로 null · 파일 없음 · 옛 꼴도 B06 이름 규칙으로 찾음 · 없으면 그 측점만 건너뜀 · 생성 복사 경고(요구 351)
- Source.stations · cross_section: 경로 칸 null · 파일 없음 · 절대 경로 · 옛 정수 m 이름이면 find_cross_file 로 찾음 · 그래도 없으면 「횡단 없음」(stations 에서 빠짐 · cross_section KeyError) · missing_stations 추가 - copy_stability: 같은 검사 → manifest missing_cross_chainages · warnings · E01 생성 응답 warnings - 실측: 검증 프로젝트 14 복사 모두 stations 성공 · 검증_브레인232 null 1 행(359 m) 살림 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
"""532-1 덧 · 요구 351 — E01 복사본 읽기가 횡단 경로 null · 파일 없음 · 옛 꼴에서도 돎.
|
||||
|
||||
- 경로 null · 경로 파일 없음 → B06 이름 규칙(`find_cross_file`)으로 찾음
|
||||
- 옛 꼴 — 절대 경로(원본 쪽을 읽지 않음) · 소수 측점의 옛 정수 m 이름 · data 없음
|
||||
- 어디에도 없으면 그 측점만 빠짐(`missing_stations`) · cross_section 은 KeyError
|
||||
- 생성 복사(`copy_stability`)가 같은 검사 → manifest `missing_cross_chainages` · `warnings`
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
|
||||
from common_util import common_util_project_copy as cp # noqa: E402
|
||||
from E01_StabRegister import E01_StabRegister_Source as src # noqa: E402
|
||||
|
||||
CROSS = "B06_Section/cross_sections"
|
||||
|
||||
|
||||
def _cross(root: Path, name: str, label: str) -> None:
|
||||
path = root / CROSS / name
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps({"label": label, "samples": [{"offset_m": 0}]}), encoding="utf-8")
|
||||
|
||||
|
||||
def _row(chainage, path, data=..., seq=0):
|
||||
design = {"design": {"ground_type": "soil"}}
|
||||
return {
|
||||
"chainage_m": chainage,
|
||||
"sequence_num": seq,
|
||||
"cross_section_file_path": path,
|
||||
"data": json.dumps(design) if data is ... else data,
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def root(tmp_path):
|
||||
outside = tmp_path / "original" / CROSS / "cross_00040m.json"
|
||||
outside.parent.mkdir(parents=True)
|
||||
outside.write_text(json.dumps({"label": "원본"}), encoding="utf-8")
|
||||
copy = tmp_path / "copy"
|
||||
_cross(copy, "cross_00000m.json", "정상")
|
||||
_cross(copy, "cross_00020m.json", "null")
|
||||
_cross(copy, "cross_00030m.json", "경로 틀림")
|
||||
_cross(copy, "cross_00040m.json", "절대")
|
||||
_cross(copy, "cross_00050m.json", "옛 정수") # 49.8 m 측점의 옛 이름
|
||||
rows = [
|
||||
_row(0.0, f"{CROSS}/cross_00000m.json"),
|
||||
_row(20.0, None, seq=None),
|
||||
_row(30.0, f"{CROSS}/cross_gone.json"),
|
||||
_row(40.0, str(outside)),
|
||||
_row(49.8, None, data=None),
|
||||
_row(60.0, None), # 어디에도 없음
|
||||
_row(None, None), # 누가거리 없는 행 — 측점 아님
|
||||
]
|
||||
(copy / src.STABILITY_DB_NAME).write_text(
|
||||
json.dumps({"cross_sections": rows}), encoding="utf-8"
|
||||
)
|
||||
(copy / src.MANIFEST_NAME).write_text("{}", encoding="utf-8")
|
||||
return copy
|
||||
|
||||
|
||||
def test_stations_skip_only_missing(root):
|
||||
got = src.stations(root)
|
||||
assert [s["chainage_m"] for s in got] == [0.0, 20.0, 30.0, 40.0, 49.8]
|
||||
assert [s["label"] for s in got] == ["정상", "null", "경로 틀림", "절대", "옛 정수"]
|
||||
assert got[0]["ground_type"] == "soil" and got[4]["ground_type"] is None
|
||||
assert src.missing_stations(root) == [60.0]
|
||||
|
||||
|
||||
def test_cross_section(root):
|
||||
assert src.cross_section(root, 20.0)["label"] == "null"
|
||||
assert src.cross_section(root, 40.0)["label"] == "절대" # 원본 쪽 파일 아님
|
||||
assert src.cross_section(root, 49.8)["design"] == {}
|
||||
with pytest.raises(KeyError, match="횡단 없음"):
|
||||
src.cross_section(root, 60.0)
|
||||
with pytest.raises(KeyError, match="측점 없음"):
|
||||
src.cross_section(root, 70.0)
|
||||
|
||||
|
||||
def test_normal_copy_has_no_missing(root):
|
||||
db = json.loads((root / src.STABILITY_DB_NAME).read_text(encoding="utf-8"))
|
||||
db["cross_sections"] = db["cross_sections"][:1]
|
||||
(root / src.STABILITY_DB_NAME).write_text(json.dumps(db), encoding="utf-8")
|
||||
assert [s["label"] for s in src.stations(root)] == ["정상"]
|
||||
assert src.missing_stations(root) == []
|
||||
|
||||
|
||||
def test_copy_stability_warns(tmp_path, monkeypatch):
|
||||
source = tmp_path / "source"
|
||||
_cross(source, "cross_00000m.json", "a")
|
||||
_cross(source, "cross_00020m.json", "b")
|
||||
dump = {
|
||||
"project": {"storage_path": "x"},
|
||||
"surface_params": {"source_filter": "none"},
|
||||
"route": None,
|
||||
"cross_sections": [
|
||||
_row(0.0, None),
|
||||
_row(20.0, f"{CROSS}/cross_00020m.json"),
|
||||
_row(35.5, None),
|
||||
],
|
||||
"route_points": [],
|
||||
"longitudinal_sections": [],
|
||||
}
|
||||
|
||||
async def fake_rows(connection, source_id):
|
||||
return dump
|
||||
|
||||
monkeypatch.setattr(cp, "_stability_rows", fake_rows)
|
||||
monkeypatch.setattr(cp, "resolve_stored_project_path", lambda _: str(source))
|
||||
manifest = asyncio.run(cp.copy_stability(None, "s" * 36, "e" * 36, tmp_path / "e"))
|
||||
assert manifest["missing_cross_chainages"] == [35.5]
|
||||
assert manifest["warnings"] == ["횡단 없는 측점 1 개 — 해석에서 빠짐"]
|
||||
written = json.loads(
|
||||
(tmp_path / "e" / cp.STABILITY_SOURCE_DIR / cp.MANIFEST_NAME).read_text("utf-8")
|
||||
)
|
||||
assert written["missing_cross_chainages"] == [35.5]
|
||||
Reference in New Issue
Block a user