"""432-3 MC 곡선 측점 열쇠 — MC 가 움직여도 B06 고침이 그 곡선 측점을 따라감. - 열쇠 `curve:<누가거리>` 는 MC 가 0.01 m 만 움직여도 바뀜 → 예전엔 「노선 밖 고침」으로 버림. - 이제 옛 목록에만 있는 곡선 열쇠 → 새 목록에만 있는 가장 가까운 곡선 열쇠(10 m 안 · 하나씩). - 짝: `common_util_station_key` `curve_moves` ↔ `curveMoves`(거울) · 서버 `carry_cross_inputs` · B06 세션 `carryStationDrafts` · `carryChainageStates`(진짜 모듈 · vite ssr). """ import json import shutil import subprocess from pathlib import Path import pytest from B05_Profile.B05_Profile_Route_Save_Parts import carry_cross_inputs from common_util.common_util_station_key import curve_moves HERE = Path(__file__).resolve().parent ROOT = HERE.parents[1] TS = ROOT / "common_util" / "common_util_station_key.ts" TYPESCRIPT = ROOT / "config" / "node_modules" / "typescript" CASES = [ # MC 하나 1.75 m 움직임 · 하나 그대로 · 하나 15 m(못 이음) ( [("end:BP", 0.0), ("curve:47.35", 47.35), ("curve:70.00", 70.0), ("curve:90.00", 90.0)], [("end:BP", 0.0), ("curve:49.10", 49.1), ("curve:70.00", 70.0), ("curve:105.00", 105.0)], ), # 두 옛 MC 가 한 새 MC 를 다툼 — 앞엣것이 가장 가까운 것만 · 둘째는 다음 가까운 것 ( [("curve:10.00", 10.0), ("curve:14.00", 14.0)], [("curve:12.00", 12.0), ("curve:20.00", 20.0)], ), # 곡선 아닌 열쇠는 안 이음 · 같은 거리 = 앞 차례 ( [("grid:1", 20.0), ("curve:30.00", 30.0)], [("grid:2", 21.0), ("curve:25", 25.0), ("curve:35", 35.0)], ), ([], []), ] MIRROR = r""" const ts = require(process.argv[1]); const src = require("fs").readFileSync(process.argv[2], "utf8"); const opts = { compilerOptions: { module: ts.ModuleKind.CommonJS } }; const js = ts.transpileModule(src, opts).outputText; const box = { exports: {} }; new Function("exports", "module", js)(box.exports, box); const cases = JSON.parse(process.argv[3]); const moves = cases.map(([a, b]) => Object.fromEntries(box.exports.curveMoves(a, b))); process.stdout.write(JSON.stringify(moves)); """ def test_곡선_이음_규칙(): assert curve_moves(*CASES[0]) == {"curve:47.35": "curve:49.10"} assert curve_moves(*CASES[1]) == {"curve:10.00": "curve:12.00", "curve:14.00": "curve:20.00"} assert curve_moves(*CASES[2]) == {"curve:30.00": "curve:25"} def test_파이썬과_TS_같음(): proc = subprocess.run( ["node", "-e", MIRROR, str(TYPESCRIPT), str(TS), json.dumps(CASES)], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr assert json.loads(proc.stdout) == [curve_moves(*case) for case in CASES] def test_서버_노선_저장_넘김은_움직인_MC_로(): old_keys = dict(CASES[0][0]) new_keys = dict(CASES[0][1]) designs = {47.35: {"ground_type": "rock"}, 90.0: {"ground_type": "soil"}} inputs, _adjusts, dropped = carry_cross_inputs(old_keys, new_keys, designs, ["ground_type"], []) assert inputs == {49.1: {"ground_type": "rock"}} assert dropped == 1 # 15 m 움직인 MC = 다른 곡선 · 「노선 밖 고침」 @pytest.fixture(scope="module") def session(tmp_path_factory): work = tmp_path_factory.mktemp("b432") build = subprocess.run( [ "node", str(ROOT / "config" / "node_modules" / "vite" / "bin" / "vite.js"), "build", "--configLoader", "runner", "--ssr", "../resources/tester/helper_432_3_entry.ts", "--outDir", str(work), "--logLevel", "error", ], cwd=ROOT, capture_output=True, text=True, encoding="utf-8", timeout=300, ) assert build.returncode == 0, build.stderr bundle = work / "bundle.mjs" shutil.copy(work / "helper_432_3_entry.js", bundle) proc = subprocess.run( ["node", str(HERE / "helper_432_3_curve_key.mjs"), str(bundle)], cwd=ROOT, capture_output=True, text=True, encoding="utf-8", timeout=120, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def test_B06_세션_고침이_움직인_MC_를_따라감(session): assert set(session["cards"]) == {"49.10"} assert session["cards"]["49.10"]["ground_type"] == "rock" assert session["shoulder"] == {"49.10": {"left": 0.5}} assert session["crossw"] == {"49.10": 3.2} assert session["outside"] == 1 # 90 m MC 카드 — 15 m 움직임 = 버림 assert session["states"] == 0