Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 208 lines 6.1 kB view raw
1import { describe, it, expect } from 'vitest'; 2import { 3 createArrayResult, 4 columnVector, 5 rowVector, 6 computeSpillRange, 7 spillCells, 8 isInSpillRange, 9 spillRangesOverlap, 10 arrayUnique, 11 arraySort, 12 arrayFilter, 13 arrayTranspose, 14 arraySequence, 15 arrayFlatten, 16 getArrayValue, 17} from '../src/sheets/array-formulas.js'; 18 19describe('createArrayResult', () => { 20 it('creates from 2D array', () => { 21 const r = createArrayResult([[1, 2], [3, 4]]); 22 expect(r.rows).toBe(2); 23 expect(r.cols).toBe(2); 24 expect(r.values).toEqual([[1, 2], [3, 4]]); 25 }); 26 27 it('normalizes ragged arrays', () => { 28 const r = createArrayResult([[1, 2, 3], [4]]); 29 expect(r.cols).toBe(3); 30 expect(r.values[1]).toEqual([4, null, null]); 31 }); 32 33 it('handles empty array', () => { 34 const r = createArrayResult([]); 35 expect(r.rows).toBe(0); 36 expect(r.cols).toBe(0); 37 }); 38}); 39 40describe('columnVector', () => { 41 it('creates column from flat array', () => { 42 const r = columnVector([1, 2, 3]); 43 expect(r.rows).toBe(3); 44 expect(r.cols).toBe(1); 45 expect(r.values).toEqual([[1], [2], [3]]); 46 }); 47}); 48 49describe('rowVector', () => { 50 it('creates row from flat array', () => { 51 const r = rowVector([1, 2, 3]); 52 expect(r.rows).toBe(1); 53 expect(r.cols).toBe(3); 54 expect(r.values).toEqual([[1, 2, 3]]); 55 }); 56}); 57 58describe('computeSpillRange', () => { 59 it('computes range from origin and result', () => { 60 const result = createArrayResult([[1, 2], [3, 4], [5, 6]]); 61 const range = computeSpillRange(2, 3, result); 62 expect(range).toEqual({ originRow: 2, originCol: 3, rows: 3, cols: 2 }); 63 }); 64}); 65 66describe('spillCells', () => { 67 it('lists all cells in range', () => { 68 const range = { originRow: 1, originCol: 1, rows: 2, cols: 3 }; 69 const cells = spillCells(range); 70 expect(cells).toHaveLength(6); 71 expect(cells[0]).toEqual({ row: 1, col: 1 }); 72 expect(cells[5]).toEqual({ row: 2, col: 3 }); 73 }); 74}); 75 76describe('isInSpillRange', () => { 77 const range = { originRow: 2, originCol: 3, rows: 3, cols: 2 }; 78 79 it('returns true for cell inside range', () => { 80 expect(isInSpillRange(3, 4, range)).toBe(true); 81 }); 82 83 it('returns true for origin cell', () => { 84 expect(isInSpillRange(2, 3, range)).toBe(true); 85 }); 86 87 it('returns false for cell outside range', () => { 88 expect(isInSpillRange(1, 3, range)).toBe(false); 89 expect(isInSpillRange(5, 3, range)).toBe(false); 90 expect(isInSpillRange(2, 5, range)).toBe(false); 91 }); 92}); 93 94describe('spillRangesOverlap', () => { 95 it('detects overlapping ranges', () => { 96 const a = { originRow: 0, originCol: 0, rows: 3, cols: 3 }; 97 const b = { originRow: 2, originCol: 2, rows: 2, cols: 2 }; 98 expect(spillRangesOverlap(a, b)).toBe(true); 99 }); 100 101 it('detects non-overlapping ranges', () => { 102 const a = { originRow: 0, originCol: 0, rows: 2, cols: 2 }; 103 const b = { originRow: 3, originCol: 3, rows: 2, cols: 2 }; 104 expect(spillRangesOverlap(a, b)).toBe(false); 105 }); 106 107 it('detects adjacent (non-overlapping)', () => { 108 const a = { originRow: 0, originCol: 0, rows: 2, cols: 2 }; 109 const b = { originRow: 0, originCol: 2, rows: 2, cols: 2 }; 110 expect(spillRangesOverlap(a, b)).toBe(false); 111 }); 112}); 113 114describe('arrayUnique', () => { 115 it('removes duplicate rows', () => { 116 const r = createArrayResult([[1, 'a'], [2, 'b'], [1, 'a'], [3, 'c']]); 117 const u = arrayUnique(r); 118 expect(u.rows).toBe(3); 119 expect(u.values).toEqual([[1, 'a'], [2, 'b'], [3, 'c']]); 120 }); 121}); 122 123describe('arraySort', () => { 124 it('sorts by first column ascending', () => { 125 const r = createArrayResult([[3, 'c'], [1, 'a'], [2, 'b']]); 126 const s = arraySort(r, 0, true); 127 expect(s.values).toEqual([[1, 'a'], [2, 'b'], [3, 'c']]); 128 }); 129 130 it('sorts descending', () => { 131 const r = createArrayResult([[1], [3], [2]]); 132 const s = arraySort(r, 0, false); 133 expect(s.values).toEqual([[3], [2], [1]]); 134 }); 135 136 it('sorts strings', () => { 137 const r = createArrayResult([['banana'], ['apple'], ['cherry']]); 138 const s = arraySort(r, 0, true); 139 expect(s.values[0][0]).toBe('apple'); 140 }); 141}); 142 143describe('arrayFilter', () => { 144 it('filters rows by predicate', () => { 145 const r = createArrayResult([[1, 'a'], [2, 'b'], [3, 'c']]); 146 const f = arrayFilter(r, 0, v => (v as number) > 1); 147 expect(f.rows).toBe(2); 148 expect(f.values).toEqual([[2, 'b'], [3, 'c']]); 149 }); 150 151 it('returns empty when nothing matches', () => { 152 const r = createArrayResult([[1], [2]]); 153 const f = arrayFilter(r, 0, v => (v as number) > 10); 154 expect(f.rows).toBe(0); 155 }); 156}); 157 158describe('arrayTranspose', () => { 159 it('swaps rows and columns', () => { 160 const r = createArrayResult([[1, 2, 3], [4, 5, 6]]); 161 const t = arrayTranspose(r); 162 expect(t.rows).toBe(3); 163 expect(t.cols).toBe(2); 164 expect(t.values).toEqual([[1, 4], [2, 5], [3, 6]]); 165 }); 166 167 it('handles empty array', () => { 168 const t = arrayTranspose(createArrayResult([])); 169 expect(t.rows).toBe(0); 170 }); 171}); 172 173describe('arraySequence', () => { 174 it('generates sequence', () => { 175 const r = arraySequence(3, 1, 1, 1); 176 expect(r.values).toEqual([[1], [2], [3]]); 177 }); 178 179 it('generates 2D sequence', () => { 180 const r = arraySequence(2, 3, 10, 5); 181 expect(r.values).toEqual([[10, 15, 20], [25, 30, 35]]); 182 }); 183}); 184 185describe('arrayFlatten', () => { 186 it('flattens 2D to column', () => { 187 const r = createArrayResult([[1, 2], [3, 4]]); 188 const f = arrayFlatten(r); 189 expect(f.rows).toBe(4); 190 expect(f.cols).toBe(1); 191 expect(f.values).toEqual([[1], [2], [3], [4]]); 192 }); 193}); 194 195describe('getArrayValue', () => { 196 it('returns value at position', () => { 197 const r = createArrayResult([[1, 2], [3, 4]]); 198 expect(getArrayValue(r, 0, 0)).toBe(1); 199 expect(getArrayValue(r, 1, 1)).toBe(4); 200 }); 201 202 it('returns null for out-of-bounds', () => { 203 const r = createArrayResult([[1]]); 204 expect(getArrayValue(r, 5, 0)).toBeNull(); 205 expect(getArrayValue(r, 0, 5)).toBeNull(); 206 expect(getArrayValue(r, -1, 0)).toBeNull(); 207 }); 208});