import { BenchmarkMeasurement, benchmarkSummaryHeader, benchmarkSummaryRow, budgetViolations, } from './leave-planner-benchmark'; const measure = (scenario: string, planningMs: number) => ({ scenario, planningMs }) as BenchmarkMeasurement; describe('benchmark budget gate', () => { const multipliers = { a: 2 }; it('accepts a mean within multiplier x calibration', () => { expect(budgetViolations([measure('a', 150), measure('a', 250)], 100, multipliers)).toEqual( [], ); }); it('reports measured time, budget, multiplier and calibration when over budget', () => { const [message] = budgetViolations( [measure('a', 300), measure('a', 320)], 100, multipliers, ); expect(message).toContain('a:'); expect(message).toContain('measured 310.0 ms'); expect(message).toContain('budget 200.0 ms'); expect(message).toContain('multiplier 2'); expect(message).toContain('calibration 100.0 ms'); }); it('fails a scenario without a multiplier', () => { expect(budgetViolations([measure('new', 1)], 100, multipliers)).toEqual([ 'new: no budget multiplier defined', ]); }); }); describe('benchmark summary table', () => { const runs = (planningMs: number[]) => planningMs.map( (ms, index) => ({ scenario: 'a', planningMs: ms, outcome: 'Plan', lastCompletedStage: 'dates', placements: 3, deterministic: index ? 'yes' : 'baseline', }) as BenchmarkMeasurement, ); it('aligns rows with the header', () => { const [header, separator] = benchmarkSummaryHeader().split('\n'); const row = benchmarkSummaryRow(runs([150, 250]), 100, { a: 2 }); expect(row).toHaveLength(header.length); expect(separator).toHaveLength(header.length); expect(row).toContain('0.15 / 0.25 s'); expect(row).toContain('Plan (dates)'); expect(row).toMatch(/\| ok +\|$/); }); it('marks scenarios over budget or without a budget', () => { expect(benchmarkSummaryRow(runs([300, 320]), 100, { a: 2 })).toMatch(/\| OVER +\|$/); expect(benchmarkSummaryRow(runs([1]), 100, {})).toMatch(/\| no budget \|$/); }); });