test: 补充单元测试提升代码覆盖率
新增测试文件: - agent/executor-extended.test.ts, presets/ - context/manager-extended.test.ts - core/agent.test.ts, providers.test.ts - lsp/cli.test.ts, client-extended.test.ts, index.test.ts - permission/file-prompt.test.ts, prompt.test.ts - skills/builtin/ - tools/filesystem/write_file-extended.test.ts - tools/git/git_commit-extended.test.ts - tools/load_description.test.ts - tools/todo/todo-manager.test.ts - tools/tool-search.test.ts - types/ - utils/config-extended.test.ts, diff-extended.test.ts 修改现有测试: - agent/manager.test.ts - tools/skill/skill.test.ts - utils/config.test.ts, diff.test.ts, image.test.ts
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { todoManager } from '../../../../src/tools/todo/todo-manager.js';
|
||||
import type { SessionManager } from '../../../../src/session/index.js';
|
||||
import type { Todo } from '../../../../src/session/types.js';
|
||||
|
||||
describe('TodoManager', () => {
|
||||
let mockSessionManager: SessionManager;
|
||||
let mockTodos: Todo[];
|
||||
|
||||
beforeEach(() => {
|
||||
mockTodos = [];
|
||||
mockSessionManager = {
|
||||
getTodos: vi.fn(() => mockTodos),
|
||||
setTodos: vi.fn(async (todos: Todo[]) => {
|
||||
mockTodos = todos;
|
||||
}),
|
||||
} as unknown as SessionManager;
|
||||
|
||||
// 重置 todoManager 状态
|
||||
todoManager.setSessionManager(mockSessionManager);
|
||||
});
|
||||
|
||||
describe('setSessionManager', () => {
|
||||
it('设置会话管理器后 isInitialized 返回 true', () => {
|
||||
const freshManager = {
|
||||
getTodos: vi.fn(() => []),
|
||||
setTodos: vi.fn(),
|
||||
} as unknown as SessionManager;
|
||||
|
||||
todoManager.setSessionManager(freshManager);
|
||||
expect(todoManager.isInitialized()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTodos', () => {
|
||||
it('返回空数组当没有 todo', () => {
|
||||
const todos = todoManager.getTodos();
|
||||
expect(todos).toEqual([]);
|
||||
});
|
||||
|
||||
it('返回现有的 todo 列表', () => {
|
||||
mockTodos = [
|
||||
{ id: '1', content: 'Task 1', status: 'pending', createdAt: '', updatedAt: '' },
|
||||
{ id: '2', content: 'Task 2', status: 'completed', createdAt: '', updatedAt: '' },
|
||||
];
|
||||
|
||||
const todos = todoManager.getTodos();
|
||||
expect(todos).toHaveLength(2);
|
||||
expect(todos[0].content).toBe('Task 1');
|
||||
expect(todos[1].content).toBe('Task 2');
|
||||
});
|
||||
|
||||
it('正确调用 sessionManager.getTodos', () => {
|
||||
todoManager.getTodos();
|
||||
expect(mockSessionManager.getTodos).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('setTodos', () => {
|
||||
it('更新 todo 列表', async () => {
|
||||
const newTodos: Todo[] = [
|
||||
{ id: '1', content: 'New Task', status: 'pending', createdAt: '', updatedAt: '' },
|
||||
];
|
||||
|
||||
await todoManager.setTodos(newTodos);
|
||||
|
||||
expect(mockSessionManager.setTodos).toHaveBeenCalledWith(newTodos);
|
||||
expect(mockTodos).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('可以设置空列表', async () => {
|
||||
mockTodos = [
|
||||
{ id: '1', content: 'Task', status: 'pending', createdAt: '', updatedAt: '' },
|
||||
];
|
||||
|
||||
await todoManager.setTodos([]);
|
||||
|
||||
expect(mockTodos).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addTodo', () => {
|
||||
it('添加新的 todo(默认状态 pending)', async () => {
|
||||
const todo = await todoManager.addTodo('新任务');
|
||||
|
||||
expect(todo.content).toBe('新任务');
|
||||
expect(todo.status).toBe('pending');
|
||||
expect(todo.id).toBeDefined();
|
||||
expect(todo.createdAt).toBeDefined();
|
||||
expect(todo.updatedAt).toBeDefined();
|
||||
expect(mockTodos).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('添加指定状态的 todo', async () => {
|
||||
const todo = await todoManager.addTodo('进行中的任务', 'in_progress');
|
||||
|
||||
expect(todo.content).toBe('进行中的任务');
|
||||
expect(todo.status).toBe('in_progress');
|
||||
});
|
||||
|
||||
it('添加已完成状态的 todo', async () => {
|
||||
const todo = await todoManager.addTodo('已完成任务', 'completed');
|
||||
|
||||
expect(todo.status).toBe('completed');
|
||||
});
|
||||
|
||||
it('生成唯一 ID', async () => {
|
||||
const todo1 = await todoManager.addTodo('Task 1');
|
||||
const todo2 = await todoManager.addTodo('Task 2');
|
||||
|
||||
expect(todo1.id).not.toBe(todo2.id);
|
||||
});
|
||||
|
||||
it('追加到现有列表', async () => {
|
||||
mockTodos = [
|
||||
{ id: 'existing', content: 'Existing', status: 'pending', createdAt: '', updatedAt: '' },
|
||||
];
|
||||
|
||||
await todoManager.addTodo('New Task');
|
||||
|
||||
expect(mockTodos).toHaveLength(2);
|
||||
expect(mockTodos[0].content).toBe('Existing');
|
||||
expect(mockTodos[1].content).toBe('New Task');
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateTodoStatus', () => {
|
||||
beforeEach(() => {
|
||||
mockTodos = [
|
||||
{ id: 'todo-1', content: 'Task 1', status: 'pending', createdAt: '2024-01-01', updatedAt: '2024-01-01' },
|
||||
{ id: 'todo-2', content: 'Task 2', status: 'pending', createdAt: '2024-01-01', updatedAt: '2024-01-01' },
|
||||
];
|
||||
});
|
||||
|
||||
it('更新存在的 todo 状态', async () => {
|
||||
const result = await todoManager.updateTodoStatus('todo-1', 'completed');
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(mockTodos[0].status).toBe('completed');
|
||||
});
|
||||
|
||||
it('更新 updatedAt 时间戳', async () => {
|
||||
const originalUpdatedAt = mockTodos[0].updatedAt;
|
||||
|
||||
await todoManager.updateTodoStatus('todo-1', 'in_progress');
|
||||
|
||||
expect(mockTodos[0].updatedAt).not.toBe(originalUpdatedAt);
|
||||
});
|
||||
|
||||
it('不存在的 todo 返回 false', async () => {
|
||||
const result = await todoManager.updateTodoStatus('non-existent', 'completed');
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('可以更新为任意状态', async () => {
|
||||
await todoManager.updateTodoStatus('todo-1', 'in_progress');
|
||||
expect(mockTodos[0].status).toBe('in_progress');
|
||||
|
||||
await todoManager.updateTodoStatus('todo-1', 'completed');
|
||||
expect(mockTodos[0].status).toBe('completed');
|
||||
|
||||
await todoManager.updateTodoStatus('todo-1', 'pending');
|
||||
expect(mockTodos[0].status).toBe('pending');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteTodo', () => {
|
||||
beforeEach(() => {
|
||||
mockTodos = [
|
||||
{ id: 'todo-1', content: 'Task 1', status: 'pending', createdAt: '', updatedAt: '' },
|
||||
{ id: 'todo-2', content: 'Task 2', status: 'completed', createdAt: '', updatedAt: '' },
|
||||
{ id: 'todo-3', content: 'Task 3', status: 'in_progress', createdAt: '', updatedAt: '' },
|
||||
];
|
||||
});
|
||||
|
||||
it('删除存在的 todo', async () => {
|
||||
const result = await todoManager.deleteTodo('todo-2');
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(mockTodos).toHaveLength(2);
|
||||
expect(mockTodos.find(t => t.id === 'todo-2')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('删除第一个 todo', async () => {
|
||||
const result = await todoManager.deleteTodo('todo-1');
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(mockTodos[0].id).toBe('todo-2');
|
||||
});
|
||||
|
||||
it('删除最后一个 todo', async () => {
|
||||
const result = await todoManager.deleteTodo('todo-3');
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(mockTodos).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('不存在的 todo 返回 false', async () => {
|
||||
const result = await todoManager.deleteTodo('non-existent');
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(mockTodos).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('删除后其他 todo 保持不变', async () => {
|
||||
await todoManager.deleteTodo('todo-2');
|
||||
|
||||
expect(mockTodos[0].content).toBe('Task 1');
|
||||
expect(mockTodos[1].content).toBe('Task 3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('clearTodos', () => {
|
||||
it('清空所有 todo', async () => {
|
||||
mockTodos = [
|
||||
{ id: '1', content: 'Task 1', status: 'pending', createdAt: '', updatedAt: '' },
|
||||
{ id: '2', content: 'Task 2', status: 'completed', createdAt: '', updatedAt: '' },
|
||||
];
|
||||
|
||||
await todoManager.clearTodos();
|
||||
|
||||
expect(mockTodos).toHaveLength(0);
|
||||
expect(mockSessionManager.setTodos).toHaveBeenCalledWith([]);
|
||||
});
|
||||
|
||||
it('空列表时调用也不报错', async () => {
|
||||
mockTodos = [];
|
||||
|
||||
await expect(todoManager.clearTodos()).resolves.not.toThrow();
|
||||
expect(mockTodos).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isInitialized', () => {
|
||||
it('初始化后返回 true', () => {
|
||||
expect(todoManager.isInitialized()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('边界情况', () => {
|
||||
it('处理包含特殊字符的 content', async () => {
|
||||
const specialContent = '任务: "测试" & <script>alert(1)</script>';
|
||||
const todo = await todoManager.addTodo(specialContent);
|
||||
|
||||
expect(todo.content).toBe(specialContent);
|
||||
});
|
||||
|
||||
it('处理非常长的 content', async () => {
|
||||
const longContent = 'A'.repeat(10000);
|
||||
const todo = await todoManager.addTodo(longContent);
|
||||
|
||||
expect(todo.content).toBe(longContent);
|
||||
});
|
||||
|
||||
it('处理空字符串 content', async () => {
|
||||
const todo = await todoManager.addTodo('');
|
||||
|
||||
expect(todo.content).toBe('');
|
||||
});
|
||||
|
||||
it('连续操作保持数据一致性', async () => {
|
||||
await todoManager.addTodo('Task 1');
|
||||
await todoManager.addTodo('Task 2');
|
||||
await todoManager.updateTodoStatus(mockTodos[0].id, 'completed');
|
||||
await todoManager.deleteTodo(mockTodos[1].id);
|
||||
await todoManager.addTodo('Task 3');
|
||||
|
||||
expect(mockTodos).toHaveLength(2);
|
||||
expect(mockTodos[0].status).toBe('completed');
|
||||
expect(mockTodos[1].content).toBe('Task 3');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user