Files
Aislo/resources/tester/test_64_1_profile_toggle.py
T
eomsangdonandClaude Sonnet 5.5 89433a352d feat(B05): 노선 추천 종단 반영 켜기·끄기 + 갈래 설명 한 쪽씩 넘기기
- 64-1: 추천 창 「종단 반영」 체크(기본 켬) — 요청 with_profile 로 서버가 가름 · 끄면 원지반만(63-4 전 점수) · 묶음 캐시에 남은 종단은 걷어 냄 · 값은 편집 창 안에서만(저장 안 함)
- 64-2: 설명 칸을 갈래 한 쪽씩 ◀ ▶ + 「n / 8」 · 고른 갈래 쪽부터 · 토공 최소 · 공사비 어림 최소 쪽에 종단 반영 설명 추가
- 시험: test_64_1_profile_toggle.py · ui_checks 64-1 · 64-2

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt
2026-10-06 23:14:14 +09:00

74 lines
3.1 KiB
Python

"""추천 「종단 반영」 켜기 · 끄기(PLAN 64-1) — 점수 분기 시험.
./venv/Scripts/python.exe -m pytest resources/tester/test_64_1_profile_toggle.py -q
켬(기본) = 후보마다 균형 종단을 세워 토공 점수를 그것으로(63-4) · 끔 = 종단 없이 원지반 가늠
(절 + 성). 끈 요청은 켠 요청이 묶음 캐시에 남긴 종단을 걷어 내고 처음부터 끈 것과 같아야 한다.
"""
import numpy as np
import pytest
from B05_Profile.B05_Profile_Engine_RouteInitial import Terrain, generate_initial_route
from B05_Profile.B05_Profile_Engine_RouteInitial_Metrics import COST_EARTH_M3
from B05_Profile.B05_Profile_Engine_RouteInitial_Pool import GOALS
from B05_Profile.B05_Profile_Engine_RouteInitial_Profile import profile_earth
from B05_Profile.B05_Profile_Router_Replan import RouteInitialRequest
GRADE = 0.14
RADIUS = 12.0
@pytest.fixture(scope="module")
def hill() -> Terrain:
x = np.arange(0.0, 802.0, 2.0)
y = np.arange(0.0, 402.0, 2.0)
xx, yy = np.meshgrid(x, y)
z = 40.0 * np.exp(-((xx - 400.0) ** 2 + (yy - 200.0) ** 2) / 90.0**2)
return Terrain(x, y, z, np.ones(xx.shape, dtype=bool))
def _run(terrain: Terrain, mode: str, with_profile: bool) -> dict:
expected = [(float(x), 200.0) for x in np.arange(50.0, 752.0, 4.0)]
return generate_initial_route(
expected,
terrain,
[],
mode=mode,
weights=None,
max_grade=GRADE,
min_radius_m=RADIUS,
with_profile=with_profile,
)
@pytest.mark.parametrize("mode", ["earthwork", "cost", "follow"])
def test_켬은_종단_끔은_원지반(hill: Terrain, mode: str) -> None:
on = _run(hill, mode, True)
off = _run(hill, mode, False)
assert on["with_profile"] is True and off["with_profile"] is False
assert "error" not in on["metrics"]["profile"]
assert "profile" not in off["metrics"] and "earth_estimate_m3" not in off["metrics"]
# 끔 점수 = 절 + 성 · 켬 점수 = 균형 종단 토공
assert GOALS["earthwork"](off["metrics"]) == (
off["metrics"]["cut_m3"] + off["metrics"]["fill_m3"],
)
assert GOALS["earthwork"](on["metrics"]) == (profile_earth(on["metrics"]["profile"]),)
# 공사비 어림 = 켬은 토공 몫을 종단 점수로 바꾼 값(고른 노선이 달라도 그 노선의 처음 값 기준)
metrics = on["metrics"]
shift = COST_EARTH_M3 * (profile_earth(metrics["profile"]) - metrics["earth_estimate_m3"])
assert metrics["cost_index"] == pytest.approx(metrics["cost_index_base"] + shift, abs=1.0)
def test_끈_요청은_묶음_캐시의_종단을_걷어_낸다(hill: Terrain) -> None:
first = _run(hill, "cost", False)
_run(hill, "cost", True) # 같은 묶음 캐시에 종단을 붙임
again = _run(hill, "cost", False)
assert again["metrics"] == first["metrics"] and again["planned"] == first["planned"]
assert "profile" not in again["metrics"]
def test_요청_기본은_켬이고_끔을_받는다() -> None:
assert RouteInitialRequest(mode="earthwork").with_profile is True
assert RouteInitialRequest(mode="earthwork", with_profile=False).with_profile is False