summaryrefslogtreecommitdiff
path: root/packages/core/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/core/src')
-rw-r--r--packages/core/src/utils/bfsFileSearch.test.ts295
-rw-r--r--packages/core/src/utils/getFolderStructure.test.ts4
2 files changed, 152 insertions, 147 deletions
diff --git a/packages/core/src/utils/bfsFileSearch.test.ts b/packages/core/src/utils/bfsFileSearch.test.ts
index 3ce452de..63198a8d 100644
--- a/packages/core/src/utils/bfsFileSearch.test.ts
+++ b/packages/core/src/utils/bfsFileSearch.test.ts
@@ -4,184 +4,189 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import * as fs from 'fs';
-import { vi, describe, it, expect, beforeEach } from 'vitest';
+import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import * as fsPromises from 'fs/promises';
-import * as gitUtils from './gitUtils.js';
+import * as path from 'path';
+import * as os from 'os';
import { bfsFileSearch } from './bfsFileSearch.js';
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
-vi.mock('fs');
-vi.mock('fs/promises');
-vi.mock('./gitUtils.js');
+describe('bfsFileSearch', () => {
+ let testRootDir: string;
-const createMockDirent = (name: string, isFile: boolean): fs.Dirent => {
- const dirent = new fs.Dirent();
- dirent.name = name;
- dirent.isFile = () => isFile;
- dirent.isDirectory = () => !isFile;
- return dirent;
-};
+ async function createEmptyDir(...pathSegments: string[]) {
+ const fullPath = path.join(testRootDir, ...pathSegments);
+ await fsPromises.mkdir(fullPath, { recursive: true });
+ return fullPath;
+ }
-// Type for the specific overload we're using
-type ReaddirWithFileTypes = (
- path: fs.PathLike,
- options: { withFileTypes: true },
-) => Promise<fs.Dirent[]>;
+ async function createTestFile(content: string, ...pathSegments: string[]) {
+ const fullPath = path.join(testRootDir, ...pathSegments);
+ await fsPromises.mkdir(path.dirname(fullPath), { recursive: true });
+ await fsPromises.writeFile(fullPath, content);
+ return fullPath;
+ }
-describe('bfsFileSearch', () => {
- beforeEach(() => {
- vi.resetAllMocks();
+ beforeEach(async () => {
+ testRootDir = await fsPromises.mkdtemp(
+ path.join(os.tmpdir(), 'bfs-file-search-test-'),
+ );
});
- it('should find a file in the root directory', async () => {
- const mockFs = vi.mocked(fsPromises);
- const mockReaddir = mockFs.readdir as unknown as ReaddirWithFileTypes;
- vi.mocked(mockReaddir).mockResolvedValue([
- createMockDirent('file1.txt', true),
- createMockDirent('file2.txt', true),
- ]);
+ afterEach(async () => {
+ await fsPromises.rm(testRootDir, { recursive: true, force: true });
+ });
- const result = await bfsFileSearch('/test', { fileName: 'file1.txt' });
- expect(result).toEqual(['/test/file1.txt']);
+ it('should find a file in the root directory', async () => {
+ const targetFilePath = await createTestFile('content', 'target.txt');
+ const result = await bfsFileSearch(testRootDir, { fileName: 'target.txt' });
+ expect(result).toEqual([targetFilePath]);
});
- it('should find a file in a subdirectory', async () => {
- const mockFs = vi.mocked(fsPromises);
- const mockReaddir = mockFs.readdir as unknown as ReaddirWithFileTypes;
- vi.mocked(mockReaddir).mockImplementation(async (dir) => {
- if (dir === '/test') {
- return [createMockDirent('subdir', false)];
- }
- if (dir === '/test/subdir') {
- return [createMockDirent('file1.txt', true)];
- }
- return [];
- });
+ it('should find a file in a nested directory', async () => {
+ const targetFilePath = await createTestFile(
+ 'content',
+ 'a',
+ 'b',
+ 'target.txt',
+ );
+ const result = await bfsFileSearch(testRootDir, { fileName: 'target.txt' });
+ expect(result).toEqual([targetFilePath]);
+ });
- const result = await bfsFileSearch('/test', { fileName: 'file1.txt' });
- expect(result).toEqual(['/test/subdir/file1.txt']);
+ it('should find multiple files with the same name', async () => {
+ const targetFilePath1 = await createTestFile('content1', 'a', 'target.txt');
+ const targetFilePath2 = await createTestFile('content2', 'b', 'target.txt');
+ const result = await bfsFileSearch(testRootDir, { fileName: 'target.txt' });
+ result.sort();
+ expect(result).toEqual([targetFilePath1, targetFilePath2].sort());
});
- it('should ignore specified directories', async () => {
- const mockFs = vi.mocked(fsPromises);
- const mockReaddir = mockFs.readdir as unknown as ReaddirWithFileTypes;
- vi.mocked(mockReaddir).mockImplementation(async (dir) => {
- if (dir === '/test') {
- return [
- createMockDirent('subdir1', false),
- createMockDirent('subdir2', false),
- ];
- }
- if (dir === '/test/subdir1') {
- return [createMockDirent('file1.txt', true)];
- }
- if (dir === '/test/subdir2') {
- return [createMockDirent('file1.txt', true)];
- }
- return [];
- });
+ it('should return an empty array if no file is found', async () => {
+ await createTestFile('content', 'other.txt');
+ const result = await bfsFileSearch(testRootDir, { fileName: 'target.txt' });
+ expect(result).toEqual([]);
+ });
- const result = await bfsFileSearch('/test', {
- fileName: 'file1.txt',
- ignoreDirs: ['subdir2'],
+ it('should ignore directories specified in ignoreDirs', async () => {
+ await createTestFile('content', 'ignored', 'target.txt');
+ const targetFilePath = await createTestFile(
+ 'content',
+ 'not-ignored',
+ 'target.txt',
+ );
+ const result = await bfsFileSearch(testRootDir, {
+ fileName: 'target.txt',
+ ignoreDirs: ['ignored'],
});
- expect(result).toEqual(['/test/subdir1/file1.txt']);
+ expect(result).toEqual([targetFilePath]);
});
- it('should respect maxDirs limit', async () => {
- const mockFs = vi.mocked(fsPromises);
- const mockReaddir = mockFs.readdir as unknown as ReaddirWithFileTypes;
- vi.mocked(mockReaddir).mockImplementation(async (dir) => {
- if (dir === '/test') {
- return [
- createMockDirent('subdir1', false),
- createMockDirent('subdir2', false),
- ];
- }
- if (dir === '/test/subdir1') {
- return [createMockDirent('file1.txt', true)];
- }
- if (dir === '/test/subdir2') {
- return [createMockDirent('file1.txt', true)];
- }
- return [];
+ it('should respect the maxDirs limit and not find the file', async () => {
+ await createTestFile('content', 'a', 'b', 'c', 'target.txt');
+ const result = await bfsFileSearch(testRootDir, {
+ fileName: 'target.txt',
+ maxDirs: 3,
});
+ expect(result).toEqual([]);
+ });
- const result = await bfsFileSearch('/test', {
- fileName: 'file1.txt',
- maxDirs: 2,
+ it('should respect the maxDirs limit and find the file', async () => {
+ const targetFilePath = await createTestFile(
+ 'content',
+ 'a',
+ 'b',
+ 'c',
+ 'target.txt',
+ );
+ const result = await bfsFileSearch(testRootDir, {
+ fileName: 'target.txt',
+ maxDirs: 4,
});
- expect(result).toEqual(['/test/subdir1/file1.txt']);
+ expect(result).toEqual([targetFilePath]);
});
- it('should respect .gitignore files', async () => {
- const mockFs = vi.mocked(fsPromises);
- const mockGitUtils = vi.mocked(gitUtils);
- mockGitUtils.isGitRepository.mockReturnValue(true);
- const mockReaddir = mockFs.readdir as unknown as ReaddirWithFileTypes;
- vi.mocked(mockReaddir).mockImplementation(async (dir) => {
- if (dir === '/test') {
- return [
- createMockDirent('.gitignore', true),
- createMockDirent('subdir1', false),
- createMockDirent('subdir2', false),
- ];
- }
- if (dir === '/test/subdir1') {
- return [createMockDirent('file1.txt', true)];
- }
- if (dir === '/test/subdir2') {
- return [createMockDirent('file1.txt', true)];
- }
- return [];
- });
- vi.mocked(fs).readFileSync.mockReturnValue('subdir2');
+ describe('with FileDiscoveryService', () => {
+ let projectRoot: string;
- const fileService = new FileDiscoveryService('/test');
- const result = await bfsFileSearch('/test', {
- fileName: 'file1.txt',
- fileService,
+ beforeEach(async () => {
+ projectRoot = await createEmptyDir('project');
});
- expect(result).toEqual(['/test/subdir1/file1.txt']);
- });
- it('should respect .geminiignore files', async () => {
- const mockFs = vi.mocked(fsPromises);
- const mockGitUtils = vi.mocked(gitUtils);
+ it('should ignore gitignored files', async () => {
+ await createEmptyDir('project', '.git');
+ await createTestFile('node_modules/', 'project', '.gitignore');
+ await createTestFile('content', 'project', 'node_modules', 'target.txt');
+ const targetFilePath = await createTestFile(
+ 'content',
+ 'project',
+ 'not-ignored',
+ 'target.txt',
+ );
- mockGitUtils.isGitRepository.mockReturnValue(false);
+ const fileService = new FileDiscoveryService(projectRoot);
+ const result = await bfsFileSearch(projectRoot, {
+ fileName: 'target.txt',
+ fileService,
+ fileFilteringOptions: {
+ respectGitIgnore: true,
+ respectGeminiIgnore: true,
+ },
+ });
- const mockReaddir = mockFs.readdir as unknown as ReaddirWithFileTypes;
- vi.mocked(mockReaddir).mockImplementation(async (dir) => {
- if (dir === '/test') {
- return [
- createMockDirent('.geminiignore', true),
- createMockDirent('subdir1', false),
- createMockDirent('subdir2', false),
- ];
- }
- if (dir === '/test/subdir1') {
- return [createMockDirent('file1.txt', true)];
- }
- if (dir === '/test/subdir2') {
- return [createMockDirent('file1.txt', true)];
- }
- return [];
+ expect(result).toEqual([targetFilePath]);
});
- vi.mocked(fs).readFileSync.mockReturnValue('subdir2');
+ it('should ignore geminiignored files', async () => {
+ await createTestFile('node_modules/', 'project', '.geminiignore');
+ await createTestFile('content', 'project', 'node_modules', 'target.txt');
+ const targetFilePath = await createTestFile(
+ 'content',
+ 'project',
+ 'not-ignored',
+ 'target.txt',
+ );
- const fileService = new FileDiscoveryService('/test');
- const result = await bfsFileSearch('/test', {
- fileName: 'file1.txt',
- fileService,
- fileFilteringOptions: {
- respectGitIgnore: true,
- respectGeminiIgnore: true,
- },
+ const fileService = new FileDiscoveryService(projectRoot);
+ const result = await bfsFileSearch(projectRoot, {
+ fileName: 'target.txt',
+ fileService,
+ fileFilteringOptions: {
+ respectGitIgnore: false,
+ respectGeminiIgnore: true,
+ },
+ });
+
+ expect(result).toEqual([targetFilePath]);
});
- expect(result).toEqual(['/test/subdir1/file1.txt']);
+ it('should not ignore files if respect flags are false', async () => {
+ await createEmptyDir('project', '.git');
+ await createTestFile('node_modules/', 'project', '.gitignore');
+ const target1 = await createTestFile(
+ 'content',
+ 'project',
+ 'node_modules',
+ 'target.txt',
+ );
+ const target2 = await createTestFile(
+ 'content',
+ 'project',
+ 'not-ignored',
+ 'target.txt',
+ );
+
+ const fileService = new FileDiscoveryService(projectRoot);
+ const result = await bfsFileSearch(projectRoot, {
+ fileName: 'target.txt',
+ fileService,
+ fileFilteringOptions: {
+ respectGitIgnore: false,
+ respectGeminiIgnore: false,
+ },
+ });
+
+ expect(result.sort()).toEqual([target1, target2].sort());
+ });
});
});
diff --git a/packages/core/src/utils/getFolderStructure.test.ts b/packages/core/src/utils/getFolderStructure.test.ts
index 3f1b4534..f7b67ae4 100644
--- a/packages/core/src/utils/getFolderStructure.test.ts
+++ b/packages/core/src/utils/getFolderStructure.test.ts
@@ -309,7 +309,7 @@ ${testRootDir}${path.sep}
fileService,
});
expect(structure).not.toContain('ignored.txt');
- expect(structure).toContain('node_modules/...');
+ expect(structure).toContain(`node_modules${path.sep}...`);
expect(structure).not.toContain('logs.json');
});
@@ -334,7 +334,7 @@ ${testRootDir}${path.sep}
});
expect(structure).toContain('ignored.txt');
// node_modules is still ignored by default
- expect(structure).toContain('node_modules/...');
+ expect(structure).toContain(`node_modules${path.sep}...`);
});
});
});