Files
Aislo/resources/tester/test_b06_save_fills_empty_design.py
T
eomsangdonandClaude Opus 5.5 8625e9eb66 fix(B05·B06): 노선 [확인] 뒤 옛 노선 id 저장 막음 — 서버 409 · 저장 앞 노선 대조 · 노선 바뀌면 페이지 새로 세움(76-1)
- 서버: sections save · confirm 이 최신 아닌 노선 id 를 409 로 거절(옛 노선 재계산 없음)
- 화면: [저장] · [확정] 앞에서 서버 노선과 대조 · 다르면 아무것도 안 보내고 페이지 새로 세움
- 화면: 종단 보기 신선도 확인에서 노선이 바뀌면 선만 다시 그리지 않고 페이지 새로 세움
- 시험: test_76_stale_route_save · 기존 저장 시험에 최신 노선 조회 가짜값

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYJJRCfHfdCGNhmXTjQKV7
2026-10-07 20:35:47 +09:00

121 lines
4.3 KiB
Python

"""[저장]이 「행은 있는데 설계가 빈 측점」을 채우는지 (2026-09-09).
재생성이 `cross_sections` 행을 지우고 다시 쓰면 `data.design` 에 면적 4키만 남는다.
`get_cross_section_designs` 는 `ground_type` 있는 줄만 담으므로 그 상태는 「설계 없음」이고,
B08 토적표가 통째로 0 이 됐다(창 셋에서 같은 증상). 예전에는 체인이 뒤이어 부르는 [확정]이
그 자리를 채워 가려져 있었다.
⚠ **값이 있는 행은 안 건드린다**가 이 시험의 핵심이다 — 사용자 조작값·이월분이 거기 있다.
"""
from __future__ import annotations
import asyncio
import sys
from pathlib import Path
from typing import Any
import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
import B06_Section.B06_Section_Router_Confirm as confirm # noqa: E402
class _Conn:
async def begin(self) -> None:
return None
async def commit(self) -> None:
return None
async def rollback(self) -> None:
return None
class _Acquire:
async def __aenter__(self) -> _Conn:
return _Conn()
async def __aexit__(self, *_: Any) -> None:
return None
class _Pool:
def acquire(self) -> _Acquire:
return _Acquire()
def _async(value: Any):
async def _inner(*_: Any, **__: Any) -> Any:
return value
return _inner
def _run_save(monkeypatch: pytest.MonkeyPatch, missing: list[float]) -> list[float]:
"""`save_sections` 를 돌리고 **기본 설계를 계산하라고 넘긴 측점 목록**을 돌려준다."""
seen: list[float] = []
monkeypatch.setattr(confirm, "get_db_pool", lambda: _Pool())
monkeypatch.setattr(
confirm, "get_longitudinal_section", _async({"longitudinal_file_path": "long.json"})
)
monkeypatch.setattr(confirm, "get_project_storage_relative_path", _async("1/3/proj"))
# 화면이 쥔 노선 = 최신 노선(옛 노선 저장 거절은 `test_76_stale_route_save`).
monkeypatch.setattr(confirm, "get_workflow_route_context", _async({"route_id": 184}))
monkeypatch.setattr(confirm, "get_cross_section_chainages", _async([0.0, 20.0, 40.0]))
monkeypatch.setattr(confirm, "get_cross_sections_missing_design_chainages", _async(missing))
monkeypatch.setattr(confirm, "resolve_stored_project_path", lambda _p: str(PROJECT_ROOT))
# 행 자체가 없는 측점은 이 시험의 관심사가 아니다 — 빈 목록으로 고정한다.
monkeypatch.setattr(confirm, "_rowless_station_chainages", lambda *_a, **_k: [])
def _spy(_root, _path, chainages, _standard):
seen.extend(chainages)
return [(value, {"ground_type": "soil"}) for value in chainages]
monkeypatch.setattr(confirm, "_compute_default_designs", _spy)
monkeypatch.setattr(confirm, "_apply_section_edits", _async(None))
monkeypatch.setattr(confirm, "_recompute_stored_designs", _async(None))
from uuid import UUID
response = asyncio.run(
confirm.save_sections(
project_id=UUID("fa76c162-71c7-46e5-a95d-fb3930665a45"), route_id=184, request=None
)
)
assert getattr(response, "confirmed", None) is False, response
return seen
def test_설계가_빈_측점을_채운다(monkeypatch: pytest.MonkeyPatch) -> None:
seen = _run_save(monkeypatch, [20.0, 40.0])
assert sorted(seen) == [20.0, 40.0]
def test_값이_있는_행은_안_건드린다(monkeypatch: pytest.MonkeyPatch) -> None:
"""빈 측점이 없으면 기본 설계를 아예 계산하지 않는다 — 덮어쓸 일이 없다."""
seen = _run_save(monkeypatch, [])
assert seen == []
def test_빈_설계의_뜻이_ground_type_없음이다() -> None:
"""판정은 `get_cross_sections_missing_design_chainages` 한 곳에서만 한다."""
import inspect
from B06_Section.B06_Section_Repository import get_cross_sections_missing_design_chainages
source = inspect.getsource(get_cross_sections_missing_design_chainages)
assert 'design.get("ground_type")' in source
def test_저장도_확정과_같은_판정을_쓴다() -> None:
"""두 갈래가 같은 조회를 써야 「저장했는데 확정과 다르다」가 안 생긴다."""
import inspect
source = inspect.getsource(confirm.save_sections)
assert "get_cross_sections_missing_design_chainages" in source