Files
Aislo/resources/tester/test_530_3_plan_logic.py
T
eomsangdonandClaude Opus 5.5 ba255f2851 feat(562-2): D03 노선 정본 GET · PUT network — 손 그은 선 · 갈래 · 마크 · 조각 → 조각 행 · 연도 행 · 사업연도 끝 · 옛 추천 엔진 · 꺾임점 R 걷음
- 새 D03_PlanAnalysis_Network.py — 서버가 marks 로 조각 경계 · 길이 · 측점 다시 셈(높이 저장 안 함) · 옛 연도 노선은 읽을 때 한 선으로 · 업체 지정 조각 지움 409 · 산림청만
- 새 db_management/021_plan_network.sql — plan_networks · plan_route_pieces · plan_route_assignees.piece_id(DB 반영함)
- main.py 라우터 한 벌 · Router.py 의 POST analyze · GET/PUT analysis 덩이 지움(지형 · 진행 길 그대로)
- 지움: D03_PlanAnalysis_Analyze.py · D03_PlanAnalysis_Edit.py · config PLAN_ANALYZE_WORKERS
- 시험: test_530_2_plan_analyze = 노선 정본 시험으로 다시 씀(옛 엔진 시험은 엔진과 함께 걷음) · test_530_2_plan_router = 분석 API 시험 지우고 끈 지점 규칙만 · test_530_3_plan_logic = Analyze 짝 시험 지움 · test_543_plan_edit 지움(꺾임점 R 고침 걷음 — 요구 389 11 직선만)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 20:05:44 +09:00

124 lines
4.0 KiB
Python

"""D03 화면 계산(PLAN 530-3) — TS `logic/D03_PlanAnalysis_Plan.ts`.
측점 누가 앞붙임 선(선 위 누가 = 등록 시작 누가) · 받은 지형 판정.
파이썬 짝(`D03_PlanAnalysis_Analyze`)은
옛 추천 엔진과 함께 걷음(PLAN 562-2).
./venv/Scripts/python.exe -m pytest resources/tester/test_530_3_plan_logic.py -q
"""
from __future__ import annotations
import json
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
TS_FILE = ROOT / "D03_PlanAnalysis" / "logic" / "D03_PlanAnalysis_Plan.ts"
TSC = ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
_RUNNER = """
import { readFileSync, writeFileSync } from "node:fs";
import * as plan from "./D03_PlanAnalysis/logic/D03_PlanAnalysis_Plan.js";
const job = JSON.parse(readFileSync(process.argv[2], "utf8"));
const out = job.cases.map((c) => {
const rows = plan.chainRows(job.results, c.choices, c.start);
return {
picks: job.results.map((r) => plan.pickMode(r, c.choices[r.year])),
rows,
line: plan.joinedLine(job.results, rows),
stations: plan.stationChainages(rows, 20),
};
});
const lead = plan.leadInLine([[0, 0], [3, 4], [10, 4]], 1234.5);
const reach = plan.nodesInReach(
[[500, 500], [900, 500], [1700, 500]],
[{ x0: 0, y0: 0, x1: 1300, y1: 1000 }, null],
);
writeFileSync(process.argv[3], JSON.stringify({ out, lead, reach }));
"""
_P0, _P1, _P2 = [0.0, 0.0], [300.0, 400.0], [900.0, 400.0]
_RESULTS = [
{
"year": 2026,
"start": _P0,
"end": _P1,
"routes": {
"gradeline": {"planned": [_P0, [100.0, 200.0], _P1], "metrics": {"length_m": 530.0}},
"earthwork": {"error": "길 없음"},
"gentle": {"planned": [_P0, _P1], "metrics": {"length_m": 500.004}},
},
},
{
"year": 2027,
"start": _P1,
"end": _P2,
"routes": {
"gradeline": {"error": "길 없음"},
"gentle": {"planned": [_P1, [600.0, 500.0], _P2], "metrics": {"length_m": 640.333}},
"weighted": {"planned": [_P1, _P2], "metrics": {"length_m": 600.0}},
},
},
]
_CASES = [
{"choices": {}, "start": 1000.0},
{"choices": {"2026": "gentle", "2027": "weighted"}, "start": 17.25},
{"choices": {"2026": "earthwork", "2027": "follow"}, "start": 0.0},
]
def _run_ts(tmp_path: Path) -> dict:
out = tmp_path / "js"
subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
str(TSC),
str(TS_FILE),
"--outDir",
str(out),
"--rootDir",
str(ROOT),
"--module",
"esnext",
"--target",
"es2022",
"--moduleResolution",
"bundler",
"--ignoreConfig",
],
cwd=str(ROOT),
check=True,
capture_output=True,
)
for emitted in out.rglob("*.js"):
emitted.write_text(
re.sub(r'(from\s+"\.\.?/[^"]+)"', r'\1.js"', emitted.read_text(encoding="utf-8")),
encoding="utf-8",
)
(out / "runner.mjs").write_text(_RUNNER, encoding="utf-8")
job = tmp_path / "job.json"
result = tmp_path / "out.json"
job.write_text(json.dumps({"results": _RESULTS, "cases": _CASES}), encoding="utf-8")
subprocess.run( # noqa: S603
["node", str(out / "runner.mjs"), str(job), str(result)],
cwd=str(ROOT),
check=True,
capture_output=True,
)
return json.loads(result.read_text(encoding="utf-8"))
def test_lead_in_and_reach(tmp_path: Path) -> None:
got = _run_ts(tmp_path)
back = got["lead"][0]
assert abs(back[0] + 1234.5 * 0.6) < 1e-9 and abs(back[1] + 1234.5 * 0.8) < 1e-9
assert got["lead"][1:] == [[0, 0], [3, 4], [10, 4]]
# 마디 0 = 첫 연도 안 · 마디 1 = 첫 연도 안 + 둘째 연도 DEM 없음 = 밖 · 마디 2 = 밖
assert got["reach"] == [True, False, False]