From 9dbb7021ae0863f4d5d78587826f7f8090224135 Mon Sep 17 00:00:00 2001 From: Code Clawd Date: Tue, 14 Apr 2026 18:40:46 +0200 Subject: [PATCH] test_runner: exclude BRDA entries for ignored lines in LCOV reporter When a line is marked with /* node:coverage ignore next */, the DA entry for that line is correctly excluded from the LCOV output. However, the corresponding BRDA entry was still being emitted, causing branch coverage to report incorrect percentages when using the lcov reporter. This commit adds: - A new test fixture (brda_ignore_output.js) with a branch that has /* node:coverage ignore next */ to test the BRDA exclusion behavior - A new test runner (lcov_reporter_brda_ignore.js) for the fixture - A separate snapshot test case for this specific scenario - Updates to lcov.js to filter BRDA entries for ignored lines PR-URL: https://github.com/nodejs/node/pull/62740 --- lib/internal/test_runner/reporter/lcov.js | 16 +++++++++- .../test-runner/output/brda_ignore_output.js | 16 ++++++++++ .../output/lcov_reporter_brda_ignore.js | 16 ++++++++++ .../output/lcov_reporter_brda_ignore.snapshot | 32 +++++++++++++++++++ .../test-output-lcov-reporter-brda-ignore.mjs | 13 ++++++++ 5 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/test-runner/output/brda_ignore_output.js create mode 100644 test/fixtures/test-runner/output/lcov_reporter_brda_ignore.js create mode 100644 test/fixtures/test-runner/output/lcov_reporter_brda_ignore.snapshot create mode 100644 test/test-runner/test-output-lcov-reporter-brda-ignore.mjs diff --git a/lib/internal/test_runner/reporter/lcov.js b/lib/internal/test_runner/reporter/lcov.js index 698913d79dec02..719ebc6582094a 100644 --- a/lib/internal/test_runner/reporter/lcov.js +++ b/lib/internal/test_runner/reporter/lcov.js @@ -2,6 +2,7 @@ const { relative } = require('path'); const Transform = require('internal/streams/transform'); +const { SafeSet } = require('internal/primordials'); // This reporter is based on the LCOV format, as described here: // https://ltp.sourceforge.net/coverage/lcov/geninfo.1.php @@ -68,7 +69,20 @@ class LcovReporter extends Transform { // Taken is either '-' if the basic block containing the branch was // never executed or a number indicating how often that branch was // taken. + // Build set of ignored line numbers from coverage data. + // A line is ignored if it appears with ignore=true in the file.lines array. + const ignoredLineSet = new SafeSet(); + for (let k = 0; k < file.lines.length; k++) { + if (file.lines[k].ignore) { + ignoredLineSet.add(file.lines[k].line); + } + } + for (let j = 0; j < file.branches.length; j++) { + // Skip branches that point to ignored lines. + if (ignoredLineSet.has(file.branches[j].line)) { + continue; + } lcov += `BRDA:${file.branches[j].line},${j},0,${file.branches[j].count}\n`; } @@ -104,4 +118,4 @@ class LcovReporter extends Transform { } } -module.exports = LcovReporter; +module.exports = LcovReporter; \ No newline at end of file diff --git a/test/fixtures/test-runner/output/brda_ignore_output.js b/test/fixtures/test-runner/output/brda_ignore_output.js new file mode 100644 index 00000000000000..2b97887ee9dcd6 --- /dev/null +++ b/test/fixtures/test-runner/output/brda_ignore_output.js @@ -0,0 +1,16 @@ +'use strict'; +require('../../../common'); +const test = require('node:test'); + +function funcWithIgnoredBranch(value) { + /* node:coverage ignore next */ + if (value > 0) { // This branch should be ignored + return 'positive'; + } else { + return 'negative'; + } +} + +test('should not report BRDA for ignored branch', () => { + funcWithIgnoredBranch(1); // Only call one path of the branch +}); diff --git a/test/fixtures/test-runner/output/lcov_reporter_brda_ignore.js b/test/fixtures/test-runner/output/lcov_reporter_brda_ignore.js new file mode 100644 index 00000000000000..f4f65847a2f4da --- /dev/null +++ b/test/fixtures/test-runner/output/lcov_reporter_brda_ignore.js @@ -0,0 +1,16 @@ +'use strict'; +require('../../../common'); +const fixtures = require('../../../common/fixtures'); +const spawn = require('node:child_process').spawn; + +spawn( + process.execPath, + [ + '--no-warnings', + '--experimental-test-coverage', + '--test-coverage-exclude=!test/**', + '--test-reporter', 'lcov', + fixtures.path('test-runner/output/brda_ignore_output.js'), + ], + { stdio: 'inherit' }, +); diff --git a/test/fixtures/test-runner/output/lcov_reporter_brda_ignore.snapshot b/test/fixtures/test-runner/output/lcov_reporter_brda_ignore.snapshot new file mode 100644 index 00000000000000..2b70ff5cb48537 --- /dev/null +++ b/test/fixtures/test-runner/output/lcov_reporter_brda_ignore.snapshot @@ -0,0 +1,32 @@ +TN: +SF:test/fixtures/test-runner/output/brda_ignore_output.js +FN:5,funcWithIgnoredBranch +FN:14,anonymous_1 +FNDA:1,funcWithIgnoredBranch +FNDA:1,anonymous_1 +FNF:2 +FNH:2 +BRDA:1,0,0,1 +BRDA:5,1,0,1 +BRDA:9,2,0,0 +BRDA:14,3,0,1 +BRF:4 +BRH:3 +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:6,1 +DA:8,1 +DA:9,1 +DA:10,0 +DA:11,0 +DA:12,1 +DA:13,1 +DA:14,1 +DA:15,1 +DA:16,1 +LH:14 +LF:16 +end_of_record diff --git a/test/test-runner/test-output-lcov-reporter-brda-ignore.mjs b/test/test-runner/test-output-lcov-reporter-brda-ignore.mjs new file mode 100644 index 00000000000000..6350634e212680 --- /dev/null +++ b/test/test-runner/test-output-lcov-reporter-brda-ignore.mjs @@ -0,0 +1,13 @@ +import * as common from '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import { spawnAndAssert, lcovTransform, ensureCwdIsProjectRoot } from '../common/assertSnapshot.js'; + +if (!process.features.inspector) { + common.skip('inspector support required'); +} + +ensureCwdIsProjectRoot(); +await spawnAndAssert( + fixtures.path('test-runner/output/lcov_reporter_brda_ignore.js'), + lcovTransform, +);