Files
Aislo/resources/tester/test_b06_design_key_split.py
T
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

89 lines
3.6 KiB
Python

"""사용자 값이 재계산에서 사라지지 않는지 — **키 이름으로** 지킨다.
왜 (2026-09-07 전수 조사) — 횡단 `design` 딕셔너리는 사용자 값과 계산 값이 한 칸에 섞여
있고, 재계산(`enforce_pavement_ranges`·`enforce_ford_surface_drops`)은 결과를 통째로
갈아 끼운다. 그래서 사용자 값이 살아남는 길은 **둘뿐**이다:
① 재계산에 **인자로 되먹여** 결과에 그대로 나오는 것
(`ground_type`·`section_mode`·`ditch_side`·`ditch_type`·`paved`·
`two_stage_slope`·`rock_boundary_offset_m`)
② 계산이 만들지 않아 **목록으로 베껴 넣는** 것 (`USER_TOUCHED_KEYS`)
어느 쪽에도 안 걸린 사용자 값은 **저장할 때 조용히 사라진다**. 실제로 그렇게 사라졌던
것이 `extra_spans` 였다(`b6941bd2`). 이 시험은 그 구멍을 다시 못 나게 못박는다 —
새 사용자 값을 `CrossSectionPatch` 에 더하면서 ①·② 어느 쪽에도 안 넣으면 여기서 깨진다.
"""
import inspect
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[2]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from B06_Section.B06_Section_Engine_Design import compute_cross_design # noqa: E402
from B06_Section.B06_Section_Router_Design import USER_TOUCHED_KEYS # noqa: E402
from B06_Section.B06_Section_Schema import CrossSectionPatch # noqa: E402
#: 측점을 가리키는 열쇠 — 값이 아니다.
_KEY_FIELDS = {"chainage_m"}
#: 사용자 값이 아니라 **계산 값**이라 재계산이 다시 내는 것이 옳은 필드.
#: 브라우저가 조작 중 값을 함께 보내지만 정본은 서버가 다시 낸다(CLAUDE.md 5장).
_COMPUTED_FIELDS = {
"cut_area_m2",
"fill_area_m2",
"cut_soil_area_m2",
"cut_rock_area_m2",
# 배수관 연장(m, 2026-09-08) — 사용자 값이 아니라 **기하가 낸 값**이다. 면적 넷과 **같은
# 다리**(`STRUCTURE_ROW_KEYS` → `B06_Section_Server_Calc_Node` →
# `recompute_server_side`)로 서버가 다시 내므로 재계산에서 안 사라진다.
"pipe_length_m",
}
def _recompute_inputs() -> set[str]:
"""재계산에 되먹이는 인자 이름 — ① 갈래."""
return set(inspect.signature(compute_cross_design).parameters)
def test_사용자_값은_되먹임이거나_보존목록이다():
fed = _recompute_inputs()
kept = set(USER_TOUCHED_KEYS)
missing = [
name
for name in CrossSectionPatch.model_fields
if name not in _KEY_FIELDS
and name not in _COMPUTED_FIELDS
and name not in fed
and name not in kept
]
assert not missing, (
"재계산에서 사라질 사용자 값: "
+ ", ".join(missing)
+ " — 재계산 인자로 넣거나 USER_TOUCHED_KEYS 에 더할 것"
)
def test_보존목록에_계산값이_섞이지_않았다():
"""반대 방향 — 계산 값을 베껴 두면 옛 값이 새 계산을 덮는다."""
overlap = sorted(set(USER_TOUCHED_KEYS) & _COMPUTED_FIELDS)
assert not overlap, f"계산 값이 보존 목록에 있음: {overlap}"
def test_되먹임_갈래가_실제로_여덟_가지():
"""①이 줄면(인자에서 빠지면) 그 값은 조용히 기본값으로 되돌아간다 — 수를 못박는다."""
fed = _recompute_inputs()
expected = {
"ground_type",
"section_mode",
"ditch_side",
"ditch_type",
"paved",
"two_stage_slope",
"ditch_enabled",
"rock_boundary_offset_m",
}
assert expected <= fed, f"재계산 인자에서 빠진 것: {sorted(expected - fed)}"