import { describe, expect, it } from 'vitest' import { ContractDecodeError, ContractEncodeError, decodeHeader, decodeMuxFrame, encodeMuxFrame, type MuxFrameHeader, } from '../src/index.js' const baseHeader = (over: Partial = {}): MuxFrameHeader => ({ version: 1, type: 'data', fin: false, rst: false, streamId: 1, payloadLen: 0, ...over, }) describe('ยง4.1 mux frame codec', () => { it('KAT: encodes a known DATA frame to a fixed byte vector', () => { const header = baseHeader({ type: 'data', fin: true, streamId: 0x01020304, payloadLen: 2 }) const payload = Uint8Array.of(0xaa, 0xbb) const bytes = encodeMuxFrame(header, payload) expect([...bytes]).toEqual([ 0x01, // version 0x02, // type=data 0x01, // flags: FIN 0x01, 0x02, 0x03, 0x04, // streamId 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // payloadLen uint64 0xaa, 0xbb, // payload ]) }) it('KAT: fixed bytes decode to fixed header + payload', () => { const bytes = Uint8Array.of( 0x01, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x99, ) const { header, payload } = decodeMuxFrame(bytes) expect(header).toEqual({ version: 1, type: 'goaway', fin: false, rst: true, streamId: 0, payloadLen: 1, }) expect([...payload]).toEqual([0x99]) }) it.each(['open', 'data', 'close', 'ping', 'pong', 'windowUpdate', 'goaway'] as const)( 'round-trips type=%s with flags', (type) => { const header = baseHeader({ type, fin: true, rst: true, streamId: 42, payloadLen: 3 }) const payload = Uint8Array.of(1, 2, 3) const decoded = decodeMuxFrame(encodeMuxFrame(header, payload)) expect(decoded.header).toEqual(header) expect([...decoded.payload]).toEqual([1, 2, 3]) }, ) it('decodeHeader reads only the header of a longer buffer', () => { const bytes = encodeMuxFrame(baseHeader({ payloadLen: 4 }), Uint8Array.of(9, 9, 9, 9)) expect(decodeHeader(bytes).payloadLen).toBe(4) }) it('rejects encode when payloadLen != payload.length', () => { expect(() => encodeMuxFrame(baseHeader({ payloadLen: 5 }), Uint8Array.of(1))).toThrow( ContractEncodeError, ) }) it('rejects an unknown frame type code on decode', () => { const bytes = Uint8Array.of(0x01, 0x7f, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) expect(() => decodeHeader(bytes)).toThrow(ContractDecodeError) }) it('rejects reserved flag bits', () => { const bytes = Uint8Array.of(0x01, 0x02, 0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) expect(() => decodeHeader(bytes)).toThrow(/reserved flag/) }) it('rejects an unsupported version', () => { const bytes = Uint8Array.of(0x02, 0x02, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) expect(() => decodeHeader(bytes)).toThrow(/version/) }) it('rejects a truncated payload', () => { const bytes = Uint8Array.of(0x01, 0x02, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x05) expect(() => decodeMuxFrame(bytes)).toThrow(/truncated/) }) it('rejects a buffer shorter than the header', () => { expect(() => decodeHeader(Uint8Array.of(0x01, 0x02))).toThrow(ContractDecodeError) }) })