Files
Aislo/resources/tester/test_306_underdrain_pick.py
T
eomsangdonandClaude Opus 5.5 0a8008ce09 feat(B06): 306 횡단 맹암거 안 엇갈려 겹친 돌 무늬 · 그림 전용 · 고르기 차례 = 안쪽 판정면 맨 아래 · 테두리 판정 면 판정 맨 위
- 돌 무늬: 켜마다 반 칸 엇갈림 · 이웃 · 위아래와 겹침 · 기울기 ±22° 번갈아 교차 · 맹암거 색(카드 · [상세] 모달 같은 그림)
- 맹암거 무리 pointer-events none — 성토 띠 · 포장 · 넓은 관 판정면이 맹암거 안에서도 골라짐
- 차례: 보라 선 > 맹암거 테두리 > 구조물 판정면(작은 것 위) > 그림 · 띠 > 맹암거 안쪽
- 시험 test_306_underdrain_pick

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
2026-10-13 18:07:53 +09:00

107 lines
4.0 KiB
Python

"""PLAN 306 — B06 횡단 맹암거 안 돌 무늬 · 고르기 차례(요구 200-1).
- 306-1 돌 무늬 = 켜마다 반 칸 엇갈리고 이웃 · 위아래와 겹친 돌 · 기울기 번갈아 교차 · 그림 전용(누름 안 받음)
- 306-2 고르기 차례 = 맹암거 안쪽 판정면 맨 아래(겹친 띠 · 관이 위) · 테두리 판정 = 면 판정 맨 위 ·
보라 선 맨 위 그대로 · 다른 구조물 차례(작은 것 위) 그대로
실제 TS 를 `helper_306_underdrain_pick.cjs` 가 Node 로 돌린다.
"""
from __future__ import annotations
import json
import os
import re
import subprocess
from collections import defaultdict
import pytest
HERE = os.path.dirname(__file__)
ROOT = os.path.join(HERE, "..", "..")
B06 = os.path.join(ROOT, "B06_Section")
pytestmark = pytest.mark.skipif(
not os.path.isdir(os.path.join(ROOT, "config", "node_modules")),
reason="프론트엔드 의존성 미설치",
)
@pytest.fixture(scope="module")
def out() -> dict:
proc = subprocess.run( # noqa: S603 — 고정 실행 파일
["node", os.path.join(HERE, "helper_306_underdrain_pick.cjs")],
capture_output=True,
text=True,
encoding="utf-8",
)
assert proc.returncode == 0, proc.stderr
return json.loads(proc.stdout)
def _rows(out: dict) -> list[list[dict]]:
"""돌을 가로(따라) · 노면 아래 깊이(켜) 좌표로 — 깊이 같은 것끼리 한 켜."""
(ax, ay), (bx, by) = out["body"][0], out["body"][1]
rows: dict[float, list[dict]] = defaultdict(list)
for s in out["stones"]:
depth = s["cy"] - (ay + (s["cx"] - ax) * (by - ay) / (bx - ax))
rows[round(depth, 1)].append({**s, "along": s["cx"]})
return [sorted(rows[k], key=lambda s: s["along"]) for k in sorted(rows)]
def test_돌_무늬_엇갈려_겹침_306_1(out):
assert out["groupClass"] == "b06-chart__underdrain"
assert out["stones"] and all(s["cls"] == "b06-chart__culvert-stone" for s in out["stones"])
rows = _rows(out)
assert len(rows) == 4 # 높이 1 m ÷ 0.25
step = rows[0][1]["along"] - rows[0][0]["along"]
gap = abs(rows[1][0]["along"] - rows[0][0]["along"]) % step
assert abs(gap - step / 2) < 1e-6 # 이웃 켜는 반 칸 엇갈림
for row in rows:
# 돌 길이(따라) > 간격 · 돌 높이(가로질러) > 켜 간격 → 이웃 · 위아래와 겹침
assert all(s["h"] > step * 1.3 for s in row)
degs = [s["deg"] for s in row]
assert all(a != b for a, b in zip(degs, degs[1:])) # 기울기 번갈아 → 교차
row_gap = 20 / len(rows) # 암거 높이 1 m = 20 px
assert all(s["w"] > row_gap for s in out["stones"])
assert len({s["deg"] for s in out["stones"]}) == 2
def test_돌_무늬는_누름_안_받음_306_1():
with open(os.path.join(B06, "B06_Section_UI_Style_Cross_Areas.css"), encoding="utf-8") as f:
css = f.read()
assert re.search(r"\.b06-chart__underdrain \{\s*pointer-events: none;", css)
assert re.search(r"\.b06-chart__shape-hit--edge \{[^}]*pointer-events: stroke;", css)
def test_고르기_차례_306_2(out):
# 안쪽 판정면 맨 아래 · 구조물 판정면 넓이 차례(작은 관 위) 그대로 · 테두리 = 면 판정 맨 위 · 보라 선 맨 위
assert out["order"] == [
"underdrain",
"band",
"g",
"bigPipe",
"smallPipe",
"underdrain+edge",
"road",
]
assert out["edgeCount"] == 1
def test_누른_자리_받는_것_306_2(out):
old, new = out["probesOld"], out["probesNew"]
# 옛 차례 — 맹암거 안 성토 띠 · 맹암거보다 넓은 관이 막힘
assert old["bandInUnderdrain"] == "underdrain" and old["pipeInUnderdrain"] == "underdrain"
assert new == {
"bandInUnderdrain": "band",
"pipeInUnderdrain": "bigPipe",
"smallPipe": "smallPipe",
"underdrainOnly": "underdrain",
"border": "underdrain+edge",
"road": "road",
}
def test_테두리_누름은_맹암거_고름_306_2(out):
assert out["picked"] == ["ud-1"]