import { describe, expect, it } from 'bun:test'; import { buildProviderAliasMap, CLIPROXY_PROVIDER_IDS, getOAuthCallbackPort, getOAuthFlowType, PROVIDER_CAPABILITIES, getProviderDisplayName, getProvidersByOAuthFlow, isCLIProxyProvider, mapExternalProviderName, QUOTA_SUPPORTED_PROVIDER_IDS, isQuotaSupportedProvider, QUOTA_PROVIDER_OPTION_VALUES, QUOTA_PROVIDER_HELP_TEXT, } from '../../../src/cliproxy/provider-capabilities'; import { OAUTH_CALLBACK_PORTS as DIAGNOSTIC_CALLBACK_PORTS, OAUTH_FLOW_TYPES, } from '../../../src/management/oauth-port-diagnostics'; import { DEFAULT_KIRO_AUTH_METHOD, getKiroCallbackPort, getKiroCLIAuthArgs, getKiroCLIAuthFlag, normalizeKiroIDCFlow, normalizeKiroAuthMethod, OAUTH_CALLBACK_PORTS as AUTH_CALLBACK_PORTS, toKiroManagementMethod, } from '../../../src/cliproxy/auth/auth-types'; describe('provider-capabilities', () => { it('keeps canonical provider IDs backward-compatible', () => { expect(CLIPROXY_PROVIDER_IDS).toEqual([ 'gemini', 'codex', 'agy', 'qwen', 'iflow', 'kiro', 'ghcp', 'claude', 'kimi', ]); }); it('validates provider IDs', () => { expect(isCLIProxyProvider('gemini')).toBe(true); expect(isCLIProxyProvider('ghcp')).toBe(true); expect(isCLIProxyProvider('not-a-provider')).toBe(false); expect(isCLIProxyProvider('Gemini')).toBe(false); }); it('returns providers by OAuth flow capability', () => { expect(getProvidersByOAuthFlow('device_code')).toEqual(['qwen', 'kiro', 'ghcp', 'kimi']); expect(getProvidersByOAuthFlow('authorization_code')).toEqual([ 'gemini', 'codex', 'agy', 'iflow', 'claude', ]); }); it('maps external provider aliases to canonical IDs', () => { expect(mapExternalProviderName('gemini-cli')).toBe('gemini'); expect(mapExternalProviderName('antigravity')).toBe('agy'); expect(mapExternalProviderName('codewhisperer')).toBe('kiro'); expect(mapExternalProviderName('github-copilot')).toBe('ghcp'); expect(mapExternalProviderName('copilot')).toBe('ghcp'); expect(mapExternalProviderName('anthropic')).toBe('claude'); expect(mapExternalProviderName(' COPILOT ')).toBe('ghcp'); expect(mapExternalProviderName('')).toBeNull(); expect(mapExternalProviderName('unknown-provider')).toBeNull(); }); it('exposes quota-supported providers and guards correctly', () => { expect(QUOTA_SUPPORTED_PROVIDER_IDS).toEqual(['agy', 'codex', 'claude', 'gemini', 'ghcp']); expect(QUOTA_PROVIDER_OPTION_VALUES).toEqual([ 'agy', 'codex', 'claude', 'gemini', 'ghcp', 'antigravity', 'anthropic', 'gemini-cli', 'github-copilot', 'copilot', 'all', ]); expect(QUOTA_PROVIDER_HELP_TEXT).toBe( 'agy, codex, claude, gemini, ghcp, antigravity, anthropic, gemini-cli, github-copilot, copilot, all' ); expect(isQuotaSupportedProvider('ghcp')).toBe(true); expect(isQuotaSupportedProvider('kiro')).toBe(false); }); it('exposes callback port and display name capabilities', () => { expect(getOAuthCallbackPort('qwen')).toBeNull(); expect(getOAuthCallbackPort('kiro')).toBeNull(); expect(getOAuthCallbackPort('gemini')).toBe(8085); expect(getProviderDisplayName('agy')).toBe('Antigravity'); }); it('throws when provider aliases collide across providers', () => { const capabilitiesWithCollision = { ...PROVIDER_CAPABILITIES, gemini: { ...PROVIDER_CAPABILITIES.gemini, aliases: ['shared-alias'], }, codex: { ...PROVIDER_CAPABILITIES.codex, aliases: ['shared-alias'], }, }; expect(() => buildProviderAliasMap(capabilitiesWithCollision as typeof PROVIDER_CAPABILITIES) ).toThrow(/shared-alias/i); }); it('keeps diagnostics flow metadata in sync with provider capabilities', () => { for (const provider of CLIPROXY_PROVIDER_IDS) { expect(OAUTH_FLOW_TYPES[provider]).toBe(getOAuthFlowType(provider)); expect(DIAGNOSTIC_CALLBACK_PORTS[provider]).toBe(getOAuthCallbackPort(provider)); } }); it('does not define callback ports for device code providers in auth constants', () => { for (const provider of getProvidersByOAuthFlow('device_code')) { expect(AUTH_CALLBACK_PORTS[provider]).toBeUndefined(); } }); it('maps Kiro auth methods to upstream CLI/management contracts', () => { expect(DEFAULT_KIRO_AUTH_METHOD).toBe('aws'); expect(normalizeKiroAuthMethod()).toBe('aws'); expect(normalizeKiroAuthMethod('GOOGLE')).toBe('google'); expect(normalizeKiroAuthMethod('IDC')).toBe('idc'); expect(normalizeKiroAuthMethod('not-valid')).toBe('aws'); expect(normalizeKiroIDCFlow()).toBe('authcode'); expect(normalizeKiroIDCFlow('DEVICE')).toBe('device'); expect(getKiroCLIAuthFlag('aws')).toBe('--kiro-aws-login'); expect(getKiroCLIAuthFlag('aws-authcode')).toBe('--kiro-aws-authcode'); expect(getKiroCLIAuthFlag('google')).toBe('--kiro-google-login'); expect(getKiroCLIAuthFlag('idc')).toBe('--kiro-idc-login'); expect(getKiroCLIAuthArgs('idc', { idcStartUrl: 'https://d-123.awsapps.com/start' })).toEqual( ['--kiro-idc-login', '--kiro-idc-start-url', 'https://d-123.awsapps.com/start', '--kiro-idc-flow', 'authcode'] ); expect(getKiroCallbackPort('aws')).toBeNull(); expect(getKiroCallbackPort('google')).toBe(9876); expect(getKiroCallbackPort('github')).toBe(9876); expect(getKiroCallbackPort('aws-authcode')).toBe(9876); expect(getKiroCallbackPort('idc')).toBe(9876); expect(getKiroCallbackPort('idc', { idcFlow: 'device' })).toBeNull(); expect(toKiroManagementMethod('aws')).toBe('aws'); expect(toKiroManagementMethod('aws-authcode')).toBe('aws'); expect(toKiroManagementMethod('google')).toBe('google'); expect(toKiroManagementMethod('github')).toBe('github'); expect(toKiroManagementMethod('idc')).toBeNull(); }); });