mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-27 03:37:27 -07:00
140 lines
4.2 KiB
TypeScript
140 lines
4.2 KiB
TypeScript
|
|
/**
|
||
|
|
* @license
|
||
|
|
* Copyright 2026 Google LLC
|
||
|
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { describe, expect, it } from 'vitest';
|
||
|
|
import {
|
||
|
|
buildToolRegistry,
|
||
|
|
resolveToolName,
|
||
|
|
getToolsByCategory,
|
||
|
|
type ToolCategory,
|
||
|
|
} from '../utils/tool-registry.js';
|
||
|
|
|
||
|
|
describe('tool-registry', () => {
|
||
|
|
const registry = buildToolRegistry();
|
||
|
|
|
||
|
|
describe('buildToolRegistry', () => {
|
||
|
|
it('includes all canonical built-in tools', () => {
|
||
|
|
expect(registry.totalTools).toBeGreaterThanOrEqual(26);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('every tool has a valid category', () => {
|
||
|
|
for (const [name, entry] of registry.tools) {
|
||
|
|
expect(entry.category).toBeTruthy();
|
||
|
|
expect(entry.name).toBe(name);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('byCategory entries match tools map', () => {
|
||
|
|
let categoryTotal = 0;
|
||
|
|
for (const [, entries] of registry.byCategory) {
|
||
|
|
for (const entry of entries) {
|
||
|
|
expect(registry.tools.get(entry.name)).toBe(entry);
|
||
|
|
}
|
||
|
|
categoryTotal += entries.length;
|
||
|
|
}
|
||
|
|
expect(categoryTotal).toBe(registry.totalTools);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('aliasLookup covers every canonical name', () => {
|
||
|
|
for (const name of registry.tools.keys()) {
|
||
|
|
expect(registry.aliasLookup.get(name)).toBe(name);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('aliasLookup covers every legacy alias', () => {
|
||
|
|
for (const [, entry] of registry.tools) {
|
||
|
|
for (const alias of entry.aliases) {
|
||
|
|
expect(registry.aliasLookup.get(alias)).toBe(entry.name);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it('is deterministic across calls', () => {
|
||
|
|
const second = buildToolRegistry();
|
||
|
|
expect([...second.tools.keys()]).toEqual([...registry.tools.keys()]);
|
||
|
|
expect(second.totalTools).toBe(registry.totalTools);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('resolveToolName', () => {
|
||
|
|
it('resolves canonical names to themselves', () => {
|
||
|
|
expect(resolveToolName(registry, 'grep_search')).toBe('grep_search');
|
||
|
|
expect(resolveToolName(registry, 'run_shell_command')).toBe(
|
||
|
|
'run_shell_command',
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('resolves legacy alias to canonical name', () => {
|
||
|
|
expect(resolveToolName(registry, 'search_file_content')).toBe(
|
||
|
|
'grep_search',
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('returns undefined for unknown tool names', () => {
|
||
|
|
expect(resolveToolName(registry, 'nonexistent_tool')).toBeUndefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('returns undefined for empty string', () => {
|
||
|
|
expect(resolveToolName(registry, '')).toBeUndefined();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('getToolsByCategory', () => {
|
||
|
|
it('returns file-system tools', () => {
|
||
|
|
const tools = getToolsByCategory(registry, 'file-system');
|
||
|
|
const names = tools.map((t) => t.name);
|
||
|
|
expect(names).toContain('glob');
|
||
|
|
expect(names).toContain('grep_search');
|
||
|
|
expect(names).toContain('read_file');
|
||
|
|
expect(names).toContain('write_file');
|
||
|
|
expect(names).toContain('replace');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('returns task-tracker tools', () => {
|
||
|
|
const tools = getToolsByCategory(registry, 'task-tracker');
|
||
|
|
const names = tools.map((t) => t.name);
|
||
|
|
expect(names).toContain('tracker_create_task');
|
||
|
|
expect(names).toContain('tracker_update_task');
|
||
|
|
expect(names).toContain('tracker_get_task');
|
||
|
|
expect(names).toContain('tracker_list_tasks');
|
||
|
|
expect(names).toContain('tracker_add_dependency');
|
||
|
|
expect(names).toContain('tracker_visualize');
|
||
|
|
expect(names).toHaveLength(6);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('returns agent tools', () => {
|
||
|
|
const tools = getToolsByCategory(registry, 'agent');
|
||
|
|
const names = tools.map((t) => t.name);
|
||
|
|
expect(names).toContain('invoke_agent');
|
||
|
|
expect(names).toContain('complete_task');
|
||
|
|
expect(names).toContain('update_topic');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('returns empty array for unknown category', () => {
|
||
|
|
expect(
|
||
|
|
getToolsByCategory(registry, 'nonexistent' as ToolCategory),
|
||
|
|
).toEqual([]);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('every defined category has at least one tool', () => {
|
||
|
|
const expectedCategories: ToolCategory[] = [
|
||
|
|
'file-system',
|
||
|
|
'shell',
|
||
|
|
'web',
|
||
|
|
'planning',
|
||
|
|
'user-interaction',
|
||
|
|
'skills',
|
||
|
|
'task-tracker',
|
||
|
|
'agent',
|
||
|
|
'mcp',
|
||
|
|
];
|
||
|
|
for (const cat of expectedCategories) {
|
||
|
|
expect(getToolsByCategory(registry, cat).length).toBeGreaterThan(0);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|