- 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>
114 lines
5.0 KiB
Python
114 lines
5.0 KiB
Python
"""591-1 예정노선 등록 기준점 · 주소 · 설계속도 지움(요구 452 · 453).
|
|
|
|
- 좌표 → {address, region} — 지번 먼저(산 번지) · region = 「시군구 (구) 읍면」 · 도로명만 = 행정동 · 실패 = 빈 값
|
|
- B08 한 줄 주소(도로명 먼저)는 그대로
|
|
- GET /api/map/address — 출처 VWorld
|
|
- 등록 몸 — 기준점 필수 · 경위도 범위 · 설계속도 칸 없음
|
|
- 옛 PLAN 기준점 = 지점 상자 가운데(꼴 셋) · 행 만들기 = 기준점 칸 셋 · 설계속도 칸 안 씀
|
|
- 화면 — 지도 · 기준점 필수 · 출처 표기 · 설계속도 글 없음
|
|
"""
|
|
|
|
import asyncio
|
|
import importlib.util
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
if str(ROOT) not in sys.path:
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from B01_Dashboard import B01_Dashboard_Map as vmap # noqa: E402
|
|
from common_util import common_util_map_router as map_router # noqa: E402
|
|
from D01_PlanRegister import D01_PlanRegister_Router as d01 # noqa: E402
|
|
|
|
|
|
def _fill_tool():
|
|
spec = importlib.util.spec_from_file_location(
|
|
"fill024", ROOT / "db_management" / "024_plan_site_fill.py"
|
|
)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
PARCEL = {"type": "parcel", "text": "경상북도 울진군 금강송면 광회리 산 47",
|
|
"structure": {"level1": "경상북도", "level2": "울진군", "level3": "",
|
|
"level4L": "금강송면", "level4A": ""}} # fmt: skip
|
|
ROAD = {"type": "road", "text": "경기도 수원시 장안구 정조로 1",
|
|
"structure": {"level2": "수원시", "level3": "장안구", "level4L": "정조로",
|
|
"level4A": "파장동"}} # fmt: skip
|
|
|
|
|
|
def _body(*items):
|
|
return json.dumps({"response": {"status": "OK", "result": list(items)}}).encode()
|
|
|
|
|
|
def test_좌표_주소_지번_먼저(monkeypatch):
|
|
monkeypatch.setattr(vmap, "_fetch", lambda url, timeout=5: _body(ROAD, PARCEL))
|
|
assert vmap._place_sync(129.1, 36.95) == {
|
|
"address": "경상북도 울진군 금강송면 광회리 산 47",
|
|
"region": "울진군 금강송면",
|
|
}
|
|
assert vmap._reverse_sync(129.1, 36.95) == "경기도 수원시 장안구 정조로 1" # B08 그대로
|
|
monkeypatch.setattr(vmap, "_fetch", lambda url, timeout=5: _body(ROAD))
|
|
assert vmap._place_sync(127.0, 37.3)["region"] == "수원시 장안구 파장동"
|
|
monkeypatch.setattr(vmap, "_fetch", lambda url, timeout=5: b"not json")
|
|
assert vmap._place_sync(127.0, 37.3) == {"address": None, "region": None}
|
|
|
|
|
|
def test_주소_길_출처(monkeypatch):
|
|
async def place(lon, lat):
|
|
return {"address": "주소", "region": "울진군 금강송면"}
|
|
|
|
monkeypatch.setattr(map_router, "reverse_place", place)
|
|
out = asyncio.run(map_router.map_address(lon=129.1, lat=36.95))
|
|
assert out == {"address": "주소", "region": "울진군 금강송면", "source": "VWorld"}
|
|
|
|
|
|
def test_등록_몸_기준점_필수():
|
|
base = {"project_name": "예정", "project_year": 2026, "region": "울진"}
|
|
with pytest.raises(ValidationError):
|
|
d01.CreatePlanRequest(**base)
|
|
with pytest.raises(ValidationError):
|
|
d01.CreatePlanRequest(**base, site={"lon": 200, "lat": 36})
|
|
ok = d01.CreatePlanRequest(**base, site={"lon": 129.1, "lat": 36.95})
|
|
assert "design_speed_kph" not in d01.CreatePlanRequest.model_fields
|
|
assert (ok.site.lon, ok.site.lat) == (129.1, 36.95)
|
|
|
|
|
|
def test_옛_기준점_지점_가운데():
|
|
center = _fill_tool().base_center
|
|
assert center({"epsg": 5186, "start": {"x": 0, "y": 10}, "end": {"x": 100, "y": 30}}) == (
|
|
50,
|
|
20,
|
|
)
|
|
pts = [{"x": 0, "y": 0}, {"x": 40, "y": 10}, {"x": 20, "y": 100}]
|
|
assert center({"points": pts}) == (20, 50)
|
|
assert center({"starts": [{"x": 0, "y": 0}], "ends": [{"x": 10, "y": 10}]}) == (5, 5)
|
|
assert center(None) is None and center({"points": []}) is None
|
|
|
|
|
|
def test_행_만들기_기준점_칸():
|
|
src = (ROOT / "common_util" / "common_util_project_kind.py").read_text(encoding="utf-8")
|
|
assert "site_lon, site_lat, site_address" in src and "design_speed_kph" not in src
|
|
sql = (ROOT / "db_management" / "024_plan_site.sql").read_text(encoding="utf-8")
|
|
assert "site_lon DOUBLE" in sql and "site_address VARCHAR(255)" in sql
|
|
assert "SET design_speed_kph = NULL WHERE project_kind = 'PLAN'" in sql
|
|
|
|
|
|
def test_화면_지도_출처():
|
|
page = (ROOT / "D01_PlanRegister" / "D01_PlanRegister_UI_Page.ts").read_text(encoding="utf-8")
|
|
assert "editMap(" in page and "/map/address" in page and "DE_Reg_SiteSource" in page
|
|
assert "site: { lon: at[0], lat: at[1] }" in page and "DE_Reg_SiteRequired" in page
|
|
assert "DesignSpeed" not in page
|
|
|
|
|
|
def test_D04_연결_설계속도_안_넘김():
|
|
# 590-1 이 씨앗 줄을 걷음 — 연결이 설계속도를 안 넘김(B05 기본 20)
|
|
link = (ROOT / "D04_PlanConfirm" / "D04_PlanConfirm_Link.py").read_text(encoding="utf-8")
|
|
assert "design_speed" not in link
|