import { describe, expect, it } from 'vitest'; import { extractFrames, frame } from './codec.js'; const F = (payload: number[]) => [ 0x94, 0xc3, (payload.length >> 8) & 0xff, payload.length & 0xff, ...payload, ]; describe('extractFrames', () => { it('emits one complete frame and empties rest', () => { const { packets, rest } = extractFrames(Uint8Array.from(F([1, 2, 3]))); expect(packets).toHaveLength(1); expect(Array.from(packets[0])).toEqual([1, 2, 3]); expect(rest.length).toBe(0); }); it('emits two frames from one chunk', () => { const buf = Uint8Array.from([...F([1]), ...F([2, 2])]); const { packets, rest } = extractFrames(buf); expect(packets.map((p) => Array.from(p))).toEqual([[1], [2, 2]]); expect(rest.length).toBe(0); }); it('reassembles a frame split across two feedings', () => { const full = Uint8Array.from(F([9, 8, 7])); const first = extractFrames(full.subarray(0, 5)); // header + 1 payload byte expect(first.packets).toHaveLength(0); expect(Array.from(first.rest)).toEqual(Array.from(full.subarray(0, 5))); const second = extractFrames( Uint8Array.from([...first.rest, ...full.subarray(5)]), ); expect(second.packets.map((p) => Array.from(p))).toEqual([[9, 8, 7]]); expect(second.rest.length).toBe(0); }); it('discards garbage bytes before the header', () => { const buf = Uint8Array.from([0xaa, 0xbb, ...F([5])]); const { packets, rest } = extractFrames(buf); expect(packets.map((p) => Array.from(p))).toEqual([[5]]); expect(rest.length).toBe(0); }); it('resyncs past a bogus len > 1024 and finds the real frame', () => { const buf = Uint8Array.from([0x94, 0xc3, 0xff, 0xfe, ...F([7, 6])]); const { packets, rest } = extractFrames(buf); expect(packets.map((p) => Array.from(p))).toEqual([[7, 6]]); expect(rest.length).toBe(0); }); it('keeps a trailing lone 0x94 in rest', () => { const { packets, rest } = extractFrames(Uint8Array.from([0xaa, 0x94])); expect(packets).toHaveLength(0); expect(Array.from(rest)).toEqual([0x94]); }); }); describe('frame', () => { it('prepends the 0x94 0xC3 big-endian length header', () => { const out = frame(Uint8Array.from([1, 2, 3])); expect(Array.from(out)).toEqual([0x94, 0xc3, 0x00, 0x03, 1, 2, 3]); }); it('encodes lengths above 255 in two bytes', () => { const payload = new Uint8Array(300).fill(7); const out = frame(payload); expect(Array.from(out.subarray(0, 4))).toEqual([0x94, 0xc3, 0x01, 0x2c]); expect(out.length).toBe(304); }); it('round-trips through extractFrames', () => { const framed = frame(Uint8Array.from([4, 5])); const { packets, rest } = extractFrames(framed); expect(packets.map((p) => Array.from(p))).toEqual([[4, 5]]); expect(rest.length).toBe(0); }); });