Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
97 lines
4.0 KiB
Python
97 lines
4.0 KiB
Python
"""107 세월교 — 유입 · 유출 따로 · 원지반 제약 삭제 · 유입 날개벽 수평 여유.
|
||
|
||
화면 TS 를 그 자리에서 돌린 값(`helper_107_ford_free.cjs`) · 픽스처 = 73-4 세월교 173.09 · 박스 352.14.
|
||
"""
|
||
|
||
import json
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
if str(ROOT) not in sys.path:
|
||
sys.path.insert(0, str(ROOT))
|
||
|
||
HELPER = Path(__file__).parent / "helper_107_ford_free.cjs"
|
||
NODE_MODULES = ROOT / "config" / "node_modules"
|
||
|
||
pytestmark = pytest.mark.skipif(not NODE_MODULES.is_dir(), reason="프론트엔드 의존성 미설치")
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def out() -> dict:
|
||
done = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||
["node", str(HELPER)], cwd=str(ROOT), capture_output=True, text=True, encoding="utf-8"
|
||
)
|
||
assert done.returncode == 0, done.stderr
|
||
return json.loads(done.stdout)
|
||
|
||
|
||
def _read(rel: str) -> str:
|
||
return (ROOT / rel).read_text(encoding="utf-8")
|
||
|
||
|
||
def test_세월교_박스를_고르면_같은_측점_벽_고름을_풂(out: dict) -> None:
|
||
assert out["released"] == [173.09, 352.14]
|
||
|
||
|
||
def test_벽을_고르면_세월교_박스_고름을_풂() -> None:
|
||
station = _read("B06_Section/B06_Section_UI_Page_Station_Controls.ts")
|
||
assert (
|
||
"if (key && ford.control.selectedFor(chainageM)) ford.control.select(chainageM, null);"
|
||
in station
|
||
)
|
||
assert (
|
||
"if (key && box.control.selectedFor(chainageM)) box.control.select(chainageM, null);"
|
||
in station
|
||
)
|
||
view = _read("B06_Section/B06_Section_UI_Cross_View.ts")
|
||
# 카드 안 — 벽을 고르면 본체 창을 닫고 · 본체를 고르면 벽 창을 닫음
|
||
assert "bodies.clearSelection(); // 세월교 · 박스 고름을 풂" in view
|
||
assert "if (activeRevet !== null) toggleRevet(activeRevet);" in view
|
||
|
||
|
||
@pytest.mark.parametrize("variant", ["guards", "inletWing"])
|
||
def test_세월교_원지반을_바꿔도_바닥_그대로(out: dict, variant: str) -> None:
|
||
"""107-2 — 바닥 = 노면 − (관경 + 최소 토피) · 하상 −2 m · 전체 +0.5 / −1 m 사본도 같은 모양."""
|
||
runs = out["ford"][variant]
|
||
for name, shape in runs.items():
|
||
assert shape == runs["base"], name
|
||
base = runs["base"]
|
||
# 바닥판 수평(139-3) — 표고 하나 · 낮은 노견 쪽 깊이 = 관경 + 토피 · 높은 쪽은 그보다 깊음
|
||
sides = base["sides"]
|
||
assert len({side["slabTop"] for side in sides}) == 1
|
||
assert min(side["depth"] for side in sides) == pytest.approx(base["pipeCover"])
|
||
assert all(side["depth"] >= base["pipeCover"] - 1e-6 for side in sides)
|
||
|
||
|
||
@pytest.mark.parametrize("variant", ["guards", "bare"])
|
||
def test_박스_원지반을_바꿔도_본체_끝_날개_흙막이_그대로(out: dict, variant: str) -> None:
|
||
runs = out["box"][variant]
|
||
for name, shape in runs.items():
|
||
assert shape == runs["base"], name
|
||
if variant == "bare":
|
||
assert all(side["apron"] for side in runs["base"]["sides"])
|
||
else:
|
||
assert len(runs["base"]["walls"]) == 2
|
||
|
||
|
||
def test_유입_날개벽_끝이_묻히면_수평_여유_뒤_절토(out: dict) -> None:
|
||
"""107-3 — 흙막이 수평공간과 같은 칸(빈 값 = 1 m) · 유출 날개벽은 수평 구간 없음."""
|
||
cuts = out["wingCut"]
|
||
for case, berm in (("auto", 1.0), ("two", 2.0)):
|
||
(x0, z0), (x1, z1) = cuts[case]["inlet"][:2]
|
||
assert z1 == pytest.approx(z0) and abs(x1 - x0) == pytest.approx(berm), case
|
||
(x0, z0), (x1, z1) = cuts["zero"]["inlet"][:2]
|
||
assert z1 > z0 + 0.1 # 0 = 바로 절토
|
||
assert cuts["auto"]["outlet"][1][1] > cuts["auto"]["outlet"][0][1] + 0.1
|
||
|
||
|
||
def test_날개벽_수평_여유_칸은_흙막이_수평공간과_같은_키() -> None:
|
||
ford = _read("A00_Common/design/design_structure_ford.ts")
|
||
assert '...bodyGuardItems(id, "본체 끝 높이(자동)", true),' in ford
|
||
guard = _read("A00_Common/design/design_structure_guard.ts")
|
||
assert "map: wingBerm ? { 흙막이: branch, 날개벽: branch } : { 흙막이: branch }," in guard
|