"""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]