feat(구조물표): 323-5 고름 한 칸 — 관 세션 id(옮겨도 그대로 · 저장 안 함) · 고름 강조 한 규칙(pickLights · 카드 형상 · 3D 같은 함수) · 그린 것마다 신원표(data-structure-id + data-part) · 같은 자리 거리 = PIPE_MATCH_M 하나 · 322-0 이 깬 옛 시험 도움 파일 · 줄 수 고침
- `design_pipe_ids.ts` — 장부(세션 pipe-ids) · pipe-s{차례} · 자리 → id(찾는 거리 안 가장 가까운 것) · followMovedPipe 가 id 를 새 자리로(고름 id 그대로 · 순환 import 없게 design_selection 에서 옮김) · 설계 페이지가 프로젝트를 정함(usePipeIds) · 자리 이름 만들기 열 곳 · 되읽기 둘 걷음 · 측점 계획 주인 = 세션 id(withPipeIds)
- `design_pick_match.ts` — pickLights(① id ② 같은 자리 ③ 고른 부분) · paintPicked(카드 통째 형상 · 부분 · 관 계열 · 포장층은 제 손잡이) · tagShape — 관 세트 벽 · 집수정 · 관 · 세월교 측벽 · 몸체 · BOX 끝 · C군 벽 · 물넘이 콘크리트에 신원표 · 형상 판정면은 통째 형상 · 콘크리트만
- 3D — 부재 맞춤 = pickLights(옛 0.01 걷음) · C군 벽 솔리드 = 구조물 id(덮는 측점 어디서 골라도 한 번 스윕한 벽이 켜짐)
- 322-0 이 깬 것 고침 — 노면공 흐름 도움 파일(165 · 231-1) 정의 판 확인 흉내 · design_view_profile 700줄(322-0 이 704)
- 시험: test_323_5_pick(세션 id · 옮김 · 강조 규칙 · 칠하기) · 옛 시험 도움 파일 흉내 · 기대 글 고침
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
This commit is contained in:
@@ -133,6 +133,8 @@ const panelModule = loadTs(
|
||||
})),
|
||||
structureAnchorM: (s) => s.chainage_m ?? s.start_m ?? 0,
|
||||
writePendingStructures() {},
|
||||
dropStaleStructureTypes: async () => {}, // 정의 판 확인(322-0)
|
||||
staleDefinitionNotice: () => null, // 판 알림(322-2)
|
||||
},
|
||||
"../B05_Profile/B05_Profile_Api_Pipes_Draft": {
|
||||
readPendingPipes: () => null,
|
||||
@@ -165,6 +167,15 @@ const panelModule = loadTs(
|
||||
setAdjustSideSlots() {},
|
||||
},
|
||||
"./B06_Section_UI_Page_Structures_Spec": { withSpecDefaults: (o) => o ?? {} },
|
||||
// 옛 소수 관 맞춤(322-3 고침) · 관 세션 id(323-5) — 프로젝트 없음 = 옛 자리 이름
|
||||
"../B05_Profile/B05_Profile_UI_Structures_Snap": {
|
||||
snapNotice() {},
|
||||
snapPlan: () => ({ structures: [], pipes: [], skipped: 0 }),
|
||||
},
|
||||
"../A00_Common/design/design_pipe_ids": {
|
||||
pipeIdAt: (at) => `pipe-${at.toFixed(2)}`,
|
||||
followMovedPipe() {},
|
||||
},
|
||||
// 요구 178 — 알약 측점 짝(진짜 `plantsStation` · 272 측점 심기 한 벌)
|
||||
"../B05_Profile/B05_Profile_UI_Profile_Structures": loadTs(
|
||||
path.join(ROOT, "B05_Profile", "B05_Profile_UI_Profile_Structures.ts"),
|
||||
|
||||
@@ -152,6 +152,8 @@ const panelModule = loadTs(
|
||||
})),
|
||||
structureAnchorM: (s) => s.chainage_m ?? s.start_m ?? 0,
|
||||
writePendingStructures() {},
|
||||
dropStaleStructureTypes: async () => {}, // 정의 판 확인(322-0)
|
||||
staleDefinitionNotice: () => null, // 판 알림(322-2)
|
||||
},
|
||||
"../B05_Profile/B05_Profile_Api_Pipes_Draft": {
|
||||
readPendingPipes: () => null,
|
||||
@@ -184,6 +186,15 @@ const panelModule = loadTs(
|
||||
setAdjustSideSlots() {},
|
||||
},
|
||||
"./B06_Section_UI_Page_Structures_Spec": { withSpecDefaults: (o) => o ?? {} },
|
||||
// 옛 소수 관 맞춤(322-3 고침) · 관 세션 id(323-5) — 프로젝트 없음 = 옛 자리 이름
|
||||
"../B05_Profile/B05_Profile_UI_Structures_Snap": {
|
||||
snapNotice() {},
|
||||
snapPlan: () => ({ structures: [], pipes: [], skipped: 0 }),
|
||||
},
|
||||
"../A00_Common/design/design_pipe_ids": {
|
||||
pipeIdAt: (at) => `pipe-${at.toFixed(2)}`,
|
||||
followMovedPipe() {},
|
||||
},
|
||||
// 요구 178 — 알약 측점 짝(진짜 `plantsStation` · 272 측점 심기 한 벌)
|
||||
"../B05_Profile/B05_Profile_UI_Profile_Structures": loadTs(
|
||||
path.join(ROOT, "B05_Profile", "B05_Profile_UI_Profile_Structures.ts"),
|
||||
|
||||
@@ -73,7 +73,12 @@ const MK3 = loadTs("B05_Profile/B05_Profile_UI_Markers.ts", {
|
||||
const MI = loadTs("B05_Profile/B05_Profile_UI_Viewer_Marker_Input.ts", {
|
||||
"./B05_Profile_UI_Markers": MK3,
|
||||
});
|
||||
const SPK = loadTs("B05_Profile/B05_Profile_UI_Viewer_Structure_Pick.ts");
|
||||
// 고름 강조 한 규칙(323-5) — 진짜 `design_pick_match`(같은 자리 = 고름 모듈 거리)
|
||||
const PM = loadTs("A00_Common/design/design_pick_match.ts", { "./design_selection": DSel });
|
||||
const SPK = loadTs("B05_Profile/B05_Profile_UI_Viewer_Structure_Pick.ts", {
|
||||
"../A00_Common/design/design_pick_match": PM,
|
||||
"../A00_Common/design/design_selection": DSel,
|
||||
});
|
||||
const SY = loadTs("B05_Profile/B05_Profile_UI_Selection.ts", {
|
||||
"../A00_Common/design/design_selection": DSel,
|
||||
"./B05_Profile_UI_IrregularStations": {
|
||||
|
||||
@@ -39,6 +39,7 @@ const SY = loadTs("B05_Profile/B05_Profile_UI_Selection.ts", {
|
||||
});
|
||||
const PP = loadTs("A00_Common/design/design_pick_profile.ts", {
|
||||
"./design_selection": DSel,
|
||||
"./design_pipe_ids": { pipeIdAt: (at) => `pipe-${at.toFixed(2)}` }, // 프로젝트 없음 = 옛 자리 이름(323-5)
|
||||
"./design_pick_escape": ESC,
|
||||
"../../B05_Profile/B05_Profile_UI_Selection": SY,
|
||||
"../../B05_Profile/B05_Profile_UI_IrregularStations": IRR,
|
||||
|
||||
@@ -78,6 +78,7 @@ const SY = loadTs("B05_Profile/B05_Profile_UI_Selection.ts", {
|
||||
});
|
||||
const PP = loadTs("A00_Common/design/design_pick_profile.ts", {
|
||||
"./design_selection": DSel,
|
||||
"./design_pipe_ids": { pipeIdAt: (at) => `pipe-${at.toFixed(2)}` }, // 프로젝트 없음 = 옛 자리 이름(323-5)
|
||||
"./design_pick_escape": ESC,
|
||||
"../../B05_Profile/B05_Profile_UI_Selection": SY,
|
||||
"../../B05_Profile/B05_Profile_UI_IrregularStations": IRR,
|
||||
@@ -85,7 +86,12 @@ const PP = loadTs("A00_Common/design/design_pick_profile.ts", {
|
||||
const MK3 = loadTs("B05_Profile/B05_Profile_UI_Markers.ts", {
|
||||
"@util/common_util_svg": { inferStationInterval: () => 20, stationLabel: (c) => `0+${c}` },
|
||||
});
|
||||
const SPK = loadTs("B05_Profile/B05_Profile_UI_Viewer_Structure_Pick.ts");
|
||||
// 고름 강조 한 규칙(323-5) — 진짜 `design_pick_match`
|
||||
const PM = loadTs("A00_Common/design/design_pick_match.ts", { "./design_selection": DSel });
|
||||
const SPK = loadTs("B05_Profile/B05_Profile_UI_Viewer_Structure_Pick.ts", {
|
||||
"../A00_Common/design/design_pick_match": PM,
|
||||
"../A00_Common/design/design_selection": DSel,
|
||||
});
|
||||
const SYNC = loadTs("B06_Section/B06_Section_UI_Page_Pick_Sync.ts", {
|
||||
"../A00_Common/design/design_selection": DSel,
|
||||
"../A00_Common/design/design_pick_escape": ESC,
|
||||
|
||||
@@ -55,6 +55,7 @@ const SY = loadTs("B05_Profile/B05_Profile_UI_Selection.ts", {
|
||||
});
|
||||
const PP = loadTs("A00_Common/design/design_pick_profile.ts", {
|
||||
"./design_selection": DSel,
|
||||
"./design_pipe_ids": { pipeIdAt: (at) => `pipe-${at.toFixed(2)}` }, // 프로젝트 없음 = 옛 자리 이름(323-5)
|
||||
"./design_pick_escape": ESC,
|
||||
"../../B05_Profile/B05_Profile_UI_Selection": SY,
|
||||
"../../B05_Profile/B05_Profile_UI_IrregularStations": IRR,
|
||||
|
||||
@@ -42,6 +42,7 @@ const SY = loadTs("B05_Profile/B05_Profile_UI_Selection.ts", {
|
||||
});
|
||||
const PP = loadTs("A00_Common/design/design_pick_profile.ts", {
|
||||
"./design_selection": DSel,
|
||||
"./design_pipe_ids": { pipeIdAt: (at) => `pipe-${at.toFixed(2)}` }, // 프로젝트 없음 = 옛 자리 이름(323-5)
|
||||
"./design_pick_escape": ESC,
|
||||
"../../B05_Profile/B05_Profile_UI_Selection": SY,
|
||||
"../../B05_Profile/B05_Profile_UI_IrregularStations": IRR,
|
||||
|
||||
@@ -31,6 +31,14 @@ const ford = loadTs(path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Ford_Pa
|
||||
{ "./B06_Section_UI_Cross_Culvert_Const": {} },
|
||||
),
|
||||
"./B06_Section_UI_Cross_Design_Surface": { appendPavementOverlay() {} },
|
||||
// 관 세션 id · 신원표(323-5) — 프로젝트 없음 = 옛 자리 이름
|
||||
"../A00_Common/design/design_pipe_ids": { pipeIdAt: (at) => `pipe-${at.toFixed(2)}` },
|
||||
"../A00_Common/design/design_pick_match": {
|
||||
tagShape: (el, id, part) => {
|
||||
if (id) el.setAttribute("data-structure-id", id);
|
||||
if (part) el.setAttribute("data-part", part);
|
||||
},
|
||||
},
|
||||
});
|
||||
// 286-3 도수로 · 돌붙임 길이 — 유출(좌 · 우가 높음) 성토사면 1:1.5(5 m 내려감 · 사면 길이 √(7.5²+5²) ≈ 9.01)
|
||||
const sets = loadTs(path.join(ROOT, "common_util", "common_util_culvert_sets.ts"));
|
||||
|
||||
@@ -183,13 +183,14 @@ async function run(setup, detail) {
|
||||
out.remove = await run({ savedStructures: [wall("retaining_wall")], draftStructures: [] }, kept);
|
||||
// 저장 뒤 다시 열기 — 초안 없음 = 서버 목록 그대로(빼 둔 옛 자리 돌아옴)
|
||||
out.reopen = await run({ savedStructures: [wall("retaining_wall")] }, kept);
|
||||
// 관을 옮겨도 고름 유지(322-3) — 고른 관이면 새 자리 · 다른 구조물 고름은 그대로
|
||||
// 관을 옮겨도 고름 유지(322-3) — 고른 관이면 새 자리 · id = 관 세션 id 그대로(323-5) · 다른 고름은 그대로
|
||||
const sel = load(file("A00_Common", "design", "design_selection.ts"));
|
||||
sel.selectDesign("P", { chainageM: 61, structureId: "pipe-61.00" });
|
||||
sel.followMovedPipe("P", 61, 75);
|
||||
const pipeIds = load(file("A00_Common", "design", "design_pipe_ids.ts"));
|
||||
sel.selectDesign("P", { chainageM: 61, structureId: pipeIds.pipeIdAt(61, "P") });
|
||||
pipeIds.followMovedPipe("P", 61, 75);
|
||||
const moved = sel.readSelection("P");
|
||||
sel.selectDesign("P", { chainageM: 101, structureId: "w1" });
|
||||
sel.followMovedPipe("P", 101, 120);
|
||||
pipeIds.followMovedPipe("P", 101, 120);
|
||||
out.follow = [moved, sel.readSelection("P")];
|
||||
// 옛 소수 관(검증_sub1 견본) — B06 을 바로 열어도 B05 와 같은 정수 m 초안(`snapPlan` · 요구 167)
|
||||
const snap = load(file("B05_Profile", "B05_Profile_UI_Structures_Snap.ts"));
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/* PLAN 323-5 고름 한 칸 헬퍼 — 진짜 `design_pipe_ids.ts`(관 세션 id) · `design_selection.ts`(고름 · 관 옮김 따라가기) ·
|
||||
* `design_pick_match.ts`(고름 강조 한 규칙)를 그 자리에서 트랜스파일해 Node 로 돌림(세션만 흉내) · 결과 = 표준출력 JSON.
|
||||
* 짝 = `test_323_5_pick.py`.
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
const ts = require(path.join(ROOT, "config", "node_modules", "typescript"));
|
||||
|
||||
const memory = new Map();
|
||||
const store = {
|
||||
getItem: (k) => (memory.has(k) ? memory.get(k) : null),
|
||||
setItem: (k, v) => memory.set(k, String(v)),
|
||||
removeItem: (k) => memory.delete(k),
|
||||
key: (i) => [...memory.keys()][i] ?? null,
|
||||
get length() {
|
||||
return memory.size;
|
||||
},
|
||||
};
|
||||
globalThis.window = { sessionStorage: store, localStorage: store, addEventListener: () => {} };
|
||||
globalThis.sessionStorage = store;
|
||||
globalThis.localStorage = store;
|
||||
|
||||
const cache = new Map();
|
||||
function load(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 need = (spec) => load(path.join(path.dirname(full), `${spec}.ts`));
|
||||
new Function("exports", "module", "require", js)(box.exports, box, need);
|
||||
return box.exports;
|
||||
}
|
||||
const D = (name) => path.join(ROOT, "A00_Common", "design", `${name}.ts`);
|
||||
const ids = load(D("design_pipe_ids"));
|
||||
const sel = load(D("design_selection"));
|
||||
const match = load(D("design_pick_match"));
|
||||
|
||||
const out = {};
|
||||
// ① 관 세션 id — 자리마다 차례 · 같은 자리(0.51 안)면 같은 id · 프로젝트 없으면 옛 자리 이름
|
||||
ids.usePipeIds("P");
|
||||
const a = ids.pipeIdAt(85.05);
|
||||
out.ids = [a, ids.pipeIdAt(85), ids.pipeIdAt(173), ids.pipeChainageOf(a)];
|
||||
ids.usePipeIds(null);
|
||||
out.legacy = [ids.pipeIdAt(85), ids.pipeChainageOf("pipe-85.00"), ids.pipeChainageOf("w1")];
|
||||
ids.usePipeIds("P");
|
||||
// ② 옮겨도 id 그대로 — 고름도 자리만 새로(부재키 그대로) · 새 자리 id = 그 id
|
||||
sel.selectDesign("P", { chainageM: 85.05, structureId: a }, { partKey: "inlet" });
|
||||
ids.followMovedPipe("P", 85.05, 90);
|
||||
out.moved = [sel.readSelection("P"), ids.pipeIdAt(90), ids.pipeChainageOf(a)];
|
||||
// 다른 것을 골랐으면 고름 그대로 · 관 id 는 따라감
|
||||
const b = ids.pipeIdAt(173);
|
||||
sel.selectDesign("P", { chainageM: 300, structureId: "w1" });
|
||||
ids.followMovedPipe("P", 173, 180);
|
||||
out.other = [sel.readSelection("P"), ids.pipeIdAt(180) === b];
|
||||
// ③ 강조 한 규칙
|
||||
const L = match.pickLights;
|
||||
out.lights = {
|
||||
idOverPlace: L({ chainageM: 93, structureId: "w1" }, { chainageM: 101, structureId: "w1" }),
|
||||
idDiffers: L({ chainageM: 101, structureId: "w2" }, { chainageM: 101, structureId: "w1" }),
|
||||
placeNear: L({ chainageM: 85, structureId: null }, { chainageM: 85.4 }),
|
||||
placeFar: L({ chainageM: 85, structureId: null }, { chainageM: 85.6 }),
|
||||
partOnly: L({ chainageM: 85, partKey: "inlet" }, { chainageM: 85, part: "outlet" }),
|
||||
partSame: L({ chainageM: 85, partKey: "inlet" }, { chainageM: 85, part: "inlet" }),
|
||||
partNoTag: L({ chainageM: 85, partKey: "inlet" }, { chainageM: 85 }),
|
||||
wholePick: L({ chainageM: 85 }, { chainageM: 85, part: "outlet" }),
|
||||
none: L(null, { chainageM: 85 }),
|
||||
};
|
||||
// ④ 카드 통째 형상 칠하기 — 부분 · 관 계열 · 포장층은 제 손잡이 몫
|
||||
class Shape {
|
||||
constructor(attrs) {
|
||||
this.attrs = attrs;
|
||||
this.on = false;
|
||||
this.classList = { toggle: (_c, v) => (this.on = v) };
|
||||
}
|
||||
getAttribute(k) {
|
||||
return this.attrs[k] ?? null;
|
||||
}
|
||||
}
|
||||
const shapes = [
|
||||
new Shape({ "data-structure-id": "ud-1" }),
|
||||
new Shape({ "data-structure-id": "w1", "data-part": "own" }),
|
||||
new Shape({ "data-structure-id": a, "data-part": "concrete" }),
|
||||
new Shape({ "data-structure-id": "pave-1", "data-pave-type": "pavement_concrete" }),
|
||||
];
|
||||
const root = { querySelectorAll: () => shapes };
|
||||
match.paintPicked(root, { structureId: "ud-1" });
|
||||
const lit1 = shapes.map((s) => s.on);
|
||||
match.paintPicked(root, { structureId: "w1" });
|
||||
out.paint = [lit1, shapes.map((s) => s.on)];
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
@@ -116,7 +116,9 @@ def test_배선():
|
||||
assert "openId" not in panel # 범위 안 빈 카드 = 연 노면공 지킴(165-1) 없앰 · 189-1
|
||||
# 관 알약은 폼 뒤(폼이 연 구조물을 닫으며 알약을 끔)
|
||||
at = panel.index("section.selectPipeByChainage(hit.pipeChainageM);")
|
||||
assert at < panel.index("deps.markStructure?.(`pipe-${hit.pipeChainageM.toFixed(2)}`);", at)
|
||||
assert at < panel.index(
|
||||
"deps.markStructure?.(pipeIdAt(hit.pipeChainageM, deps.projectId));", at
|
||||
)
|
||||
view = _read("B06_Section", "B06_Section_UI_Section_View.ts")
|
||||
assert "spanMarkId = span || isPavement(structureId) ? structureId : null;" in view
|
||||
assert "held" not in view # 범위 카드 재누름 = 그대로(167-3) 없앰 · 189-1
|
||||
|
||||
@@ -60,13 +60,20 @@ def test_물넘이포장_측점길은_콘크리트_안켬(out):
|
||||
view = _read("B06_Section", "B06_Section_UI_Section_View.ts")
|
||||
assert "highlightShapes(card, pickedMarkId);" in view
|
||||
shape = _read("B06_Section", "B06_Section_UI_Cross_Shape_Pick.ts")
|
||||
assert 'if (id.startsWith("pipe-")) continue;' in shape
|
||||
assert "paintPicked(root, { structureId })" in shape # 고름 강조 한 규칙(323-5)
|
||||
paint = _read("A00_Common", "design", "design_pick_match.ts")
|
||||
assert (
|
||||
'if (id.startsWith("pipe-") || shape.getAttribute("data-part") !== null) continue;' in paint
|
||||
)
|
||||
# 네 길이 모이는 자리 — 카드 고름 리스너 · 목록 관 줄 · 폼 관 열기 · 측점 없는 관
|
||||
cross = _read("A00_Common", "design", "design_view_cross.ts")
|
||||
assert "sectionView.selectMark(mark, false);" in cross
|
||||
panel = _read("B06_Section", "B06_Section_UI_Page_Structures_Panel.ts")
|
||||
assert "deps.markStructure?.(`pipe-${hit.pipeChainageM.toFixed(2)}`);" in panel # 카드 → 폼
|
||||
assert "deps.markStructure?.(chainageM === null ? null : `pipe-${" in panel # 목록 관 줄
|
||||
# 알약 id = 관 세션 id(323-5)
|
||||
assert (
|
||||
"deps.markStructure?.(pipeIdAt(hit.pipeChainageM, deps.projectId));" in panel
|
||||
) # 카드 → 폼
|
||||
assert "deps.markStructure?.(chainageM === null ? null : pipeIdAt(" in panel # 목록 관 줄
|
||||
# 측점 길은 「관」 벽 고름을 안 엶 — 카드만 고르면 벽 고름을 비움(그대로)
|
||||
assert "stationControls.revetOffset.select(target.chainage_m, null);" in cross
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ def test_cross_owner_switch_drops_pipe_drawing(flows: dict) -> None:
|
||||
|
||||
def test_pick_follows_moved_pipe(flows: dict) -> None:
|
||||
moved, other = flows["follow"]
|
||||
assert (moved["chainageM"], moved["structureId"]) == (75, "pipe-75.00")
|
||||
assert (moved["chainageM"], moved["structureId"]) == (75, "pipe-s1") # 세션 id 그대로(323-5)
|
||||
assert (other["chainageM"], other["structureId"]) == (101, "w1") # 구조물 고름은 그대로
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
"""PLAN 323-5 고름 한 칸 — 관 세션 id(옮겨도 그대로 · 저장 안 함) · 고름 강조 한 규칙(`pickLights`).
|
||||
|
||||
- 관 id = 자리마다 차례(`pipe-s1` …) · 같은 자리(PIPE_MATCH_M 안)면 같은 id · 프로젝트 없으면 옛 자리 이름.
|
||||
- 관을 옮기면 id 가 새 자리로 · 그 관을 고른 고름은 자리만 새로(부재키 그대로) · 다른 고름은 그대로.
|
||||
- 강조 = id 둘 다 있으면 id · 아니면 같은 자리 · 고른 부분이 있으면 그 부분만 — 카드 형상 · 3D 같은 함수.
|
||||
- 카드 통째 형상 칠하기는 부분(조정창 부재) · 관 계열 · 포장층을 안 건드림(307).
|
||||
TS 쪽 = `helper_323_5_pick.cjs`(Node).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
ROOT = HERE.parent.parent
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not (ROOT / "config" / "node_modules").is_dir(), reason="프론트엔드 의존성 미설치"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def out() -> dict:
|
||||
run = subprocess.run(
|
||||
["node", str(HERE / "helper_323_5_pick.cjs")],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
timeout=120,
|
||||
check=True,
|
||||
)
|
||||
return json.loads(run.stdout)
|
||||
|
||||
|
||||
def test_session_ids(out: dict) -> None:
|
||||
assert out["ids"] == ["pipe-s1", "pipe-s1", "pipe-s2", 85.05]
|
||||
assert out["legacy"] == ["pipe-85.00", 85, None]
|
||||
|
||||
|
||||
def test_move_keeps_id_and_pick(out: dict) -> None:
|
||||
picked, at90, moved_to = out["moved"]
|
||||
assert picked == {"chainageM": 90, "structureId": "pipe-s1", "partKey": "inlet"}
|
||||
assert (at90, moved_to) == ("pipe-s1", 90)
|
||||
other, same = out["other"]
|
||||
assert other["structureId"] == "w1" and other["chainageM"] == 300 and same is True
|
||||
|
||||
|
||||
def test_one_highlight_rule(out: dict) -> None:
|
||||
assert out["lights"] == {
|
||||
"idOverPlace": True,
|
||||
"idDiffers": False,
|
||||
"placeNear": True,
|
||||
"placeFar": False,
|
||||
"partOnly": False,
|
||||
"partSame": True,
|
||||
"partNoTag": False,
|
||||
"wholePick": True,
|
||||
"none": False,
|
||||
}
|
||||
|
||||
|
||||
def test_card_paint_whole_shapes_only(out: dict) -> None:
|
||||
assert out["paint"] == [[True, False, False, False], [False, False, False, False]]
|
||||
Reference in New Issue
Block a user