import { describe, test, expect, beforeEach, jest } from '@jest/globals'; import ListWalker from '../../app/player/common/ListWalker'; import type { Timed } from '../../app/player/common/types'; interface Item extends Timed { value?: string; } describe('ListWalker', () => { let walker: ListWalker; beforeEach(() => { walker = new ListWalker([]); jest.spyOn(console, 'error').mockImplementation(() => {}); }); test('append maintains order and prevents out of order inserts', () => { walker.append({ time: 1 }); walker.append({ time: 3 }); expect(walker.list.map((i) => i.time)).toEqual([1, 3]); walker.append({ time: 2 }); expect(walker.list.map((i) => i.time)).toEqual([1, 3]); expect((console.error as jest.Mock).mock.calls.length).toBe(1); }); test('unshift prepends items', () => { walker.append({ time: 2 }); walker.unshift({ time: 1 }); expect(walker.list.map((i) => i.time)).toEqual([1, 2]); }); test('insert places item according to time', () => { walker.append({ time: 1 }); walker.append({ time: 3 }); walker.insert({ time: 2 }); expect(walker.list.map((i) => i.time)).toEqual([1, 2, 3]); }); test('moveGetLast advances pointer and returns item', () => { walker = new ListWalker([{ time: 1 }, { time: 3 }, { time: 5 }]); expect(walker.moveGetLast(3)?.time).toBe(3); expect(walker.countNow).toBe(2); expect(walker.moveGetLast(3)).toBeNull(); expect(walker.moveGetLast(4)).toBeNull(); expect(walker.moveGetLast(4, undefined, true)?.time).toBe(3); expect(walker.moveGetLast(1)?.time).toBe(1); expect(walker.countNow).toBe(1); }); test('getNew returns items when pointer moves or time decreases', () => { walker = new ListWalker([{ time: 1 }, { time: 3 }, { time: 5 }]); expect(walker.getNew(2)?.time).toBe(1); expect(walker.getNew(4)?.time).toBe(3); expect(walker.getNew(4)).toBeNull(); expect(walker.getNew(1)?.time).toBe(1); }); test('findLast performs binary search', () => { walker = new ListWalker([{ time: 1 }, { time: 3 }, { time: 5 }]); expect(walker.findLast(4)?.time).toBe(3); expect(walker.findLast(5)?.time).toBe(5); expect(walker.findLast(0)).toBeNull(); }); test('moveApply iterates over items up to time', () => { walker = new ListWalker([{ time: 1 }, { time: 2 }, { time: 3 }]); const collected: number[] = []; walker.moveApply(2.5, (m) => collected.push(m.time)); expect(collected).toEqual([1, 2]); expect(walker.countNow).toBe(2); walker.moveApply(1.5, (m) => collected.push(m.time)); expect(collected).toEqual([1, 2, 1]); expect(walker.countNow).toBe(1); }); });