From 0c2e1bc6471eb9bd1ec2b20dd37ed8c74f8f63d1 Mon Sep 17 00:00:00 2001 From: quality Date: Sun, 11 Oct 2026 04:08:49 -0400 Subject: [PATCH 1/2] test(e2e-coverage): assert splitRangeAtBoundaries' never-empty postcondition `splitRangeAtBoundaries` is the cut that keeps a V8 range inside the module it started in; `v8-to-istanbul` abandons any range whose start and end map to different originals, so "the split never returns the unsplit range" is a postcondition the rest of the conversion leans on. Nothing asserted it. The function's last line, `parts.length === 0 ? [range] : parts`, cannot take its `[range]` arm: `cuts` is built strictly below `range.endOffset` and the `cuts.length === 0` guard returns early, so `start` always sits below `range.endOffset` and the tail part is always pushed. An edit that broke that would return the straddling range, `v8-to-istanbul` would drop it, and the two specs that exercise the cut today -- source-boundary and source-boundary-segments -- would stay green, because both assert on a rendered region count several transformations downstream. Export the function alongside the existing getLineCoverage/getRegionCoverage block and pin the arithmetic directly: the no-cut identity, the strict endpoint comparisons, the deliberate `cut - 1` gap, property preservation, the tiling, and -- exhaustively over every cut list of a 7-offset space -- the invariant that a non-empty cut list always leaves at least the tail part. Record at the fallback that it is unreachable, why, and which test holds it that way, so the zero region reads as a documented residual rather than a missing fixture; that is the form 4184f33 settled on for the e2e side. Tests only. No production code and no workflow is touched. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: quality --- tests/e2e-coverage-split-range.test.mjs | 132 ++++++++++++++++++++++++ tests/tools/e2e-coverage-report.mjs | 10 ++ 2 files changed, 142 insertions(+) create mode 100644 tests/e2e-coverage-split-range.test.mjs diff --git a/tests/e2e-coverage-split-range.test.mjs b/tests/e2e-coverage-split-range.test.mjs new file mode 100644 index 00000000..5743b106 --- /dev/null +++ b/tests/e2e-coverage-split-range.test.mjs @@ -0,0 +1,132 @@ +// `splitRangeAtBoundaries` (tests/tools/e2e-coverage-report.mjs) is the cut +// that keeps a V8 range inside the module it started in: `convertScript` maps +// every range through it before handing the result to v8-to-istanbul, which +// abandons any range whose start and end resolve to different originals. +// +// tests/e2e-coverage-source-boundary.test.mjs and +// tests/e2e-coverage-source-boundary-segments.test.mjs pin what the cut does +// to a *report* -- a bundle, a source map, an artifact, a region count. That +// is the right level for "a range that straddles two modules is not lost", and +// the wrong level for the arithmetic itself: a fixture can only ever present +// the handful of cut lists a hand-written bundle happens to produce, and the +// report's region count is several transformations downstream of the offsets +// this function returns. These tests call it directly, so the postconditions +// are stated on the offsets. +// +// The postcondition that matters is the one the function's own last line +// depends on: +// +// return parts.length === 0 ? [range] : parts; +// +// `parts` is empty only when the loop pushed nothing *and* the tail push did +// not fire. The tail push fires whenever `range.endOffset > start`, and when +// there is at least one cut `start` is the last cut, which `cuts` built under +// `offset < range.endOffset`. So a non-empty cut list always leaves at least +// the tail part, and the `[range]` arm is unreachable -- `npm run +// test:unit:coverage` names line 627 among the uncovered regions of +// tests/tools/e2e-coverage-report.mjs, with the file at 97.98%. +// +// An unreachable arm asserted by nothing is indistinguishable from an arm +// whose fixture is merely missing. `every cut list leaves at least the tail +// part` below asserts the invariant over every cut list of a small offset +// space, so an edit that makes the fallback reachable fails on that test's +// name rather than quietly changing what the report counts. +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { splitRangeAtBoundaries } from './tools/e2e-coverage-report.mjs'; + +const RANGE = { startOffset: 10, endOffset: 20, count: 3 }; + +test('a range with no boundary inside it is returned unchanged', () => { + for (const boundaries of [[], [0], [40], [0, 40]]) { + assert.deepEqual(splitRangeAtBoundaries(RANGE, boundaries), [RANGE]); + } +}); + +test('a boundary on either endpoint does not cut', () => { + // `cuts` is built with strict comparisons on both sides. A boundary at + // `startOffset` would otherwise emit an empty leading part, and one at + // `endOffset` an empty trailing part. + assert.deepEqual( + splitRangeAtBoundaries(RANGE, [RANGE.startOffset, RANGE.endOffset]), + [RANGE], + ); +}); + +test('an interior boundary ends the leading part one offset short of it', () => { + // The gap is deliberate: the first offset at a boundary already belongs to + // the next source, so a leading part that ended *at* the cut would map its + // end into the following module and v8-to-istanbul would drop the whole + // range. The offset is not lost -- it opens the trailing part. + assert.deepEqual(splitRangeAtBoundaries(RANGE, [15]), [ + { startOffset: 10, endOffset: 14, count: 3 }, + { startOffset: 15, endOffset: 20, count: 3 }, + ]); +}); + +test('every part carries the properties of the range it came from', () => { + const range = { ...RANGE, isBlockCoverage: true, functionName: 'render' }; + for (const part of splitRangeAtBoundaries(range, [15])) { + assert.equal(part.count, 3); + assert.equal(part.isBlockCoverage, true); + assert.equal(part.functionName, 'render'); + } +}); + +test('a cut one offset past the start drops the lone leading offset', () => { + // `end = cut - 1` equals `start`, which is not `> start`, so no leading part + // is pushed. This is the only shape that makes the loop contribute nothing, + // and it is exactly the shape the unreachable fallback would have to catch. + assert.deepEqual(splitRangeAtBoundaries(RANGE, [RANGE.startOffset + 1]), [ + { startOffset: 11, endOffset: 20, count: 3 }, + ]); +}); + +test('consecutive cuts contribute only the parts that have width', () => { + assert.deepEqual(splitRangeAtBoundaries(RANGE, [15, 16]), [ + { startOffset: 10, endOffset: 14, count: 3 }, + { startOffset: 16, endOffset: 20, count: 3 }, + ]); +}); + +test('the parts tile the range: ascending, non-overlapping, ending at the end', () => { + const parts = splitRangeAtBoundaries(RANGE, [13, 17]); + assert.equal(parts.at(-1).endOffset, RANGE.endOffset); + for (const part of parts) { + assert.ok(part.startOffset < part.endOffset); + assert.ok(part.startOffset >= RANGE.startOffset); + assert.ok(part.endOffset <= RANGE.endOffset); + } + for (let index = 1; index < parts.length; index += 1) { + assert.ok(parts[index - 1].endOffset < parts[index].startOffset); + } +}); + +test('every cut list leaves at least the tail part', () => { + // Exhaustive over the subsets of a small offset space rather than over a + // chosen fixture, because the claim being pinned is that *no* cut list + // produces an empty `parts` -- a claim one example cannot support. Any + // counter-example here is a cut list that reaches the `[range]` fallback. + const range = { startOffset: 0, endOffset: 6, count: 1 }; + const offsets = [0, 1, 2, 3, 4, 5, 6]; + let withCuts = 0; + for (let mask = 0; mask < 1 << offsets.length; mask += 1) { + const boundaries = offsets.filter((_, index) => mask & (1 << index)); + const parts = splitRangeAtBoundaries(range, boundaries); + assert.ok( + parts.length > 0, + `empty parts for ${JSON.stringify(boundaries)}`, + ); + const cuts = boundaries.filter( + (offset) => offset > range.startOffset && offset < range.endOffset, + ); + if (cuts.length === 0) continue; + withCuts += 1; + // The tail part, which is what makes `parts` non-empty on this path. + assert.equal(parts.at(-1).startOffset, cuts.at(-1)); + assert.equal(parts.at(-1).endOffset, range.endOffset); + } + // Non-vacuity: the loop above must actually have reached the cut path. + assert.ok(withCuts > 0); +}); diff --git a/tests/tools/e2e-coverage-report.mjs b/tests/tools/e2e-coverage-report.mjs index 014569d4..51329197 100644 --- a/tests/tools/e2e-coverage-report.mjs +++ b/tests/tools/e2e-coverage-report.mjs @@ -541,6 +541,7 @@ export { getRegionCoverage, isPhantomRegion, isContradictedRegion, + splitRangeAtBoundaries, }; // Captured scripts are resolved against each root in order -- the run's own @@ -621,6 +622,15 @@ function splitRangeAtBoundaries(range, boundaries) { } start = cut; } + // The tail push always fires once there is a cut: every cut is strictly + // below `range.endOffset`, and `start` holds the last of them, so + // `range.endOffset > start`. `parts` is therefore never empty on this path, + // and the `parts.length === 0` arm below is unreachable -- it is kept as the + // statement of the invariant rather than deleted, and + // tests/e2e-coverage-split-range.test.mjs asserts the invariant directly so + // a future edit that breaks it fails on its own name instead of silently + // turning this arm live. It is one of the residual zero regions that cap + // this file below 100% (#1232, folded finding). if (range.endOffset > start) { parts.push({ ...range, startOffset: start, endOffset: range.endOffset }); } From 1ce22d0508cf76567a94e73966c530a6721a8e02 Mon Sep 17 00:00:00 2001 From: Bob Killen Date: Sun, 11 Oct 2026 09:03:35 -0500 Subject: [PATCH 2/2] docs(e2e-coverage): point the splitRangeAtBoundaries note at the residual list The in-place comment restated the header entry from #1253 and attributed the region to #1232; reference the list instead so there is one place to shorten when a probe lands. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Killen --- tests/tools/e2e-coverage-report.mjs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/tools/e2e-coverage-report.mjs b/tests/tools/e2e-coverage-report.mjs index 51329197..2f8be089 100644 --- a/tests/tools/e2e-coverage-report.mjs +++ b/tests/tools/e2e-coverage-report.mjs @@ -622,15 +622,13 @@ function splitRangeAtBoundaries(range, boundaries) { } start = cut; } - // The tail push always fires once there is a cut: every cut is strictly - // below `range.endOffset`, and `start` holds the last of them, so - // `range.endOffset > start`. `parts` is therefore never empty on this path, - // and the `parts.length === 0` arm below is unreachable -- it is kept as the - // statement of the invariant rather than deleted, and - // tests/e2e-coverage-split-range.test.mjs asserts the invariant directly so - // a future edit that breaks it fails on its own name instead of silently - // turning this arm live. It is one of the residual zero regions that cap - // this file below 100% (#1232, folded finding). + // The `parts.length === 0` arm below is unreachable (see the residual note + // at the top of this file, #1253): every cut is strictly below + // `range.endOffset`, and `start` holds the last of them, so the tail push + // always fires. It is kept as the statement of the invariant rather than + // deleted, and tests/e2e-coverage-split-range.test.mjs asserts the invariant + // directly so a future edit that breaks it fails on its own name instead of + // silently turning this arm live. if (range.endOffset > start) { parts.push({ ...range, startOffset: start, endOffset: range.endOffset }); }