| 1 | import assert from 'node:assert/strict'; |
| 2 | import { test } from 'node:test'; |
| 3 | import { dropSlot, moveBy, moveToSlot, type Box } from '../src/lib/reorder-model.ts'; |
| 4 | |
| 5 | const box = (left: number, top: number): Box => ({ left, top, width: 30, height: 24 }); |
| 6 | |
| 7 | const wrapped = [box(0, 0), box(34, 0), box(68, 0), box(0, 28), box(34, 28)]; |
| 8 | |
| 9 | test('a pointer left of a chip centre lands before it', () => { |
| 10 | assert.deepEqual(dropSlot(wrapped, 40, 10), { slot: 1, after: false }); |
| 11 | assert.deepEqual(dropSlot(wrapped, 2, 10), { slot: 0, after: false }); |
| 12 | }); |
| 13 | |
| 14 | test('a pointer right of every chip in a row lands after its last chip', () => { |
| 15 | assert.deepEqual(dropSlot(wrapped, 200, 10), { slot: 3, after: true }); |
| 16 | assert.deepEqual(dropSlot(wrapped, 200, 30), { slot: 5, after: true }); |
| 17 | }); |
| 18 | |
| 19 | test('the nearest row wins when the pointer is above or below the chips', () => { |
| 20 | assert.deepEqual(dropSlot(wrapped, 40, -50), { slot: 1, after: false }); |
| 21 | assert.deepEqual(dropSlot(wrapped, 40, 90), { slot: 4, after: false }); |
| 22 | assert.deepEqual(dropSlot(wrapped, 10, 27), { slot: 3, after: false }); |
| 23 | }); |
| 24 | |
| 25 | test('chips of slightly different heights share a row', () => { |
| 26 | const mixed = [box(0, 0), { left: 34, top: 2, width: 12, height: 20 }, box(50, 0)]; |
| 27 | assert.deepEqual(dropSlot(mixed, 100, 10), { slot: 3, after: true }); |
| 28 | }); |
| 29 | |
| 30 | test('an empty list always lands at the start', () => { |
| 31 | assert.deepEqual(dropSlot([], 10, 10), { slot: 0, after: false }); |
| 32 | }); |
| 33 | |
| 34 | test('moving to a slot after the source accounts for the removed item', () => { |
| 35 | assert.deepEqual(moveToSlot(['a', 'b', 'c', 'd'], 0, 3), ['b', 'c', 'a', 'd']); |
| 36 | assert.deepEqual(moveToSlot(['a', 'b', 'c', 'd'], 0, 4), ['b', 'c', 'd', 'a']); |
| 37 | assert.deepEqual(moveToSlot(['a', 'b', 'c', 'd'], 3, 1), ['a', 'd', 'b', 'c']); |
| 38 | }); |
| 39 | |
| 40 | test('moving onto its own slot returns the same list', () => { |
| 41 | const list = ['a', 'b', 'c']; |
| 42 | assert.equal(moveToSlot(list, 1, 1), list); |
| 43 | assert.equal(moveToSlot(list, 1, 2), list); |
| 44 | assert.equal(moveToSlot(list, 5, 0), list); |
| 45 | assert.equal(moveToSlot(list, -1, 0), list); |
| 46 | }); |
| 47 | |
| 48 | test('moving never mutates the input and clamps the slot', () => { |
| 49 | const list = ['a', 'b', 'c']; |
| 50 | assert.deepEqual(moveToSlot(list, 0, 99), ['b', 'c', 'a']); |
| 51 | assert.deepEqual(moveToSlot(list, 2, -4), ['c', 'a', 'b']); |
| 52 | assert.deepEqual(list, ['a', 'b', 'c']); |
| 53 | }); |
| 54 | |
| 55 | test('moving by a step swaps neighbours and stops at the ends', () => { |
| 56 | const list = ['a', 'b', 'c']; |
| 57 | assert.deepEqual(moveBy(list, 0, 1), ['b', 'a', 'c']); |
| 58 | assert.deepEqual(moveBy(list, 2, -1), ['a', 'c', 'b']); |
| 59 | assert.equal(moveBy(list, 0, -1), list); |
| 60 | assert.equal(moveBy(list, 2, 1), list); |
| 61 | }); |