Skip to content

Commit 2d8a2b1

Browse files
committed
feat: enhance file format detection with error handling for unreadable files
1 parent 4c5d634 commit 2d8a2b1

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

src/__tests__/file-finder.test.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
3-
import { findCoverageFiles } from '../file-finder';
3+
import { findCoverageFiles, FileFinder } from '../file-finder';
44

55
// Mock @actions/glob
66
jest.mock('@actions/glob', () => ({
@@ -246,5 +246,26 @@ describe('file-finder', () => {
246246
expect(files).toHaveLength(1);
247247
expect(files[0].format).toBe('json');
248248
});
249+
250+
it('should skip files that cannot be read for content detection', async () => {
251+
// Create a file path that will trigger content detection but fail to read
252+
const testPath = path.join(testDir, 'unreadable.xml');
253+
// Write the file so statSync works (file exists check)
254+
fs.writeFileSync(testPath, 'dummy content');
255+
256+
mockGlob.create.mockResolvedValue(createMockGlobber([testPath]));
257+
258+
const spySampleFileContent = jest.spyOn(FileFinder, 'sampleFileContent').mockImplementation(_ => {
259+
throw new Error('EACCES: permission denied');
260+
});
261+
262+
try {
263+
const files = await findCoverageFiles('**/*.xml');
264+
// The file should be skipped due to read error (returns null from detectCoverageFormat)
265+
expect(files.some((f) => f.path === testPath)).toBe(false);
266+
} finally {
267+
spySampleFileContent.mockRestore();
268+
}
269+
});
249270
});
250271
});

src/file-finder.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,15 @@ export interface CoverageFile {
77
format: string;
88
}
99

10-
// Coverage format detection based on file patterns and content
10+
export class FileFinder {
11+
/**
12+
* Reads file content for format detection. Extracted for testability.
13+
*/
14+
static sampleFileContent(filePath: string): string {
15+
return fs.readFileSync(filePath, 'utf-8').slice(0, 2000); // Read first 2KB for detection
16+
}
17+
}
18+
1119
const FORMAT_PATTERNS: { pattern: RegExp; format: string; contentCheck?: (content: string) => boolean }[] = [
1220
// JaCoCo - XML format with jacoco in root element
1321
{
@@ -74,7 +82,7 @@ function detectFormat(filePath: string, content?: string): string | null {
7482
// Second pass: need to check content for files that require content checking
7583
if (!content && (filePath.endsWith('.xml') || filePath.endsWith('.json') || filePath.endsWith('.out'))) {
7684
try {
77-
content = fs.readFileSync(filePath, 'utf-8').slice(0, 2000); // Read first 2KB for detection
85+
content = FileFinder.sampleFileContent(filePath);
7886
} catch {
7987
return null;
8088
}

0 commit comments

Comments
 (0)