Files
Aislo/resources/tester/test_287_ford_pavement_followup.py
T
eomsangdonandClaude Opus 5.5 6c86612f65 fix(b05,b06): 월류 폭 → 높이 — 세월교 · 물넘이 한 벌 overflowSync · 안내 글 · 높이 비우면 다시 채움 (287-3)
- 까닭: 폭 → 높이 계산은 설계유량(담당 유역)이 있어야 돎 — 유량 없는 지점은 아무 일도 안 일어나고 안내도 없었음 · 높이를 비우면 안 채움
- overflowSync(design_structure_ford_calc) — 폭 바꿈 = 필요 수심 · 높이 비움 · 그 아래 = 필요 수심 · 상자 끝 안내 「필요 수심 n 이상」 · 「설계유량 없음 — 수기 입력」 · 유량이 오면 안내 다시 그림
- 세월교 · 물넘이 폼이 같은 것을 씀 · Facility.ts 줄 줄임(697 → 686)
- 시험 test_287 화면 길(폼 onChange 훅) — 유량 있음 · 없음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
2026-10-12 21:24:35 +09:00

161 lines
7.5 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.
"""287 물넘이포장 후속(요구 183-2 · 4 · 6 · 7 · 8 · 9).
못박는 것
- 287-1 도수로/돌붙임 길이 ↔ 면적 — 길이 넣음 = 월류 폭 × 길이 · 비움 = 칸 기본값 · 월류 폭을 바꾸면
길이가 있을 때만 다시 셈 · 폭이 비면 물넘이 기본 폭.
- 287-3 월류 폭 → 높이 자동 = 세월교 한 벌(`fordHeightM` · 폼 `overflow(…, "slope")`) · 유량 없으면 손 입력.
- 287-5 물넘이포장 형상 누름 = 다른 시설과 같은 고름 창구(`toggleRevet("pipe")` → 폼 · 알약 · 측점선) ·
판정면은 보라 손잡이 아래(요구 185 ①) · 끌기(3 px 넘게 움직임) = 고름 아님(②) · 노면공 포장층
(범위 표식)은 형상 고름 밖(③) · 목록 · 알약 고름이 형상 강조를 따라옴.
- 287-2 · 287-4 콘크리트 윗면 = 설계 노면(서버 · TS 짝이 경사각도로 지대 낮은 쪽 한 경사 · 중심점이 그 위)
· 포장층 = 노면공 포장 형상 노견까지(노면공 항목과 안 섞임) · 월류 높이 점선 = 노면 위 같은 각도 ·
3D 노면을 파지 않음 · 설계 측구 없음.
진짜 TS 는 `helper_287_ford_pavement.cjs` 가 Node 로 돌림. 화면은 사용자 확인.
"""
from __future__ import annotations
import json
import subprocess
import sys
from pathlib import Path
import pytest
HERE = Path(__file__).resolve().parent
ROOT = HERE.parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
pytestmark = pytest.mark.skipif(
not (ROOT / "config" / "node_modules" / "typescript").is_dir(),
reason="프론트엔드 의존성 미설치",
)
def _read(*parts: str) -> str:
return (ROOT.joinpath(*parts)).read_text(encoding="utf-8")
@pytest.fixture(scope="module")
def ts() -> dict:
proc = subprocess.run(
["node", str(HERE / "helper_287_ford_pavement.cjs")],
capture_output=True,
text=True,
encoding="utf-8",
timeout=60,
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
def test_도수로_길이_면적(ts):
assert ts["areaByLength"] == "24" # 6 m × 4 m
assert ts["areaCleared"] == "30" # 길이 비움 = 기본값
assert ts["areaByWidth"] == "20" # 폭 8 m × 2.5 m
assert ts["areaWidthNoLength"] == "17" # 길이 없으면 폭을 바꿔도 그대로
assert ts["areaNoWidth"] == "30" # 폭 비움 = 기본 폭 10 m × 3 m
def test_물넘이_폼이_길이_면적을_잇는다():
form = _read("B05_Profile", "B05_Profile_UI_Drainage_Facility.ts")
assert "syncChuteArea(paveForm, c, item), paveFlowBox.onChange(c, item)" in form
def _pts(text: str) -> list[float]:
return [float(v) for pair in text.split() for v in pair.split(",")]
def test_포장층_노견까지_점선은_노면_위(ts):
assert ts["drew"] is True
# 포장층 하나 = 노견 끝(±3)까지 · 윗면 = 설계 노면 · 두께 0.2
assert len(ts["pavePoints"]) == 1
assert _pts(ts["pavePoints"][0]) == pytest.approx([3, 100.15, -3, 99.85, -3, 99.65, 3, 99.95])
# 월류 높이선 = 노면 + 0.4 · 같은 각도
assert _pts(ts["planPoints"][0]) == pytest.approx([3, 100.55, -3, 100.25])
assert ts["inflowLeft"] is True # 노면 높은 쪽 = 유입 · 도수로 띠 = 낮은 쪽
def test_3D_노면을_파지_않고_옛_파임_그림을_걷음():
station = _read("B05_Profile", "B05_Profile_UI_Corridor_Station.ts")
assert "fordDeckElevationAt" not in station
pave = _read("B06_Section", "B06_Section_UI_Cross_Ford_Pavement.ts")
assert "hideFordPavedRoad" not in pave and "fordDeckElevationAt" not in pave
view = _read("B06_Section", "B06_Section_UI_Cross_View.ts")
assert "hideFordPavedRoad" not in view
def test_월류_폭_넣으면_높이_자동_세월교_한_벌(ts):
assert ts["paveSlopeItems"] == ["angle", "width", "height"]
assert ts["heightByWidth"] and ts["heightByWidth"] > 0
assert ts["heightNoFlow"] is None
form = _read("B05_Profile", "B05_Profile_UI_Drainage_Facility.ts")
assert 'if (facility === "ford_pavement") paveFlowBox.fill();' in form
def test_형상_판정면은_보라_손잡이_아래(ts):
order = ts["shapeOrder"]
# 그림 → 형상 판정면 → 보라 손잡이 판정 → 구조물 판정면(위가 이김)
assert (
order.index("b06-chart__shape-hit")
< order.index("b06-chart__design-hit")
< order.index("b06-chart__culvert-revet-hit")
)
def test_형상_누름은_고름_끌기는_고름_아님(ts):
assert ts["picked"] == ["pipe-230.00"] # 누름 한 번만 고름 · 끌기는 안 셈
assert ts["clickStops"] is True and ts["dragStops"] is False # 끌기는 카드로 그대로
assert ts["pavedShapeIsPicked"] is False # 노면공 포장층은 형상 고름 밖(포장 고름 몫)
def test_형상_강조와_표식(ts):
assert ts["activeAfterSet"] is True
assert ts["activeAfterOther"] is False and ts["activeAfterSame"] is True
assert ts["fordTag"] == ["pipe-230.00"] # 포장층 표식 = 관 지점 알약 id
def test_보라_손잡이는_계획고만_형상_누름은_고름만():
view = _read("B06_Section", "B06_Section_UI_Cross_View.ts")
# 형상 누름 = 시설 고름 창구만(설계 · 계획고를 안 건드림) · 보라 선 고름보다 먼저 꽂음(손잡이가 위)
assert 'shapePickRoute(svg, () => toggleRevet("pipe"))' in view
assert view.index("attachShapePick(") < view.index("attachDesignLinePick({")
pick = _read("B06_Section", "B06_Section_UI_Cross_Shape_Pick.ts")
assert "onDesignChange" not in pick and "design_elevation" not in pick
assert '"b06-chart__culvert-revet-hit"' in pick # 구조물 판정면 앞(아래)에 꽂을 기준만
assert 'hit.setAttribute("class", "b06-chart__shape-hit")' in pick
# 보라 손잡이 판정 = 계획고 · 사면 이동 창구(설계선 고름 · 구조물 판정면 아래)
design_pick = _read("B06_Section", "B06_Section_UI_Cross_Design_Pick.ts")
assert 'el.classList.contains("b06-chart__culvert-revet-hit")' in design_pick
# 목록 · 알약 · 폼 고름 → 형상 강조
section_view = _read("B06_Section", "B06_Section_UI_Section_View.ts")
assert "highlightShapes(card, pickedMarkId);" in section_view
selection = _read("B06_Section", "B06_Section_UI_Page_Structures_Selection.ts")
assert "sectionAt.ford_pavement?.chainage_m" in selection
def test_월류_폭_높이_화면_길_유량_있음(ts):
got = ts["overflowFlow"]
assert got["afterWidth8"] == "0.26" # 폭 8 → 필요 수심(유량 14.58 ㎥/s)
assert got["afterClear"] == "0.26" # 높이 비움 → 다시 채움
assert got["afterLow"] == "0.26" # 필요 수심 아래 → 끌어올림
assert got["afterHigh"] == "0.9" # 올려 적은 값은 그대로
assert got["hint"] == ["필요 수심 0.26 이상"] and got["otherBoxHint"] == 0
assert got["emitted"] == 4
def test_월류_폭_높이_화면_길_유량_없음(ts):
got = ts["overflowNoFlow"]
assert got["afterWidth8"] == "0.05" and got["afterClear"] == "" # 손 입력 그대로
assert got["hint"] == ["설계유량 없음 — 수기 입력"]
def test_세월교_물넘이_한_벌_안내_훅():
form = _read("B05_Profile", "B05_Profile_UI_Drainage_Facility.ts")
flat = " ".join(form.split())
assert 'overflowSync( () => fordForm, "ford", () => fordFlow, emit, )' in flat
assert 'overflowSync( () => paveForm, "slope", () => fordFlow, emit, )' in flat
assert "...fordFlowBox.fields(c)" in form and "fields: paveFlowBox.fields," in form