Skip to content

Commit ba8b317

Browse files
committed
fix(plugin-coverage): skip invalid line numbers from tools like pytest-cov
1 parent ca85822 commit ba8b317

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,18 @@ export async function parseLcovFiles(
7777
);
7878
}
7979
const parsedRecords = parseLcov(toUnixNewlines(lcovFileContent));
80-
return parsedRecords.map<LCOVRecord>(record => ({
81-
...record,
82-
file:
83-
typeof result === 'string' || result.pathToProject == null
84-
? record.file
85-
: path.join(result.pathToProject, record.file),
86-
}));
80+
return parsedRecords.map(
81+
(record): LCOVRecord => ({
82+
title: record.title,
83+
file:
84+
typeof result === 'string' || result.pathToProject == null
85+
? record.file
86+
: path.join(result.pathToProject, record.file),
87+
functions: filterOutInvalidLines(record, 'functions'),
88+
branches: filterOutInvalidLines(record, 'branches'),
89+
lines: filterOutInvalidLines(record, 'lines'),
90+
}),
91+
);
8792
}),
8893
)
8994
).flat();
@@ -95,6 +100,26 @@ export async function parseLcovFiles(
95100
return parsedResults;
96101
}
97102

103+
/**
104+
* Filters out invalid line numbers.
105+
*
106+
* Some tools like pytest-cov emit line number 0. https://github.com/nedbat/coveragepy/issues/1846
107+
*
108+
* @param record LCOV record
109+
* @param type Coverage type
110+
* @returns Coverage output from record without invalid line numbers
111+
*/
112+
function filterOutInvalidLines<T extends 'branches' | 'functions' | 'lines'>(
113+
record: LCOVRecord,
114+
type: T,
115+
): LCOVRecord[T] {
116+
const stats = record[type];
117+
return {
118+
...stats,
119+
details: stats.details.filter(detail => detail.line > 0),
120+
};
121+
}
122+
98123
/**
99124
* This function aggregates coverage stats from all coverage files
100125
* @param records LCOV record for each file

packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.unit.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,26 @@ LH:1
3131
BRF:0
3232
BRH:0
3333
end_of_record
34+
`;
35+
36+
const PYTEST_REPORT = `
37+
TN:
38+
SF:kw/__init__.py
39+
DA:1,1,gG9L/J2A/IwO9tZM1raZxQ
40+
DA:0,0,gG9L/J2A/IwO9tZM1raZxQ
41+
LF:2
42+
LH:1
43+
BRF:0
44+
BRH:0
45+
end_of_record
3446
`;
3547

3648
beforeEach(() => {
3749
vol.fromJSON(
3850
{
3951
[path.join('integration-tests', 'lcov.info')]: UTILS_REPORT, // file name value under SF used in tests
4052
[path.join('unit-tests', 'lcov.info')]: CONSTANTS_REPORT, // file name value under SF used in tests
53+
[path.join('pytest', 'lcov.info')]: PYTEST_REPORT,
4154
'lcov.info': '', // empty report file
4255
},
4356
'coverage',
@@ -106,4 +119,19 @@ end_of_record
106119
)}.`,
107120
);
108121
});
122+
123+
it('should skip lines numbered 0', async () => {
124+
await expect(
125+
parseLcovFiles([path.join('coverage', 'pytest', 'lcov.info')]),
126+
).resolves.toEqual([
127+
expect.objectContaining({
128+
lines: expect.objectContaining({
129+
details: [
130+
{ hit: 1, line: 1 },
131+
// no { hit: 0, line: 0 },
132+
],
133+
}),
134+
}),
135+
]);
136+
});
109137
});

0 commit comments

Comments
 (0)