test(spreadsheet): D 알약 연결 — 행열 따라가기 · 되돌리기 규칙 시험 · 시험 틀(harness_links)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6KXAabDTenEU7hrDQmCKY
This commit is contained in:
2026-09-28 12:09:33 +09:00
co-authored by Claude Opus 5.5
parent 854531cfd8
commit 5de2f75828
4 changed files with 107 additions and 0 deletions
@@ -0,0 +1,22 @@
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<title>알약 막대 시험 틀</title>
<style>
body {
margin: 0;
font-family: sans-serif;
}
#host {
height: 520px;
margin: 8px;
border: 1px solid #999;
}
</style>
</head>
<body>
<div id="host"></div>
<script type="module" src="./harness_links.ts"></script>
</body>
</html>
@@ -0,0 +1,57 @@
/* 알약 막대 시험 틀 — 진짜 부품(createSpreadsheet)에 `links` 선택 · 가짜 입력값 · 가짜 자재 목록.
* Vite 개발 서버가 바로 풂: /resources/tester/spreadsheet/harness_links.html?mode=입력|자재
* window.ss = 부품 손잡이(getDoc · getLinkedValues) · window.ssFind = 자재찾기 부른 글 목록 */
import "../../../ui_template/ui_template_theme.css"; // 앱 색 · 간격 토큰
import { createSpreadsheet } from "../../../A00_Common/spreadsheet/spreadsheet";
import type { LinkMaterial, Workbook } from "../../../A00_Common/spreadsheet/spreadsheet";
const w = window as unknown as Record<string, unknown>;
const mode = new URLSearchParams(location.search).get("mode") === "자재" ? "자재" : "입력";
const book: Workbook = {
종류: "통합문서",
판: 1,
열: "harness",
서식: [{}],
시트: [
{
id: "s1",
이름: "면적산출",
칸: {
A1: { 값: "길이" },
B1: { 값: 12.5 },
A2: { 값: "높이" },
B2: { 값: 3 },
A3: { 값: "면적" },
B3: { 식: "B1*B2" },
},
},
],
활성: "s1",
};
const MATERIALS: LinkMaterial[] = [
{ 코드: "M001", 이름: "레미콘", 규격: "25-21-12", 단위: "m³" },
{ 코드: "M002", 이름: "철근", 규격: "SD400 D13", 단위: "ton" },
{ 코드: "M003", 이름: "거푸집", 규격: "합판 3회", 단위: "m²" },
];
const asked: string[] = [];
w.ssFind = asked;
w.ss = createSpreadsheet(document.getElementById("host")!, book, {
tabs: false,
onChange: () => (w.ssChanges = ((w.ssChanges as number) ?? 0) + 1),
links: {
모드: mode,
항목: [
{ 키: "L", 이름: "길이", 단위: "m" },
{ 키: "H", 이름: "높이", 단위: "m" },
{ 키: "A", 이름: "면적", 단위: "m²" },
],
자재찾기: async (글) => {
asked.push(글);
await new Promise((r) => setTimeout(r, 50));
return MATERIALS.filter((m) => !글 || `${m.코드}${m.이름}${m.규격}`.includes(글));
},
},
});
@@ -123,5 +123,28 @@ const out = {
};
return addr.toA1(sel.move(s, sel.selectCell(s, 1, 11), 1, 0).활성.r, 11);
})(),
// 알약 연결 — 행 넣기 · 열 지우기(연결 칸 지움 → 빠짐) · 되돌리기 두 번
links: (() => {
const lk = load(path.join(SS, "spreadsheet_links.ts"));
const book = JSON.parse(JSON.stringify(sample));
const id = book.시트[0].id;
book.시트[0].연결 = [
{ 키: "L", 이름: "길이", 칸: "B5" },
{ 키: "W", 이름: "폭", 칸: "D3" },
];
const read = () => (book.시트[0].연결 ?? []).map((l) => `${l.키}:${l.칸}`).join(",");
const out = [];
const ins = lk.applyLinked(book, { 종류: "행넣기", 시트: id, at: 2, 수: 2 });
out.push(read());
const del = lk.applyLinked(book, { 종류: "열지우기", 시트: id, at: 3, 수: 1 });
out.push(read());
lk.applyLinked(book, del.undo);
out.push(read());
lk.applyLinked(book, ins.undo);
out.push(read());
const one = [{ 키: "a", 칸: "C1" }];
out.push(lk.shiftLinks(one, { 종류: "열넣기", 시트: id, at: 0, 수: 1 })[0].칸);
return out;
})(),
};
console.log(JSON.stringify(out));
@@ -106,3 +106,8 @@ def test_abs_cycle_and_fold(r):
None,
]
assert r["foldSkip"] == "L5"
def test_links_follow_rows_cols(r):
# 행 넣기 → 밀림 · 연결 칸 열 지움 → 빠짐 · 되돌리기 → 제자리
assert r["links"] == ["L:B7,W:D5", "L:B7", "L:B7,W:D5", "L:B5,W:D3", "D1"]