1import { describe, expect, it } from "vitest";
2import {
3 TableOpError,
4 insertColumn,
5 insertRow,
6 moveColumn,
7 moveRow,
8 removeColumn,
9 removeRow,
10 setCell,
11 tableColumns,
12 tableRows
13} from "./table-ops.js";
14
15const T = (rows: string[][]) => ({ rows });
16
17describe("table ops (T-146)", () => {
18 it("inserts rows (top / after) with the right width", () => {
19 const c = T([["a", "b"], ["c", "d"]]);
20 const top = insertRow(c, -1);
21 expect(top.rows).toEqual([["", ""], ["a", "b"], ["c", "d"]]);
22 const mid = insertRow(c, 0);
23 expect(mid.rows).toEqual([["a", "b"], ["", ""], ["c", "d"]]);
24 expect(tableRows(top)).toBe(3);
25 expect(tableColumns(top)).toBe(2);
26 });
27
28 it("removes rows; rejects removing the only row", () => {
29 const c = T([["h1", "h2"], ["a", "b"]]);
30 expect(removeRow(c, 1).rows).toEqual([["h1", "h2"]]);
31 expect(() => removeRow(T([["h"]]), 0)).toThrow(TableOpError);
32 const c2 = T([["h"], ["a"], ["b"]]);
33 expect(removeRow(c2, 1).rows).toEqual([["h"], ["b"]]);
34 });
35
36 it("moves rows (down and up)", () => {
37 const c = T([["h"], ["a"], ["b"]]);
38 const down = moveRow(c, 1, 2);
39 expect(down.rows.map((r) => r[0])).toEqual(["h", "b", "a"]);
40 const up = moveRow(c, 2, 1);
41 expect(up.rows.map((r) => r[0])).toEqual(["h", "b", "a"]);
42 });
43
44 it("inserts/removes/moves columns across all rows", () => {
45 const c = T([["h1", "h2"], ["a", "b"]]);
46 const mid = insertColumn(c, 0);
47 expect(mid.rows).toEqual([["h1", "", "h2"], ["a", "", "b"]]);
48 expect(tableColumns(mid)).toBe(3);
49 expect(removeColumn(c, 0).rows).toEqual([["h2"], ["b"]]);
50 const moved = moveColumn(c, 1, 0);
51 expect(moved.rows).toEqual([["h2", "h1"], ["b", "a"]]);
52 expect(() => removeColumn(T([["x"]]), 0)).toThrow(TableOpError);
53 });
54
55 it("rectangularizes ragged rows (pads with empty cells)", () => {
56 const c = { rows: [["a"], ["b", "c"]] };
57
58 expect(insertRow(c, -1).rows).toEqual([["", ""], ["a", ""], ["b", "c"]]);
59 });
60
61 it("setCell writes one cell without resizing", () => {
62 const c = T([["h1", "h2"], ["a", "b"]]);
63 expect(setCell(c, 1, 1, "Z").rows).toEqual([["h1", "h2"], ["a", "Z"]]);
64 expect(() => setCell(c, 5, 0, "x")).toThrow(TableOpError);
65 });
66
67 it("never mutates the input", () => {
68 const c = T([["a", "b"]]);
69 insertRow(c, 0);
70 insertColumn(c, 0);
71 expect(c.rows).toEqual([["a", "b"]]);
72 });
73
74 it("rejects non-table content", () => {
75 expect(() => tableRows({ text: "hi" })).toThrow(TableOpError);
76 expect(() => insertRow("nope", 0)).toThrow(TableOpError);
77 });
78});
79