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:
@@ -0,0 +1,156 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { matchPattern, matchRules, parseCommand, generateAskPattern } from '../../../src/permission/wildcard.js';
|
||||
|
||||
describe('matchPattern - 通配符模式匹配', () => {
|
||||
describe('* 通配符', () => {
|
||||
it('匹配任意字符', () => {
|
||||
expect(matchPattern('git diff', 'git diff*')).toBe(true);
|
||||
expect(matchPattern('git diff --staged', 'git diff*')).toBe(true);
|
||||
expect(matchPattern('git diff HEAD~1', 'git diff*')).toBe(true);
|
||||
});
|
||||
|
||||
it('不匹配不同前缀', () => {
|
||||
expect(matchPattern('git status', 'git diff*')).toBe(false);
|
||||
expect(matchPattern('git pull', 'git diff*')).toBe(false);
|
||||
});
|
||||
|
||||
it('匹配危险命令模式 rm -rf*', () => {
|
||||
expect(matchPattern('rm -rf /', 'rm -rf*')).toBe(true);
|
||||
expect(matchPattern('rm -rf /home', 'rm -rf*')).toBe(true);
|
||||
expect(matchPattern('rm -rf .', 'rm -rf*')).toBe(true);
|
||||
});
|
||||
|
||||
it('rm 普通命令不匹配 rm -rf*', () => {
|
||||
expect(matchPattern('rm file.txt', 'rm -rf*')).toBe(false);
|
||||
expect(matchPattern('rm -r dir', 'rm -rf*')).toBe(false);
|
||||
});
|
||||
|
||||
it('中间位置的通配符', () => {
|
||||
expect(matchPattern('git push origin main', 'git push * main')).toBe(true);
|
||||
expect(matchPattern('git push upstream main', 'git push * main')).toBe(true);
|
||||
});
|
||||
|
||||
it('多个通配符', () => {
|
||||
expect(matchPattern('git push origin main', 'git * origin *')).toBe(true);
|
||||
expect(matchPattern('git pull origin main', 'git * origin *')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('? 通配符', () => {
|
||||
it('匹配单个字符', () => {
|
||||
expect(matchPattern('ls -a', 'ls -?')).toBe(true);
|
||||
expect(matchPattern('ls -l', 'ls -?')).toBe(true);
|
||||
});
|
||||
|
||||
it('不匹配多个字符', () => {
|
||||
expect(matchPattern('ls -la', 'ls -?')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('精确匹配', () => {
|
||||
it('完全相同的字符串', () => {
|
||||
expect(matchPattern('ls', 'ls')).toBe(true);
|
||||
expect(matchPattern('pwd', 'pwd')).toBe(true);
|
||||
});
|
||||
|
||||
it('不匹配带参数的命令', () => {
|
||||
expect(matchPattern('ls -la', 'ls')).toBe(false);
|
||||
expect(matchPattern('pwd /home', 'pwd')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('大小写不敏感', () => {
|
||||
it('匹配不同大小写', () => {
|
||||
expect(matchPattern('GIT DIFF', 'git diff*')).toBe(true);
|
||||
expect(matchPattern('Git Diff', 'git diff*')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('特殊字符转义', () => {
|
||||
it('正确处理点号', () => {
|
||||
expect(matchPattern('file.txt', 'file.txt')).toBe(true);
|
||||
expect(matchPattern('fileatxt', 'file.txt')).toBe(false);
|
||||
});
|
||||
|
||||
it('正确处理括号', () => {
|
||||
expect(matchPattern('echo (test)', 'echo (test)')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('matchRules - 规则匹配', () => {
|
||||
const rules = [
|
||||
{ pattern: 'ls *', action: 'allow' as const },
|
||||
{ pattern: 'rm -rf*', action: 'deny' as const },
|
||||
{ pattern: 'git *', action: 'ask' as const },
|
||||
];
|
||||
|
||||
it('匹配 allow 规则', () => {
|
||||
const result = matchRules('ls -la', rules, 'ask');
|
||||
expect(result.action).toBe('allow');
|
||||
});
|
||||
|
||||
it('匹配 deny 规则', () => {
|
||||
const result = matchRules('rm -rf /', rules, 'ask');
|
||||
expect(result.action).toBe('deny');
|
||||
});
|
||||
|
||||
it('匹配 ask 规则', () => {
|
||||
const result = matchRules('git push', rules, 'deny');
|
||||
expect(result.action).toBe('ask');
|
||||
});
|
||||
|
||||
it('无匹配时返回默认动作', () => {
|
||||
const result = matchRules('npm install', rules, 'ask');
|
||||
expect(result.action).toBe('ask');
|
||||
});
|
||||
|
||||
it('返回匹配的模式', () => {
|
||||
const result = matchRules('rm -rf /home', rules, 'ask');
|
||||
expect(result.matchedPattern).toBe('rm -rf*');
|
||||
});
|
||||
|
||||
it('空规则列表返回默认动作', () => {
|
||||
const result = matchRules('any command', [], 'allow');
|
||||
expect(result.action).toBe('allow');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseCommand - 命令解析', () => {
|
||||
it('解析简单命令', () => {
|
||||
const result = parseCommand('ls');
|
||||
expect(result.head).toBe('ls');
|
||||
expect(result.sub).toBeUndefined();
|
||||
});
|
||||
|
||||
it('解析带子命令的命令', () => {
|
||||
const result = parseCommand('git push');
|
||||
expect(result.head).toBe('git');
|
||||
expect(result.sub).toBe('push');
|
||||
});
|
||||
|
||||
it('解析带参数的命令', () => {
|
||||
const result = parseCommand('git push origin main');
|
||||
expect(result.head).toBe('git');
|
||||
expect(result.sub).toBe('push');
|
||||
expect(result.args).toContain('origin');
|
||||
expect(result.args).toContain('main');
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateAskPattern - 生成询问模式', () => {
|
||||
it('简单命令生成 cmd *', () => {
|
||||
const pattern = generateAskPattern('ls -la');
|
||||
expect(pattern).toBe('ls *');
|
||||
});
|
||||
|
||||
it('带子命令生成 cmd sub *', () => {
|
||||
const pattern = generateAskPattern('git push origin');
|
||||
expect(pattern).toBe('git push *');
|
||||
});
|
||||
|
||||
it('npm install 生成 npm install *', () => {
|
||||
const pattern = generateAskPattern('npm install lodash');
|
||||
expect(pattern).toBe('npm install *');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user