Skip to content

Commit

Permalink
test_runner: report covered lines, functions and branches to reporters.
Browse files Browse the repository at this point in the history
Fixes #49303
  • Loading branch information
philnash committed Aug 25, 2023
1 parent 0d080a2 commit ada1bd1
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 8 deletions.
14 changes: 12 additions & 2 deletions doc/api/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -2011,8 +2011,18 @@ object, streaming a series of events representing the execution of the tests.
* `coveredLinePercent` {number} The percentage of lines covered.
* `coveredBranchPercent` {number} The percentage of branches covered.
* `coveredFunctionPercent` {number} The percentage of functions covered.
* `uncoveredLineNumbers` {Array} An array of integers representing line
numbers that are uncovered.
* `functions` {Array} An array of functions representing function
coverage.
* `name` {string} The name of the function.
* `line` {number} The line number where the function is defined.
* `count` {number} The number of times the function was called.
* `branches` {Array} An array of branches representing branch coverage.
* `line` {number} The line number where the branch is defined.
* `count` {number} The number of times the branch was taken.
* `lines` {Array} An array of lines representing line
numbers and the number of times they were covered.
* `line` {number} The line number.
* `count` {number} The number of times the line was covered.
* `totals` {Object} An object containing a summary of coverage for all
files.
* `totalLineCount` {number} The total number of lines.
Expand Down
30 changes: 27 additions & 3 deletions lib/internal/test_runner/coverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {
StringPrototypeIncludes,
StringPrototypeLocaleCompare,
StringPrototypeStartsWith,
MathMax
} = primordials;
const {
copyFileSync,
Expand Down Expand Up @@ -43,6 +44,7 @@ class CoverageLine {
this.startOffset = startOffset;
this.endOffset = startOffset + src.length - newlineLength;
this.ignore = false;
this.count = 0;
this.#covered = true;
}

Expand Down Expand Up @@ -118,6 +120,8 @@ class TestCoverage {
let totalFunctions = 0;
let branchesCovered = 0;
let functionsCovered = 0;
const functionReports = [];
const branchReports = [];

const lines = ArrayPrototypeMap(linesWithBreaks, (line, i) => {
const startOffset = offset;
Expand Down Expand Up @@ -165,6 +169,11 @@ class TestCoverage {
mapRangeToLines(range, lines);

if (isBlockCoverage) {
ArrayPrototypePush(branchReports, {
line: range.lines[0].line,
count: range.count
});

if (range.count !== 0 ||
range.ignoredLines === range.lines.length) {
branchesCovered++;
Expand All @@ -177,6 +186,12 @@ class TestCoverage {
if (j > 0 && ranges.length > 0) {
const range = ranges[0];

ArrayPrototypePush(functionReports, {
name: functions[j].functionName,
count: MathMax(...ArrayPrototypeMap(ranges, r => r.count)),
line: range.lines[0].line
});

if (range.count !== 0 || range.ignoredLines === range.lines.length) {
functionsCovered++;
}
Expand All @@ -186,15 +201,18 @@ class TestCoverage {
}

let coveredCnt = 0;
const uncoveredLineNums = [];
const lineReports = [];

for (let j = 0; j < lines.length; ++j) {
const line = lines[j];

if (line.covered || line.ignore) {
coveredCnt++;
if (!line.ignore) {
ArrayPrototypePush(lineReports, { line: line.line, count: line.count })
}
} else {
ArrayPrototypePush(uncoveredLineNums, line.line);
ArrayPrototypePush(lineReports, { line: line.line, count: 0 });
}
}

Expand All @@ -210,7 +228,9 @@ class TestCoverage {
coveredLinePercent: toPercentage(coveredCnt, lines.length),
coveredBranchPercent: toPercentage(branchesCovered, totalBranches),
coveredFunctionPercent: toPercentage(functionsCovered, totalFunctions),
uncoveredLineNumbers: uncoveredLineNums,
functions: functionReports,
branches: branchReports,
lines: lineReports,
});

coverageSummary.totals.totalLineCount += lines.length;
Expand Down Expand Up @@ -321,6 +341,10 @@ function mapRangeToLines(range, lines) {
endOffset >= line.endOffset) {
line.covered = false;
}
if (count > 0 && startOffset <= line.startOffset &&
endOffset >= line.endOffset) {
line.count = count;
}

ArrayPrototypePush(mappedLines, line);

Expand Down
16 changes: 13 additions & 3 deletions lib/internal/test_runner/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,15 @@ function formatLinesToRanges(values) {
}, []), (range) => ArrayPrototypeJoin(range, '-'));
}

function getUncoveredLines(lines) {
return ArrayPrototypeReduce(lines, (acc, line) => {
if (line.count === 0) {
ArrayPrototypePush(acc, line.line);
}
return acc;
}, []);
}

function formatUncoveredLines(lines, table) {
if (table) return ArrayPrototypeJoin(formatLinesToRanges(lines), ' ');
return ArrayPrototypeJoin(lines, ', ');
Expand Down Expand Up @@ -325,8 +334,9 @@ function getCoverageReport(pad, summary, symbol, color, table) {
columnPadLengths = ArrayPrototypeMap(kColumns, (column) => (table ? MathMax(column.length, 6) : 0));
const columnsWidth = ArrayPrototypeReduce(columnPadLengths, (acc, columnPadLength) => acc + columnPadLength + 3, 0);

uncoveredLinesPadLength = table && ArrayPrototypeReduce(summary.files, (acc, file) =>
MathMax(acc, formatUncoveredLines(file.uncoveredLineNumbers, table).length), 0);
uncoveredLinesPadLength = table && ArrayPrototypeReduce(summary.files, (acc, file) => {
return MathMax(acc, formatUncoveredLines(getUncoveredLines(file.lines), table).length)
}, 0);
uncoveredLinesPadLength = MathMax(uncoveredLinesPadLength, 'uncovered lines'.length);
const uncoveredLinesWidth = uncoveredLinesPadLength + 2;

Expand Down Expand Up @@ -388,7 +398,7 @@ function getCoverageReport(pad, summary, symbol, color, table) {

report += `${prefix}${getCell(relativePath, filePadLength, StringPrototypePadEnd, truncateStart, fileCoverage)}${kSeparator}` +
`${ArrayPrototypeJoin(ArrayPrototypeMap(coverages, (coverage, j) => getCell(NumberPrototypeToFixed(coverage, 2), columnPadLengths[j], StringPrototypePadStart, false, coverage)), kSeparator)}${kSeparator}` +
`${getCell(formatUncoveredLines(file.uncoveredLineNumbers, table), uncoveredLinesPadLength, false, truncateEnd)}\n`;
`${getCell(formatUncoveredLines(getUncoveredLines(file.lines), table), uncoveredLinesPadLength, false, truncateEnd)}\n`;
}

// Foot
Expand Down

0 comments on commit ada1bd1

Please sign in to comment.