supercov 2.0.1 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -22
- package/docs/agent-loop.md +8 -13
- package/docs/assertions.md +161 -75
- package/docs/cli.md +111 -59
- package/docs/coverage-model.md +5 -6
- package/docs/evidence.md +0 -11
- package/docs/getting-started.md +1 -1
- package/docs/performance.md +6 -14
- package/docs/quality.md +1 -1
- package/docs/security.md +43 -12
- package/docs/supported-suites.md +44 -48
- package/docs/troubleshooting.md +12 -5
- package/docs/workspace-isolation.md +23 -2
- package/package.json +33 -21
- package/runtime/javascript/atomic.mjs +46 -2
- package/runtime/javascript/ava.mjs +82 -0
- package/runtime/javascript/bootstrap.cjs +43 -0
- package/runtime/javascript/jest.cjs +52 -15
- package/runtime/javascript/jest.config.mjs +9 -1
- package/runtime/javascript/jestReporter.mjs +5 -6
- package/runtime/javascript/launchSupervisor.mjs +127 -15
- package/runtime/javascript/mocha.mjs +180 -0
- package/runtime/javascript/nodeTest.mjs +57 -3
- package/runtime/javascript/playwright.mjs +241 -32
- package/runtime/javascript/provenance.mjs +1 -1
- package/runtime/javascript/register.mjs +290 -2
- package/runtime/javascript/resolve-loader.mjs +40 -1
- package/runtime/javascript/runnerEvidence.mjs +3 -5
- package/runtime/javascript/runtime.mjs +551 -61
- package/runtime/javascript/tap.mjs +130 -0
- package/runtime/javascript/transport.mjs +7 -2
- package/runtime/javascript/vitest.mjs +5 -8
- package/runtime/javascript/vitestReporter.mjs +3 -10
- package/docs/assertion-agent.md +0 -150
- package/docs/assertion-evidence.md +0 -103
- package/docs/assertion-maps.md +0 -316
- package/schemas/assertions.schema.json +0 -276
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
-
var __defProps = Object.defineProperties;
|
|
3
|
-
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
2
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
3
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
4
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
-
|
|
5
|
+
// The runtime runs inside the application under test, and its tests may
|
|
6
|
+
// pollute Object.prototype on purpose: axios's set `Object.prototype.get`, and
|
|
7
|
+
// a descriptor that inherits `get` makes defineProperty throw "Getter must be a
|
|
8
|
+
// function", failing tests that pass without Supercov. Every descriptor here has
|
|
9
|
+
// no prototype, and spreading copies values rather than descriptors.
|
|
10
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { __proto__: null, enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
11
|
var __spreadValues = (a, b) => {
|
|
9
12
|
for (var prop in b || (b = {}))
|
|
10
13
|
if (__hasOwnProp.call(b, prop))
|
|
@@ -16,7 +19,15 @@ var __spreadValues = (a, b) => {
|
|
|
16
19
|
}
|
|
17
20
|
return a;
|
|
18
21
|
};
|
|
19
|
-
var __spreadProps = (a, b) =>
|
|
22
|
+
var __spreadProps = (a, b) => __spreadValues(a, b);
|
|
23
|
+
|
|
24
|
+
// Buffer as it was when Supercov loaded. Tests replace globals -- axios's set
|
|
25
|
+
// `globalThis.Buffer = undefined` to check it copes -- and the runtime runs
|
|
26
|
+
// inside those tests; it must not fail where the application does not.
|
|
27
|
+
var capturedBuffer = typeof Buffer === "undefined" ? void 0 : Buffer;
|
|
28
|
+
// Likewise the timer: a test that installs fake timers would otherwise hold
|
|
29
|
+
// the browser's evidence back until it advanced its clock.
|
|
30
|
+
var capturedSetTimeout = setTimeout;
|
|
20
31
|
|
|
21
32
|
// dist/transport.js
|
|
22
33
|
var COVERAGE_SCOPE_HEADER = "x-supercov-scope";
|
|
@@ -77,13 +88,13 @@ function decodeCoverageScope(encoded) {
|
|
|
77
88
|
}
|
|
78
89
|
}
|
|
79
90
|
function encodeCoverageCarrier(carrier) {
|
|
80
|
-
return
|
|
91
|
+
return capturedBuffer.from(JSON.stringify(carrier), "utf8").toString("base64url");
|
|
81
92
|
}
|
|
82
93
|
function decodeCoverageCarrier(encoded) {
|
|
83
94
|
if (!encoded)
|
|
84
95
|
return void 0;
|
|
85
96
|
try {
|
|
86
|
-
const value = JSON.parse(
|
|
97
|
+
const value = JSON.parse(capturedBuffer.from(encoded, "base64url").toString("utf8"));
|
|
87
98
|
if (value.version !== 1)
|
|
88
99
|
return void 0;
|
|
89
100
|
if (value.scope) {
|
|
@@ -154,6 +165,8 @@ function createState() {
|
|
|
154
165
|
backgroundBuffers: /* @__PURE__ */ new Map(),
|
|
155
166
|
backgroundWriters: /* @__PURE__ */ new Map(),
|
|
156
167
|
backgroundShardSizes: /* @__PURE__ */ new Map(),
|
|
168
|
+
backgroundDescriptors: /* @__PURE__ */ new Map(),
|
|
169
|
+
pendingBackgroundAppends: /* @__PURE__ */ new Map(),
|
|
157
170
|
backgroundSequence: 0,
|
|
158
171
|
runtimeSnapshots: false,
|
|
159
172
|
assertionPhases: /* @__PURE__ */ new Map(),
|
|
@@ -330,6 +343,80 @@ function resetCoverage(testId2) {
|
|
|
330
343
|
runtimeGlobal.__SUPERCOV_MCDC_SNAPSHOT__ = decisionSnapshot;
|
|
331
344
|
runtimeGlobal.__SUPERCOV_COVERAGE_SNAPSHOT__ = coverageSnapshot;
|
|
332
345
|
runtimeGlobal.__SUPERCOV_RESET__ = resetCoverage;
|
|
346
|
+
// A dedicated worker blocked in `Atomics.wait` runs no evaluation, so the
|
|
347
|
+
// test runner could not read its evidence and reported the test as a lower
|
|
348
|
+
// bound: Actual's database worker waits that way between every query. The
|
|
349
|
+
// worker pushes its evidence to its pages instead, on a BroadcastChannel,
|
|
350
|
+
// each time it is about to block with something recorded since its last
|
|
351
|
+
// push; a worker that wakes and records something new says its push is no
|
|
352
|
+
// longer current. A page keeps the latest push of each worker, and the runner
|
|
353
|
+
// reads that when the worker itself does not answer: complete when current.
|
|
354
|
+
var workerEvidenceChannelName = "__supercov_worker_evidence__";
|
|
355
|
+
var workerEvidence = null;
|
|
356
|
+
function workerEvidenceChanged() {
|
|
357
|
+
if (workerEvidence === null || workerEvidence.changed)
|
|
358
|
+
return;
|
|
359
|
+
workerEvidence.changed = true;
|
|
360
|
+
if (!workerEvidence.pushed)
|
|
361
|
+
return;
|
|
362
|
+
workerEvidence.pushed = false;
|
|
363
|
+
try {
|
|
364
|
+
workerEvidence.channel.postMessage({ token: workerEvidence.token, current: false });
|
|
365
|
+
} catch (e) {
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function pushWorkerEvidence() {
|
|
369
|
+
if (workerEvidence === null || workerEvidence.pushed)
|
|
370
|
+
return;
|
|
371
|
+
workerEvidence.changed = false;
|
|
372
|
+
workerEvidence.pushed = true;
|
|
373
|
+
try {
|
|
374
|
+
workerEvidence.channel.postMessage({ token: workerEvidence.token, url: workerEvidence.url, current: true, snapshot: coverageSnapshot() });
|
|
375
|
+
} catch (e) {
|
|
376
|
+
workerEvidence.pushed = false;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
(function installWorkerEvidenceTransport() {
|
|
380
|
+
if (!isBrowser || typeof BroadcastChannel !== "function")
|
|
381
|
+
return;
|
|
382
|
+
if (typeof WorkerGlobalScope === "function" && runtimeGlobal instanceof WorkerGlobalScope) {
|
|
383
|
+
if (typeof Atomics !== "object" || typeof Atomics.wait !== "function" || runtimeGlobal.__SUPERCOV_WORKER_TOKEN__)
|
|
384
|
+
return;
|
|
385
|
+
try {
|
|
386
|
+
const token = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
387
|
+
const url = runtimeGlobal.location ? String(runtimeGlobal.location.href) : "";
|
|
388
|
+
workerEvidence = { channel: new BroadcastChannel(workerEvidenceChannelName), token, url, changed: true, pushed: false };
|
|
389
|
+
runtimeGlobal.__SUPERCOV_WORKER_TOKEN__ = token;
|
|
390
|
+
const wait = Atomics.wait;
|
|
391
|
+
Atomics.wait = function wait2(typedArray, index, value, timeout) {
|
|
392
|
+
pushWorkerEvidence();
|
|
393
|
+
return Reflect.apply(wait, Atomics, arguments);
|
|
394
|
+
};
|
|
395
|
+
} catch (e) {
|
|
396
|
+
workerEvidence = null;
|
|
397
|
+
}
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (typeof document === "undefined" || runtimeGlobal.__SUPERCOV_WORKER_EVIDENCE__)
|
|
401
|
+
return;
|
|
402
|
+
const received = /* @__PURE__ */ new Map();
|
|
403
|
+
try {
|
|
404
|
+
const channel = new BroadcastChannel(workerEvidenceChannelName);
|
|
405
|
+
channel.onmessage = (event) => {
|
|
406
|
+
const message = event.data;
|
|
407
|
+
if (!message || typeof message.token !== "string")
|
|
408
|
+
return;
|
|
409
|
+
const pushed = received.get(message.token);
|
|
410
|
+
if (message.current)
|
|
411
|
+
received.set(message.token, { url: message.url, snapshot: message.snapshot, current: true });
|
|
412
|
+
else if (pushed)
|
|
413
|
+
pushed.current = false;
|
|
414
|
+
};
|
|
415
|
+
} catch (e) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
runtimeGlobal.__SUPERCOV_WORKER_EVIDENCE__ = () => Array.from(received, ([token, pushed]) => ({ token, url: pushed.url, current: pushed.current, snapshot: pushed.snapshot }));
|
|
419
|
+
})();
|
|
333
420
|
var persistBrowserScheduled = false;
|
|
334
421
|
var persistBrowserListenersInstalled = false;
|
|
335
422
|
function persistBrowserNow() {
|
|
@@ -361,7 +448,7 @@ function persistBrowser() {
|
|
|
361
448
|
if (persistBrowserScheduled)
|
|
362
449
|
return;
|
|
363
450
|
persistBrowserScheduled = true;
|
|
364
|
-
|
|
451
|
+
capturedSetTimeout(() => {
|
|
365
452
|
persistBrowserScheduled = false;
|
|
366
453
|
persistBrowserNow();
|
|
367
454
|
}, 0);
|
|
@@ -449,15 +536,54 @@ function backgroundWriterToken() {
|
|
|
449
536
|
}
|
|
450
537
|
return Math.floor(Math.random() * 4294967295).toString(16);
|
|
451
538
|
}
|
|
539
|
+
// Background records -- every first hit under tap, AVA or Mocha, and code run
|
|
540
|
+
// outside any test -- are written once per event-loop turn, as a test's own
|
|
541
|
+
// records are, and on exit and the terminating signals. Written one by one
|
|
542
|
+
// they cost lru-cache's 10 ms TTL test a write and a stat for each of the 132
|
|
543
|
+
// first hits in its window, and the test missed its deadline under load. A
|
|
544
|
+
// process killed in the middle of a turn loses that turn's records.
|
|
452
545
|
function appendDurableBackgroundRecord(fs, runId, record) {
|
|
453
|
-
var _a8;
|
|
454
546
|
const records = state.backgroundBuffers.get(runId) != null ? state.backgroundBuffers.get(runId) : /* @__PURE__ */ new Map();
|
|
455
547
|
const key = serverRecordKey(record);
|
|
456
548
|
if (records.has(key))
|
|
457
549
|
return state.backgroundWriters.get(runId);
|
|
550
|
+
if (state.serverTransportFailure)
|
|
551
|
+
throw state.serverTransportFailure;
|
|
552
|
+
records.set(key, record);
|
|
553
|
+
state.backgroundBuffers.set(runId, records);
|
|
554
|
+
let pending = state.pendingBackgroundAppends.get(runId);
|
|
555
|
+
if (!pending) {
|
|
556
|
+
pending = [];
|
|
557
|
+
state.pendingBackgroundAppends.set(runId, pending);
|
|
558
|
+
}
|
|
559
|
+
pending.push(JSON.stringify(record) + "\n");
|
|
560
|
+
if (pending.length >= 2048)
|
|
561
|
+
flushServerAppends();
|
|
562
|
+
else
|
|
563
|
+
scheduleServerFlush();
|
|
564
|
+
return state.backgroundWriters.get(runId);
|
|
565
|
+
}
|
|
566
|
+
function flushBackgroundAppends(fs) {
|
|
567
|
+
for (const [runId, lines] of state.pendingBackgroundAppends) {
|
|
568
|
+
state.pendingBackgroundAppends.delete(runId);
|
|
569
|
+
try {
|
|
570
|
+
if (!fs)
|
|
571
|
+
throw new Error("node:fs is unavailable");
|
|
572
|
+
writeBackgroundLines(fs, runId, lines.join(""));
|
|
573
|
+
} catch (cause) {
|
|
574
|
+
const failure = cause instanceof Error && cause.code === "SUPERCOV_EVIDENCE_TRANSPORT_FAILED" ? cause : serverTransportError(runId, cause);
|
|
575
|
+
state.serverTransportFailure = failure;
|
|
576
|
+
throw failure;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
function writeBackgroundLines(fs, runId, payload) {
|
|
581
|
+
var _a8;
|
|
458
582
|
const directory = backgroundEvidenceDirectory(runId);
|
|
459
|
-
|
|
460
|
-
|
|
583
|
+
if (!state.createdEvidenceDirectories.has(directory)) {
|
|
584
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
585
|
+
state.createdEvidenceDirectories.add(directory);
|
|
586
|
+
}
|
|
461
587
|
let path = state.backgroundWriters.get(runId);
|
|
462
588
|
// A pid is not an identity: pool VMs restored from one snapshot run clones
|
|
463
589
|
// of this very process, same pid and same cached shard path, and their
|
|
@@ -470,7 +596,8 @@ function appendDurableBackgroundRecord(fs, runId, record) {
|
|
|
470
596
|
currentSize = fs.statSync(path).size;
|
|
471
597
|
} catch (e) {
|
|
472
598
|
}
|
|
473
|
-
if (currentSize !== (state.backgroundShardSizes.get(path)
|
|
599
|
+
if (currentSize !== (state.backgroundShardSizes.has(path) ? state.backgroundShardSizes.get(path) : -1)) {
|
|
600
|
+
closeBackgroundShard(fs, path);
|
|
474
601
|
path = void 0;
|
|
475
602
|
}
|
|
476
603
|
}
|
|
@@ -481,14 +608,28 @@ function appendDurableBackgroundRecord(fs, runId, record) {
|
|
|
481
608
|
state.backgroundSequence = nextSequence;
|
|
482
609
|
path = backgroundEvidencePath(runId, `${writer}-${nextSequence - 1}`);
|
|
483
610
|
state.backgroundWriters.set(runId, path);
|
|
484
|
-
state.backgroundShardSizes.set(path,
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
611
|
+
state.backgroundShardSizes.set(path, capturedBuffer.byteLength(payload));
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
let descriptor = state.backgroundDescriptors.get(path);
|
|
615
|
+
if (descriptor === void 0) {
|
|
616
|
+
descriptor = fs.openSync(path, "a");
|
|
617
|
+
state.backgroundDescriptors.set(path, descriptor);
|
|
618
|
+
}
|
|
619
|
+
const bytes = capturedBuffer.from(payload);
|
|
620
|
+
for (let written = 0; written < bytes.length; )
|
|
621
|
+
written += fs.writeSync(descriptor, bytes, written, bytes.length - written);
|
|
622
|
+
state.backgroundShardSizes.set(path, (state.backgroundShardSizes.get(path) || 0) + bytes.length);
|
|
623
|
+
}
|
|
624
|
+
function closeBackgroundShard(fs, path) {
|
|
625
|
+
const descriptor = state.backgroundDescriptors.get(path);
|
|
626
|
+
if (descriptor === void 0)
|
|
627
|
+
return;
|
|
628
|
+
state.backgroundDescriptors.delete(path);
|
|
629
|
+
try {
|
|
630
|
+
fs.closeSync(descriptor);
|
|
631
|
+
} catch (e) {
|
|
488
632
|
}
|
|
489
|
-
records.set(key, record);
|
|
490
|
-
state.backgroundBuffers.set(runId, records);
|
|
491
|
-
return path;
|
|
492
633
|
}
|
|
493
634
|
var _a7;
|
|
494
635
|
// Evidence buffered for the current turn is lost when a signal ends the
|
|
@@ -560,9 +701,10 @@ function serverTransportError(runId, cause) {
|
|
|
560
701
|
}
|
|
561
702
|
function flushServerAppends() {
|
|
562
703
|
const pending = state.pendingServerAppends;
|
|
563
|
-
if (pending.size === 0)
|
|
704
|
+
if (pending.size === 0 && state.pendingBackgroundAppends.size === 0)
|
|
564
705
|
return;
|
|
565
706
|
const fs = getFs();
|
|
707
|
+
flushBackgroundAppends(fs);
|
|
566
708
|
for (const [path, entry] of pending) {
|
|
567
709
|
pending.delete(path);
|
|
568
710
|
try {
|
|
@@ -593,6 +735,9 @@ function enqueueServerAppend(directory, path, line, runId) {
|
|
|
593
735
|
} else {
|
|
594
736
|
state.pendingServerAppends.set(path, { directory, runId, lines: [line] });
|
|
595
737
|
}
|
|
738
|
+
scheduleServerFlush();
|
|
739
|
+
}
|
|
740
|
+
function scheduleServerFlush() {
|
|
596
741
|
if (!state.serverExitHookInstalled && typeof process !== "undefined") {
|
|
597
742
|
state.serverExitHookInstalled = true;
|
|
598
743
|
try {
|
|
@@ -676,11 +821,19 @@ function appendServer(record) {
|
|
|
676
821
|
throw serverTransportError(runId, cause);
|
|
677
822
|
}
|
|
678
823
|
}
|
|
824
|
+
// Read on every probe outside a test, and the variable rarely changes: decode
|
|
825
|
+
// it once per value.
|
|
826
|
+
var decodedEnvironmentCarrier = { raw: void 0, context: void 0 };
|
|
679
827
|
function environmentRequestContext() {
|
|
680
828
|
if (isBrowser || typeof process === "undefined")
|
|
681
829
|
return void 0;
|
|
682
|
-
const
|
|
683
|
-
|
|
830
|
+
const raw = process.env[COVERAGE_CARRIER_ENV];
|
|
831
|
+
if (raw === decodedEnvironmentCarrier.raw)
|
|
832
|
+
return decodedEnvironmentCarrier.context;
|
|
833
|
+
const carrier = decodeCoverageCarrier(raw);
|
|
834
|
+
const context = carrier ? __spreadValues(__spreadValues({}, carrier.scope ? { scope: carrier.scope } : {}), carrier.phaseId ? { phaseId: carrier.phaseId } : {}) : void 0;
|
|
835
|
+
decodedEnvironmentCarrier = { raw, context };
|
|
836
|
+
return context;
|
|
684
837
|
}
|
|
685
838
|
function currentRequestContext() {
|
|
686
839
|
const stored = serverPhaseStorage == null ? void 0 : serverPhaseStorage.getStore();
|
|
@@ -718,7 +871,8 @@ function assertionPhaseState(scope) {
|
|
|
718
871
|
const key = attemptKey(scope);
|
|
719
872
|
const existing = state.assertionPhases.get(key);
|
|
720
873
|
if (existing) {
|
|
721
|
-
|
|
874
|
+
if (existing.phaseIds == null)
|
|
875
|
+
existing.phaseIds = new Set(existing.phases.filter(phase => phase.kind === "assertion").map(phase => phase.id));
|
|
722
876
|
return existing;
|
|
723
877
|
}
|
|
724
878
|
const created = { counter: 0, phases: [], phaseIds: new Set() };
|
|
@@ -806,6 +960,92 @@ function bindNodeAssertionPhase(operation, source, target, property = null) {
|
|
|
806
960
|
const receiver = property === null ? undefined : target;
|
|
807
961
|
return (...args) => withNodeAssertionPhase(operation, source, () => Reflect.apply(callback, receiver, args));
|
|
808
962
|
}
|
|
963
|
+
// withCoverageCarrier for code that runs in place rather than in a callback:
|
|
964
|
+
// the carrier holds until the returned function restores what it replaced.
|
|
965
|
+
// Opened and restored within one synchronous run, it is what run() does.
|
|
966
|
+
function enterCoverageCarrier(carrier) {
|
|
967
|
+
if (!serverPhaseStorage)
|
|
968
|
+
return () => {
|
|
969
|
+
};
|
|
970
|
+
const previousStore = serverPhaseStorage.getStore();
|
|
971
|
+
const previousEpoch = state.probeV2Clock.epoch;
|
|
972
|
+
const context = __spreadValues(__spreadValues({}, carrier.scope ? { scope: carrier.scope } : {}), carrier.phaseId ? { phaseId: carrier.phaseId } : {});
|
|
973
|
+
serverPhaseStorage.enterWith(context);
|
|
974
|
+
activateProbeV2Context(context);
|
|
975
|
+
return () => {
|
|
976
|
+
serverPhaseStorage.enterWith(previousStore);
|
|
977
|
+
state.probeV2Clock.epoch = previousEpoch;
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
var inertAssertionPhase = { close: (value) => value, fail: (error) => error };
|
|
981
|
+
// The phase withNodeAssertionPhase runs its callback in, opened before a
|
|
982
|
+
// TypeScript assertion's operands and closed after its call. The rewrite calls
|
|
983
|
+
// the assertion in place because TypeScript narrows nothing into a callback:
|
|
984
|
+
// `prior < id` under `if (prior !== undefined)`, an evolving `const ids = []`
|
|
985
|
+
// and an `asserts` signature all failed to typecheck once wrapped in one.
|
|
986
|
+
function openNodeAssertionPhase(operation, source) {
|
|
987
|
+
var _a8;
|
|
988
|
+
const context = currentRequestContext();
|
|
989
|
+
const scope = context.scope;
|
|
990
|
+
if (!scope)
|
|
991
|
+
return inertAssertionPhase;
|
|
992
|
+
const nested = context.phaseId && assertionPhaseState(scope).phaseIds.has(context.phaseId);
|
|
993
|
+
if (nested && typeof source !== "string")
|
|
994
|
+
return inertAssertionPhase;
|
|
995
|
+
if (typeof source === "function")
|
|
996
|
+
source = source();
|
|
997
|
+
let carrier;
|
|
998
|
+
let finish;
|
|
999
|
+
let release;
|
|
1000
|
+
const bridged = (_a8 = runtimeGlobal.__SUPERCOV_ASSERTION_PHASE_OPENER__) == null ? void 0 : _a8.call(runtimeGlobal, operation, source);
|
|
1001
|
+
if (bridged) {
|
|
1002
|
+
({ carrier, finish, release } = bridged);
|
|
1003
|
+
} else {
|
|
1004
|
+
const attempt = assertionPhaseState(scope);
|
|
1005
|
+
const phase = __spreadProps(__spreadValues({
|
|
1006
|
+
id: `${scope.attemptId}:assertion:${++attempt.counter}`,
|
|
1007
|
+
kind: "assertion",
|
|
1008
|
+
operation
|
|
1009
|
+
}, source ? { source } : {}), {
|
|
1010
|
+
startedAtMs: Date.now()
|
|
1011
|
+
});
|
|
1012
|
+
attempt.phases.push(phase);
|
|
1013
|
+
attempt.phaseIds.add(phase.id);
|
|
1014
|
+
carrier = { version: 1, scope, phaseId: phase.id };
|
|
1015
|
+
finish = (error) => finishAssertionPhase(phase, error);
|
|
1016
|
+
}
|
|
1017
|
+
const restore = enterCoverageCarrier(carrier);
|
|
1018
|
+
let open = true;
|
|
1019
|
+
const settle = () => {
|
|
1020
|
+
if (!open)
|
|
1021
|
+
return false;
|
|
1022
|
+
open = false;
|
|
1023
|
+
restore();
|
|
1024
|
+
release == null ? void 0 : release();
|
|
1025
|
+
return true;
|
|
1026
|
+
};
|
|
1027
|
+
return {
|
|
1028
|
+
close(value) {
|
|
1029
|
+
if (!settle())
|
|
1030
|
+
return value;
|
|
1031
|
+
if (value && typeof value.then === "function")
|
|
1032
|
+
return Promise.resolve(value).then((resolved) => {
|
|
1033
|
+
finish();
|
|
1034
|
+
return resolved;
|
|
1035
|
+
}, (error) => {
|
|
1036
|
+
finish(error);
|
|
1037
|
+
throw cleanInstrumentationStack(error);
|
|
1038
|
+
});
|
|
1039
|
+
finish();
|
|
1040
|
+
return value;
|
|
1041
|
+
},
|
|
1042
|
+
fail(error) {
|
|
1043
|
+
if (settle())
|
|
1044
|
+
finish(error);
|
|
1045
|
+
return cleanInstrumentationStack(error);
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
809
1049
|
function takeNodeAssertionPhases(scope) {
|
|
810
1050
|
var _a8, _b;
|
|
811
1051
|
const key = attemptKey(scope);
|
|
@@ -846,6 +1086,35 @@ function installServerFetchPropagation() {
|
|
|
846
1086
|
runtimeGlobal.__SUPERCOV_FETCH_PATCHED__ = true;
|
|
847
1087
|
}
|
|
848
1088
|
installServerFetchPropagation();
|
|
1089
|
+
// util.promisify(exec) and util.promisify(execFile) resolve { stdout, stderr }
|
|
1090
|
+
// through a function Node keeps on the original, and that function calls the
|
|
1091
|
+
// original. A wrapper carries its own, which calls the wrapper, or a promisified
|
|
1092
|
+
// call resolves the bare stdout string and skips the wrapper.
|
|
1093
|
+
const promisifyCustom = Symbol.for("nodejs.util.promisify.custom");
|
|
1094
|
+
function keepPromisifiedShape(original, wrapper) {
|
|
1095
|
+
if (typeof original[promisifyCustom] !== "function")
|
|
1096
|
+
return wrapper;
|
|
1097
|
+
Object.defineProperty(wrapper, promisifyCustom, {
|
|
1098
|
+
configurable: true,
|
|
1099
|
+
value: (...args) => {
|
|
1100
|
+
let settle, reject;
|
|
1101
|
+
const promise = new Promise((ok, fail) => {
|
|
1102
|
+
settle = ok;
|
|
1103
|
+
reject = fail;
|
|
1104
|
+
});
|
|
1105
|
+
promise.child = wrapper(...args, (error, stdout, stderr) => {
|
|
1106
|
+
if (error !== null) {
|
|
1107
|
+
error.stdout = stdout;
|
|
1108
|
+
error.stderr = stderr;
|
|
1109
|
+
reject(error);
|
|
1110
|
+
} else
|
|
1111
|
+
settle({ stdout, stderr });
|
|
1112
|
+
});
|
|
1113
|
+
return promise;
|
|
1114
|
+
}
|
|
1115
|
+
});
|
|
1116
|
+
return wrapper;
|
|
1117
|
+
}
|
|
849
1118
|
function installServerChildPropagation() {
|
|
850
1119
|
var _a8;
|
|
851
1120
|
if (isBrowser || runtimeGlobal.__SUPERCOV_CHILD_PATCHED__ || typeof process === "undefined")
|
|
@@ -855,9 +1124,12 @@ function installServerChildPropagation() {
|
|
|
855
1124
|
if (!child)
|
|
856
1125
|
return;
|
|
857
1126
|
const mutableChild = child;
|
|
1127
|
+
// (file, args?, options?, callback?): options follow an argument list, or an
|
|
1128
|
+
// explicit null or undefined in its place. exec itself calls execFile as
|
|
1129
|
+
// (file, options, callback), and that object is the options, not a list.
|
|
858
1130
|
const optionIndex = (method, args) => {
|
|
859
1131
|
if (method === "spawn" || method === "spawnSync" || method === "fork" || method === "execFile" || method === "execFileSync")
|
|
860
|
-
return Array.isArray(args[1]) || args
|
|
1132
|
+
return Array.isArray(args[1]) || args[1] == null && args.length > 2 ? 2 : 1;
|
|
861
1133
|
return 1;
|
|
862
1134
|
};
|
|
863
1135
|
for (const method of [
|
|
@@ -872,12 +1144,15 @@ function installServerChildPropagation() {
|
|
|
872
1144
|
const original = mutableChild[method];
|
|
873
1145
|
if (typeof original !== "function")
|
|
874
1146
|
continue;
|
|
875
|
-
mutableChild[method] = function(...args) {
|
|
1147
|
+
mutableChild[method] = keepPromisifiedShape(original, function(...args) {
|
|
876
1148
|
var _a9;
|
|
877
1149
|
const index = optionIndex(method, args);
|
|
878
1150
|
const existing = args[index] && typeof args[index] === "object" ? args[index] : {};
|
|
1151
|
+
// An env the caller passed is the child's whole environment -- execa's
|
|
1152
|
+
// extendEnv: false keeps the parent's CI out of chalk's fixtures -- so
|
|
1153
|
+
// only the carrier joins it. Without one, the child inherits ours.
|
|
879
1154
|
const options = __spreadProps(__spreadValues({}, existing), {
|
|
880
|
-
env: __spreadValues(__spreadValues(
|
|
1155
|
+
env: __spreadValues(__spreadValues({}, (_a9 = existing.env) != null ? _a9 : process.env), coverageContextEnvironment())
|
|
881
1156
|
});
|
|
882
1157
|
const scoped = [...args];
|
|
883
1158
|
if (typeof scoped[index] === "function")
|
|
@@ -885,7 +1160,7 @@ function installServerChildPropagation() {
|
|
|
885
1160
|
else
|
|
886
1161
|
scoped[index] = options;
|
|
887
1162
|
return Reflect.apply(original, child, scoped);
|
|
888
|
-
};
|
|
1163
|
+
});
|
|
889
1164
|
}
|
|
890
1165
|
const moduleBuiltin = getBuiltinModule == null ? void 0 : getBuiltinModule("node:module");
|
|
891
1166
|
(_a8 = moduleBuiltin == null ? void 0 : moduleBuiltin.syncBuiltinESMExports) == null ? void 0 : _a8.call(moduleBuiltin);
|
|
@@ -897,13 +1172,26 @@ installServerChildPropagation();
|
|
|
897
1172
|
* against the attempt it claims to belong to without a lookup.
|
|
898
1173
|
*/
|
|
899
1174
|
function phaseBelongsToAttempt(phaseId, attemptId) {
|
|
900
|
-
return typeof phaseId === "string" && typeof attemptId === "string" && attemptId.length > 0 && phaseId.startsWith(`${attemptId}
|
|
1175
|
+
return typeof phaseId === "string" && typeof attemptId === "string" && attemptId.length > 0 && phaseId.startsWith(`${attemptId}:`);
|
|
901
1176
|
}
|
|
902
1177
|
function currentPhaseId() {
|
|
903
1178
|
if (runtimeGlobal.__SUPERCOV_PHASE_ID__)
|
|
904
1179
|
return runtimeGlobal.__SUPERCOV_PHASE_ID__;
|
|
905
|
-
if (!isBrowser)
|
|
906
|
-
|
|
1180
|
+
if (!isBrowser) {
|
|
1181
|
+
// Async work an earlier test started -- a stream, a socket, a timer --
|
|
1182
|
+
// keeps that test's context and can run after the next test has begun.
|
|
1183
|
+
// Its phase belongs to the earlier attempt, and tagging this test's
|
|
1184
|
+
// evidence with it made the whole run unreadable ("unknown frontend phase
|
|
1185
|
+
// reference"): axios's HTTP/2 upload tests did it three times in 2,201.
|
|
1186
|
+
// Where the process knows which test is running, only that test's phases
|
|
1187
|
+
// are honoured; a server process, which learns its test from the request,
|
|
1188
|
+
// keeps the carried phase.
|
|
1189
|
+
const context = currentRequestContext();
|
|
1190
|
+
const active = runtimeGlobal.__SUPERCOV_ACTIVE_SCOPE__;
|
|
1191
|
+
if (context.phaseId && active && !phaseBelongsToAttempt(context.phaseId, active.attemptId))
|
|
1192
|
+
return void 0;
|
|
1193
|
+
return context.phaseId;
|
|
1194
|
+
}
|
|
907
1195
|
try {
|
|
908
1196
|
// The stored phase is per origin, so in a browser context that outlives
|
|
909
1197
|
// its test (a persistent profile shared by a whole worker) it still holds
|
|
@@ -976,15 +1264,23 @@ function requestCoverageContext(value) {
|
|
|
976
1264
|
}
|
|
977
1265
|
// Keep connection ownership on the emitter, without changing listener
|
|
978
1266
|
// identity (removeListener/off and once still see the original callbacks).
|
|
979
|
-
|
|
980
|
-
|
|
1267
|
+
if (runtimeGlobal.__SUPERCOV_EMITTER_CONTEXT_MAPS__ == null)
|
|
1268
|
+
runtimeGlobal.__SUPERCOV_EMITTER_CONTEXT_MAPS__ = new Map();
|
|
1269
|
+
const emitterContextMaps = runtimeGlobal.__SUPERCOV_EMITTER_CONTEXT_MAPS__;
|
|
1270
|
+
const emitterCoverageContexts = emitterContextMaps.get(runtimeInstance) || new WeakMap();
|
|
981
1271
|
emitterContextMaps.set(runtimeInstance, emitterCoverageContexts);
|
|
982
|
-
|
|
1272
|
+
if (runtimeGlobal.__SUPERCOV_EMITTER_PATCHED_INSTANCES__ == null)
|
|
1273
|
+
runtimeGlobal.__SUPERCOV_EMITTER_PATCHED_INSTANCES__ = new Set();
|
|
1274
|
+
const patchedEmitterInstances = runtimeGlobal.__SUPERCOV_EMITTER_PATCHED_INSTANCES__;
|
|
983
1275
|
function installNodeRequestPropagation() {
|
|
984
1276
|
if (isBrowser || patchedEmitterInstances.has(runtimeInstance) || typeof process === "undefined") return;
|
|
985
|
-
const
|
|
986
|
-
const
|
|
987
|
-
const
|
|
1277
|
+
const builtin = (name) => typeof process.getBuiltinModule === "function" ? process.getBuiltinModule(name) : void 0;
|
|
1278
|
+
const events = builtin("node:events");
|
|
1279
|
+
const http = builtin("node:http");
|
|
1280
|
+
const https = builtin("node:https");
|
|
1281
|
+
const EventEmitter = events && events.EventEmitter;
|
|
1282
|
+
const Server = http && http.Server;
|
|
1283
|
+
const SecureServer = https && https.Server;
|
|
988
1284
|
if (!EventEmitter) return;
|
|
989
1285
|
const original = EventEmitter.prototype.emit;
|
|
990
1286
|
EventEmitter.prototype.emit = function(event, ...args) {
|
|
@@ -994,7 +1290,7 @@ function installNodeRequestPropagation() {
|
|
|
994
1290
|
// HTTP headers establish ownership even when Express/SDK listeners and
|
|
995
1291
|
// the server process were created by a shared before hook.
|
|
996
1292
|
const incoming = requestCoverageContext(args[0]);
|
|
997
|
-
if (incoming) context = incoming.scope ? incoming : context
|
|
1293
|
+
if (incoming) context = incoming.scope ? incoming : context != null ? context : currentRequestContext();
|
|
998
1294
|
}
|
|
999
1295
|
const invoke = () => Reflect.apply(original, this, [event, ...args]);
|
|
1000
1296
|
try {
|
|
@@ -1016,7 +1312,7 @@ function withRequestPhase(handler, event) {
|
|
|
1016
1312
|
const requestContext = args.map((argument) => requestCoverageContext(argument)).find((context2) => context2 !== void 0);
|
|
1017
1313
|
// An untagged request to a test-owned server must not erase that server's
|
|
1018
1314
|
// owner. Shared servers have no captured test scope and stay unattributed.
|
|
1019
|
-
const inheritedContext = requestContext
|
|
1315
|
+
const inheritedContext = requestContext && requestContext.scope ? {} : registeredContext.scope ? registeredContext : requestContext === void 0 ? currentRequestContext() : {};
|
|
1020
1316
|
const context = __spreadValues(__spreadValues({}, ((_a8 = requestContext == null ? void 0 : requestContext.scope) != null ? _a8 : inheritedContext.scope) ? { scope: (_b = requestContext == null ? void 0 : requestContext.scope) != null ? _b : inheritedContext.scope } : {}), ((_c = requestContext == null ? void 0 : requestContext.phaseId) != null ? _c : inheritedContext.phaseId) ? { phaseId: (_d = requestContext == null ? void 0 : requestContext.phaseId) != null ? _d : inheritedContext.phaseId } : {});
|
|
1021
1317
|
const invoke = () => {
|
|
1022
1318
|
if (event === "connection" && context.scope && args[0] &&
|
|
@@ -1038,10 +1334,36 @@ function recordBrowserEvent(event) {
|
|
|
1038
1334
|
return false;
|
|
1039
1335
|
state.eventKeys.add(key);
|
|
1040
1336
|
state.events.push(event);
|
|
1337
|
+
workerEvidenceChanged();
|
|
1041
1338
|
return true;
|
|
1042
1339
|
}
|
|
1340
|
+
// A hit is recorded once per context, as a statement probe's is: selections,
|
|
1341
|
+
// optional chains, defaults and loops reach here on every evaluation, and
|
|
1342
|
+
// each built and serialized its record before the transport dropped it as a
|
|
1343
|
+
// repeat.
|
|
1043
1344
|
function coverageHit(id) {
|
|
1345
|
+
const clock = state.probeV2Clock;
|
|
1346
|
+
if (clock.fast && state.hitEpochs !== void 0 && state.hitEpochs.get(id) === clock.epoch)
|
|
1347
|
+
return;
|
|
1348
|
+
recordCoverageHit(id);
|
|
1349
|
+
}
|
|
1350
|
+
// resetCoverage forces a fresh epoch, so a hit skipped above was recorded in
|
|
1351
|
+
// this epoch after the last reset and is in state.hits already.
|
|
1352
|
+
function recordCoverageHit(id) {
|
|
1044
1353
|
state.hits.add(id);
|
|
1354
|
+
const clock = state.probeV2Clock;
|
|
1355
|
+
let epoch = clock.epoch;
|
|
1356
|
+
if (!clock.fast) {
|
|
1357
|
+
const previousEpoch = clock.epoch;
|
|
1358
|
+
activateProbeV2Context(currentRequestContext());
|
|
1359
|
+
epoch = clock.epoch;
|
|
1360
|
+
clock.epoch = previousEpoch;
|
|
1361
|
+
}
|
|
1362
|
+
if (!state.hitEpochs)
|
|
1363
|
+
state.hitEpochs = /* @__PURE__ */ new Map();
|
|
1364
|
+
if (state.hitEpochs.get(id) === epoch)
|
|
1365
|
+
return;
|
|
1366
|
+
state.hitEpochs.set(id, epoch);
|
|
1045
1367
|
const timestampMs = Date.now();
|
|
1046
1368
|
const phaseId = currentPhaseId();
|
|
1047
1369
|
if (isBrowser) {
|
|
@@ -1075,7 +1397,12 @@ function registerProbeV2(definition) {
|
|
|
1075
1397
|
}),
|
|
1076
1398
|
decisionObservationEpochs: new Uint32Array(definition.decisions.length),
|
|
1077
1399
|
decisionObservationCounts: new Uint16Array(definition.decisions.length),
|
|
1078
|
-
decisionCompleteEpochs: new Uint32Array(definition.decisions.length)
|
|
1400
|
+
decisionCompleteEpochs: new Uint32Array(definition.decisions.length),
|
|
1401
|
+
pendingDefaults: new Uint32Array(definition.defaultCount || 0),
|
|
1402
|
+
// A selection's outcomes -- short falsy, short truthy, right falsy, right
|
|
1403
|
+
// truthy -- are four consecutive points per site from the first index.
|
|
1404
|
+
selectionPoints: definition.selectionPoints,
|
|
1405
|
+
none: optionalCallEmptySpread
|
|
1079
1406
|
};
|
|
1080
1407
|
state.probeV2Files.add(file);
|
|
1081
1408
|
if (isBrowser) {
|
|
@@ -1083,10 +1410,27 @@ function registerProbeV2(definition) {
|
|
|
1083
1410
|
activateProbeV2Key(`browser\0${(_a8 = runtimeGlobal.__SUPERCOV_MCDC_TEST_ID__) != null ? _a8 : testId}\0${(_b = runtimeGlobal.__SUPERCOV_PHASE_ID__) != null ? _b : "unscoped"}`);
|
|
1084
1411
|
} else {
|
|
1085
1412
|
installProbeV2AsyncHook();
|
|
1413
|
+
// The hook sets the epoch when an async callback begins. Code that runs
|
|
1414
|
+
// before any did -- a script's own top level -- found it NaN, which no
|
|
1415
|
+
// epoch equals, so every probe there took the slow path every time: a
|
|
1416
|
+
// million-iteration loop ran 1,700 times slower than without Supercov.
|
|
1417
|
+
if (Number.isNaN(state.probeV2Clock.epoch))
|
|
1418
|
+
activateProbeV2Context(currentRequestContext());
|
|
1086
1419
|
}
|
|
1087
1420
|
return file;
|
|
1088
1421
|
}
|
|
1422
|
+
// Every repeat of a probe in the same context ends at the first check, so it
|
|
1423
|
+
// stays small enough for V8 to inline into the instrumented function; the
|
|
1424
|
+
// rest runs once per context. minimatch's backtracking guard test needs a
|
|
1425
|
+
// pathological match inside a second, and the full body in every call put it
|
|
1426
|
+
// at ten times the uninstrumented time.
|
|
1089
1427
|
function coverageHitV2(file, index) {
|
|
1428
|
+
const clock = file.clock;
|
|
1429
|
+
if (clock.fast && file.hitEpochs[index] === clock.epoch)
|
|
1430
|
+
return;
|
|
1431
|
+
recordCoverageHitV2(file, index);
|
|
1432
|
+
}
|
|
1433
|
+
function recordCoverageHitV2(file, index) {
|
|
1090
1434
|
const id = file.pointIds[index];
|
|
1091
1435
|
if (!id)
|
|
1092
1436
|
return;
|
|
@@ -1100,6 +1444,9 @@ function coverageHitV2(file, index) {
|
|
|
1100
1444
|
return;
|
|
1101
1445
|
file.hitEpochs[index] = epoch;
|
|
1102
1446
|
coverageHit(id);
|
|
1447
|
+
const selections = file.selectionPoints;
|
|
1448
|
+
if (selections !== void 0 && index >= selections[0] && index < selections[0] + 4 * selections[1])
|
|
1449
|
+
recordSelectionOutcome(id, index - selections[0] & 3);
|
|
1103
1450
|
} finally {
|
|
1104
1451
|
if (fallbackEpoch)
|
|
1105
1452
|
file.clock.epoch = previousEpoch;
|
|
@@ -1118,6 +1465,15 @@ function decodeProbeV2Vector(conditionCount, encoded, outcome) {
|
|
|
1118
1465
|
return remaining === 0 ? { values, outcome } : void 0;
|
|
1119
1466
|
}
|
|
1120
1467
|
function mcdcEndV2(file, decisionIndex, encoded, value) {
|
|
1468
|
+
const clock = file.clock;
|
|
1469
|
+
if (clock.fast) {
|
|
1470
|
+
const seen = file.decisionEpochs[decisionIndex];
|
|
1471
|
+
if (seen instanceof Uint32Array && seen[encoded * 2 + (value ? 1 : 0)] === clock.epoch)
|
|
1472
|
+
return value;
|
|
1473
|
+
}
|
|
1474
|
+
return recordMcdcEndV2(file, decisionIndex, encoded, value);
|
|
1475
|
+
}
|
|
1476
|
+
function recordMcdcEndV2(file, decisionIndex, encoded, value) {
|
|
1121
1477
|
var _a8, _b;
|
|
1122
1478
|
const meta = file.decisions[decisionIndex];
|
|
1123
1479
|
if (!meta || !Number.isSafeInteger(encoded) || encoded < 0)
|
|
@@ -1170,6 +1526,7 @@ function selectionBegin(shortId, rightId) {
|
|
|
1170
1526
|
function applyInferredName(value, inferredName) {
|
|
1171
1527
|
if (inferredName && typeof value === "function" && value.name === "") {
|
|
1172
1528
|
Object.defineProperty(value, "name", {
|
|
1529
|
+
__proto__: null,
|
|
1173
1530
|
value: inferredName,
|
|
1174
1531
|
configurable: true
|
|
1175
1532
|
});
|
|
@@ -1189,24 +1546,38 @@ function selectionRight(frame, value, inferredName) {
|
|
|
1189
1546
|
frame.rightEvaluated = true;
|
|
1190
1547
|
return applyInferredName(value, inferredName);
|
|
1191
1548
|
}
|
|
1549
|
+
var selectionOutcomeKeys = ["SF", "ST", "RF", "RT"];
|
|
1550
|
+
var selectionBranchIds = /* @__PURE__ */ new Map();
|
|
1192
1551
|
function selectionEnd(frame, value) {
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
const separator = frame.shortId.lastIndexOf(":");
|
|
1197
|
-
if (separator > 0) {
|
|
1198
|
-
const branchId = frame.shortId.slice(0, separator);
|
|
1199
|
-
const right = frame.rightEvaluated;
|
|
1200
|
-
const truthy = Boolean(value);
|
|
1201
|
-
let vectors = state.logicals.get(branchId);
|
|
1202
|
-
if (!vectors) {
|
|
1203
|
-
vectors = /* @__PURE__ */ new Map();
|
|
1204
|
-
state.logicals.set(branchId, vectors);
|
|
1205
|
-
}
|
|
1206
|
-
vectors.set(`${right ? "R" : "S"}${truthy ? "T" : "F"}`, { right, truthy });
|
|
1207
|
-
}
|
|
1552
|
+
const right = frame.rightEvaluated;
|
|
1553
|
+
coverageHit(right ? frame.rightId : frame.shortId);
|
|
1554
|
+
recordSelectionOutcome(frame.shortId, (right ? 2 : 0) + (value ? 1 : 0));
|
|
1208
1555
|
return value;
|
|
1209
1556
|
}
|
|
1557
|
+
// Per-operand outcomes for the verifier: which side was selected and whether
|
|
1558
|
+
// the result is truthy. With the operator (known from the manifest) this gives
|
|
1559
|
+
// each operand's outcome. The branch id is cut from the outcome's id -- its
|
|
1560
|
+
// short or right id, which share it -- once, not on every evaluation.
|
|
1561
|
+
function recordSelectionOutcome(id, outcome) {
|
|
1562
|
+
let branchId = selectionBranchIds.get(id);
|
|
1563
|
+
if (branchId === void 0) {
|
|
1564
|
+
const separator = id.lastIndexOf(":");
|
|
1565
|
+
branchId = separator > 0 ? id.slice(0, separator) : null;
|
|
1566
|
+
selectionBranchIds.set(id, branchId);
|
|
1567
|
+
}
|
|
1568
|
+
if (branchId === null)
|
|
1569
|
+
return;
|
|
1570
|
+
let vectors = state.logicals.get(branchId);
|
|
1571
|
+
if (!vectors) {
|
|
1572
|
+
vectors = /* @__PURE__ */ new Map();
|
|
1573
|
+
state.logicals.set(branchId, vectors);
|
|
1574
|
+
}
|
|
1575
|
+
const key = selectionOutcomeKeys[outcome];
|
|
1576
|
+
if (!vectors.has(key)) {
|
|
1577
|
+
vectors.set(key, { right: outcome >= 2, truthy: (outcome & 1) === 1 });
|
|
1578
|
+
workerEvidenceChanged();
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1210
1581
|
// A JSX expression container has nowhere to put a statement and cannot hold a
|
|
1211
1582
|
// bare comma operator, so a rendered expression carries its probe as a call
|
|
1212
1583
|
// that returns the value through. Like optionalSelect, it records after the
|
|
@@ -1220,6 +1591,75 @@ function optionalSelect(shortId, continuedId, value) {
|
|
|
1220
1591
|
coverageHit(value === null || value === void 0 ? shortId : continuedId);
|
|
1221
1592
|
return value;
|
|
1222
1593
|
}
|
|
1594
|
+
// `a || b` (kind 0), `a && b` (1), `a ?? b` (2), with the program's own
|
|
1595
|
+
// operator between the two calls: the left operand records its short outcome
|
|
1596
|
+
// when it decides the result -- truthy, falsy, present -- and the right one
|
|
1597
|
+
// whether it came out truthy. The outcomes are the selection's four points.
|
|
1598
|
+
function selectShortV2(file, first, value, kind) {
|
|
1599
|
+
if (kind === 0 ? value : kind === 1 ? !value : value !== null && value !== void 0)
|
|
1600
|
+
coverageHitV2(file, value ? first + 1 : first);
|
|
1601
|
+
return value;
|
|
1602
|
+
}
|
|
1603
|
+
function selectRightV2(file, first, value) {
|
|
1604
|
+
coverageHitV2(file, value ? first + 3 : first + 2);
|
|
1605
|
+
return value;
|
|
1606
|
+
}
|
|
1607
|
+
// A leaf of nested selections, `(a && b) || c`: the program's operators stay
|
|
1608
|
+
// between the leaves, so a coverage tool the tests run flattens them into the
|
|
1609
|
+
// one branch it reads without Supercov. Each step after the value names a
|
|
1610
|
+
// selection above the leaf, nearest first, as `first * 4 + code`: code 3 when
|
|
1611
|
+
// the leaf is on its right side, which records that side's outcome, and the
|
|
1612
|
+
// operator's kind (0 `||`, 1 `&&`, 2 `??`) when on its left, which records the
|
|
1613
|
+
// short outcome when the value decides it; otherwise the selection goes on to
|
|
1614
|
+
// its right side, and the leaf decides nothing further up.
|
|
1615
|
+
function selectPathV2(file, value) {
|
|
1616
|
+
for (let index = 2; index < arguments.length; index += 1) {
|
|
1617
|
+
const step = arguments[index];
|
|
1618
|
+
const code = step & 3;
|
|
1619
|
+
const first = (step - code) / 4;
|
|
1620
|
+
if (code === 3)
|
|
1621
|
+
coverageHitV2(file, value ? first + 3 : first + 2);
|
|
1622
|
+
else if (code === 0 ? value : code === 1 ? !value : value !== null && value !== void 0)
|
|
1623
|
+
coverageHitV2(file, value ? first + 1 : first);
|
|
1624
|
+
else
|
|
1625
|
+
break;
|
|
1626
|
+
}
|
|
1627
|
+
return value;
|
|
1628
|
+
}
|
|
1629
|
+
// `x ||= y`, `x &&= y`, `x ??= y` keep their operator and their single
|
|
1630
|
+
// evaluation of the target: the right side goes through selectRightV2 (or the
|
|
1631
|
+
// named form, for an anonymous function the assignment would have named), and
|
|
1632
|
+
// a site temporary set to 1 after it tells the end whether the assignment was
|
|
1633
|
+
// skipped, which is then the short outcome for the value the target kept.
|
|
1634
|
+
function selectNamedRightV2(file, first, value, inferredName) {
|
|
1635
|
+
coverageHitV2(file, value ? first + 3 : first + 2);
|
|
1636
|
+
return applyInferredName(value, inferredName);
|
|
1637
|
+
}
|
|
1638
|
+
function selectAssignEndV2(file, first, value, right) {
|
|
1639
|
+
if (!right)
|
|
1640
|
+
coverageHitV2(file, value ? first + 1 : first);
|
|
1641
|
+
return value;
|
|
1642
|
+
}
|
|
1643
|
+
// `object?.member`: the short and continued outcomes are two V2 points.
|
|
1644
|
+
// Whether the previous optional link of the chain being evaluated cut it
|
|
1645
|
+
// short. In `a?.b?.c` the object of `?.c` is undefined when `a` is, though
|
|
1646
|
+
// `?.c` never ran: `?.b` says so here and `?.c` records nothing. `links` has
|
|
1647
|
+
// 1 when an earlier link of the chain runs first and 2 when a later one
|
|
1648
|
+
// follows. Every link with a later one writes this and that later one reads
|
|
1649
|
+
// and clears it, so code run in between -- a getter, a call -- that
|
|
1650
|
+
// evaluates chains of its own leaves it as it found it. 4 means the earlier
|
|
1651
|
+
// link is an optional call, whose frame `call` is 2 only if it went ahead.
|
|
1652
|
+
var optionalChainCut = false;
|
|
1653
|
+
function optionalSelectV2(file, first, value, links, call) {
|
|
1654
|
+
if (links & 1 && optionalChainCut || links & 4 && call !== 2) {
|
|
1655
|
+
optionalChainCut = (links & 2) !== 0;
|
|
1656
|
+
return value;
|
|
1657
|
+
}
|
|
1658
|
+
var nullish = value === null || value === void 0;
|
|
1659
|
+
coverageHitV2(file, nullish ? first : first + 1);
|
|
1660
|
+
optionalChainCut = nullish && (links & 2) !== 0;
|
|
1661
|
+
return value;
|
|
1662
|
+
}
|
|
1223
1663
|
function optionalCallBegin(shortId, continuedId) {
|
|
1224
1664
|
return { shortId, continuedId, reached: false, continued: false };
|
|
1225
1665
|
}
|
|
@@ -1227,13 +1667,17 @@ function optionalCallReached(frame, value) {
|
|
|
1227
1667
|
frame.reached = true;
|
|
1228
1668
|
return value;
|
|
1229
1669
|
}
|
|
1670
|
+
// Spread into an optional call's arguments to mark that the call went ahead:
|
|
1671
|
+
// it yields nothing, and allocates nothing per call.
|
|
1672
|
+
var optionalCallDone = { done: true, value: void 0 };
|
|
1673
|
+
var optionalCallEmptyIterator = {
|
|
1674
|
+
next() {
|
|
1675
|
+
return optionalCallDone;
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1230
1678
|
var optionalCallEmptySpread = {
|
|
1231
1679
|
[Symbol.iterator]() {
|
|
1232
|
-
return
|
|
1233
|
-
next() {
|
|
1234
|
-
return { done: true, value: void 0 };
|
|
1235
|
-
}
|
|
1236
|
-
};
|
|
1680
|
+
return optionalCallEmptyIterator;
|
|
1237
1681
|
}
|
|
1238
1682
|
};
|
|
1239
1683
|
function optionalCallContinued(frame) {
|
|
@@ -1245,6 +1689,13 @@ function optionalCallEnd(frame, value) {
|
|
|
1245
1689
|
coverageHit(frame.continued ? frame.continuedId : frame.shortId);
|
|
1246
1690
|
return value;
|
|
1247
1691
|
}
|
|
1692
|
+
// The site's state, read after the chain: 0 not reached, 1 reached and
|
|
1693
|
+
// short-circuited, 2 called. Short and continued are two V2 points.
|
|
1694
|
+
function optionalCallEndV2(file, first, value, state) {
|
|
1695
|
+
if (state)
|
|
1696
|
+
coverageHitV2(file, state === 2 ? first + 1 : first);
|
|
1697
|
+
return value;
|
|
1698
|
+
}
|
|
1248
1699
|
function defaultSelected(defaultId, value, inferredName) {
|
|
1249
1700
|
var _a8;
|
|
1250
1701
|
pendingDefaults.set(defaultId, ((_a8 = pendingDefaults.get(defaultId)) != null ? _a8 : 0) + 1);
|
|
@@ -1260,6 +1711,24 @@ function defaultEntered(defaultId, providedId) {
|
|
|
1260
1711
|
coverageHit(providedId);
|
|
1261
1712
|
}
|
|
1262
1713
|
}
|
|
1714
|
+
// The same count per default, in a slot of the file's typed array instead of
|
|
1715
|
+
// a Map keyed by the default's id, and the outcome recorded through the V2
|
|
1716
|
+
// point check, which ends at one comparison once it fired in this context.
|
|
1717
|
+
// lru-cache's set and get destructure options with defaults: the Map and the
|
|
1718
|
+
// two calls behind each were a third of a hot loop.
|
|
1719
|
+
function defaultSelectedV2(file, slot, value, inferredName) {
|
|
1720
|
+
file.pendingDefaults[slot] += 1;
|
|
1721
|
+
return inferredName ? applyInferredName(value, inferredName) : value;
|
|
1722
|
+
}
|
|
1723
|
+
function defaultEnteredV2(file, slot, defaultPoint, providedPoint) {
|
|
1724
|
+
const pending = file.pendingDefaults;
|
|
1725
|
+
if (pending[slot] > 0) {
|
|
1726
|
+
pending[slot] -= 1;
|
|
1727
|
+
coverageHitV2(file, defaultPoint);
|
|
1728
|
+
} else {
|
|
1729
|
+
coverageHitV2(file, providedPoint);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1263
1732
|
function tryBegin(successId, catchId) {
|
|
1264
1733
|
return { successId, catchId, caught: false };
|
|
1265
1734
|
}
|
|
@@ -1349,7 +1818,9 @@ const directRuntimeApi = {
|
|
|
1349
1818
|
coverageSnapshot,
|
|
1350
1819
|
decodeProbeV2Vector,
|
|
1351
1820
|
defaultEntered,
|
|
1821
|
+
defaultEnteredV2,
|
|
1352
1822
|
defaultSelected,
|
|
1823
|
+
defaultSelectedV2,
|
|
1353
1824
|
enableRuntimeSnapshotEvidence,
|
|
1354
1825
|
flushBufferedBackgroundEvidence,
|
|
1355
1826
|
flushBufferedServerEvidence,
|
|
@@ -1364,7 +1835,9 @@ const directRuntimeApi = {
|
|
|
1364
1835
|
optionalCallContinued,
|
|
1365
1836
|
optionalCallEnd,
|
|
1366
1837
|
optionalCallReached,
|
|
1838
|
+
optionalCallEndV2,
|
|
1367
1839
|
optionalSelect,
|
|
1840
|
+
optionalSelectV2,
|
|
1368
1841
|
renderedValueV2,
|
|
1369
1842
|
parenthesizedAssignmentValue,
|
|
1370
1843
|
phaseBelongsToAttempt,
|
|
@@ -1373,6 +1846,11 @@ const directRuntimeApi = {
|
|
|
1373
1846
|
selectionBegin,
|
|
1374
1847
|
selectionEnd,
|
|
1375
1848
|
selectionRight,
|
|
1849
|
+
selectShortV2,
|
|
1850
|
+
selectRightV2,
|
|
1851
|
+
selectNamedRightV2,
|
|
1852
|
+
selectAssignEndV2,
|
|
1853
|
+
selectPathV2,
|
|
1376
1854
|
takeNodeAssertionPhases,
|
|
1377
1855
|
tryBegin,
|
|
1378
1856
|
tryCatch,
|
|
@@ -1380,12 +1858,14 @@ const directRuntimeApi = {
|
|
|
1380
1858
|
withCoverageCarrier,
|
|
1381
1859
|
withNodeAssertionPhase,
|
|
1382
1860
|
bindNodeAssertionPhase,
|
|
1861
|
+
openNodeAssertionPhase,
|
|
1383
1862
|
withRequestPhase,
|
|
1384
1863
|
writeExclusiveBackgroundRecord
|
|
1385
1864
|
};
|
|
1386
|
-
globalThis.__SUPERCOV_DIRECT_RUNTIME__
|
|
1387
|
-
|
|
1388
|
-
|
|
1865
|
+
if (globalThis.__SUPERCOV_DIRECT_RUNTIME__ == null)
|
|
1866
|
+
globalThis.__SUPERCOV_DIRECT_RUNTIME__ = directRuntimeApi;
|
|
1867
|
+
if (typeof process !== "undefined" && process.__SUPERCOV_DIRECT_RUNTIME__ == null)
|
|
1868
|
+
process.__SUPERCOV_DIRECT_RUNTIME__ = directRuntimeApi;
|
|
1389
1869
|
export {
|
|
1390
1870
|
activateCoverageScope,
|
|
1391
1871
|
beginBufferedServerEvidence,
|
|
@@ -1399,7 +1879,9 @@ export {
|
|
|
1399
1879
|
coverageSnapshot,
|
|
1400
1880
|
decodeProbeV2Vector,
|
|
1401
1881
|
defaultEntered,
|
|
1882
|
+
defaultEnteredV2,
|
|
1402
1883
|
defaultSelected,
|
|
1884
|
+
defaultSelectedV2,
|
|
1403
1885
|
enableRuntimeSnapshotEvidence,
|
|
1404
1886
|
flushBufferedBackgroundEvidence,
|
|
1405
1887
|
flushBufferedServerEvidence,
|
|
@@ -1415,7 +1897,9 @@ export {
|
|
|
1415
1897
|
optionalCallContinued,
|
|
1416
1898
|
optionalCallEnd,
|
|
1417
1899
|
optionalCallReached,
|
|
1900
|
+
optionalCallEndV2,
|
|
1418
1901
|
optionalSelect,
|
|
1902
|
+
optionalSelectV2,
|
|
1419
1903
|
renderedValueV2,
|
|
1420
1904
|
parenthesizedAssignmentValue,
|
|
1421
1905
|
phaseBelongsToAttempt,
|
|
@@ -1424,6 +1908,11 @@ export {
|
|
|
1424
1908
|
selectionBegin,
|
|
1425
1909
|
selectionEnd,
|
|
1426
1910
|
selectionRight,
|
|
1911
|
+
selectShortV2,
|
|
1912
|
+
selectRightV2,
|
|
1913
|
+
selectNamedRightV2,
|
|
1914
|
+
selectAssignEndV2,
|
|
1915
|
+
selectPathV2,
|
|
1427
1916
|
takeNodeAssertionPhases,
|
|
1428
1917
|
tryBegin,
|
|
1429
1918
|
tryCatch,
|
|
@@ -1431,6 +1920,7 @@ export {
|
|
|
1431
1920
|
withCoverageCarrier,
|
|
1432
1921
|
withNodeAssertionPhase,
|
|
1433
1922
|
bindNodeAssertionPhase,
|
|
1923
|
+
openNodeAssertionPhase,
|
|
1434
1924
|
withRequestPhase,
|
|
1435
1925
|
writeExclusiveBackgroundRecord
|
|
1436
1926
|
};
|