import { describe, test, expect } from 'vitest' import { initialStreamState, nextStreamState, isTerminal, type StreamState, type StreamTransition, } from '../mux/stream.js' function legal(t: StreamTransition): StreamState { if ('illegal' in t) throw new Error('expected legal transition') return t.next } describe('stream state machine (T3, §4.1 lifecycle)', () => { test('legal path: idle --OPEN--> open --DATA*--> open --CLOSE--> closed', () => { let s = initialStreamState() expect(s).toBe('idle') s = legal(nextStreamState(s, 'open', false, 'outbound')) expect(s).toBe('open') s = legal(nextStreamState(s, 'data', false, 'outbound')) s = legal(nextStreamState(s, 'data', false, 'inbound')) expect(s).toBe('open') s = legal(nextStreamState(s, 'close', true, 'outbound')) expect(s).toBe('closed') expect(isTerminal(s)).toBe(true) }) test('DATA with fin half-closes the SENDING direction; both-side FIN ⇒ closed', () => { const outFin = legal(nextStreamState('open', 'data', true, 'outbound')) expect(outFin).toBe('halfClosedLocal') const inFin = legal(nextStreamState('open', 'data', true, 'inbound')) expect(inFin).toBe('halfClosedRemote') // The other side FINs ⇒ fully closed. expect(legal(nextStreamState('halfClosedLocal', 'data', true, 'inbound'))).toBe('closed') expect(legal(nextStreamState('halfClosedRemote', 'data', true, 'outbound'))).toBe('closed') }) test('illegal: DATA before OPEN', () => { expect(nextStreamState('idle', 'data', false, 'inbound')).toEqual({ illegal: true }) }) test('illegal: any frame after closed', () => { for (const t of ['data', 'close', 'windowUpdate', 'open'] as const) { expect(nextStreamState('closed', t, false, 'inbound')).toEqual({ illegal: true }) } }) test('illegal: OPEN on an already-open stream', () => { expect(nextStreamState('open', 'open', false, 'inbound')).toEqual({ illegal: true }) }) test('illegal: CLOSE before OPEN', () => { expect(nextStreamState('idle', 'close', false, 'inbound')).toEqual({ illegal: true }) }) test('WINDOW_UPDATE keeps state and is legal while flowing', () => { expect(legal(nextStreamState('open', 'windowUpdate', false, 'inbound'))).toBe('open') expect(legal(nextStreamState('halfClosedLocal', 'windowUpdate', false, 'inbound'))).toBe( 'halfClosedLocal', ) }) test('illegal: re-FIN on the already-closed direction', () => { expect(nextStreamState('halfClosedLocal', 'data', true, 'outbound')).toEqual({ illegal: true }) }) })