112 lines
5.0 KiB
Python
112 lines
5.0 KiB
Python
"""597-2 예정노선 지점 칸 손 고침 계산 — 이름 규칙 · 보이는 이름 · 경위도 읽기 · 더함 · 이름 바꿈 · 경위도로 옮김
|
|
(요구 463 7 · 8) — TS `logic/D03_PlanAnalysis_PointEdit.ts`.
|
|
|
|
./venv/Scripts/python.exe -m pytest resources/tester/test_597_point_edit.py -q
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
TS_FILE = ROOT / "D03_PlanAnalysis" / "logic" / "D03_PlanAnalysis_PointEdit.ts"
|
|
TSC = ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
|
|
|
|
_RUNNER = """
|
|
import { writeFileSync } from "node:fs";
|
|
import * as plan from "./D03_PlanAnalysis/logic/D03_PlanAnalysis_Plan.js";
|
|
import * as pe from "./D03_PlanAnalysis/logic/D03_PlanAnalysis_PointEdit.js";
|
|
import * as tmx from "./D03_PlanAnalysis/logic/D03_PlanAnalysis_Tm.js";
|
|
const Y = 2026;
|
|
const tm = tmx.tmParams(5187);
|
|
// 지점 (100,0) 에서 시작하는 선 · 지점 둘
|
|
let n = plan.newLine(plan.emptyNetwork(), [100, 0]);
|
|
n = plan.normalizePieces(plan.appendVertex(n, 0, [200, 0]), Y);
|
|
const state = { points: [[100, 0], [500, 500]], names: ["", "가"], network: n };
|
|
const added = pe.addPoint(state, [7, 8]);
|
|
const full = { points: Array.from({ length: 40 }, (_, i) => [i, 0]), names: [], network: n };
|
|
const [lon, lat] = tmx.tmToLonLat(tm, 100, 0);
|
|
const moved = pe.movePointTo(state, 0, tm, lon + 0.001, lat);
|
|
const back = tmx.tmToLonLat(tm, ...moved.points[0]);
|
|
writeFileSync(process.argv[2], JSON.stringify({
|
|
errors: ["", "가나다", "a/b", "a" + String.fromCharCode(92) + "b", "a:b", "a*b", "a?b", 'a"b', "a<b", "a>b", "a|b", "x".repeat(20), "x".repeat(21)]
|
|
.map((s) => pe.pointNameError(s)),
|
|
labels: [pe.pointLabel(["", " ", "가"], 0), pe.pointLabel(["", " ", "가"], 1), pe.pointLabel(["", " ", "가"], 2), pe.pointLabel([], 3)],
|
|
parse: [pe.parseLonLat("128.5", "36.9"), pe.parseLonLat("", "36.9"), pe.parseLonLat("128.5", "abc"), pe.parseLonLat("181", "0"), pe.parseLonLat("0", "-91")],
|
|
added: [added.points, added.names, added.network === n],
|
|
full: pe.addPoint(full, [1, 1]) === full,
|
|
renamed: [pe.renamePoint(state, 1, " 나 ").names, pe.renamePoint({ ...state, names: [] }, 1, "다").names],
|
|
moved: { points: moved.points, lines: moved.network.lines.map((l) => l.vertices), back, expect: [lon + 0.001, lat], untouched: moved.points[1], names: moved.names },
|
|
}));
|
|
"""
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def got(tmp_path_factory: pytest.TempPathFactory) -> dict:
|
|
tmp_path = tmp_path_factory.mktemp("pe")
|
|
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,
|
|
) # fmt: skip
|
|
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")
|
|
result = tmp_path / "out.json"
|
|
subprocess.run( # noqa: S603
|
|
["node", str(out / "runner.mjs"), str(result)],
|
|
cwd=str(ROOT),
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
return json.loads(result.read_text(encoding="utf-8"))
|
|
|
|
|
|
def test_name_rule(got: dict) -> None:
|
|
ok, bad = got["errors"][:2], got["errors"][2:11]
|
|
assert ok == [None, None] # 빈 이름 · 한글 = 됨
|
|
assert all(msg and "못 씁니다" in msg for msg in bad) # 파일 이름 못 쓰는 글자 아홉
|
|
assert got["errors"][11] is None # 20 자
|
|
assert "20 자" in got["errors"][12] # 21 자 = 막음
|
|
|
|
|
|
def test_label_blank_falls_back(got: dict) -> None:
|
|
assert got["labels"] == ["지점 1", "지점 2", "가", "지점 4"]
|
|
|
|
|
|
def test_parse_lonlat(got: dict) -> None:
|
|
ok, no_lon, bad_lat, big_lon, big_lat = got["parse"]
|
|
assert ok == [128.5, 36.9]
|
|
assert no_lon.startswith("경도") and bad_lat.startswith("위도")
|
|
assert big_lon.startswith("경도") and big_lat.startswith("위도")
|
|
|
|
|
|
def test_add_and_limit(got: dict) -> None:
|
|
points, names, network_same = got["added"]
|
|
assert points == [[100, 0], [500, 500], [7, 8]] and names == ["", "가", ""]
|
|
assert network_same # 더해도 노선 그대로
|
|
assert got["full"] # 40 개 = 그대로
|
|
|
|
|
|
def test_rename(got: dict) -> None:
|
|
assert got["renamed"][0] == ["", "나"] # 앞뒤 빈칸 뺌
|
|
assert got["renamed"][1] == ["", "다"] # 이름 목록이 짧아도 차례 맞춤
|
|
|
|
|
|
def test_move_by_lonlat_drags_node(got: dict) -> None:
|
|
moved = got["moved"]
|
|
assert moved["back"] == pytest.approx(moved["expect"], abs=1e-7) # 경위도 왕복
|
|
assert moved["lines"][0][0] == moved["points"][0] # 그 자리 노선 노드도 같이
|
|
assert moved["lines"][0][1] == [200, 0] # 다른 노드는 그대로
|
|
assert moved["untouched"] == [500, 500] and moved["names"] == ["", "가"]
|