import { describe, it, expect, vi, beforeEach } from 'vitest'; // Mock fs vi.mock('fs', () => ({ readFileSync: vi.fn(), })); import * as fs from 'fs'; import { loadDescription } from '../../../src/tools/load_description.js'; describe('loadDescription', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('带分类的工具', () => { it('加载 shell 类工具描述', () => { vi.mocked(fs.readFileSync).mockReturnValue(' Bash 工具描述 '); const result = loadDescription('bash'); expect(result).toBe('Bash 工具描述'); expect(fs.readFileSync).toHaveBeenCalledWith( expect.stringContaining('descriptions/shell/bash.txt'), 'utf-8' ); }); it('加载 filesystem 类工具描述', () => { vi.mocked(fs.readFileSync).mockReturnValue('读取文件描述'); const result = loadDescription('read_file'); expect(result).toBe('读取文件描述'); expect(fs.readFileSync).toHaveBeenCalledWith( expect.stringContaining('descriptions/filesystem/read_file.txt'), 'utf-8' ); }); it('加载 write_file 描述', () => { vi.mocked(fs.readFileSync).mockReturnValue('写入文件描述'); loadDescription('write_file'); expect(fs.readFileSync).toHaveBeenCalledWith( expect.stringContaining('descriptions/filesystem/write_file.txt'), 'utf-8' ); }); it('加载 edit_file 描述', () => { vi.mocked(fs.readFileSync).mockReturnValue('编辑文件描述'); loadDescription('edit_file'); expect(fs.readFileSync).toHaveBeenCalledWith( expect.stringContaining('descriptions/filesystem/edit_file.txt'), 'utf-8' ); }); it('加载 git 类工具描述', () => { vi.mocked(fs.readFileSync).mockReturnValue('Git status 描述'); loadDescription('git_status'); expect(fs.readFileSync).toHaveBeenCalledWith( expect.stringContaining('descriptions/git/git_status.txt'), 'utf-8' ); }); it('加载 web 类工具描述', () => { vi.mocked(fs.readFileSync).mockReturnValue('Web search 描述'); loadDescription('web_search'); expect(fs.readFileSync).toHaveBeenCalledWith( expect.stringContaining('descriptions/web/web_search.txt'), 'utf-8' ); }); it('加载 todo 类工具描述', () => { vi.mocked(fs.readFileSync).mockReturnValue('Todo read 描述'); loadDescription('todo_read'); expect(fs.readFileSync).toHaveBeenCalledWith( expect.stringContaining('descriptions/todo/todo_read.txt'), 'utf-8' ); }); }); describe('不带分类的工具', () => { it('未知工具使用根目录', () => { vi.mocked(fs.readFileSync).mockReturnValue('未知工具描述'); loadDescription('unknown_tool'); expect(fs.readFileSync).toHaveBeenCalledWith( expect.stringContaining('descriptions/unknown_tool.txt'), 'utf-8' ); // 确保不包含子目录 expect(fs.readFileSync).not.toHaveBeenCalledWith( expect.stringContaining('descriptions/filesystem/unknown_tool.txt'), 'utf-8' ); }); }); describe('错误处理', () => { it('文件不存在时抛出错误', () => { vi.mocked(fs.readFileSync).mockImplementation(() => { throw new Error('ENOENT'); }); expect(() => loadDescription('nonexistent')).toThrow('无法加载工具描述文件'); }); it('错误信息包含文件路径', () => { vi.mocked(fs.readFileSync).mockImplementation(() => { throw new Error('ENOENT'); }); expect(() => loadDescription('some_tool')).toThrow('some_tool.txt'); }); }); describe('内容处理', () => { it('去除前后空白', () => { vi.mocked(fs.readFileSync).mockReturnValue('\n\n 内容 \n\n'); const result = loadDescription('bash'); expect(result).toBe('内容'); }); it('保留中间空白', () => { vi.mocked(fs.readFileSync).mockReturnValue('第一行\n第二行\n第三行'); const result = loadDescription('bash'); expect(result).toBe('第一行\n第二行\n第三行'); }); it('空文件返回空字符串', () => { vi.mocked(fs.readFileSync).mockReturnValue(' '); const result = loadDescription('bash'); expect(result).toBe(''); }); }); describe('所有映射的工具', () => { const toolCategories = [ // shell { tool: 'bash', category: 'shell' }, // filesystem { tool: 'read_file', category: 'filesystem' }, { tool: 'write_file', category: 'filesystem' }, { tool: 'edit_file', category: 'filesystem' }, { tool: 'list_directory', category: 'filesystem' }, { tool: 'create_directory', category: 'filesystem' }, { tool: 'search_files', category: 'filesystem' }, { tool: 'grep_content', category: 'filesystem' }, { tool: 'get_file_info', category: 'filesystem' }, { tool: 'move_file', category: 'filesystem' }, { tool: 'copy_file', category: 'filesystem' }, { tool: 'delete_file', category: 'filesystem' }, // web { tool: 'web_search', category: 'web' }, { tool: 'web_extract', category: 'web' }, // git { tool: 'git_status', category: 'git' }, { tool: 'git_diff', category: 'git' }, { tool: 'git_log', category: 'git' }, { tool: 'git_branch', category: 'git' }, { tool: 'git_add', category: 'git' }, { tool: 'git_commit', category: 'git' }, { tool: 'git_push', category: 'git' }, { tool: 'git_pull', category: 'git' }, { tool: 'git_checkout', category: 'git' }, { tool: 'git_stash', category: 'git' }, // todo { tool: 'todo_read', category: 'todo' }, { tool: 'todo_write', category: 'todo' }, ]; it.each(toolCategories)('$tool 映射到 $category 目录', ({ tool, category }) => { vi.mocked(fs.readFileSync).mockReturnValue('描述'); loadDescription(tool); expect(fs.readFileSync).toHaveBeenCalledWith( expect.stringContaining(`descriptions/${category}/${tool}.txt`), 'utf-8' ); }); }); });