import path from 'node:path'; import { beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; import { collectFiles } from '../../../src/core/file/fileCollect.js'; import type { FileReadResult } from '../../../src/core/file/fileRead.js'; import { createMockConfig } from '../../testing/testUtils.js'; // Define the max file size constant for tests const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB describe('fileCollect', () => { let mockReadRawFile: Mock<(filePath: string, maxFileSize: number) => Promise>; beforeEach(() => { mockReadRawFile = vi.fn(); }); it('should collect non-binary files', async () => { const mockFilePaths = ['file1.txt', 'file2.txt']; const mockRootDir = '/root'; const mockConfig = createMockConfig(); mockReadRawFile.mockResolvedValue({ content: 'file content' }); const result = await collectFiles(mockFilePaths, mockRootDir, mockConfig, () => {}, { readRawFile: mockReadRawFile, }); expect(result).toEqual({ rawFiles: [ { path: 'file1.txt', content: 'file content' }, { path: 'file2.txt', content: 'file content' }, ], skippedFiles: [], }); expect(mockReadRawFile).toHaveBeenCalledTimes(2); expect(mockReadRawFile).toHaveBeenCalledWith(path.resolve('/root/file1.txt'), MAX_FILE_SIZE); expect(mockReadRawFile).toHaveBeenCalledWith(path.resolve('/root/file2.txt'), MAX_FILE_SIZE); }); it('should skip binary files', async () => { const mockFilePaths = ['binary.bin', 'text.txt']; const mockRootDir = '/root'; const mockConfig = createMockConfig(); mockReadRawFile.mockImplementation(async (filePath) => { if (filePath.endsWith('binary.bin')) { return { content: null, skippedReason: 'binary-extension' }; } return { content: 'file content' }; }); const result = await collectFiles(mockFilePaths, mockRootDir, mockConfig, () => {}, { readRawFile: mockReadRawFile, }); expect(result).toEqual({ rawFiles: [{ path: 'text.txt', content: 'file content' }], skippedFiles: [{ path: 'binary.bin', reason: 'binary-extension' }], }); }); it('should skip large files based on default maxFileSize', async () => { const mockFilePaths = ['large.txt', 'normal.txt']; const mockRootDir = '/root'; const mockConfig = createMockConfig(); mockReadRawFile.mockImplementation(async (filePath) => { if (filePath.endsWith('large.txt')) { return { content: null, skippedReason: 'size-limit' }; } return { content: 'file content' }; }); const result = await collectFiles(mockFilePaths, mockRootDir, mockConfig, () => {}, { readRawFile: mockReadRawFile, }); expect(result).toEqual({ rawFiles: [{ path: 'normal.txt', content: 'file content' }], skippedFiles: [{ path: 'large.txt', reason: 'size-limit' }], }); }); it('should respect custom maxFileSize setting', async () => { const mockFilePaths = ['medium.txt', 'small.txt']; const mockRootDir = '/root'; const customMaxFileSize = 5 * 1024 * 1024; // 5MB const mockConfig = createMockConfig({ input: { maxFileSize: customMaxFileSize, }, }); mockReadRawFile.mockImplementation(async (filePath) => { if (filePath.endsWith('medium.txt')) { return { content: null, skippedReason: 'size-limit' }; } return { content: 'file content' }; }); const result = await collectFiles(mockFilePaths, mockRootDir, mockConfig, () => {}, { readRawFile: mockReadRawFile, }); expect(result).toEqual({ rawFiles: [{ path: 'small.txt', content: 'file content' }], skippedFiles: [{ path: 'medium.txt', reason: 'size-limit' }], }); // Verify readRawFile is called with custom maxFileSize expect(mockReadRawFile).toHaveBeenCalledWith(path.resolve('/root/medium.txt'), customMaxFileSize); expect(mockReadRawFile).toHaveBeenCalledWith(path.resolve('/root/small.txt'), customMaxFileSize); }); it('should handle file read errors', async () => { const mockFilePaths = ['error.txt']; const mockRootDir = '/root'; const mockConfig = createMockConfig(); mockReadRawFile.mockResolvedValue({ content: null, skippedReason: 'encoding-error' }); const result = await collectFiles(mockFilePaths, mockRootDir, mockConfig, () => {}, { readRawFile: mockReadRawFile, }); expect(result).toEqual({ rawFiles: [], skippedFiles: [{ path: 'error.txt', reason: 'encoding-error' }], }); }); it('should call progressCallback for each file', async () => { const mockFilePaths = ['file1.txt', 'file2.txt']; const mockRootDir = '/root'; const mockConfig = createMockConfig(); const mockProgress = vi.fn(); mockReadRawFile.mockResolvedValue({ content: 'file content' }); await collectFiles(mockFilePaths, mockRootDir, mockConfig, mockProgress, { readRawFile: mockReadRawFile, }); expect(mockProgress).toHaveBeenCalledTimes(2); }); });