Files
ai-terminal-assistant/packages/core/tests/unit/utils/diff-extended.test.ts
T
kurihada 1d69fd876d feat(permission): 实现 WebSocket 权限确认机制
重构权限系统,将终端 UI 代码从 core 模块移除,实现基于 WebSocket 的权限确认流程:

Core 模块清理:
- 删除 permission/prompt.ts 和 file-prompt.ts(终端交互)
- 删除 diff.ts 中的 chalk 渲染函数
- 删除 config.ts 中的 inquirer 交互
- 移除 chalk 依赖

Server 权限处理:
- 新增 permission/handler.ts,实现 WebSocket 权限请求/响应
- 更新 agent/adapter.ts 设置权限回调
- 更新 ws.ts 处理 permission_response 消息

Web 权限组件:
- 新增 PermissionDialog 组件,显示权限请求详情和 Diff
- 更新 useChat hook 管理权限状态
- 更新 Chat 页面集成权限弹窗
2025-12-13 01:09:35 +08:00

122 lines
4.2 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { computeDiff, countChanges } from '../../../src/utils/diff.js';
describe('Diff - 差异比较扩展测试', () => {
describe('computeDiff - 计算 diff', () => {
it('新文件所有行都是添加', () => {
const diff = computeDiff(null, 'line1\nline2\nline3');
expect(diff.isNew).toBe(true);
expect(diff.oldContent).toBeNull();
expect(diff.hunks.length).toBe(1);
expect(diff.hunks[0].lines.every(l => l.type === 'add')).toBe(true);
expect(diff.hunks[0].newCount).toBe(3);
});
it('相同内容返回空 hunks', () => {
const content = 'line1\nline2\nline3';
const diff = computeDiff(content, content);
expect(diff.isNew).toBe(false);
// 相同内容可能没有实际变化的 hunks
const hasChanges = diff.hunks.some(h =>
h.lines.some(l => l.type === 'add' || l.type === 'remove')
);
expect(hasChanges).toBe(false);
});
it('检测添加的行', () => {
const oldContent = 'line1\nline2';
const newContent = 'line1\nline2\nline3';
const diff = computeDiff(oldContent, newContent);
expect(diff.isNew).toBe(false);
const addedLines = diff.hunks.flatMap(h => h.lines.filter(l => l.type === 'add'));
expect(addedLines.some(l => l.content === 'line3')).toBe(true);
});
it('检测删除的行', () => {
const oldContent = 'line1\nline2\nline3';
const newContent = 'line1\nline2';
const diff = computeDiff(oldContent, newContent);
const removedLines = diff.hunks.flatMap(h => h.lines.filter(l => l.type === 'remove'));
expect(removedLines.some(l => l.content === 'line3')).toBe(true);
});
it('检测修改的行(删除+添加)', () => {
const oldContent = 'line1\nold line\nline3';
const newContent = 'line1\nnew line\nline3';
const diff = computeDiff(oldContent, newContent);
const removedLines = diff.hunks.flatMap(h => h.lines.filter(l => l.type === 'remove'));
const addedLines = diff.hunks.flatMap(h => h.lines.filter(l => l.type === 'add'));
expect(removedLines.some(l => l.content === 'old line')).toBe(true);
expect(addedLines.some(l => l.content === 'new line')).toBe(true);
});
it('处理空文件', () => {
const diff = computeDiff('', 'new content');
expect(diff.isNew).toBe(false);
// 空到有内容是添加
const addedLines = diff.hunks.flatMap(h => h.lines.filter(l => l.type === 'add'));
expect(addedLines.length).toBeGreaterThan(0);
});
it('处理多个不连续的变更', () => {
const oldContent = 'line1\nkeep1\nold2\nkeep2\nold3\nline6';
const newContent = 'line1\nkeep1\nnew2\nkeep2\nnew3\nline6';
const diff = computeDiff(oldContent, newContent);
// 应该有变更
const changes = diff.hunks.flatMap(h =>
h.lines.filter(l => l.type === 'add' || l.type === 'remove')
);
expect(changes.length).toBeGreaterThan(0);
});
it('处理完全不同的内容', () => {
const oldContent = 'completely\ndifferent\ncontent';
const newContent = 'totally\nnew\nstuff';
const diff = computeDiff(oldContent, newContent);
expect(diff.hunks.length).toBeGreaterThan(0);
});
});
describe('countChanges - 统计变更', () => {
it('统计添加行数', () => {
const diff = computeDiff(null, 'line1\nline2\nline3');
const changes = countChanges(diff);
expect(changes.additions).toBe(3);
expect(changes.deletions).toBe(0);
});
it('统计删除行数', () => {
const diff = computeDiff('line1\nline2\nline3', '');
const changes = countChanges(diff);
expect(changes.deletions).toBe(3);
});
it('统计混合变更', () => {
const diff = computeDiff('old1\nold2', 'new1\nold2\nnew2');
const changes = countChanges(diff);
// 具体数字取决于 diff 算法实现
expect(changes.additions).toBeGreaterThanOrEqual(0);
expect(changes.deletions).toBeGreaterThanOrEqual(0);
});
it('无变更返回零', () => {
const diff = computeDiff('same', 'same');
const changes = countChanges(diff);
expect(changes.additions + changes.deletions).toBe(0);
});
});
});