- D02 걷음 — 길 · 단계(PLAN 단계 둘 = 노선 분석 · 확정) · [>] · 대시보드 단계 점 · 서버 길 · 폴더 만들기 · 캐시 등록 · 글 · 가이드 폴더 - 등록 [등록] · 받은 예정노선 [보기] = D03 으로 곧바로 - D03 지점 = 긋기에 붙는 점 · 목록 칸(여섯 색 · 「지점 N」 · 🗑) · 핀 끌기 = 그 자리 노선 노드 같이 · [저장] 몸에 실음 · [초기화] = 선만 지우고 지점 남김 - 지도 우클릭 메뉴(부품 상자) — 여기서 긋기 시작(빈 땅 = 새 본선) · 갈래 시작 · 이어 긋기 · 지점 놓기 · 지점 지우기 · 긋기 끝 - 받기 — 처음 = 등록 기준점 둘레 ± 1 km(지점 · 선 없을 때) · 지점 · 선 · 지도 보기 가운데가 받은 범위 밖이면 조용히 이어 받음(단추 · 막는 창 걷음 · 실패만 [다시 받기]) - 좌표계 = 파일 머리 · 없으면 기준점 경도 TM 띠 - 시험: 529_3(D02 지점 API) 지움 → 591_2 로 갈음 · 280_2 · 528 · 530_2 · 547_1 · 548 · 553_4 · 556_2 · 560_4 · 401 · 54_2 = D02 단계 · 페이지 걷음에 맞춤 · 590_1 · 530_2_analyze = 사업연도 · 기준점 한 번에 읽음 · 591_1 D04 씨앗 시험 = 590-1 이 씨앗 줄 걷음에 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
119 lines
4.4 KiB
Python
119 lines
4.4 KiB
Python
"""D 지형 API(PLAN 530-1 · 561-2 · 591-2) — 범위 = 지점(설계 내용 파일) 상자 + 여유 · 지점 · 선이
|
|
없으면 등록 기준점 둘레 ± 1 km · 받기 = 한 벌.
|
|
|
|
옛 분석 API 시험(GET · PUT analysis · 꺾임점 고침)은 옛 추천 엔진과 함께 걷음(PLAN 562-2) ·
|
|
노선 정본 시험 = `test_530_2_plan_analyze.py` · 지형 셈 시험 = `test_530_1_plan_terrain.py`.
|
|
|
|
./venv/Scripts/python.exe -m pytest resources/tester/test_530_2_plan_router.py -q
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
from contextlib import asynccontextmanager
|
|
|
|
import pytest
|
|
from fastapi import FastAPI
|
|
from fastapi.testclient import TestClient
|
|
|
|
from D03_PlanAnalysis import D03_PlanAnalysis_Router as router_mod
|
|
|
|
PID = "12953f5a-5ba1-42ad-a427-8ac857a58bc2"
|
|
P0, P2 = (0.0, 0.0), (900.0, 400.0)
|
|
URL = f"/api/projects/{PID}/plan/terrain"
|
|
|
|
|
|
class _Pool:
|
|
@asynccontextmanager
|
|
async def acquire(self):
|
|
yield None
|
|
|
|
|
|
@pytest.fixture
|
|
def client(tmp_path, monkeypatch):
|
|
plan = {
|
|
"epsg": 5186,
|
|
"points": [{"x": P0[0], "y": P0[1]}, {"x": P2[0], "y": P2[1]}],
|
|
"lines": [],
|
|
}
|
|
info = {"year_start": 2026, "site": None}
|
|
|
|
async def load_plan(project_id):
|
|
return tmp_path, plan
|
|
|
|
async def project_info(project_id):
|
|
return info
|
|
|
|
monkeypatch.setattr(router_mod.store, "load_plan", load_plan)
|
|
monkeypatch.setattr(router_mod.network, "project_info", project_info)
|
|
monkeypatch.setattr(router_mod, "get_db_pool", lambda: _Pool())
|
|
app = FastAPI()
|
|
app.include_router(router_mod.router)
|
|
test = TestClient(app)
|
|
test.plan = plan
|
|
test.info = info
|
|
return test
|
|
|
|
|
|
def test_extent_uses_whole_ends(client) -> None:
|
|
got = client.get(f"{URL}/extent?margin_m=400").json()
|
|
m = 400.0
|
|
assert got["margin_m"] == m and got["have"] is None and got["covered"] is False
|
|
# 지점 모두(D02 정본) — 연도 구간 아님
|
|
assert got["box_m"] == [P0[0] - m, P0[1] - m, P2[0] + m, P2[1] + m]
|
|
extra = client.get(f"{URL}/extent", params={"extra": json.dumps([[2000, 0]])}).json()
|
|
assert extra["box_m"][2] == 2000 + extra["margin_m"]
|
|
assert client.get(f"{URL}/extent", params={"extra": "[1]"}).status_code == 400
|
|
client.plan["points"] = [] # 지점 · 기준점 빔
|
|
assert client.get(f"{URL}/extent").status_code == 400
|
|
|
|
|
|
def test_extent_site_first(client) -> None:
|
|
"""591-2 — 지점 · 선 없음 = 기준점 둘레 ± 1 km(처음 여유 포함) ·
|
|
좌표계 = 파일 머리 없으면 기준점 띠."""
|
|
from common_util.common_util_crs import lonlat_to_tm
|
|
|
|
client.plan.update(epsg=None, points=[])
|
|
client.info["site"] = {"lon": 127.8, "lat": 36.3, "address": None}
|
|
got = client.get(f"{URL}/extent").json()
|
|
x, y = lonlat_to_tm(127.8, 36.3, 5186)
|
|
r = router_mod.terrain.SITE_RADIUS_M
|
|
assert got["epsg"] == 5186
|
|
assert got["box_m"] == pytest.approx([x - r, y - r, x + r, y + r])
|
|
# 지점이 있으면 기준점은 안 넣음(받은 범위가 이미 덮음 · 옛 프로젝트 그대로)
|
|
client.plan.update(epsg=5186, points=[{"x": P0[0], "y": P0[1]}])
|
|
got = client.get(f"{URL}/extent?margin_m=400").json()
|
|
assert got["box_m"] == [P0[0] - 400, P0[1] - 400, P0[0] + 400, P0[1] + 400]
|
|
|
|
|
|
def test_post_runs_one_set(client, monkeypatch) -> None:
|
|
calls: list = []
|
|
saved: list = []
|
|
works: list = []
|
|
|
|
def ensure(root, points, epsg, margin_m, report):
|
|
calls.append((points, epsg, margin_m))
|
|
return {"sheets": {"downloaded": ["1"]}, "models": [{"model_file_path": "m"}]}
|
|
|
|
async def save(project_id, models, epsg):
|
|
saved.append((models, epsg))
|
|
|
|
def start(project_id, kind, work):
|
|
works.append(work)
|
|
return {"status": "accepted", "kind": kind}
|
|
|
|
def post(body):
|
|
res = client.post(URL, json=body)
|
|
asyncio.run(works.pop()(lambda percent, message: None))
|
|
return res
|
|
|
|
monkeypatch.setattr(router_mod.terrain, "ensure_plan_terrain", ensure)
|
|
monkeypatch.setattr(router_mod, "_save_models", save)
|
|
monkeypatch.setattr(router_mod, "_start_job", start)
|
|
res = post({"margin_m": 500, "extra": [[5, 6]]})
|
|
assert res.json() == {"status": "accepted", "kind": "terrain"}
|
|
assert calls == [([P0, P2, (5.0, 6.0)], 5186, 500.0)]
|
|
assert saved == [([{"model_file_path": "m"}], 5186)]
|
|
# 옛 화면 꼴(points 몸) — 여유 처음 값 · 전체 시점 · 종점
|
|
post({"points": []})
|
|
assert calls[-1] == ([P0, P2], 5186, None)
|