import { describe, expect, it } from 'vitest' import { ReplayError } from '../src/errors.js' import { SequenceGuard } from '../src/sequence.js' describe('T7 SequenceGuard (INV13)', () => { it('send: next() yields 0,1,2… strictly increasing', () => { const g = new SequenceGuard('send') expect(g.next()).toBe(0n) expect(g.next()).toBe(1n) expect(g.next()).toBe(2n) }) it('two guards never share state', () => { const a = new SequenceGuard('send') const b = new SequenceGuard('send') a.next() a.next() expect(b.next()).toBe(0n) }) it('recv: in-order 0,1,2 accepted; lastAccepted tracks', () => { const g = new SequenceGuard('recv') g.accept(0n) g.accept(1n) g.accept(2n) expect(g.lastAccepted).toBe(2n) }) it('recv: replay of an accepted seq → ReplayError', () => { const g = new SequenceGuard('recv') g.accept(0n) expect(() => g.accept(0n)).toThrow(ReplayError) }) it('recv: reorder / gap / rewind all → ReplayError', () => { const g1 = new SequenceGuard('recv') expect(() => g1.accept(2n)).toThrow(ReplayError) // gap from start const g2 = new SequenceGuard('recv') g2.accept(0n) expect(() => g2.accept(2n)).toThrow(ReplayError) // reorder/gap const g3 = new SequenceGuard('recv') g3.accept(0n) g3.accept(1n) g3.accept(2n) g3.accept(3n) g3.accept(4n) expect(() => g3.accept(3n)).toThrow(ReplayError) // rewind (5 then 4-style) }) it('bigint boundary: accepts near-u64-max without float error', () => { const g = new SequenceGuard('recv') // seed just below the boundary by direct successor stepping is impractical; assert range guard. expect(() => g.accept(-1n)).toThrow(ReplayError) expect(() => g.accept(2n ** 64n)).toThrow(ReplayError) }) it('role misuse is rejected', () => { expect(() => new SequenceGuard('recv').next()).toThrow(ReplayError) expect(() => new SequenceGuard('send').accept(0n)).toThrow(ReplayError) }) })