/* setLink 순수 길(`spreadsheet_link_set.ts`) 시험 진입 — vite --ssr 로 번들해 Node 로 돌림. * 결과 = JSON {pass, fail, failures} 한 줄(`test_spreadsheet_set_link.py` 가 읽음) */ import { applyCommand } from "../../../A00_Common/spreadsheet/spreadsheet_commands"; import { linkHues } from "../../../A00_Common/spreadsheet/spreadsheet_link_color"; import { linkAreaCell, linkCommand } from "../../../A00_Common/spreadsheet/spreadsheet_link_set"; import type { Command, Workbook } from "../../../A00_Common/spreadsheet/spreadsheet_types"; let pass = 0; const failures: string[] = []; const eq = (name: string, got: unknown, want: unknown): void => { if (JSON.stringify(got) === JSON.stringify(want)) pass += 1; else failures.push(`${name}: ${JSON.stringify(got)} ≠ ${JSON.stringify(want)}`); }; const book = (): Workbook => ({ 종류: "통합문서", 판: 1, 열: "t", 서식: [{}], 시트: [ { id: "s1", 이름: "면적산출", 칸: { B1: { 값: 12.5 } }, 연결: [{ 키: "깔기|㎡", 이름: "깔기", 단위: "㎡", 칸: "B6" }], }, { id: "s2", 이름: "둘", 칸: {}, 연결: [{ 키: "치기|㎥", 이름: "치기", 칸: "C3" }] }, ], 활성: "s1", }) as unknown as Workbook; const links = (b: Workbook) => b.시트.map((s) => s.연결 ?? null); const run = (b: Workbook, c: Command | null | false) => { if (!c) return null; return applyCommand(b, c).undo; }; // 새 키를 칸에 — 이름 · 단위 · 자재가 같이 들어감 · 소문자 · 빈칸 주소도 받음 let b = book(); const mt = { 코드: "MT000008", 이름: "치즐", 규격: "", 단위: "EA" }; let undo = run( b, linkCommand(b, "s1", "자재|MT000008", " d2 ", { 이름: "치즐", 단위: "EA", 자재: mt }), ); eq("새 연결", b.시트[0].연결?.[1], { 키: "자재|MT000008", 칸: "D2", 이름: "치즐", 단위: "EA", 자재: mt, }); // 되돌리기 = 처음 그대로 run(b, undo); eq("되돌림", links(b), links(book())); // 있는 키를 다른 칸으로 — 옛 칸 빠지고 이름 · 단위는 있던 것 b = book(); run(b, linkCommand(b, "s1", "깔기|㎡", "B1")); eq("옮김", b.시트[0].연결, [{ 키: "깔기|㎡", 칸: "B1", 이름: "깔기", 단위: "㎡" }]); // 같은 칸에 다른 키 — 그 칸 옛 키 빠짐(칸 하나 = 키 하나) b = book(); run(b, linkCommand(b, "s1", "새|m", "B6", { 이름: "새", 단위: "m" })); eq("칸 하나 키 하나", b.시트[0].연결, [{ 키: "새|m", 칸: "B6", 이름: "새", 단위: "m" }]); // 다른 시트에 있던 키를 이 시트로 — 저쪽 연결 빠짐(연결 칸 없으면 `연결` 지움) · 되돌리기 한 번에 둘 다 b = book(); undo = run(b, linkCommand(b, "s1", "치기|㎥", "A1")); eq("시트 넘어 옮김", links(b), [ [ { 키: "깔기|㎡", 이름: "깔기", 단위: "㎡", 칸: "B6" }, { 키: "치기|㎥", 칸: "A1", 이름: "치기" }, ], null, ]); run(b, undo); eq("시트 넘어 되돌림", links(b), links(book())); // 풀기 — 그 키만 빠지고 마지막이면 `연결` 칸이 없어짐 b = book(); run(b, linkCommand(b, "s1", "깔기|㎡", null)); eq("풀기", links(b), [null, [{ 키: "치기|㎥", 이름: "치기", 칸: "C3" }]]); // 바뀔 것 없음 = null · 틀린 주소 = false · 없는 시트 = false b = book(); eq("이미 그 칸", linkCommand(b, "s1", "깔기|㎡", "b6"), null); eq("없는 키 풀기", linkCommand(b, "s1", "없음", null), null); eq("틀린 주소", linkCommand(b, "s1", "깔기|㎡", "가1"), false); eq("빈 주소", linkCommand(b, "s1", "깔기|㎡", ""), false); eq("없는 시트", linkCommand(b, "s9", "깔기|㎡", "A1"), false); eq("문서 그대로", links(b), links(book())); // linkAreaCell — 새 문서(받은 문서 그대로) · 활성 시트 · 번호 칸 그대로 · 틀린 주소 null · 풀기 b = { ...book(), 면적번: "SA-000001" } as Workbook & { 면적번: string }; const before = JSON.stringify(b); const got = linkAreaCell(b, "철근|ton", "c9", { 이름: "철근", 단위: "ton" }); eq("받은 문서 그대로", JSON.stringify(b), before); eq("새 문서 연결", got?.시트[0].연결?.[1], { 키: "철근|ton", 칸: "C9", 이름: "철근", 단위: "ton" }); eq("번호 그대로", (got as { 면적번?: string } | null)?.면적번, "SA-000001"); eq("틀린 주소", linkAreaCell(b, "철근|ton", "9C"), null); eq("풀기 · 시트 넘어", links(linkAreaCell(b, "치기|㎥", null)!), [links(book())[0], null]); eq("바뀔 것 없음 = 사본", JSON.stringify(linkAreaCell(b, "깔기|㎡", "B6")), before); // linkHues — 키로 정해짐 · 차례 무관 · 24 개까지 서로 다름 · 12 개까지 30° 바퀴 · 15° 눈금 const keys = Array.from({ length: 24 }, (_, i) => `알약${i}|㎡`); const h1 = linkHues(keys); const h2 = linkHues([...keys].reverse()); eq("차례 무관", [...h1.entries()].sort(), [...h2.entries()].sort()); eq("24 개 서로 다름", new Set(h1.values()).size, 24); eq( "15° 눈금", [...h1.values()].every((h) => h % 15 === 0 && h >= 0 && h < 360), true, ); const few = linkHues(keys.slice(0, 12)); eq( "12 개 = 30° 바퀴", [...few.values()].every((h) => h % 30 === 0), true, ); eq( "같은 키 같은 색", linkHues(["철근|ton", "깔기|㎡"]).get("철근|ton"), linkHues(["철근|ton"]).get("철근|ton"), ); console.log(JSON.stringify({ pass, fail: failures.length, failures }));