Files
Aislo/resources/tester/test_b05_map_interval_spans.py
eomsangdonandClaude Opus 5 0ef32b5279 chore(tester): 시험을 resources/tester/ 로 옮김 — 창끼리 건너가게
⚠ **뿌리** — `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>
2026-09-09 17:12:30 +09:00

69 lines
3.7 KiB
Python

"""평면(지도)에 **구간형 구조물 띠**가 서는지 — 계획서 3-6 마지막 항목.
왜 (2026-09-07 사용자 지시) — 산마루측구·도수로·옹벽처럼 **구간**으로 놓이는 시설이 종단에는
띠로 보이는데 **평면에는 아무 표시가 없었다**. 계획서에는 「노선 위에 임의 구간을 얹는 부품이
없어 새로 짜야 함」으로 남아 있었다.
새로 짠 것은 작다 — 계획선 표본(`strengthSamples`)이 **1m 간격이라 배열 인덱스가 곧
누가거리**여서, 구간 → 화면 선은 그 토막을 잘라 굵게 긋기만 하면 된다.
이 시험이 지키는 것 — ① 띠를 그리는 부품이 있고 ② 배수유역도가 그것을 계획선 **위**,
강도 색칠 **아래**에 그리며 ③ 띠 자료는 **종단과 같은 자료**(구조물 정본 + 타입 레지스트리)에서
나오고 ④ 구간이 없는 점형 시설은 빠지는 것.
"""
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[2]
_B05 = PROJECT_ROOT / "B05_Profile"
_SPANS = _B05 / "B05_Profile_UI_Drainage_Spans.ts"
_RENDER = _B05 / "B05_Profile_UI_Drainage_Render.ts"
_PANEL = _B05 / "B05_Profile_UI_Drainage_Panel.ts"
_PROFILE = _B05 / "B05_Profile_UI_Profile_Panel.ts"
def test_띠를_그리는_부품이_있다():
source = _SPANS.read_text(encoding="utf-8")
assert "export function drawRouteSpans" in source
# 인덱스 = 누가거리(m) 라는 전제가 코드에 남아 있어야 한다 — 표본 간격이 바뀌면 깨진다.
assert "Math.floor(Math.min(span.startM, span.endM))" in source
def test_범위_밖_구간도_안전하게_잘린다():
"""저장분에 노선보다 긴 구간이 남아 있어도 그리다 죽지 않아야 한다."""
source = _SPANS.read_text(encoding="utf-8")
assert "Math.max(0, Math.min(last," in source
assert "Math.max(from + 1," in source, "시작=끝인 구간이 사라지지 않게 한 칸을 준다"
def test_계획선_위_강도색칠_아래에_그린다():
"""쌓는 순서가 뒤집히면 띠가 계획선을 덮거나 마커에 가린다."""
render = _RENDER.read_text(encoding="utf-8")
assert "drawRouteSpans(context, scene.strengthSamples" in render
# 호출 자리끼리 견준다 — 파일 머리의 import 는 순서 판정에 쓰면 안 된다.
order_route = render.index("drawPreparedLayer(context, scene.routeLayer")
order_span = render.index("drawRouteSpans(context")
order_strength = render.index("drawStrengthLine(context")
assert order_route < order_span < order_strength
def test_종단과_같은_자료에서_뽑는다():
"""색은 레지스트리 표시색, 구간은 구조물 정본 — 새 정본을 만들지 않는다."""
spans = _SPANS.read_text(encoding="utf-8")
assert "export function routeSpansFromStructures" in spans
assert 'item.placement !== "interval"' in spans, "구간형만 띠로 그린다"
assert "type.style?.color" in spans, "색을 새로 정하지 않고 레지스트리 값을 쓴다"
profile = _PROFILE.read_text(encoding="utf-8")
assert "drainagePanel.setIntervalSpans(routeSpansFromStructures(" in profile
def test_목록이_바뀌면_다시_그린다():
"""구조물을 넣거나 빼면 띠도 따라와야 한다 — 안 그러면 옛 띠가 남는다."""
profile = _PROFILE.read_text(encoding="utf-8")
body = profile[profile.index("setStructures(next: StructureInstance[])") :][:400]
assert "syncDrainageSpans()" in body
types_body = profile[profile.index("setStructureTypes(types: StructureType[])") :][:300]
assert "syncDrainageSpans()" in types_body
panel = _PANEL.read_text(encoding="utf-8")
assert "setIntervalSpans(spans) {" in panel and "scheduleDraw();" in panel