import { describe, expect, it } from "vitest"; import { TableOpError, insertColumn, insertRow, moveColumn, moveRow, removeColumn, removeRow, setCell, tableColumns, tableRows } from "./table-ops.js"; const T = (rows: string[][]) => ({ rows }); describe("table ops (T-146)", () => { it("inserts rows (top / after) with the right width", () => { const c = T([["a", "b"], ["c", "d"]]); const top = insertRow(c, -1); expect(top.rows).toEqual([["", ""], ["a", "b"], ["c", "d"]]); const mid = insertRow(c, 0); expect(mid.rows).toEqual([["a", "b"], ["", ""], ["c", "d"]]); expect(tableRows(top)).toBe(3); expect(tableColumns(top)).toBe(2); }); it("removes rows; rejects removing the only row", () => { const c = T([["h1", "h2"], ["a", "b"]]); expect(removeRow(c, 1).rows).toEqual([["h1", "h2"]]); expect(() => removeRow(T([["h"]]), 0)).toThrow(TableOpError); // only row const c2 = T([["h"], ["a"], ["b"]]); expect(removeRow(c2, 1).rows).toEqual([["h"], ["b"]]); }); it("moves rows (down and up)", () => { const c = T([["h"], ["a"], ["b"]]); const down = moveRow(c, 1, 2); expect(down.rows.map((r) => r[0])).toEqual(["h", "b", "a"]); const up = moveRow(c, 2, 1); expect(up.rows.map((r) => r[0])).toEqual(["h", "b", "a"]); }); it("inserts/removes/moves columns across all rows", () => { const c = T([["h1", "h2"], ["a", "b"]]); const mid = insertColumn(c, 0); expect(mid.rows).toEqual([["h1", "", "h2"], ["a", "", "b"]]); expect(tableColumns(mid)).toBe(3); expect(removeColumn(c, 0).rows).toEqual([["h2"], ["b"]]); const moved = moveColumn(c, 1, 0); expect(moved.rows).toEqual([["h2", "h1"], ["b", "a"]]); expect(() => removeColumn(T([["x"]]), 0)).toThrow(TableOpError); }); it("rectangularizes ragged rows (pads with empty cells)", () => { const c = { rows: [["a"], ["b", "c"]] }; // insert at the top (-1); the ragged row ["a"] is padded to width 2 expect(insertRow(c, -1).rows).toEqual([["", ""], ["a", ""], ["b", "c"]]); }); it("setCell writes one cell without resizing", () => { const c = T([["h1", "h2"], ["a", "b"]]); expect(setCell(c, 1, 1, "Z").rows).toEqual([["h1", "h2"], ["a", "Z"]]); expect(() => setCell(c, 5, 0, "x")).toThrow(TableOpError); }); it("never mutates the input", () => { const c = T([["a", "b"]]); insertRow(c, 0); insertColumn(c, 0); expect(c.rows).toEqual([["a", "b"]]); }); it("rejects non-table content", () => { expect(() => tableRows({ text: "hi" })).toThrow(TableOpError); expect(() => insertRow("nope", 0)).toThrow(TableOpError); }); });