feat: 添加完整的单元测试套件

- 新增 vitest 测试框架配置
- 添加 54 个测试文件,共 951 个测试用例
- 覆盖核心模块:
  - Agent: executor, registry, config-loader, permission-merger
  - Context: manager, compaction, prune, token-counter
  - Permission: manager, bash/file/git/web checkers, wildcard
  - Session: manager, storage
  - Tools: filesystem (12个), git (10个), web, shell, todo, task
  - LSP: client, server, language
  - Utils: config, diff
  - UI: terminal
This commit is contained in:
2025-12-11 14:45:24 +08:00
parent f4df6483a6
commit 729fb2d42a
58 changed files with 14320 additions and 3 deletions
+163
View File
@@ -0,0 +1,163 @@
import { describe, it, expect } from 'vitest';
import { parseCommandSimple } from '../../../src/permission/bash-parser.js';
// 注意:parseBashCommand 需要初始化 tree-sitter wasm,在单元测试中使用 parseCommandSimple
describe('parseCommandSimple - 简单命令解析', () => {
describe('基本命令解析', () => {
it('解析单个命令', () => {
const result = parseCommandSimple('ls');
expect(result.name).toBe('ls');
expect(result.subcommand).toBeUndefined();
expect(result.args).toEqual([]);
expect(result.text).toBe('ls');
});
it('解析带子命令的命令', () => {
const result = parseCommandSimple('git status');
expect(result.name).toBe('git');
expect(result.subcommand).toBe('status');
expect(result.args).toEqual([]);
});
it('解析带参数的命令', () => {
const result = parseCommandSimple('git commit -m "message"');
expect(result.name).toBe('git');
expect(result.subcommand).toBe('commit');
expect(result.args).toContain('-m');
});
it('解析带 flag 前缀的子命令', () => {
const result = parseCommandSimple('rm -rf node_modules');
expect(result.name).toBe('rm');
// -rf 以 - 开头,所以 node_modules 是第一个非 flag 参数
expect(result.subcommand).toBe('node_modules');
expect(result.args).toContain('-rf');
});
});
describe('flag 和参数分离', () => {
it('短 flag 放入 args', () => {
const result = parseCommandSimple('ls -la');
expect(result.name).toBe('ls');
expect(result.subcommand).toBeUndefined();
expect(result.args).toContain('-la');
});
it('长 flag 放入 args', () => {
const result = parseCommandSimple('npm install --save-dev');
expect(result.name).toBe('npm');
expect(result.subcommand).toBe('install');
expect(result.args).toContain('--save-dev');
});
it('混合 flag 和参数', () => {
const result = parseCommandSimple('git checkout -b feature-branch');
expect(result.name).toBe('git');
expect(result.subcommand).toBe('checkout');
expect(result.args).toContain('-b');
expect(result.args).toContain('feature-branch');
});
});
describe('空白处理', () => {
it('处理前后空格', () => {
const result = parseCommandSimple(' git status ');
expect(result.name).toBe('git');
expect(result.subcommand).toBe('status');
});
it('处理多个空格分隔', () => {
const result = parseCommandSimple('git status -v');
expect(result.name).toBe('git');
expect(result.subcommand).toBe('status');
expect(result.args).toContain('-v');
});
it('空字符串返回空命令', () => {
const result = parseCommandSimple('');
expect(result.name).toBe('');
expect(result.subcommand).toBeUndefined();
expect(result.args).toEqual([]);
});
it('只有空格返回空命令', () => {
const result = parseCommandSimple(' ');
expect(result.name).toBe('');
});
});
describe('复杂命令', () => {
it('解析 git push 命令', () => {
const result = parseCommandSimple('git push origin main --force');
expect(result.name).toBe('git');
expect(result.subcommand).toBe('push');
expect(result.args).toContain('origin');
expect(result.args).toContain('main');
expect(result.args).toContain('--force');
});
it('解析 npm 命令', () => {
const result = parseCommandSimple('npm run build -- --watch');
expect(result.name).toBe('npm');
expect(result.subcommand).toBe('run');
expect(result.args).toContain('build');
});
it('解析 docker 命令', () => {
const result = parseCommandSimple('docker run -d -p 8080:80 nginx');
expect(result.name).toBe('docker');
expect(result.subcommand).toBe('run');
expect(result.args).toContain('-d');
expect(result.args).toContain('-p');
});
it('解析管道前的命令', () => {
// 简单解析不处理管道,只作为普通参数
const result = parseCommandSimple('cat file.txt');
expect(result.name).toBe('cat');
expect(result.subcommand).toBe('file.txt');
});
});
describe('保留原始文本', () => {
it('text 字段保留原始命令', () => {
const original = 'git commit -m "fix bug"';
const result = parseCommandSimple(original);
expect(result.text).toBe(original);
});
});
});
describe('ParsedCommand 结构', () => {
it('包含所有必要字段', () => {
const result = parseCommandSimple('git push');
expect(result).toHaveProperty('name');
expect(result).toHaveProperty('subcommand');
expect(result).toHaveProperty('args');
expect(result).toHaveProperty('text');
});
it('args 始终是数组', () => {
const result = parseCommandSimple('ls');
expect(Array.isArray(result.args)).toBe(true);
});
});