import * as assert from 'assert'; import * as vscode from 'vscode'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { getProviders, invalidateProviderCache, getProviderById, getAllProviderMeta } from '../src/ai/registry'; import type { ProviderConfig } from '../src/ai/types'; function cfg(overrides: Partial): ProviderConfig { return { id: 'x', name: 'X', protocol: 'openai-compatible', defaultBaseUrl: 'https://api.x.test/v1', models: ['m1'], ...overrides, }; } function writeTempProviders(providers: ProviderConfig[]): string { const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'reg-test-')); fs.writeFileSync(path.join(dir, 'providers.json'), JSON.stringify({ providers }), 'utf8'); return dir; } suite('Provider Registry Tests', () => { setup(() => invalidateProviderCache()); test('returns empty when no extension uri', () => { assert.deepStrictEqual(getProviders(), []); }); test('loads builtin providers from extension providers.json', () => { const dir = writeTempProviders([cfg({ id: 'a', name: 'A' })]); const uri = vscode.Uri.file(dir); const providers = getProviders(uri); assert.strictEqual(providers.length, 1); assert.strictEqual(providers[0].id, 'a'); fs.rmSync(dir, { recursive: true, force: true }); }); test('caches providers across calls', () => { const dir = writeTempProviders([cfg({ id: 'b', name: 'B' })]); const uri = vscode.Uri.file(dir); const first = getProviders(uri); fs.rmSync(dir, { recursive: true, force: true }); const second = getProviders(uri); assert.strictEqual(second, first); }); test('invalidateProviderCache forces reload', () => { const dir = writeTempProviders([cfg({ id: 'c', name: 'C' })]); const uri = vscode.Uri.file(dir); getProviders(uri); invalidateProviderCache(); assert.strictEqual(getProviders(uri).length, 1); fs.rmSync(dir, { recursive: true, force: true }); }); test('returns empty for missing or invalid providers.json', () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'reg-test2-')); const uri = vscode.Uri.file(dir); assert.deepStrictEqual(getProviders(uri), []); fs.writeFileSync(path.join(dir, 'providers.json'), 'not json', 'utf8'); invalidateProviderCache(); assert.deepStrictEqual(getProviders(uri), []); fs.rmSync(dir, { recursive: true, force: true }); }); test('getProviderById finds or misses', () => { const dir = writeTempProviders([cfg({ id: 'x', name: 'X', models: ['m'] })]); const uri = vscode.Uri.file(dir); assert.strictEqual(getProviderById(uri, 'x')?.name, 'X'); assert.strictEqual(getProviderById(uri, 'nope'), undefined); fs.rmSync(dir, { recursive: true, force: true }); }); test('getAllProviderMeta returns name and models', () => { const dir = writeTempProviders([cfg({ id: 'p1', name: 'P1', models: ['a', 'b'] })]); const uri = vscode.Uri.file(dir); const meta = getAllProviderMeta(uri); assert.deepStrictEqual(meta.p1, { name: 'P1', models: ['a', 'b'] }); fs.rmSync(dir, { recursive: true, force: true }); }); });