Merge remote-tracking branch 'origin/sub_laptop_5' into main_laptop_1
This commit is contained in:
@@ -33,6 +33,10 @@ const STUBS = {
|
||||
showLoadingOverlay: () => calls.push("overlay:on"),
|
||||
hideLoadingOverlay: () => calls.push("overlay:off"),
|
||||
},
|
||||
// 노선 저장(346-3) — 이 시험은 노선이 그대로인 [저장]만 봄
|
||||
[path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Apply.ts")]: {
|
||||
pendingRouteSave: async () => null,
|
||||
},
|
||||
[path.join(B06, "B06_Section_Api_Fetch.ts")]: {
|
||||
fetchSectionDetail: async () => (calls.push(`fetch:${server}`), detail()),
|
||||
saveSections: async () => calls.push("cross:save"),
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/* 346-3 노선 저장 이음 헬퍼 — `B05_Profile_UI_RouteEdit_Apply.ts` 를 트랜스파일해 서버 · 화면 창구는 가짜로,
|
||||
* 가게 · 캐시(`design_store` · `b_page_state`)는 진짜로 돌림. 보낸 본문 · 부른 차례를 적어 JSON 한 벌로 냄.
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
|
||||
function memoryStorage() {
|
||||
const map = new Map();
|
||||
return {
|
||||
getItem: (key) => (map.has(key) ? map.get(key) : null),
|
||||
setItem: (key, value) => map.set(key, String(value)),
|
||||
removeItem: (key) => map.delete(key),
|
||||
key: (index) => [...map.keys()][index] ?? null,
|
||||
get length() {
|
||||
return map.size;
|
||||
},
|
||||
};
|
||||
}
|
||||
const session = memoryStorage();
|
||||
globalThis.window = { sessionStorage: session, localStorage: memoryStorage() };
|
||||
globalThis.sessionStorage = session;
|
||||
|
||||
const calls = [];
|
||||
const bodies = [];
|
||||
let failReplan = false;
|
||||
const STUBS = {
|
||||
"@ui/ui_template_elements": {
|
||||
showToast: (text, kind) => calls.push(`toast:${kind}:${text}`),
|
||||
showLoadingOverlay: () => calls.push("overlay:on"),
|
||||
hideLoadingOverlay: () => calls.push("overlay:off"),
|
||||
},
|
||||
"../A00_Common/router": {
|
||||
currentRoute: () => "b05-profile",
|
||||
remountRoute: () => calls.push("remount"),
|
||||
},
|
||||
"../B06_Section/B06_Section_Section_Store": {
|
||||
invalidateSectionDetail: (_p, routeId) => calls.push(`invalidate:${routeId ?? "all"}`),
|
||||
loadSectionDetail: async (_p, routeId) => (calls.push(`load:${routeId}`), { tag: routeId }),
|
||||
saveCachedCrossPatches: async (_p, routeId) => (calls.push(`crossSave:${routeId}`), 1),
|
||||
},
|
||||
"../B06_Section/B06_Section_Station_Keys": {
|
||||
useStationKeys: (_p, routeId, detail) => calls.push(`keys:${routeId}:${detail.tag}`),
|
||||
carryStationDrafts: (_p, from, to) => (calls.push(`carry:${from}->${to}`), 2),
|
||||
},
|
||||
"./B05_Profile_Api_Fetch": { clearRouteLatestCache: () => calls.push("latest:clear") },
|
||||
"./B05_Profile_Api_Replan": {
|
||||
replanRoute: async (_p, body) => {
|
||||
bodies.push(JSON.parse(JSON.stringify(body)));
|
||||
calls.push("replan");
|
||||
if (failReplan) throw new Error("체인 실패");
|
||||
return {
|
||||
route_id: 9,
|
||||
pipes: { kept: 3, crossing: 1, concave: 2 },
|
||||
structures: { moved: 1, far: 0 },
|
||||
cross_dropped: 1,
|
||||
drainage_stale: true,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const cache = new Map();
|
||||
function loadTs(file) {
|
||||
const full = path.resolve(file);
|
||||
if (cache.has(full)) return cache.get(full);
|
||||
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
|
||||
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
||||
}).outputText;
|
||||
const box = { exports: {} };
|
||||
cache.set(full, box.exports);
|
||||
const localRequire = (request) => {
|
||||
if (STUBS[request]) return STUBS[request];
|
||||
if (request.startsWith(".")) return loadTs(path.join(path.dirname(full), `${request}.ts`));
|
||||
return require(request);
|
||||
};
|
||||
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
|
||||
return box.exports;
|
||||
}
|
||||
|
||||
const { useDesignStore } = loadTs(path.join(ROOT, "A00_Common", "design", "design_store.ts"));
|
||||
const { readState, writeState } = loadTs(path.join(ROOT, "A00_Common", "b_page_state.ts"));
|
||||
const apply = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Apply.ts"));
|
||||
|
||||
(async () => {
|
||||
const out = {};
|
||||
const draft = {
|
||||
rev: 3,
|
||||
nodes: [
|
||||
[0, 0],
|
||||
[5, 5],
|
||||
[10, 0],
|
||||
],
|
||||
curveOn: [true, true, true],
|
||||
};
|
||||
// 편집기 없음 — 가게 routeDraft 를 보냄 · 없으면 null
|
||||
out.noneAtAll = await apply.pendingRouteSave("p1");
|
||||
useDesignStore("p1", null).set("routeDraft", draft);
|
||||
out.storeOnly = await apply.pendingRouteSave("p1");
|
||||
|
||||
// 편집기 등록 — 안 바뀌었으면 null(가게에 초안이 있어도 편집기가 정함) · 바뀌면 계약 꼴
|
||||
let changed = false;
|
||||
let kept = 0;
|
||||
let rebuilt = 0;
|
||||
apply.bindRouteApply({
|
||||
projectId: "p1",
|
||||
nodes: () => ({
|
||||
planned: [
|
||||
[0, 0],
|
||||
[5, 5],
|
||||
[10, 0],
|
||||
],
|
||||
curveOn: [true, false],
|
||||
curveRadius: [null, 25],
|
||||
}),
|
||||
changed: () => changed,
|
||||
terrain: () => "sheet",
|
||||
stationSnap: () => true,
|
||||
initial: { current: () => ({ mode: "follow" }), keep: () => (kept += 1) },
|
||||
profileShown: async () => true,
|
||||
onApplied: () => (rebuilt += 1),
|
||||
});
|
||||
out.unchanged = await apply.pendingRouteSave("p1");
|
||||
changed = true;
|
||||
const body = await apply.pendingRouteSave("p1");
|
||||
out.body = body;
|
||||
|
||||
// 저장 — 가게 초안 비움 · 결과 캐시 비움 · 추천 다시 적음
|
||||
writeState("design-stations", [{ k: 1 }], "p1");
|
||||
const saved = await apply.saveRouteDraft("p1", body);
|
||||
out.savedRouteId = saved.route_id;
|
||||
out.storeAfterSave = useDesignStore("p1", null).get("routeDraft");
|
||||
out.keptAfterSave = kept;
|
||||
out.summary = apply.routeSaveSummary(saved, 2);
|
||||
|
||||
// 저장 뒤 횡단 초안 넘김 차례 — 새 상세 → 측점 열쇠 → 넘김 → 넘긴 고침 저장
|
||||
calls.length = 0;
|
||||
out.outside = await apply.carryAfterRouteSave("p1", 7, 9);
|
||||
out.carryCalls = [...calls];
|
||||
|
||||
// 추천 [적용] — as_initial · 잠금 막 · 초안 비움 · 다시 세움
|
||||
useDesignStore("p1", null).set("routeDraft", draft);
|
||||
writeState("pipes", [{ chainage_m: 1 }], "p1");
|
||||
calls.length = 0;
|
||||
const snapshot = {
|
||||
planned: [
|
||||
[1, 1],
|
||||
[9, 9],
|
||||
],
|
||||
curveOn: [true, true],
|
||||
curveRadius: [null, null],
|
||||
};
|
||||
out.recommendOk = await apply.saveRecommendedRoute("p1", snapshot, { mode: "earthwork" }, true);
|
||||
out.recommendBody = bodies[bodies.length - 1];
|
||||
out.recommendCalls = calls.filter((c) => !c.startsWith("toast:"));
|
||||
out.recommendDraftsLeft = {
|
||||
route: useDesignStore("p1", null).get("routeDraft"),
|
||||
pipes: readState("pipes", "p1"),
|
||||
};
|
||||
out.rebuilt = rebuilt;
|
||||
|
||||
// 추천 저장 실패 — false · 오류 한 줄 · 다시 안 세움
|
||||
failReplan = true;
|
||||
calls.length = 0;
|
||||
out.recommendFail = await apply.saveRecommendedRoute("p1", snapshot, null, false);
|
||||
out.recommendFailCalls = [...calls];
|
||||
out.rebuiltAfterFail = rebuilt;
|
||||
console.log(JSON.stringify(out));
|
||||
})();
|
||||
@@ -30,7 +30,22 @@ const record = (name, fail) => async () => {
|
||||
if (fail) throw new Error(`${name} 실패`);
|
||||
};
|
||||
let failStructures = false;
|
||||
// 노선 저장(346-3) — 초안 · 실패를 시험이 정함
|
||||
let routeBody = null;
|
||||
let failRoute = false;
|
||||
const routeStub = {
|
||||
pendingRouteSave: async () => routeBody,
|
||||
saveRouteDraft: async () => {
|
||||
calls.push("route");
|
||||
if (failRoute) throw new Error("노선 저장 실패");
|
||||
return { route_id: 9, pipes: { kept: 3, crossing: 1, concave: 0 }, cross_dropped: 1 };
|
||||
},
|
||||
carryAfterRouteSave: async (_p, from, to) => (calls.push(`carry:${from}->${to}`), 2),
|
||||
routeSaveSummary: (saved, outside) => (calls.push(`summary:${saved.route_id}:${outside}`), ""),
|
||||
rebuildAfterRouteSave: async () => calls.push("rebuild"),
|
||||
};
|
||||
const STUBS = {
|
||||
"../../B05_Profile/B05_Profile_UI_RouteEdit_Apply": routeStub,
|
||||
"@ui/ui_template_elements": {
|
||||
showToast: (text, kind) => calls.push(`toast:${kind}`),
|
||||
showLoadingOverlay: () => calls.push("overlay:on"),
|
||||
@@ -161,6 +176,57 @@ async function run() {
|
||||
});
|
||||
out.noRouteCalls = [...calls];
|
||||
|
||||
// ⑥ 노선이 바뀜(346-3) — 노선 먼저 · 뒤 차례는 새 노선(9) · 화면 몫 건너뜀 · 횡단 초안 넘김 · 다시 세움
|
||||
b05.replace({ station_offsets: { "30.000": 0.2 }, curve_radii: {} }); // 옛 노선(7) 계획고 초안
|
||||
routeBody = {
|
||||
draft: {
|
||||
rev: 1,
|
||||
nodes: [
|
||||
[0, 0],
|
||||
[10, 0],
|
||||
],
|
||||
},
|
||||
};
|
||||
calls.length = 0;
|
||||
out.routeOk = await saveDesign({
|
||||
projectId: "p1",
|
||||
routeId: () => 7,
|
||||
prepare: record("prepare"),
|
||||
steps: { pipes: record("pipes:screen"), alignment: record("alignment:screen") },
|
||||
cross: async (confirm) => calls.push(`cross:${confirm}`),
|
||||
done: async (confirm) => calls.push(`done:${confirm}`),
|
||||
failed: () => calls.push("failed"),
|
||||
});
|
||||
out.routeCalls = [...calls];
|
||||
// ⑦ 노선 저장 실패 — 거기서 멈춤 · 다른 초안 그대로
|
||||
b05.replace({ station_offsets: { "50.000": 0.3 }, curve_radii: {} });
|
||||
failRoute = true;
|
||||
calls.length = 0;
|
||||
out.routeFailOk = await saveDesign({
|
||||
projectId: "p1",
|
||||
routeId: () => 7,
|
||||
cross: async (confirm) => calls.push(`cross:${confirm}`),
|
||||
done: async (confirm) => calls.push(`done:${confirm}`),
|
||||
failed: () => calls.push("failed"),
|
||||
});
|
||||
out.routeFailCalls = [...calls];
|
||||
out.routeFailDraft = edit.pendingAlignment(7)?.station_offsets ?? null;
|
||||
failRoute = false;
|
||||
// ⑧ [확정] 중 노선이 바뀜 — 노선 저장 뒤 다시 세움 · 확정 단계는 안 닫음(새 노선으로 다시)
|
||||
calls.length = 0;
|
||||
await saveDesign(
|
||||
{
|
||||
projectId: "p1",
|
||||
routeId: () => 7,
|
||||
cross: async (confirm) => calls.push(`cross:${confirm}`),
|
||||
done: async (confirm) => calls.push(`done:${confirm}`),
|
||||
failed: () => calls.push("failed"),
|
||||
},
|
||||
{ confirm: true },
|
||||
);
|
||||
out.routeConfirmCalls = [...calls];
|
||||
routeBody = null;
|
||||
|
||||
// ⑤ [초기화] — 초안 · 한 벌 모두 버림
|
||||
b05.replace({ station_offsets: { "80.000": 1 }, curve_radii: {} });
|
||||
edit.clearAlignmentDrafts();
|
||||
|
||||
@@ -291,6 +291,7 @@ def test_화면_확인이_고른_지형을_실음():
|
||||
page = ROOT / "B05_Profile"
|
||||
apply = (page / "B05_Profile_UI_RouteEdit_Apply.ts").read_text(encoding="utf-8")
|
||||
main = (page / "B05_Profile_UI_RouteEdit.ts").read_text(encoding="utf-8")
|
||||
assert "terrain: params.terrain()," in apply
|
||||
# 346-3 — 노선 초안(draft.terrain)에 실림 · [저장]이 보냄
|
||||
assert "terrain: params.terrain() })" in apply and "terrain: settings.terrain," in apply
|
||||
assert "pickedTerrain() !== designTerrain" in main # 지형만 바꿔도 [확인]이 다시 셈
|
||||
assert "analysisTerrain(projectId, designTerrain)" in main # 고른 값 없으면 설계 지형
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
"""346-3 화면 — [노선 반영] 없앰 · [저장]이 노선부터 · 추천 [적용] = as_initial 저장 · 저장 뒤 초안 넘김.
|
||||
|
||||
노선 이음(`B05_Profile_UI_RouteEdit_Apply`)은 Node 헬퍼 `helper_346_3_route_save.cjs` 가 서버 · 화면
|
||||
창구만 가짜로 두고 돌림 · 서버 길 시험은 `test_346_3_route_save.py` · 저장 차례(노선 먼저 · 안 바뀌면
|
||||
안 보냄 · 실패 때 초안 남음)는 `test_design_store_save.py`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
ROOT = HERE.parents[1]
|
||||
|
||||
|
||||
def _read(rel: str) -> str:
|
||||
return (ROOT / rel).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def out() -> dict:
|
||||
run = subprocess.run(
|
||||
["node", str(HERE / "helper_346_3_route_save.cjs")],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
check=True,
|
||||
)
|
||||
return json.loads(run.stdout)
|
||||
|
||||
|
||||
def test_노선_안_바뀜_안_보냄(out):
|
||||
assert out["noneAtAll"] is None
|
||||
assert out["unchanged"] is None # 편집기가 정함 — 가게에 초안이 남아 있어도
|
||||
assert out["storeOnly"]["draft"]["rev"] == 3 # 편집기 없으면 가게 routeDraft
|
||||
|
||||
|
||||
def test_초안은_계약_RouteDraft_꼴(out):
|
||||
draft = out["body"]["draft"]
|
||||
assert set(draft) == {
|
||||
"rev",
|
||||
"nodes",
|
||||
"curveOn",
|
||||
"curveRadius",
|
||||
"curveLock",
|
||||
"curveArc",
|
||||
"stationSnap",
|
||||
"terrain",
|
||||
}
|
||||
n = len(draft["nodes"])
|
||||
assert all(
|
||||
len(draft[name]) == n for name in ("curveOn", "curveRadius", "curveLock", "curveArc")
|
||||
)
|
||||
assert draft["curveOn"] == [True, False, True] and draft["curveRadius"] == [None, 25, None]
|
||||
assert draft["stationSnap"] is True and draft["terrain"] == "sheet"
|
||||
assert out["body"]["initial"] == {"mode": "follow"} and out["body"]["balanced_profile"] is True
|
||||
assert "as_initial" not in out["body"] # 손으로 고친 노선 = 초기값 그대로
|
||||
|
||||
|
||||
def test_저장_뒤_가게_초안_비움_결과_한_줄(out):
|
||||
assert out["savedRouteId"] == 9
|
||||
assert out["storeAfterSave"] is None
|
||||
assert out["keptAfterSave"] == 1
|
||||
assert out["summary"] == (
|
||||
"노선 저장 — 관 지킴 3 · 새 교차 관 1 · 오목 보충 관 2 · 구조물 옮김 1 · 멀어짐 0 · "
|
||||
"노선 밖 고침 3 건 · 배수유역 낡음"
|
||||
) # 서버 cross_dropped 1 + 화면 넘김 밖 2 = 한 줄
|
||||
|
||||
|
||||
def test_초안_넘김_차례(out):
|
||||
assert out["carryCalls"] == ["invalidate:9", "load:9", "keys:9:9", "carry:7->9", "crossSave:9"]
|
||||
assert out["outside"] == 2
|
||||
|
||||
|
||||
def test_추천_적용은_as_initial_저장_뒤_다시_세움(out):
|
||||
assert out["recommendOk"] is True
|
||||
body = out["recommendBody"]
|
||||
assert body["as_initial"] is True and body["initial"] == {"mode": "earthwork"}
|
||||
assert body["draft"]["nodes"] == [[1, 1], [9, 9]]
|
||||
assert out["recommendCalls"] == ["overlay:on", "replan", "overlay:off"] # 잠금 막 하나
|
||||
assert out["recommendDraftsLeft"] == {"route": None, "pipes": None} # 새 초기값에서 다시
|
||||
assert out["rebuilt"] == 1
|
||||
|
||||
|
||||
def test_추천_저장_실패는_한_줄_다시_안_세움(out):
|
||||
assert out["recommendFail"] is False
|
||||
errors = [c for c in out["recommendFailCalls"] if c.startswith("toast:error:")]
|
||||
assert len(errors) == 1 and "체인 실패" in errors[0]
|
||||
assert out["rebuiltAfterFail"] == 1
|
||||
|
||||
|
||||
def test_노선_반영_단추_없앰_배선():
|
||||
chrome = _read("B05_Profile/B05_Profile_UI_RouteEdit_Chrome.ts")
|
||||
assert 'data-act="apply"' not in chrome and "노선 반영</button>" not in chrome
|
||||
apply = _read("B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts")
|
||||
assert "addEventListener" not in apply # 단추 듣기 없음 — [저장]이 부름
|
||||
save = _read("A00_Common/design/design_save.ts")
|
||||
assert save.index('"route",') < save.index('"pipes",')
|
||||
assert "await pendingRouteSave(ctx.projectId)" in save
|
||||
assert "carryAfterRouteSave(ctx.projectId, fromRouteId, routeId)" in save
|
||||
initial = _read("B05_Profile/B05_Profile_UI_RouteEdit_Initial.ts")
|
||||
at = initial.index("onApply: (picked) => {")
|
||||
assert "saveRecommendedRoute(" in initial[at : at + 900]
|
||||
replan = _read("B05_Profile/B05_Profile_Api_Replan.ts")
|
||||
assert "body: JSON.stringify(body)" in replan and "as_initial?: boolean;" in replan
|
||||
@@ -33,10 +33,12 @@ def test_겉틀은_본문_칸():
|
||||
assert 'overlay.className = "b05-routeedit";' in chrome
|
||||
assert "b05-routeedit__close" not in chrome and 'data-slot="close"' not in chrome
|
||||
assert '"tools"' in chrome and "replaceWith(...tools)" in chrome
|
||||
assert ">반영 전으로</button>" in chrome and ">노선 반영</button>" in chrome
|
||||
# 346-3 — [노선 반영] 없앰(노선은 페이지 [저장]이 맨 앞에서 보냄) · [취소] = [저장 전으로]
|
||||
assert ">저장 전으로</button>" in chrome and 'data-act="apply"' not in chrome
|
||||
assert "노선 반영</button>" not in chrome
|
||||
assert ">취소</button>" not in chrome and ">확인</button>" not in chrome
|
||||
# 시험 · 배선이 집는 자리는 남김
|
||||
for hook in ('data-act="apply"', 'data-act="cancel"', "b05-routeedit__measure-close"):
|
||||
for hook in ('data-act="cancel"', "b05-routeedit__measure-close"):
|
||||
assert hook in chrome
|
||||
assert 'data-act="side-toggle"' in chrome and "is-collapsed" in chrome
|
||||
|
||||
|
||||
@@ -114,9 +114,9 @@ def test_초기화_계획노선_편집은_다시_세움():
|
||||
assert step in rebuild
|
||||
assert rebuild.index("invalidateSectionDetail") < rebuild.index("remountRoute(")
|
||||
assert "mountRouteEditor(mainContent, host, activeProjectId, rebuildAfterReplan," in view
|
||||
# 346-3 — [저장]이 노선을 보낸 뒤 결과 캐시를 비우고 편집기가 건 다시 세우기(rebuildAfterReplan)
|
||||
apply = _read("B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts")
|
||||
assert apply.index("clearDrafts(projectId);") < apply.index("await params.onApplied();")
|
||||
assert "clearResults(projectId);" in apply
|
||||
assert "clearResults(projectId);" in apply and "rebuild: params.onApplied," in apply
|
||||
|
||||
|
||||
def test_종단_보기_확정은_횡단_보기를_숨긴_채_세움():
|
||||
|
||||
@@ -48,7 +48,15 @@ def test_계획고_가게_한_벌(out):
|
||||
|
||||
|
||||
def test_저장_차례(out):
|
||||
assert out["order"] == ["pipes", "structures", "alignment", "culvertOptions", "uphill", "cross"]
|
||||
assert out["order"] == [
|
||||
"route",
|
||||
"pipes",
|
||||
"structures",
|
||||
"alignment",
|
||||
"culvertOptions",
|
||||
"uphill",
|
||||
"cross",
|
||||
] # 346-3 노선 먼저
|
||||
assert out["saveOk"] is True
|
||||
assert out["saveCalls"] == [
|
||||
"overlay:on",
|
||||
@@ -78,3 +86,43 @@ def test_구조물_실패는_알리고_넘어감_확정_노선없음(out):
|
||||
|
||||
def test_초기화는_초안과_한_벌을_버림(out):
|
||||
assert out["cleared"] == {"draft": None, "pending": None}
|
||||
|
||||
|
||||
def test_노선이_바뀌면_노선_먼저_뒤_차례는_새_노선(out):
|
||||
"""346-3 — 노선 초안이 있으면 맨 앞 · 관 · 구조물 기본 창구 · 계획고 초안(옛 노선 7 칸)을 새 노선 9 로 ·
|
||||
화면 몫 일(옛 노선 판)은 건너뜀 · 횡단 초안 넘김(측점 열쇠) · 결과 한 줄 · 다시 세움."""
|
||||
assert out["routeOk"] is True
|
||||
assert out["routeCalls"] == [
|
||||
"overlay:on",
|
||||
"prepare",
|
||||
"route",
|
||||
"pipes",
|
||||
"structures",
|
||||
'alignment:9:{"30.000":0.2}',
|
||||
"culvert:aislo:draft:culvertopt:p1:7",
|
||||
"uphill",
|
||||
"carry:7->9",
|
||||
"summary:9:2",
|
||||
"toast:info",
|
||||
"done:false",
|
||||
"rebuild",
|
||||
"overlay:off",
|
||||
]
|
||||
assert "pipes:screen" not in out["routeCalls"] and "alignment:screen" not in out["routeCalls"]
|
||||
assert "cross:false" not in out["routeCalls"] # 옛 노선 횡단 본문 대신 넘김
|
||||
|
||||
|
||||
def test_노선이_그대로면_안_보냄(out):
|
||||
assert "route" not in out["saveCalls"]
|
||||
|
||||
|
||||
def test_노선_저장_실패는_멈추고_초안_남음(out):
|
||||
assert out["routeFailOk"] is False
|
||||
assert out["routeFailCalls"] == ["overlay:on", "route", "failed", "overlay:off"]
|
||||
assert out["routeFailDraft"] == {"50.000": 0.3} # 계획고 초안 그대로
|
||||
|
||||
|
||||
def test_확정_중_노선이_바뀌면_다시_세우고_확정은_다시(out):
|
||||
calls = out["routeConfirmCalls"]
|
||||
assert calls[1] == "route" and calls[-2:] == ["rebuild", "overlay:off"]
|
||||
assert "done:true" not in calls and "cross:true" not in calls
|
||||
|
||||
Reference in New Issue
Block a user