diff options
Diffstat (limited to 'packages/core/src/tools/write-file.test.ts')
| -rw-r--r-- | packages/core/src/tools/write-file.test.ts | 71 |
1 files changed, 31 insertions, 40 deletions
diff --git a/packages/core/src/tools/write-file.test.ts b/packages/core/src/tools/write-file.test.ts index 2d877115..e5d5ece9 100644 --- a/packages/core/src/tools/write-file.test.ts +++ b/packages/core/src/tools/write-file.test.ts @@ -37,6 +37,7 @@ import { CorrectedEditResult, } from '../utils/editCorrector.js'; import { createMockWorkspaceContext } from '../test-utils/mockWorkspaceContext.js'; +import { StandardFileSystemService } from '../services/fileSystemService.js'; const rootDir = path.resolve(os.tmpdir(), 'gemini-cli-test-root'); @@ -55,11 +56,13 @@ vi.mocked(ensureCorrectFileContent).mockImplementation( ); // Mock Config +const fsService = new StandardFileSystemService(); const mockConfigInternal = { getTargetDir: () => rootDir, getApprovalMode: vi.fn(() => ApprovalMode.DEFAULT), setApprovalMode: vi.fn(), getGeminiClient: vi.fn(), // Initialize as a plain mock function + getFileSystemService: () => fsService, getIdeClient: vi.fn(), getIdeMode: vi.fn(() => false), getWorkspaceContext: () => createMockWorkspaceContext(rootDir), @@ -316,10 +319,9 @@ describe('WriteFileTool', () => { fs.writeFileSync(filePath, 'content', { mode: 0o000 }); const readError = new Error('Permission denied'); - const originalReadFileSync = fs.readFileSync; - vi.spyOn(fs, 'readFileSync').mockImplementationOnce(() => { - throw readError; - }); + vi.spyOn(fsService, 'readTextFile').mockImplementationOnce(() => + Promise.reject(readError), + ); const result = await getCorrectedFileContent( mockConfig, @@ -328,7 +330,7 @@ describe('WriteFileTool', () => { abortSignal, ); - expect(fs.readFileSync).toHaveBeenCalledWith(filePath, 'utf8'); + expect(fsService.readTextFile).toHaveBeenCalledWith(filePath); expect(mockEnsureCorrectEdit).not.toHaveBeenCalled(); expect(mockEnsureCorrectFileContent).not.toHaveBeenCalled(); expect(result.correctedContent).toBe(proposedContent); @@ -339,7 +341,6 @@ describe('WriteFileTool', () => { code: undefined, }); - vi.spyOn(fs, 'readFileSync').mockImplementation(originalReadFileSync); fs.chmodSync(filePath, 0o600); }); }); @@ -353,16 +354,14 @@ describe('WriteFileTool', () => { fs.writeFileSync(filePath, 'original', { mode: 0o000 }); const readError = new Error('Simulated read error for confirmation'); - const originalReadFileSync = fs.readFileSync; - vi.spyOn(fs, 'readFileSync').mockImplementationOnce(() => { - throw readError; - }); + vi.spyOn(fsService, 'readTextFile').mockImplementationOnce(() => + Promise.reject(readError), + ); const invocation = tool.build(params); const confirmation = await invocation.shouldConfirmExecute(abortSignal); expect(confirmation).toBe(false); - vi.spyOn(fs, 'readFileSync').mockImplementation(originalReadFileSync); fs.chmodSync(filePath, 0o600); }); @@ -453,15 +452,14 @@ describe('WriteFileTool', () => { const params = { file_path: filePath, content: 'test content' }; fs.writeFileSync(filePath, 'original', { mode: 0o000 }); - const readError = new Error('Simulated read error for execute'); - const originalReadFileSync = fs.readFileSync; - vi.spyOn(fs, 'readFileSync').mockImplementationOnce(() => { - throw readError; + vi.spyOn(fsService, 'readTextFile').mockImplementationOnce(() => { + const readError = new Error('Simulated read error for execute'); + return Promise.reject(readError); }); const invocation = tool.build(params); const result = await invocation.execute(abortSignal); - expect(result.llmContent).toContain('Error checking existing file:'); + expect(result.llmContent).toContain('Error checking existing file'); expect(result.returnDisplay).toMatch( /Error checking existing file: Simulated read error for execute/, ); @@ -471,7 +469,6 @@ describe('WriteFileTool', () => { type: ToolErrorType.FILE_WRITE_FAILURE, }); - vi.spyOn(fs, 'readFileSync').mockImplementation(originalReadFileSync); fs.chmodSync(filePath, 0o600); }); @@ -504,7 +501,8 @@ describe('WriteFileTool', () => { /Successfully created and wrote to new file/, ); expect(fs.existsSync(filePath)).toBe(true); - expect(fs.readFileSync(filePath, 'utf8')).toBe(correctedContent); + const writtenContent = await fsService.readTextFile(filePath); + expect(writtenContent).toBe(correctedContent); const display = result.returnDisplay as FileDiff; expect(display.fileName).toBe('execute_new_corrected_file.txt'); expect(display.fileDiff).toMatch( @@ -563,7 +561,8 @@ describe('WriteFileTool', () => { abortSignal, ); expect(result.llmContent).toMatch(/Successfully overwrote file/); - expect(fs.readFileSync(filePath, 'utf8')).toBe(correctedProposedContent); + const writtenContent = await fsService.readTextFile(filePath); + expect(writtenContent).toBe(correctedProposedContent); const display = result.returnDisplay as FileDiff; expect(display.fileName).toBe('execute_existing_corrected_file.txt'); expect(display.fileDiff).toMatch( @@ -675,12 +674,11 @@ describe('WriteFileTool', () => { const filePath = path.join(rootDir, 'permission_denied_file.txt'); const content = 'test content'; - // Mock writeFileSync to throw EACCES error - const originalWriteFileSync = fs.writeFileSync; - vi.spyOn(fs, 'writeFileSync').mockImplementationOnce(() => { + // Mock FileSystemService writeTextFile to throw EACCES error + vi.spyOn(fsService, 'writeTextFile').mockImplementationOnce(() => { const error = new Error('Permission denied') as NodeJS.ErrnoException; error.code = 'EACCES'; - throw error; + return Promise.reject(error); }); const params = { file_path: filePath, content }; @@ -694,22 +692,19 @@ describe('WriteFileTool', () => { expect(result.returnDisplay).toContain( `Permission denied writing to file: ${filePath} (EACCES)`, ); - - vi.spyOn(fs, 'writeFileSync').mockImplementation(originalWriteFileSync); }); it('should return NO_SPACE_LEFT error when write fails with ENOSPC', async () => { const filePath = path.join(rootDir, 'no_space_file.txt'); const content = 'test content'; - // Mock writeFileSync to throw ENOSPC error - const originalWriteFileSync = fs.writeFileSync; - vi.spyOn(fs, 'writeFileSync').mockImplementationOnce(() => { + // Mock FileSystemService writeTextFile to throw ENOSPC error + vi.spyOn(fsService, 'writeTextFile').mockImplementationOnce(() => { const error = new Error( 'No space left on device', ) as NodeJS.ErrnoException; error.code = 'ENOSPC'; - throw error; + return Promise.reject(error); }); const params = { file_path: filePath, content }; @@ -723,8 +718,6 @@ describe('WriteFileTool', () => { expect(result.returnDisplay).toContain( `No space left on device: ${filePath} (ENOSPC)`, ); - - vi.spyOn(fs, 'writeFileSync').mockImplementation(originalWriteFileSync); }); it('should return TARGET_IS_DIRECTORY error when write fails with EISDIR', async () => { @@ -740,12 +733,11 @@ describe('WriteFileTool', () => { return originalExistsSync(path as string); }); - // Mock writeFileSync to throw EISDIR error - const originalWriteFileSync = fs.writeFileSync; - vi.spyOn(fs, 'writeFileSync').mockImplementationOnce(() => { + // Mock FileSystemService writeTextFile to throw EISDIR error + vi.spyOn(fsService, 'writeTextFile').mockImplementationOnce(() => { const error = new Error('Is a directory') as NodeJS.ErrnoException; error.code = 'EISDIR'; - throw error; + return Promise.reject(error); }); const params = { file_path: dirPath, content }; @@ -761,7 +753,6 @@ describe('WriteFileTool', () => { ); vi.spyOn(fs, 'existsSync').mockImplementation(originalExistsSync); - vi.spyOn(fs, 'writeFileSync').mockImplementation(originalWriteFileSync); }); it('should return FILE_WRITE_FAILURE for generic write errors', async () => { @@ -771,10 +762,10 @@ describe('WriteFileTool', () => { // Ensure fs.existsSync is not mocked for this test vi.restoreAllMocks(); - // Mock writeFileSync to throw generic error - vi.spyOn(fs, 'writeFileSync').mockImplementationOnce(() => { - throw new Error('Generic write error'); - }); + // Mock FileSystemService writeTextFile to throw generic error + vi.spyOn(fsService, 'writeTextFile').mockImplementationOnce(() => + Promise.reject(new Error('Generic write error')), + ); const params = { file_path: filePath, content }; const invocation = tool.build(params); |
