/** * Unit tests for shared composite variant validation. */ import { describe, it, expect } from 'bun:test'; import { validateCompositeDefaultTier, validateCompositeTiers, } from '../../../src/cliproxy/composite-validator'; const validTier = { provider: 'agy', model: 'claude-sonnet-4-6', }; describe('validateCompositeDefaultTier', () => { it('accepts valid tier names', () => { expect(validateCompositeDefaultTier('opus')).toBeNull(); expect(validateCompositeDefaultTier('sonnet')).toBeNull(); expect(validateCompositeDefaultTier('haiku')).toBeNull(); }); it('rejects invalid tier names', () => { const error = validateCompositeDefaultTier('invalid-tier'); expect(error).toContain("Invalid default_tier 'invalid-tier'"); }); }); describe('validateCompositeTiers', () => { it('rejects missing required tiers in create mode', () => { const error = validateCompositeTiers( { opus: validTier, sonnet: validTier, }, { defaultTier: 'sonnet', requireAllTiers: true } ); expect(error).toContain("Missing required tier 'haiku'"); }); it('rejects null tier objects', () => { const error = validateCompositeTiers( { opus: null, sonnet: validTier, haiku: validTier, }, { defaultTier: 'sonnet', requireAllTiers: true } ); expect(error).toContain("Invalid tier config for 'opus'"); }); it('accepts partial updates in update mode', () => { const error = validateCompositeTiers( { opus: { provider: 'gemini', model: 'gemini-2.5-pro' }, }, { defaultTier: 'sonnet' } ); expect(error).toBeNull(); }); it('rejects circular fallback definitions', () => { const error = validateCompositeTiers( { opus: { provider: 'gemini', model: 'gemini-2.5-pro', fallback: { provider: 'gemini', model: 'gemini-2.5-pro' }, }, }, { defaultTier: 'opus' } ); expect(error).toContain("Circular fallback in tier 'opus'"); }); it('rejects denylisted agy 4.5 models', () => { const error = validateCompositeTiers( { opus: { provider: 'agy', model: 'claude-opus-4.5-thinking' }, sonnet: { provider: 'gemini', model: 'gemini-2.5-pro' }, haiku: { provider: 'gemini', model: 'gemini-2.5-flash' }, }, { defaultTier: 'opus', requireAllTiers: true } ); expect(error).toContain('denylist'); }); });