@nerdo/code-reviewer
Version:
A web-based visual git diff tool for reviewing code changes between commits, branches, and tags
136 lines (135 loc) • 7.75 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vitest_1 = require("vitest");
const GitFileRepository_1 = require("../GitFileRepository");
const simple_git_1 = __importDefault(require("simple-git"));
vitest_1.vi.mock('simple-git');
(0, vitest_1.describe)('GitFileRepository', () => {
(0, vitest_1.describe)('getFileTree', () => {
(0, vitest_1.it)('should build file tree from git ls-tree output', async () => {
const { gitFileRepository, mockGit } = makeTestGitFileRepository();
mockGit.raw.mockResolvedValue('src/index.ts\nsrc/utils.ts\nREADME.md\n');
const tree = await gitFileRepository.getFileTree('/repo', 'abc123');
(0, vitest_1.expect)(mockGit.raw).toHaveBeenCalledWith(['ls-tree', '-r', '--name-only', 'abc123']);
(0, vitest_1.expect)(tree.type).toBe('directory');
(0, vitest_1.expect)(tree.children).toHaveLength(2); // src directory and README.md
const srcDir = tree.children?.find(c => c.name === 'src');
(0, vitest_1.expect)(srcDir?.type).toBe('directory');
(0, vitest_1.expect)(srcDir?.children).toHaveLength(2);
});
(0, vitest_1.it)('should handle empty repository', async () => {
const { gitFileRepository, mockGit } = makeTestGitFileRepository();
mockGit.raw.mockResolvedValue('');
const tree = await gitFileRepository.getFileTree('/repo', 'abc123');
(0, vitest_1.expect)(tree.children).toHaveLength(0);
});
});
(0, vitest_1.describe)('getFileChanges', () => {
(0, vitest_1.it)('should map diff summary to file changes', async () => {
const { gitFileRepository, mockGit } = makeTestGitFileRepository();
const diffSummary = makeTestDiffSummary();
mockGit.diffSummary.mockResolvedValue(diffSummary);
const changes = await gitFileRepository.getFileChanges('/repo', 'abc123', 'def456');
(0, vitest_1.expect)(changes).toHaveLength(4);
(0, vitest_1.expect)(changes[0].changeType).toBe('modified');
(0, vitest_1.expect)(changes[1].changeType).toBe('added');
(0, vitest_1.expect)(changes[2].changeType).toBe('deleted');
(0, vitest_1.expect)(changes[3].changeType).toBe('renamed');
(0, vitest_1.expect)(changes[3].previousPath).toBe('old.ts');
});
});
(0, vitest_1.describe)('getFileDiff', () => {
(0, vitest_1.it)('should get diff with content for text files', async () => {
const { gitFileRepository, mockGit } = makeTestGitFileRepository();
mockGit.show.mockImplementation((args) => {
if (args[0] === 'abc123:test.ts')
return Promise.resolve('old content');
if (args[0] === 'def456:test.ts')
return Promise.resolve('new content');
return Promise.reject(new Error('File not found'));
});
mockGit.raw.mockResolvedValue('1\t1\ttest.ts');
const diff = await gitFileRepository.getFileDiff('/repo', 'abc123', 'def456', 'test.ts');
(0, vitest_1.expect)(diff.path).toBe('test.ts');
(0, vitest_1.expect)(diff.oldContent).toBe('old content');
(0, vitest_1.expect)(diff.newContent).toBe('new content');
(0, vitest_1.expect)(diff.isBinary).toBe(false);
(0, vitest_1.expect)(diff.hunks).toBeDefined();
});
(0, vitest_1.it)('should handle binary files', async () => {
const { gitFileRepository, mockGit } = makeTestGitFileRepository();
mockGit.show.mockImplementation((args) => {
if (args[0] === 'abc123:image.png')
return Promise.resolve('binary content old');
if (args[0] === 'def456:image.png')
return Promise.resolve('binary content new');
return Promise.reject(new Error('File not found'));
});
mockGit.raw.mockResolvedValue('-\t-\timage.png');
const diff = await gitFileRepository.getFileDiff('/repo', 'abc123', 'def456', 'image.png');
(0, vitest_1.expect)(diff.isBinary).toBe(true);
(0, vitest_1.expect)(diff.hunks).toHaveLength(0);
});
(0, vitest_1.it)('should handle deleted files', async () => {
const { gitFileRepository, mockGit } = makeTestGitFileRepository();
mockGit.show.mockImplementation((args) => {
if (args[0] === 'abc123:deleted.ts')
return Promise.resolve('content');
return Promise.reject(new Error('File not found'));
});
mockGit.raw.mockResolvedValue('10\t0\tdeleted.ts');
const diff = await gitFileRepository.getFileDiff('/repo', 'abc123', 'def456', 'deleted.ts');
(0, vitest_1.expect)(diff.oldContent).toBe('content');
(0, vitest_1.expect)(diff.newContent).toBe('');
});
(0, vitest_1.it)('should handle unchanged files', async () => {
const { gitFileRepository, mockGit } = makeTestGitFileRepository();
const sameContent = 'unchanged content';
mockGit.show.mockResolvedValue(sameContent);
mockGit.raw.mockResolvedValue('0\t0\tunchanged.ts');
const diff = await gitFileRepository.getFileDiff('/repo', 'abc123', 'def456', 'unchanged.ts');
(0, vitest_1.expect)(diff.oldContent).toBe(sameContent);
(0, vitest_1.expect)(diff.newContent).toBe(sameContent);
(0, vitest_1.expect)(diff.hunks).toHaveLength(0);
(0, vitest_1.expect)(diff.isBinary).toBe(false);
});
});
(0, vitest_1.describe)('getFileContent', () => {
(0, vitest_1.it)('should get file content at specific commit', async () => {
const { gitFileRepository, mockGit } = makeTestGitFileRepository();
mockGit.show.mockResolvedValue('file content');
const content = await gitFileRepository.getFileContent('/repo', 'abc123', 'test.ts');
(0, vitest_1.expect)(mockGit.show).toHaveBeenCalledWith(['abc123:test.ts']);
(0, vitest_1.expect)(content).toBe('file content');
});
(0, vitest_1.it)('should throw error for non-existent file', async () => {
const { gitFileRepository, mockGit } = makeTestGitFileRepository();
mockGit.show.mockRejectedValue(new Error('pathspec'));
await (0, vitest_1.expect)(gitFileRepository.getFileContent('/repo', 'abc123', 'nonexistent.ts')).rejects.toThrow('File nonexistent.ts not found in commit abc123');
});
});
function makeTestGitFileRepository() {
const mockGit = {
raw: vitest_1.vi.fn(),
diffSummary: vitest_1.vi.fn(),
show: vitest_1.vi.fn()
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
simple_git_1.default.mockReturnValue(mockGit);
const gitFileRepository = new GitFileRepository_1.GitFileRepository();
return { gitFileRepository, mockGit };
}
function makeTestDiffSummary() {
return {
files: [
{ file: 'src/index.ts', insertions: 10, deletions: 5, changes: 15 },
{ file: 'new.ts', insertions: 20, deletions: 0, changes: 20 },
{ file: 'deleted.ts', insertions: 0, deletions: 30, changes: 30 },
{ file: 'old.ts => new.ts', insertions: 5, deletions: 3, changes: 8 }
]
};
}
});