Files

346 lines
9.4 KiB
TypeScript

import { parseTable, serializeTable, addRow, addColumn, deleteRow, deleteColumn, generateTable, ColumnAlignment } from './tableUtils';
describe('tableUtils', () => {
// parseTable
it('should parse a simple 2x2 table', () => {
const text = [
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n');
const table = parseTable(text);
expect(table).not.toBeNull();
expect(table!.header.cells).toHaveLength(2);
expect(table!.header.cells[0].content).toBe('A');
expect(table!.header.cells[1].content).toBe('B');
expect(table!.body).toHaveLength(1);
expect(table!.body[0].cells[0].content).toBe('1');
expect(table!.body[0].cells[1].content).toBe('2');
});
it('should parse alignment markers', () => {
const text = [
'| Left | Center | Right | None |',
'|:-----|:------:|------:|------|',
'| a | b | c | d |',
].join('\n');
const table = parseTable(text);
expect(table).not.toBeNull();
expect(table!.alignments[0]).toBe(ColumnAlignment.Left);
expect(table!.alignments[1]).toBe(ColumnAlignment.Center);
expect(table!.alignments[2]).toBe(ColumnAlignment.Right);
expect(table!.alignments[3]).toBe(ColumnAlignment.None);
});
it('should parse a table with multiple body rows', () => {
const text = [
'| H1 | H2 |',
'|----|-----|',
'| a | b |',
'| c | d |',
'| e | f |',
].join('\n');
const table = parseTable(text);
expect(table).not.toBeNull();
expect(table!.body).toHaveLength(3);
});
it('should return null for invalid input', () => {
expect(parseTable('hello world')).toBeNull();
expect(parseTable('| A |\n| B |')).toBeNull(); // no delimiter
expect(parseTable('')).toBeNull();
});
it('should handle header-only tables (no body rows)', () => {
const text = [
'| A | B |',
'|---|---|',
].join('\n');
const table = parseTable(text);
expect(table).not.toBeNull();
expect(table!.body).toHaveLength(0);
});
it('should normalize rows with fewer cells than header', () => {
const text = [
'| A | B | C |',
'|---|---|---|',
'| 1 |',
].join('\n');
const table = parseTable(text);
expect(table).not.toBeNull();
expect(table!.body[0].cells).toHaveLength(3);
expect(table!.body[0].cells[0].content).toBe('1');
expect(table!.body[0].cells[1].content).toBe('');
expect(table!.body[0].cells[2].content).toBe('');
});
// serializeTable
it('should produce valid Markdown output when serializing', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n'));
const result = serializeTable(table!);
const reparsed = parseTable(result);
expect(reparsed).not.toBeNull();
expect(reparsed!.header.cells[0].content).toBe('A');
expect(reparsed!.header.cells[1].content).toBe('B');
expect(reparsed!.body[0].cells[0].content).toBe('1');
expect(reparsed!.body[0].cells[1].content).toBe('2');
});
it('should preserve alignment markers when serializing', () => {
const text = [
'| Left | Center | Right |',
'|:-----|:------:|------:|',
'| a | b | c |',
].join('\n');
const table = parseTable(text);
const result = serializeTable(table!);
const reparsed = parseTable(result);
expect(reparsed).not.toBeNull();
expect(reparsed!.alignments[0]).toBe(ColumnAlignment.Left);
expect(reparsed!.alignments[1]).toBe(ColumnAlignment.Center);
expect(reparsed!.alignments[2]).toBe(ColumnAlignment.Right);
});
it('should round-trip: parse then serialize preserves content', () => {
const original = [
'| Name | Age | City |',
'|------|-----|---------|',
'| Alice | 30 | NYC |',
'| Bob | 25 | London |',
].join('\n');
const table = parseTable(original);
const serialized = serializeTable(table!);
const reparsed = parseTable(serialized);
expect(reparsed).not.toBeNull();
expect(reparsed!.header.cells[0].content).toBe('Name');
expect(reparsed!.body[0].cells[0].content).toBe('Alice');
expect(reparsed!.body[1].cells[2].content).toBe('London');
});
it('should pad columns for alignment when serializing', () => {
const table = parseTable([
'| A | LongHeader |',
'|---|---|',
'| x | y |',
].join('\n'));
const result = serializeTable(table!);
const lines = result.split('\n');
expect(lines).toHaveLength(3);
const pipeCount = (s: string) => (s.match(/\|/g) || []).length;
expect(pipeCount(lines[0])).toBe(pipeCount(lines[1]));
expect(pipeCount(lines[1])).toBe(pipeCount(lines[2]));
});
// addRow
it('should add a row after the specified index', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
'| 3 | 4 |',
].join('\n'));
const result = addRow(table!, 0);
expect(result.body).toHaveLength(3);
expect(result.body[0].cells[0].content).toBe('1');
expect(result.body[1].cells[0].content).toBe(''); // new row
expect(result.body[2].cells[0].content).toBe('3');
});
it('should add a row at the beginning with afterIndex = -1', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n'));
const result = addRow(table!, -1);
expect(result.body).toHaveLength(2);
expect(result.body[0].cells[0].content).toBe(''); // new row
expect(result.body[1].cells[0].content).toBe('1');
});
it('should add a row with correct column count', () => {
const table = parseTable([
'| A | B | C |',
'|---|---|---|',
'| 1 | 2 | 3 |',
].join('\n'));
const result = addRow(table!, 0);
expect(result.body[1].cells).toHaveLength(3);
});
// addColumn
it('should add a column after the specified index', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n'));
const result = addColumn(table!, 0);
expect(result.header.cells).toHaveLength(3);
expect(result.header.cells[0].content).toBe('A');
expect(result.header.cells[1].content).toBe(''); // new column
expect(result.header.cells[2].content).toBe('B');
expect(result.alignments).toHaveLength(3);
expect(result.body[0].cells).toHaveLength(3);
});
it('should add a column at the beginning with afterIndex = -1', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n'));
const result = addColumn(table!, -1);
expect(result.header.cells[0].content).toBe(''); // new column
expect(result.header.cells[1].content).toBe('A');
});
// deleteRow
it('should delete the row at the given index', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
'| 3 | 4 |',
].join('\n'));
const result = deleteRow(table!, 0);
expect(result).not.toBeNull();
expect(result!.body).toHaveLength(1);
expect(result!.body[0].cells[0].content).toBe('3');
});
it('deleteRow should return null for invalid index', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n'));
expect(deleteRow(table!, -1)).toBeNull();
expect(deleteRow(table!, 5)).toBeNull();
});
it('should allow deleting all body rows (header-only table)', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n'));
const result = deleteRow(table!, 0);
expect(result).not.toBeNull();
expect(result!.body).toHaveLength(0);
});
// deleteColumn
it('should delete the column at the given index', () => {
const table = parseTable([
'| A | B | C |',
'|---|---|---|',
'| 1 | 2 | 3 |',
].join('\n'));
const result = deleteColumn(table!, 1);
expect(result).not.toBeNull();
expect(result!.header.cells).toHaveLength(2);
expect(result!.header.cells[0].content).toBe('A');
expect(result!.header.cells[1].content).toBe('C');
expect(result!.body[0].cells).toHaveLength(2);
});
it('should return null when deleting the last column', () => {
const table = parseTable([
'| A |',
'|---|',
'| 1 |',
].join('\n'));
expect(deleteColumn(table!, 0)).toBeNull();
});
it('deleteColumn should return null for invalid index', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n'));
expect(deleteColumn(table!, -1)).toBeNull();
expect(deleteColumn(table!, 5)).toBeNull();
});
// generateTable
it('should generate a valid table with the specified dimensions', () => {
const result = generateTable(2, 3);
const table = parseTable(result);
expect(table).not.toBeNull();
expect(table!.header.cells).toHaveLength(3);
expect(table!.body).toHaveLength(2);
});
it('should generate a header-only table with 0 body rows', () => {
const result = generateTable(0, 2);
const table = parseTable(result);
expect(table).not.toBeNull();
expect(table!.header.cells).toHaveLength(2);
expect(table!.body).toHaveLength(0);
});
it('should reject non-integer dimensions', () => {
expect(() => generateTable(1.5, 2)).toThrow();
expect(() => generateTable(2, 2.5)).toThrow();
});
it('should reject invalid dimensions', () => {
expect(() => generateTable(0, 0)).toThrow();
expect(() => generateTable(-1, 2)).toThrow();
});
it('addRow should reject out-of-range afterIndex', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n'));
expect(() => addRow(table!, -2)).toThrow(RangeError);
expect(() => addRow(table!, 5)).toThrow(RangeError);
});
it('addColumn should reject out-of-range afterIndex', () => {
const table = parseTable([
'| A | B |',
'|---|---|',
'| 1 | 2 |',
].join('\n'));
expect(() => addColumn(table!, -2)).toThrow(RangeError);
expect(() => addColumn(table!, 5)).toThrow(RangeError);
});
});