Skip to content

Commit 876e7b3

Browse files
cjihrigRafaelGSS
authored andcommitted
test_runner: refactor coverage to pass in config options
This commit updates the test runner's code coverage so that coverage options are explicitly passed in instead of pulled from command line options. PR-URL: #53931 Refs: #53924 Refs: #53867 Refs: #53866 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent c457f9e commit 876e7b3

File tree

2 files changed

+62
-60
lines changed

2 files changed

+62
-60
lines changed

lib/internal/test_runner/coverage.js

+61-59
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,11 @@ const { tmpdir } = require('os');
2929
const { join, resolve, relative, matchesGlob } = require('path');
3030
const { fileURLToPath } = require('internal/url');
3131
const { kMappings, SourceMap } = require('internal/source_map/source_map');
32-
const { parseCommandLine } = require('internal/test_runner/utils');
3332
const kCoverageFileRegex = /^coverage-(\d+)-(\d{13})-(\d+)\.json$/;
3433
const kIgnoreRegex = /\/\* node:coverage ignore next (?<count>\d+ )?\*\//;
3534
const kLineEndingRegex = /\r?\n$/u;
3635
const kLineSplitRegex = /(?<=\r?\n)/u;
3736
const kStatusRegex = /\/\* node:coverage (?<status>enable|disable) \*\//;
38-
const {
39-
coverageExcludeGlobs,
40-
coverageIncludeGlobs,
41-
} = parseCommandLine();
4237

4338
class CoverageLine {
4439
constructor(line, startOffset, src, length = src?.length) {
@@ -55,10 +50,12 @@ class CoverageLine {
5550
}
5651

5752
class TestCoverage {
58-
constructor(coverageDirectory, originalCoverageDirectory, workingDirectory) {
53+
constructor(coverageDirectory, originalCoverageDirectory, workingDirectory, excludeGlobs, includeGlobs) {
5954
this.coverageDirectory = coverageDirectory;
6055
this.originalCoverageDirectory = originalCoverageDirectory;
6156
this.workingDirectory = workingDirectory;
57+
this.excludeGlobs = excludeGlobs;
58+
this.includeGlobs = includeGlobs;
6259
}
6360

6461
#sourceLines = new SafeMap();
@@ -313,7 +310,7 @@ class TestCoverage {
313310

314311
const coverageFile = join(this.coverageDirectory, entry.name);
315312
const coverage = JSONParse(readFileSync(coverageFile, 'utf8'));
316-
mergeCoverage(result, this.mapCoverageWithSourceMap(coverage), this.workingDirectory);
313+
this.mergeCoverage(result, this.mapCoverageWithSourceMap(coverage));
317314
}
318315

319316
return ArrayFrom(result.values());
@@ -336,7 +333,7 @@ class TestCoverage {
336333
const script = result[i];
337334
const { url, functions } = script;
338335

339-
if (shouldSkipFileCoverage(url, this.workingDirectory) || sourceMapCache[url] == null) {
336+
if (this.shouldSkipFileCoverage(url) || sourceMapCache[url] == null) {
340337
newResult.set(url, script);
341338
continue;
342339
}
@@ -412,6 +409,54 @@ class TestCoverage {
412409
return MathMin(lines[line].startOffset + entry.originalColumn, lines[line].endOffset);
413410
}
414411

412+
mergeCoverage(merged, coverage) {
413+
for (let i = 0; i < coverage.length; ++i) {
414+
const newScript = coverage[i];
415+
const { url } = newScript;
416+
417+
if (this.shouldSkipFileCoverage(url)) {
418+
continue;
419+
}
420+
421+
const oldScript = merged.get(url);
422+
423+
if (oldScript === undefined) {
424+
merged.set(url, newScript);
425+
} else {
426+
mergeCoverageScripts(oldScript, newScript);
427+
}
428+
}
429+
}
430+
431+
shouldSkipFileCoverage(url) {
432+
// This check filters out core modules, which start with 'node:' in
433+
// coverage reports, as well as any invalid coverages which have been
434+
// observed on Windows.
435+
if (!StringPrototypeStartsWith(url, 'file:')) return true;
436+
437+
const absolutePath = fileURLToPath(url);
438+
const relativePath = relative(this.workingDirectory, absolutePath);
439+
440+
// This check filters out files that match the exclude globs.
441+
if (this.excludeGlobs?.length > 0) {
442+
for (let i = 0; i < this.excludeGlobs.length; ++i) {
443+
if (matchesGlob(relativePath, this.excludeGlobs[i]) ||
444+
matchesGlob(absolutePath, this.excludeGlobs[i])) return true;
445+
}
446+
}
447+
448+
// This check filters out files that do not match the include globs.
449+
if (this.includeGlobs?.length > 0) {
450+
for (let i = 0; i < this.includeGlobs.length; ++i) {
451+
if (matchesGlob(relativePath, this.includeGlobs[i]) ||
452+
matchesGlob(absolutePath, this.includeGlobs[i])) return false;
453+
}
454+
return true;
455+
}
456+
457+
// This check filters out the node_modules/ directory, unless it is explicitly included.
458+
return StringPrototypeIncludes(url, '/node_modules/');
459+
}
415460
}
416461

417462
function toPercentage(covered, total) {
@@ -422,7 +467,7 @@ function sortCoverageFiles(a, b) {
422467
return StringPrototypeLocaleCompare(a.path, b.path);
423468
}
424469

425-
function setupCoverage() {
470+
function setupCoverage(options) {
426471
let originalCoverageDirectory = process.env.NODE_V8_COVERAGE;
427472
const cwd = process.cwd();
428473

@@ -446,7 +491,13 @@ function setupCoverage() {
446491
// child processes.
447492
process.env.NODE_V8_COVERAGE = coverageDirectory;
448493

449-
return new TestCoverage(coverageDirectory, originalCoverageDirectory, cwd);
494+
return new TestCoverage(
495+
coverageDirectory,
496+
originalCoverageDirectory,
497+
cwd,
498+
options.coverageExcludeGlobs,
499+
options.coverageIncludeGlobs,
500+
);
450501
}
451502

452503
function mapRangeToLines(range, lines) {
@@ -490,55 +541,6 @@ function mapRangeToLines(range, lines) {
490541
return { __proto__: null, lines: mappedLines, ignoredLines };
491542
}
492543

493-
function shouldSkipFileCoverage(url, workingDirectory) {
494-
// This check filters out core modules, which start with 'node:' in
495-
// coverage reports, as well as any invalid coverages which have been
496-
// observed on Windows.
497-
if (!StringPrototypeStartsWith(url, 'file:')) return true;
498-
499-
const absolutePath = fileURLToPath(url);
500-
const relativePath = relative(workingDirectory, absolutePath);
501-
502-
// This check filters out files that match the exclude globs.
503-
if (coverageExcludeGlobs?.length > 0) {
504-
for (let i = 0; i < coverageExcludeGlobs.length; ++i) {
505-
if (matchesGlob(relativePath, coverageExcludeGlobs[i]) ||
506-
matchesGlob(absolutePath, coverageExcludeGlobs[i])) return true;
507-
}
508-
}
509-
510-
// This check filters out files that do not match the include globs.
511-
if (coverageIncludeGlobs?.length > 0) {
512-
for (let i = 0; i < coverageIncludeGlobs.length; ++i) {
513-
if (matchesGlob(relativePath, coverageIncludeGlobs[i]) ||
514-
matchesGlob(absolutePath, coverageIncludeGlobs[i])) return false;
515-
}
516-
return true;
517-
}
518-
519-
// This check filters out the node_modules/ directory, unless it is explicitly included.
520-
return StringPrototypeIncludes(url, '/node_modules/');
521-
}
522-
523-
function mergeCoverage(merged, coverage, workingDirectory) {
524-
for (let i = 0; i < coverage.length; ++i) {
525-
const newScript = coverage[i];
526-
const { url } = newScript;
527-
528-
if (shouldSkipFileCoverage(url, workingDirectory)) {
529-
continue;
530-
}
531-
532-
const oldScript = merged.get(url);
533-
534-
if (oldScript === undefined) {
535-
merged.set(url, newScript);
536-
} else {
537-
mergeCoverageScripts(oldScript, newScript);
538-
}
539-
}
540-
}
541-
542544
function mergeCoverageScripts(oldScript, newScript) {
543545
// Merge the functions from the new coverage into the functions from the
544546
// existing (merged) coverage.

lib/internal/test_runner/harness.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ function configureCoverage(rootTest, globalOptions) {
9595
const { setupCoverage } = require('internal/test_runner/coverage');
9696

9797
try {
98-
return setupCoverage();
98+
return setupCoverage(globalOptions);
9999
} catch (err) {
100100
const msg = `Warning: Code coverage could not be enabled. ${err}`;
101101

0 commit comments

Comments
 (0)