Files
repomix/tests/core/file/fileSearch.test.ts
Kazuki Yamada 398047b1a6 feat(rename): Rename to repomix
# Conflicts:
#	src/core/packager.ts
#	src/core/security/securityCheck.ts
#	src/shared/processConcurrency.ts

# Conflicts:
#	package-lock.json
#	package.json
2024-11-02 15:26:32 +09:00

227 lines
6.7 KiB
TypeScript

import * as fs from 'node:fs/promises';
import path from 'node:path';
import process from 'node:process';
import { globby } from 'globby';
import { minimatch } from 'minimatch';
import { beforeEach, describe, expect, test, vi } from 'vitest';
import {
getIgnoreFilePatterns,
getIgnorePatterns,
parseIgnoreContent,
searchFiles,
} from '../../../src/core/file/fileSearch.js';
import { createMockConfig, isWindows } from '../../testing/testUtils.js';
vi.mock('fs/promises');
vi.mock('globby');
describe('fileSearch', () => {
beforeEach(() => {
vi.resetAllMocks();
});
describe('getIgnoreFilePaths', () => {
test('should return correct paths when .gitignore and .repomixignore exist', async () => {
vi.mocked(fs.access).mockResolvedValue(undefined);
const mockConfig = createMockConfig({
ignore: {
useGitignore: true,
useDefaultPatterns: true,
customPatterns: [],
},
});
const filePatterns = await getIgnoreFilePatterns(mockConfig);
expect(filePatterns).toEqual(['**/.gitignore', '**/.repomixignore']);
});
test('should not include .gitignore when useGitignore is false', async () => {
vi.mocked(fs.access).mockResolvedValue(undefined);
const mockConfig = createMockConfig({
ignore: {
useGitignore: false,
useDefaultPatterns: true,
customPatterns: [],
},
});
const filePatterns = await getIgnoreFilePatterns(mockConfig);
expect(filePatterns).toEqual(['**/.repomixignore']);
});
});
describe('getIgnorePatterns', () => {
test('should return default patterns when useDefaultPatterns is true', async () => {
const mockConfig = createMockConfig({
ignore: {
useGitignore: true,
useDefaultPatterns: true,
customPatterns: [],
},
});
const patterns = await getIgnorePatterns(process.cwd(), mockConfig);
expect(patterns.length).toBeGreaterThan(0);
expect(patterns).toContain('**/node_modules/**');
});
test('should include custom patterns', async () => {
const mockConfig = createMockConfig({
ignore: {
useGitignore: true,
useDefaultPatterns: false,
customPatterns: ['*.custom', 'temp/'],
},
});
const patterns = await getIgnorePatterns(process.cwd(), mockConfig);
expect(patterns).toEqual(['repomix-output.txt', '*.custom', 'temp/']);
});
test('should combine default and custom patterns', async () => {
const mockConfig = createMockConfig({
ignore: {
useGitignore: true,
useDefaultPatterns: true,
customPatterns: ['*.custom', 'temp/'],
},
});
const patterns = await getIgnorePatterns(process.cwd(), mockConfig);
expect(patterns).toContain('**/node_modules/**');
expect(patterns).toContain('*.custom');
expect(patterns).toContain('temp/');
});
});
describe('parseIgnoreContent', () => {
test('should correctly parse ignore content', () => {
const content = `
# Comment
node_modules
*.log
.DS_Store
`;
const patterns = parseIgnoreContent(content);
expect(patterns).toEqual(['node_modules', '*.log', '.DS_Store']);
});
test('should handle mixed line endings', () => {
const content = 'node_modules\n*.log\r\n.DS_Store\r';
const patterns = parseIgnoreContent(content);
expect(patterns).toEqual(['node_modules', '*.log', '.DS_Store']);
});
});
describe('filterFiles', () => {
beforeEach(() => {
vi.resetAllMocks();
});
test('should call globby with correct parameters', async () => {
const mockConfig = createMockConfig({
include: ['**/*.js'],
ignore: {
useGitignore: true,
useDefaultPatterns: false,
customPatterns: ['*.custom'],
},
});
vi.mocked(globby).mockResolvedValue(['file1.js', 'file2.js']);
vi.mocked(fs.access).mockResolvedValue(undefined);
await searchFiles('/mock/root', mockConfig);
expect(globby).toHaveBeenCalledWith(
['**/*.js'],
expect.objectContaining({
cwd: '/mock/root',
ignore: expect.arrayContaining(['*.custom']),
ignoreFiles: expect.arrayContaining(['**/.gitignore', '**/.repomixignore']),
onlyFiles: true,
absolute: false,
dot: true,
followSymbolicLinks: false,
}),
);
});
test.runIf(!isWindows)('Honor .gitignore files in subdirectories', async () => {
const mockConfig = createMockConfig({
include: ['**/*.js'],
ignore: {
useGitignore: true,
useDefaultPatterns: false,
customPatterns: [],
},
});
const mockFileStructure = [
'root/file1.js',
'root/subdir/file2.js',
'root/subdir/ignored.js',
'root/another/file3.js',
];
const mockGitignoreContent = {
'/mock/root/.gitignore': '*.log',
'/mock/root/subdir/.gitignore': 'ignored.js',
};
vi.mocked(globby).mockImplementation(async () => {
// Simulate filtering files based on .gitignore
return mockFileStructure.filter((file) => {
const relativePath = file.replace('root/', '');
const dir = path.dirname(relativePath);
const gitignorePath = path.join('/mock/root', dir, '.gitignore');
const gitignoreContent = mockGitignoreContent[gitignorePath as keyof typeof mockGitignoreContent];
if (gitignoreContent && minimatch(path.basename(file), gitignoreContent)) {
return false;
}
return true;
});
});
vi.mocked(fs.readFile).mockImplementation(async (filePath) => {
return mockGitignoreContent[filePath as keyof typeof mockGitignoreContent] || '';
});
const result = await searchFiles('/mock/root', mockConfig);
expect(result).toEqual(['root/another/file3.js', 'root/subdir/file2.js', 'root/file1.js']);
expect(result).not.toContain('root/subdir/ignored.js');
});
test('should not apply .gitignore when useGitignore is false', async () => {
const mockConfig = createMockConfig({
include: ['**/*.js'],
ignore: {
useGitignore: false,
useDefaultPatterns: false,
customPatterns: [],
},
});
const mockFileStructure = [
'root/file1.js',
'root/another/file3.js',
'root/subdir/file2.js',
'root/subdir/ignored.js',
];
vi.mocked(globby).mockResolvedValue(mockFileStructure);
const result = await searchFiles('/mock/root', mockConfig);
expect(result).toEqual(mockFileStructure);
expect(result).toContain('root/subdir/ignored.js');
});
});
});