⚠ **뿌리** — `tmp/` 는 창 사이에 안 건너감(실측 확인: 상대 창이 놓은 `tmp/_sync_probe.txt` 가 시간을 두고 두 번 봐도 안 보임). 그래서 **정본(등록부 스키마)만 건너가고 그것을 읽는 시험은 안 건너가** 오늘 두 번, 같은 시험이 **연 창은 통과·받은 창은 실패**가 됐음. - `tmp/tests/*` 를 `resources/tester/` 로 **복사**(127 파일). 내용은 **한 줄도 안 고침** - `tmp/tests` 는 **남겨 둠** — 되돌릴 자리(사용자 지시) - 실행: `./venv/Scripts/python.exe -m pytest resources/tester/ -q` 옮기기 전과 **같은 수**: 617 통과 / 22 건너뜀 / 실패 0 ⇒ 이제 시험·예외·까닭이 **정본과 함께** 움직임. 오늘 세운 「예외는 정본 스키마에」와 짝임. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
124 lines
5.0 KiB
Python
124 lines
5.0 KiB
Python
"""B06 배수관 세트(배관·기슭막이·보호공) 엔진 검증.
|
||
|
||
정본(`pipe_points.json`) + 레지스트리 기본값 조합이 계획서(3-0 근거 표)대로
|
||
나오는지, 배관 외 시설(BOX암거 등)이 이번 범위에서 빠지는지 확인한다.
|
||
"""
|
||
|
||
import json
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||
if str(PROJECT_ROOT) not in sys.path:
|
||
sys.path.insert(0, str(PROJECT_ROOT))
|
||
|
||
from B06_Section.B06_Section_Engine_Culvert import ( # noqa: E402
|
||
APRON_LENGTH_FACTOR,
|
||
APRON_THICKNESS_M,
|
||
MIN_PIPE_COVER_M,
|
||
REVET_FACE_SLOPE,
|
||
_culvert_set,
|
||
attach_culvert_sets,
|
||
pipe_points_file,
|
||
)
|
||
|
||
|
||
def test_cross_reference_constants_match_plan():
|
||
"""계획서 3-0 표 값 — 토피 0.5m·보호공 길이 2배·두께 0.45m(사용자 확정)·전면 1:0.3."""
|
||
assert MIN_PIPE_COVER_M == 0.5
|
||
assert APRON_LENGTH_FACTOR == 2.0
|
||
assert APRON_THICKNESS_M == 0.45
|
||
assert REVET_FACE_SLOPE == 0.3
|
||
# 배관은 수평도 가능 — 세트에 경사 강제값을 싣지 않는다(2026-08-20 사용자 확정).
|
||
assert "min_slope" not in _culvert_set(None)
|
||
|
||
|
||
def test_empty_options_fall_back_to_registry_defaults():
|
||
"""옵션이 빈 저장분은 레지스트리 기본값(Ø1000·기슭막이 H2.5/L10)으로 채운다."""
|
||
spec = _culvert_set(None)
|
||
assert spec["type"] == "pipe"
|
||
assert spec["diameter_m"] == 1.0
|
||
assert spec["min_cover_m"] == MIN_PIPE_COVER_M
|
||
for side in ("inlet", "outlet"):
|
||
part = spec[side]
|
||
assert part["structure"] == "기슭막이"
|
||
assert part["revet_height_m"] == 2.5
|
||
assert part["revet_length_m"] == 10
|
||
assert part["face_slope"] == REVET_FACE_SLOPE
|
||
# 보호공 = 낙차고(2.5) × 2 = 5.0m, 두께 0.45m(사용자 확정).
|
||
assert part["apron_length_m"] == 5.0
|
||
assert part["apron_thickness_m"] == 0.45
|
||
# 레지스트리 기본 형태: 유입 찰 / 유출 메.
|
||
assert spec["inlet"]["revet_form"] == "돌쌓기(찰)"
|
||
assert spec["outlet"]["revet_form"] == "돌쌓기(메)"
|
||
|
||
|
||
def test_basin_inlet_skips_revet_and_apron():
|
||
"""유입구 = 집수정이면 그쪽 기슭막이·보호공을 만들지 않는다(라벨만)."""
|
||
spec = _culvert_set({"inlet_type": "집수정"})
|
||
assert spec["inlet"]["structure"] == "집수정"
|
||
assert "revet_height_m" not in spec["inlet"]
|
||
assert "apron_length_m" not in spec["inlet"]
|
||
# 유출측은 그대로 세트를 갖춘다.
|
||
assert spec["outlet"]["structure"] == "기슭막이"
|
||
assert spec["outlet"]["apron_length_m"] == 5.0
|
||
|
||
|
||
def test_string_diameter_and_custom_height():
|
||
"""관경 문자열 저장분("800")과 사용자 높이 변경이 그대로 반영된다."""
|
||
spec = _culvert_set({"pipe_diameter_mm": "800", "outlet_revet_height_m": 1.5})
|
||
assert spec["diameter_m"] == 0.8
|
||
assert spec["outlet"]["revet_height_m"] == 1.5
|
||
assert spec["outlet"]["apron_length_m"] == 3.0 # 1.5 × 2
|
||
|
||
|
||
def test_attach_only_pipe_facilities(tmp_path):
|
||
"""배관은 `culvert`, 세월교는 `ford`, BOX암거는 `box` 키로 얹는다.
|
||
|
||
배관 매칭은 chainage ±0.02m 그대로다. 세월교·BOX암거는 구체 폭만큼 이어져
|
||
기준 측점 전후 절반까지 붙는다(2026-08-25 사용자 확정) — 아래 100.0m은
|
||
어느 쪽 범위에도 들지 않는다.
|
||
"""
|
||
target = pipe_points_file(tmp_path)
|
||
target.parent.mkdir(parents=True)
|
||
target.write_text(
|
||
json.dumps(
|
||
{
|
||
"route_signature": "x",
|
||
"points": [
|
||
{
|
||
"chainage_m": 84.3,
|
||
"source": "spacing",
|
||
"options": {"pipe_diameter_mm": 1000},
|
||
},
|
||
{"chainage_m": 149.73, "source": "stream", "facility": "ford_bridge"},
|
||
{"chainage_m": 200.92, "source": "spacing", "facility": "box_culvert"},
|
||
],
|
||
},
|
||
ensure_ascii=False,
|
||
),
|
||
encoding="utf-8",
|
||
)
|
||
cross_sections = [
|
||
{"chainage_m": 84.3, "samples": []},
|
||
{"chainage_m": 149.73, "samples": []},
|
||
{"chainage_m": 200.92, "samples": []},
|
||
{"chainage_m": 100.0, "samples": []},
|
||
]
|
||
attached = attach_culvert_sets(tmp_path, cross_sections)
|
||
assert attached == 3
|
||
assert "culvert" in cross_sections[0]
|
||
assert cross_sections[0]["culvert"]["diameter_m"] == 1.0
|
||
# 세월교·BOX암거는 그림이 달라 키를 나눈다 — 배수관 소비처가 집어가면 안 된다.
|
||
assert cross_sections[1]["ford"]["type"] == "ford"
|
||
assert cross_sections[2]["box"]["type"] == "box"
|
||
assert all("culvert" not in section for section in cross_sections[1:])
|
||
assert all("ford" not in section for section in (cross_sections[0], *cross_sections[2:]))
|
||
|
||
|
||
def test_attach_without_file_is_noop(tmp_path):
|
||
"""정본 파일이 없으면 아무 것도 얹지 않고 0을 돌려준다."""
|
||
sections = [{"chainage_m": 10.0}]
|
||
assert attach_culvert_sets(tmp_path, sections) == 0
|
||
assert "culvert" not in sections[0]
|