Files
Aislo/resources/tester/test_472_1_golden.py
T
eomsangdonandClaude Opus 5.5 172ff8170b refactor(511-B B-6 정리): 운영 부름 0 파이썬 짝 걷음 · 남는 짝 머리에 남는 까닭 · 등록부 until 걷음 · 알려진 차 까닭 · 322_3 flow 빨강 고침
걷은 함수(운영 부름 0 · 전수 확인 = 화면 · 서버 · 체인 · 추천 엔진 · B07 · 시험)
- common_util/common_util_excavation.py 통째(126 줄 · pipe_trench_width_m · wall_trench_area_m2 · wall_trench_width_m · 서버 = Node excavation.trench)
- Engine_Grade_Carry.carry_edits(Node carry_seat 겉) · Route_Save_Parts.seat_route_moved(시험 헬퍼 helper_475_1_moved 로 옮김)
- Engine_Tilt.attach_underdrains · Engine_Structures_Wall.attach_wall_structures · load_wall_structures
- Engine_Grade_Alignment.tangent_elevation(부름 0) · station_key.dedupe_station_keys · loose_chainage
줄 수 전 → 후: excavation.py 126 → 0 · Grade_Carry 178 → 157 · Save_Parts 289 → 269 · Wall 221 → 197 · Tilt 115 → 112 · station_key 141 → 122 · Alignment 657 → 654

남는 짝(머리 「남는 까닭」 한 줄) — Grade · Grade_Profile · Alignment · CurveLaw(2~4 순위 폴백 · 추천) · NodeEdits · SampleExtend · Router_Design · Ranges · Engine_Design · Areas · cross_berm(DTM 아닌 지표면 · Node 못 부를 때 · B07 · 추천) · Tilt · Wall · Culvert(B04 B07 B08) · route_follow · structure_station · station_key · route_polyline(745 줄 · 까닭 = 등록부 R1 줄)

등록부 — until 칸 걷음(G1 = py 표본기 남김 · 까닭 note) · C6 pair = attach_underdrain_specs · F8 pair null
알려진 차 — golden KNOWN 셋 그대로 나타남(R7 표본 출처 · W0 저장 때 경고 · X2 입력 선 자릿수 · 까닭 고침) · underdrain 알려진 차 까닭 · 511_b5 KNOWN_ARC 그대로
계산 자리 창 — 45 줄 · 서버만 아닌 41(바꿀 수 있음 40 + F9) · 서버만 넷(G3 D1 D2 N1 줄마다 까닭) · 옛 까닭 「짝 모으는 중 · B-4」 글 걷음
test_322_3_flow 빨강 — 헬퍼가 @config/config_frontend 흉내(511-A design_calc_server import)
시험 기준 — 걷은 짝 거울 = 걷기 전 파이썬 값 고정(excavation · station_key) · Node carry_seat · attach_underdrain_specs · wall_specs_from

검증: 고친 대상 시험 97 파일 562 통과 · 21 건너뜀 · typecheck 0 · 700 줄 넘는 새 파일 없음 — 요구 320-4

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:34:08 +09:00

171 lines
7.0 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.
"""PLAN 472-1 (요구 273) — B05 · B06 기준값 시험 · 구조 다시 세움 단계마다의 문.
고정 자료 `fixtures/golden_472/`(검증_랩탑메인 노선 370 · 읽기만 뜸) 하나로 길 넷의 값을 떠
`golden_472_values.json` 과 견줌(값 꼴 · 길 = `helper_472_1_paths.py` 머리).
못박는 것
- 길마다 자기 값과 0 차 — 측점(수 · 열쇠 · 누가거리 · x · y) · 계획고 ·
면적(절 · 성 · 토사 · 암 · 측구) · 층따기 밑수 · 단면 모양 · 누가토량(측점별 · 끝값) ·
관 길이 · 종단 경고 · 기울기 위반 수.
- 두 길 사이 = 「알려진 차」(`KNOWN`)만 · 그 밖 차는 실패 · 안 나타난 알려진 차도 실패
(목록에서 지움). 짝 모으기(511-B) 끝 — 남은 줄은 계산 짝이 아닌 까닭(표본 출처 · 입력 선
자릿수 · 저장 때 코드) · 줄마다 `why`.
- 화면 참값 — 정본 누가토량 −17,570.70 ㎥ · 측점 57(465 기준값).
이 고정 자료가 안 거치는 짝인데 값이 갈리는 자리 — X1 단면 모양 기본값(설계 없는 새 측점 없음) ·
X3 면적 두 갈래(구조물 = 관 351 하나 · 두 길 다 Node TS 로 셈) · X4 · X6(노선 안 바뀜).
값 다시 뜨기 = `helper_472_1_dump.py`(승인 때만 · 시험은 다시 안 뜸).
./venv/Scripts/python.exe -m pytest resources/tester/test_472_1_golden.py -q
"""
from __future__ import annotations
import copy
import json
from dataclasses import dataclass
import helper_472_1_paths as paths
import pytest
pytestmark = pytest.mark.skipif(
not (paths.ROOT / "config" / "node_modules" / "vite").is_dir(),
reason="프론트엔드 의존성 미설치",
)
GOLDEN = json.loads(paths.VALUES.read_text(encoding="utf-8"))
AREAS = ("cut_m2", "fill_m2", "cut_soil_m2", "cut_rock_m2", "ditch_m2")
@dataclass(frozen=True)
class Known:
"""알려진 차 한 줄 — 칸 → 허용 폭(None = 같지 않아도 됨 · 글 칸) · 까닭."""
id: str
fields: dict[str, float | None]
why: str
KNOWN: dict[tuple[str, str], list[Known]] = {
# [저장] 재계산 = 정본 그대로(사용자 원칙 — 입력 안 바뀌면 값 안 바뀜) · 경고만 지금 코드
("server_save", "stored"): [
Known(
"W0",
{"warnings": None},
"정본 종단 경고 = 10-17 저장 때 코드(법정 R · L 미달 46 줄 전) · "
"[저장] 재계산이 지금 코드로 다시 씀(472 덧 · 기하 그대로)",
),
],
("server_route", "stored"): [
Known(
"R7",
{"fill_m2": 0.00011, "cumulative_m3": 0.011},
"지반 표본 출처(G1) — 정본 = 10-17 파이썬 표본 · 노선 저장 = Node 격자 표본 · "
"grid:37 성토 1e-4 ㎡ · 누가토량 0.01 ㎥ 넷(끝값 같음 · 기준값 다시 뜸 안 함 B-2)",
),
Known(
"W0",
{"warnings": None},
"정본 종단 경고 = 10-17 저장 때 코드(법정 R · L 미달 46 줄 전) · "
"노선 저장 체인은 지금 코드",
),
],
("browser", "server_route"): [
Known(
"X2",
{
"x": 0.002,
"y": 0.002,
**dict.fromkeys(AREAS, 0.1),
"bench_m": 1.0,
"cumulative_m3": 2.0,
"final_cumulative_m3": 1.0,
},
"입력 선 — 브라우저 /route/plan planned(0.1 mm) · 서버 노선 geojson(1 mm) · "
"측점 자리 ≤ 1 mm → 표본 · 면적 ≤ 0.07 ㎡ · 층따기 밑수 ≤ 0.52 m · "
"누가토량 끝값 0.69 ㎥(−17,570.01 ↔ −17,570.70)",
),
],
}
@pytest.fixture(scope="module")
def got(tmp_path_factory) -> dict:
out = {}
for name in paths.PATHS:
out[name] = paths.run_path(name, tmp_path_factory.mktemp(name))
return out
def diffs(a: dict, b: dict) -> list[tuple[str, str, object, object]]:
"""(칸, 측점 열쇠, a, b) — 측점은 같은 차례(수가 다르면 측점 수 한 줄)."""
out = []
for field in ("station_count", "final_cumulative_m3", "pipe_lengths", "warnings", "violations"):
if a[field] != b[field]:
out.append((field, "-", a[field], b[field]))
if a["station_count"] == b["station_count"]:
for x, y in zip(a["stations"], b["stations"], strict=True):
out += [(k, x["key"], x[k], y[k]) for k in x if x[k] != y[k]]
return out
def allowed(diff: tuple, known: Known) -> bool:
field, _key, a, b = diff
if field not in known.fields:
return False
width = known.fields[field]
if width is None:
return True
return isinstance(a, (int, float)) and isinstance(b, (int, float)) and abs(a - b) <= width
@pytest.mark.parametrize("name", paths.PATHS)
def test_길마다_기준값_그대로(got, name) -> None:
found = diffs(got[name], GOLDEN[name])
assert not found, f"{name} 기준값과 다름 {len(found)}곳 — 앞 10: {found[:10]}"
@pytest.mark.parametrize("pair", list(KNOWN), ids=lambda pair: f"{pair[0]}-{pair[1]}")
def test_두_길_사이_알려진_차만(got, pair) -> None:
known = KNOWN[pair]
found = diffs(got[pair[0]], got[pair[1]])
stray = [d for d in found if not any(allowed(d, k) for k in known)]
assert not stray, f"알려진 차 밖 {len(stray)}곳 — 앞 10: {stray[:10]}"
gone = [k.id for k in known if not any(allowed(d, k) for d in found)]
assert not gone, f"안 나타난 알려진 차 {gone} — KNOWN 에서 지움"
def test_저장_설계선_점_정본과_1e4_안(tmp_path) -> None:
"""[저장] 다시 셈 설계선(472-4 ② = Node TS) — 정본과 점 수 · offset 같음 · 고도 1e-4 m 안.
알려진 차 = 반올림 동점(파이썬 round 짝수 쪽 · TS 위쪽) 13 점(브레인 10-19 승인).
"""
detail = copy.deepcopy(paths.read("detail.json"))
before = {s["chainage_m"]: s["design"]["design_line"] for s in detail["cross_sections"]}
sections, _ = paths._save_tail(detail, paths.stage_project(tmp_path / "project"))
moved = 0
for section in sections:
old, new = before[section["chainage_m"]], section["design"]["design_line"]
assert [p["offset_m"] for p in new] == [p["offset_m"] for p in old], section["chainage_m"]
for a, b in zip(old, new, strict=True):
gap = abs(a["elevation_m"] - b["elevation_m"])
assert gap <= 1e-4 + 1e-9, (section["chainage_m"], a, b)
moved += gap > 0
assert moved == 13, f"반올림 동점 점 수 {moved} — 알려진 차(13)와 다름"
def test_화면_참값() -> None:
stored = GOLDEN["stored"]
assert stored["final_cumulative_m3"] == -17570.7
assert stored["station_count"] == 57
assert stored["pipe_lengths"] == {"pipe:p35100": 7.9}
def test_고정_자료_크기() -> None:
size = sum(p.stat().st_size for p in paths.FIXTURE.rglob("*") if p.is_file())
assert size < 5e6
@pytest.mark.skip(reason="API 왕복(목록 4.2 ③ 선택) — 472-1 에서 건너뜀")
def test_API_왕복() -> None:
raise AssertionError