@systemfsoftware/stryker-js 10.0.0 → 10.1.0
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/CHANGELOG.md +12 -0
- package/dist/{Run.schema-C0Cxsfe9.mjs → Run.schema-B0ERLxQj.mjs} +78 -65
- package/dist/{Run.schema-BBKIZ81u.d.mts → Run.schema-RWUb38ZE.d.mts} +13 -5
- package/dist/{compiler-Bq9Nelu8.mjs → compiler-Dc7TYMb_.mjs} +1709 -991
- package/dist/{compiler-C8aLIb5U.mjs → compiler-Faeg70AC.mjs} +1709 -991
- package/dist/config.d.mts +1 -1
- package/dist/{dist-B3nT7z4G.mjs → dist-Dmv1WEP8.mjs} +625 -443
- package/dist/events.d.mts +1 -1
- package/dist/events.mjs +1 -1
- package/dist/{index-DnAm4mSL.d.mts → index-BopuZXrl.d.mts} +51 -11
- package/dist/index.d.mts +48 -12
- package/dist/index.mjs +2 -2
- package/dist/main.mjs +16461 -35430
- package/dist/{mutation-test.cell-m9T-X2Qx.d.mts → mutation-test.cell-CobzlfL-.d.mts} +14 -6
- package/dist/parser.wasm32-wasi.wasm +0 -0
- package/dist/promises.d.mts +2 -2
- package/dist/promises.mjs +1 -1
- package/dist/{src-Bu4i-Lt2.mjs → src-Baq6uz-6.mjs} +541 -623
- package/dist/{src-js-DRK8boNV.mjs → src-js-CvBdbRpe.mjs} +129 -56
- package/dist/{wasm-Dg4JcQ2d.mjs → wasm-CUFfND2k.mjs} +4545 -4335
- package/package.json +31 -31
- package/dist/execAsync-CfPZgJSD.mjs +0 -10
- package/dist/getMachineId-bsd-YZILidse.mjs +0 -27
- package/dist/getMachineId-darwin-B_CgClId.mjs +0 -24
- package/dist/getMachineId-linux-DprzjpT3.mjs +0 -20
- package/dist/getMachineId-unsupported-Ce9f061A.mjs +0 -15
- package/dist/getMachineId-win-DETv1PQd.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as WorkerEntryUrl, F as MutationTestingPlanReady, G as TRACEPARENT_HEADER, I as NonNegativeInt, J as TestRunnerFailed, K as TRACESTATE_HEADER, L as PropagatedTrace, M as MutantTested, N as MutationTestReportReady, O as Metrics, P as MutationTestResultSchema$1, Q as WALL_CLOCK_TIMEOUT_REASON, S as CheckerMutantWire, T as DryRunCompleted, U as ReporterRpcs, V as ReporterFailed, W as StrykerOptionsSchema, X as TraceContextMiddleware, Y as TestRunnerRpcs, Z as TraceContextReference, _ as RunStarted, at as wallClockTimeoutStopsRun, c as PhaseEntered, ct as Mutant, et as WorkerPluginKind, f as RunEvent, ft as disableTypeChecks, ht as normalizeFileName$4, it as toMutantRunResult, k as MetricsResultSchema, l as PlanKnown, m as RunMutantTested, mt as instrument, n as StageError, nt as isCustomTestRunner, ot as INSTRUMENTER_CONSTANTS, pt as errorToString, r as Heartbeat, rt as parseTraceparent, t as PrepareError, tt as formatTraceparent, v as VerdictReached, w as CheckerRpcs } from "./Run.schema-B0ERLxQj.mjs";
|
|
2
2
|
import { t as mergeConfig } from "./merge-config-BrrNQWje.mjs";
|
|
3
3
|
import * as Effect$1 from "effect/Effect";
|
|
4
4
|
import * as FileSystem from "effect/FileSystem";
|
|
@@ -16,12 +16,12 @@ import * as Ref from "effect/Ref";
|
|
|
16
16
|
import * as Result from "effect/Result";
|
|
17
17
|
import * as S from "effect/Schema";
|
|
18
18
|
import * as Stream from "effect/Stream";
|
|
19
|
-
import { Cell, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
19
|
+
import { Cell, Sandwich, Workflow } from "@systemfsoftware/effect-cell-types";
|
|
20
20
|
import * as Predicate from "effect/Predicate";
|
|
21
21
|
import * as Array$1 from "effect/Array";
|
|
22
|
-
import { Schema } from "effect";
|
|
22
|
+
import { Schema, SchemaGetter } from "effect";
|
|
23
23
|
import * as RpcMiddleware from "effect/unstable/rpc/RpcMiddleware";
|
|
24
|
-
import * as SchemaGetter from "effect/SchemaGetter";
|
|
24
|
+
import * as SchemaGetter$1 from "effect/SchemaGetter";
|
|
25
25
|
import * as Exit from "effect/Exit";
|
|
26
26
|
import * as Scope from "effect/Scope";
|
|
27
27
|
import * as Duration from "effect/Duration";
|
|
@@ -52,7 +52,7 @@ import * as Equivalence from "effect/Equivalence";
|
|
|
52
52
|
import * as Metric from "effect/Metric";
|
|
53
53
|
import * as Pool from "effect/Pool";
|
|
54
54
|
import * as Semaphore from "effect/Semaphore";
|
|
55
|
-
import * as SchemaTransformation from "effect/SchemaTransformation";
|
|
55
|
+
import * as SchemaTransformation$1 from "effect/SchemaTransformation";
|
|
56
56
|
import { randomBytes } from "@noble/hashes/utils.js";
|
|
57
57
|
import * as Console from "effect/Console";
|
|
58
58
|
import "effect/Sink";
|
|
@@ -142,8 +142,8 @@ const frameRunEvent = Workflow.total(FrameRunEventCommand, decideFrame);
|
|
|
142
142
|
//#endregion
|
|
143
143
|
//#region src/run-event-wire.schema.ts
|
|
144
144
|
const RunEventWireLine = S.String.pipe(S.decodeTo(S.fromJsonString(RunEvent), {
|
|
145
|
-
decode: SchemaGetter.transform((line) => line.replace(/\n$/, "")),
|
|
146
|
-
encode: SchemaGetter.transform((json) => `${json}\n`)
|
|
145
|
+
decode: SchemaGetter$1.transform((line) => line.replace(/\n$/, "")),
|
|
146
|
+
encode: SchemaGetter$1.transform((json) => `${json}\n`)
|
|
147
147
|
}));
|
|
148
148
|
//#endregion
|
|
149
149
|
//#region src/RunEvents.ts
|
|
@@ -345,9 +345,18 @@ const calculateTotalTimeForIds = (testIds, testTimeById) => testIds.reduce((acc,
|
|
|
345
345
|
if (t !== void 0) return acc + t;
|
|
346
346
|
return acc;
|
|
347
347
|
}, 0);
|
|
348
|
+
const hitLimitForCount = (hitCount) => hitCount * 100;
|
|
349
|
+
const coveredWhenKnown = (covered, coverageKnown) => {
|
|
350
|
+
if (!coverageKnown) return false;
|
|
351
|
+
return covered;
|
|
352
|
+
};
|
|
353
|
+
const isMissingHitCount = (hitCount, covered, coverageKnown) => {
|
|
354
|
+
if (!coveredWhenKnown(covered, coverageKnown)) return false;
|
|
355
|
+
return hitCount === void 0;
|
|
356
|
+
};
|
|
348
357
|
const getHitLimit = (hitCount) => {
|
|
349
358
|
if (hitCount === void 0) return;
|
|
350
|
-
return hitCount
|
|
359
|
+
return hitLimitForCount(hitCount);
|
|
351
360
|
};
|
|
352
361
|
const getMutantActivation = (testFilter) => {
|
|
353
362
|
if (testFilter !== void 0) return "runtime";
|
|
@@ -407,6 +416,16 @@ const planForStaticallyCovered = (mutant, command, isStatic) => {
|
|
|
407
416
|
const useCovered = Match.value(isStatic).pipe(Match.when(false, () => true), Match.orElse(() => ignoreStatic && tests.length > ZERO));
|
|
408
417
|
return Match.value(useCovered).pipe(Match.when(true, () => toRunPlan(mutant, command, calculateTotalTimeForIds(tests, command.testTimeById), coveredBy, isStatic, coveredBy)), Match.orElse(() => Match.value(ignoreStatic).pipe(Match.when(true, () => toEarlyResultPlan(mutant, isStatic, "Ignored", "Static mutant (and \"ignoreStatic\" was enabled)", coveredBy)), Match.orElse(() => toRunPlan(mutant, command, command.timeSpentAllTests, getTestFilter(command.globalTestFilter), isStatic, coveredBy)))));
|
|
409
418
|
};
|
|
419
|
+
const hasCoveringTests = (tests) => {
|
|
420
|
+
if (tests === void 0) return false;
|
|
421
|
+
return tests.length > 0;
|
|
422
|
+
};
|
|
423
|
+
const mutantIsCovered = (command, mutantId) => {
|
|
424
|
+
if (hasCoveringTests(command.testsByMutantId[mutantId])) return true;
|
|
425
|
+
return hasStaticCoverageForPlan(command.staticCoverage, mutantId);
|
|
426
|
+
};
|
|
427
|
+
const coverageKnown = (command) => command.staticCoverage !== void 0;
|
|
428
|
+
const boundFor = (command, mutant) => isMissingHitCount(command.hitsByMutantId[mutant.id], mutantIsCovered(command, mutant.id), coverageKnown(command));
|
|
410
429
|
const decidePlanForMutant = (mutant, command) => {
|
|
411
430
|
const isStatic = hasStaticCoverageForPlan(command.staticCoverage, mutant.id);
|
|
412
431
|
return Option.match(Option.fromUndefinedOr(mutant.status), {
|
|
@@ -414,6 +433,15 @@ const decidePlanForMutant = (mutant, command) => {
|
|
|
414
433
|
onNone: () => Match.value(hasCoverageForPlan(command.staticCoverage)).pipe(Match.when(true, () => planForStaticallyCovered(mutant, command, isStatic)), Match.orElse(() => toRunPlan(mutant, command, command.timeSpentAllTests, getTestFilter(command.globalTestFilter), void 0, void 0)))
|
|
415
434
|
});
|
|
416
435
|
};
|
|
436
|
+
const isClosedMutant = (mutant) => mutant.status !== void 0;
|
|
437
|
+
const missingIdOf = (command, mutant) => {
|
|
438
|
+
if (!boundFor(command, mutant)) return [];
|
|
439
|
+
return [mutant.id];
|
|
440
|
+
};
|
|
441
|
+
const missingHitCountIds = (command) => command.mutants.flatMap((mutant) => {
|
|
442
|
+
if (isClosedMutant(mutant)) return [];
|
|
443
|
+
return missingIdOf(command, mutant);
|
|
444
|
+
});
|
|
417
445
|
const planMutantTests = (command) => {
|
|
418
446
|
const plans = command.mutants.map((mutant) => decidePlanForMutant(mutant, command));
|
|
419
447
|
return {
|
|
@@ -510,15 +538,28 @@ const materializePlan = (plan, original) => {
|
|
|
510
538
|
}
|
|
511
539
|
};
|
|
512
540
|
};
|
|
541
|
+
const missingHitFailure = (missing) => {
|
|
542
|
+
if (missing.length === 0) return;
|
|
543
|
+
return Effect$1.fail(StageError.make({
|
|
544
|
+
stage: "mutationTest",
|
|
545
|
+
reason: `covered mutant missing dry-run hit count: ${missing.join(", ")}`
|
|
546
|
+
}));
|
|
547
|
+
};
|
|
548
|
+
const mutantsById = (mutants) => {
|
|
549
|
+
const byId = /* @__PURE__ */ new Map();
|
|
550
|
+
for (const mutant of mutants) byId.set(mutant.id, mutant);
|
|
551
|
+
return byId;
|
|
552
|
+
};
|
|
553
|
+
const materializeKnown = (plan, byId) => {
|
|
554
|
+
const original = byId.get(plan.mutantId);
|
|
555
|
+
if (original === void 0) return Effect$1.die(/* @__PURE__ */ new Error(`planner returned an unknown mutant id: ${plan.mutantId}`));
|
|
556
|
+
return Effect$1.succeed(materializePlan(plan, original));
|
|
557
|
+
};
|
|
513
558
|
const makeMutantTestPlanner = (command) => {
|
|
559
|
+
const failed = missingHitFailure(missingHitCountIds(command));
|
|
560
|
+
if (failed !== void 0) return failed;
|
|
514
561
|
const { plans } = planMutantTests(command);
|
|
515
|
-
|
|
516
|
-
for (const mutant of command.mutants) byId.set(mutant.id, mutant);
|
|
517
|
-
return Effect$1.forEach(plans, (plan) => {
|
|
518
|
-
const original = byId.get(plan.mutantId);
|
|
519
|
-
if (original === void 0) return Effect$1.die(/* @__PURE__ */ new Error(`planner returned an unknown mutant id: ${plan.mutantId}`));
|
|
520
|
-
return Effect$1.succeed(materializePlan(plan, original));
|
|
521
|
-
});
|
|
562
|
+
return Effect$1.forEach(plans, (plan) => materializeKnown(plan, mutantsById(command.mutants)));
|
|
522
563
|
};
|
|
523
564
|
const decidePlans = (mutants, testCoverage, options, timeOverheadMS, globalTestFilter, sandboxFileByName) => {
|
|
524
565
|
const command = coverageToCommand(mutants, testCoverage, options, timeOverheadMS, globalTestFilter, sandboxFileByName);
|
|
@@ -915,9 +956,9 @@ Layer.succeed(TraceContextMiddleware, serverMiddleware);
|
|
|
915
956
|
let wire;
|
|
916
957
|
const workerOptionsWire = () => wire ??= S.fromJsonString(S.toCodecJson(StrykerOptionsSchema));
|
|
917
958
|
const encodeWorkerOptions = (options) => S.encodeEffect(workerOptionsWire())(options).pipe(Effect$1.orDie);
|
|
918
|
-
const decodeWorkerOptions = (raw) => S.
|
|
959
|
+
const decodeWorkerOptions = (raw) => S.decodeEffect(workerOptionsWire())(raw);
|
|
919
960
|
Effect$1.gen(function* () {
|
|
920
|
-
const workerDir = yield* Config.
|
|
961
|
+
const workerDir = yield* Config.String("STRYKER_WORKER_DIR");
|
|
921
962
|
const fs = yield* FileSystem.FileSystem;
|
|
922
963
|
const path = yield* Path.Path;
|
|
923
964
|
const raw = yield* fs.readFileString(path.join(workerDir, "options.json"));
|
|
@@ -936,9 +977,9 @@ const otlpLayer = (serviceName, endpoint) => NodeSdk.layer(() => ({
|
|
|
936
977
|
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter({ url: tracesUrl(endpoint) }))
|
|
937
978
|
}));
|
|
938
979
|
Layer.unwrap(Effect$1.gen(function* () {
|
|
939
|
-
if (!(yield* Config.
|
|
940
|
-
const serviceName = yield* Config.
|
|
941
|
-
const endpoint = yield* Config.
|
|
980
|
+
if (!(yield* Config.Boolean("OTEL_ENABLED").pipe(Config.withDefault(false)))) return Layer.empty;
|
|
981
|
+
const serviceName = yield* Config.String("OTEL_SERVICE_NAME").pipe(Config.withDefault(WORKER_SERVICE_NAME));
|
|
982
|
+
const endpoint = yield* Config.String("OTEL_EXPORTER_OTLP_ENDPOINT").pipe(Config.withDefault(DEFAULT_ENDPOINT));
|
|
942
983
|
return otlpLayer(serviceName, endpoint);
|
|
943
984
|
}));
|
|
944
985
|
//#endregion
|
|
@@ -1202,7 +1243,7 @@ const makeWorkerClient = (params) => Effect$1.gen(function* () {
|
|
|
1202
1243
|
});
|
|
1203
1244
|
//#endregion
|
|
1204
1245
|
//#region src/platform/node.ts
|
|
1205
|
-
const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(Effect$1.
|
|
1246
|
+
const restrictToOwnerOrWarn = (fs, file) => fs.chmod(file, 384).pipe(Effect$1.tapError((cause) => Effect$1.logWarning(`Could not restrict "${file}" to its owner; the worker directory's own mode still protects it.`).pipe(Effect$1.annotateLogs("cause", cause))), Effect$1.catchTag("PlatformError", () => Effect$1.void));
|
|
1206
1247
|
/**
|
|
1207
1248
|
* The Node worker launcher: spawn a worker child with this runtime's
|
|
1208
1249
|
* executable, host the RPC server's address as a `net` `path` endpoint (a
|
|
@@ -1217,12 +1258,12 @@ const nodeWorkerLauncherLayer = Layer.effect(WorkerLauncher, Effect$1.gen(functi
|
|
|
1217
1258
|
return { spawn: (params) => Effect$1.gen(function* () {
|
|
1218
1259
|
const workerDir = yield* fs.makeTempDirectoryScoped({ prefix: params.tempDirPrefix });
|
|
1219
1260
|
const workerId = yield* crypto.randomUUIDv4;
|
|
1220
|
-
const socketPath = Match.value(process.platform).pipe(Match.when("win32", () => `\\\\.\\pipe\\stryker-worker-${workerId}`), Match.orElse(() => path.join(workerDir, "worker.sock")));
|
|
1261
|
+
const socketPath = Match.value(globalThis.process.platform).pipe(Match.when("win32", () => `\\\\.\\pipe\\stryker-worker-${workerId}`), Match.orElse(() => path.join(workerDir, "worker.sock")));
|
|
1221
1262
|
const optionsFile = path.join(workerDir, "options.json");
|
|
1222
1263
|
yield* fs.writeFileString(optionsFile, params.optionsJson);
|
|
1223
1264
|
yield* restrictToOwnerOrWarn(fs, optionsFile);
|
|
1224
1265
|
const entrypointPath = yield* path.fromFileUrl(new URL(params.entrypoint));
|
|
1225
|
-
const handle = yield* ChildProcess.make(process.execPath, [...params.execArgv, entrypointPath], {
|
|
1266
|
+
const handle = yield* ChildProcess.make(globalThis.process.execPath, [...params.execArgv, entrypointPath], {
|
|
1226
1267
|
cwd: params.workingDirectory,
|
|
1227
1268
|
extendEnv: true,
|
|
1228
1269
|
env: {
|
|
@@ -1256,14 +1297,14 @@ const nodePlatformLayer = Layer.mergeAll(nodeWorkerLauncherLayer.pipe(Layer.prov
|
|
|
1256
1297
|
* The in-memory runner's platform: the V8 sandbox module and the module
|
|
1257
1298
|
* builtin that strips TypeScript and resolves a sandbox's `require`.
|
|
1258
1299
|
*
|
|
1259
|
-
* Reached through `process.getBuiltinModule` rather than an `import` because a
|
|
1300
|
+
* Reached through `globalThis.process.getBuiltinModule` rather than an `import` because a
|
|
1260
1301
|
* Node builtin import is forbidden in product code; the call is wrapped in
|
|
1261
1302
|
* `Effect.promise` so a platform without `node:vm` fails as a defect — the
|
|
1262
1303
|
* runner has no fallback to fall back to.
|
|
1263
1304
|
*/
|
|
1264
1305
|
const nodeVmPlatformLayer = Layer.effect(VmRunner, Effect$1.sync(() => ({
|
|
1265
|
-
module: process.getBuiltinModule("node:module"),
|
|
1266
|
-
vm: process.getBuiltinModule("node:vm")
|
|
1306
|
+
module: globalThis.process.getBuiltinModule("node:module"),
|
|
1307
|
+
vm: globalThis.process.getBuiltinModule("node:vm")
|
|
1267
1308
|
})));
|
|
1268
1309
|
S.TaggedError()("CommandRunnerUnsupportedOption", { option: S.String });
|
|
1269
1310
|
S.Struct({
|
|
@@ -1338,18 +1379,25 @@ const withTimeout = (inner) => ({
|
|
|
1338
1379
|
dryRun: (options) => {
|
|
1339
1380
|
const policy = Effect$1.timeoutOrElse({
|
|
1340
1381
|
duration: Duration.millis(options.timeout),
|
|
1341
|
-
orElse: () => Effect$1.succeed({
|
|
1382
|
+
orElse: () => Effect$1.succeed({
|
|
1383
|
+
status: "timeout",
|
|
1384
|
+
reason: WALL_CLOCK_TIMEOUT_REASON
|
|
1385
|
+
})
|
|
1342
1386
|
});
|
|
1343
1387
|
return inner.dryRun(options).pipe(policy);
|
|
1344
1388
|
},
|
|
1345
1389
|
mutantRun: (options) => {
|
|
1346
1390
|
const policy = Effect$1.timeoutOrElse({
|
|
1347
1391
|
duration: Duration.millis(options.timeout),
|
|
1348
|
-
orElse: () => Effect$1.succeed({
|
|
1392
|
+
orElse: () => Effect$1.succeed({
|
|
1393
|
+
status: "timeout",
|
|
1394
|
+
reason: WALL_CLOCK_TIMEOUT_REASON
|
|
1395
|
+
})
|
|
1349
1396
|
});
|
|
1350
1397
|
return inner.mutantRun(options).pipe(policy);
|
|
1351
1398
|
}
|
|
1352
1399
|
});
|
|
1400
|
+
const invalidatesRunnerPool = (status, reason) => status === "timeout" && reason === "wall-clock-timeout";
|
|
1353
1401
|
/**
|
|
1354
1402
|
* Retry a run whose runner crashed, and report the crash as a result once the
|
|
1355
1403
|
* attempts are spent.
|
|
@@ -2002,7 +2050,7 @@ function findConfigFile(configFileName) {
|
|
|
2002
2050
|
return Match.value(configFileName).pipe(Match.when(Match.string, (fileName) => configFileFor(fileName)), Match.orElse(() => discoverConfigFile()));
|
|
2003
2051
|
}
|
|
2004
2052
|
const resolveChildExtends = (configFile, child, configEnv) => Match.value("extends" in child).pipe(Match.when(true, () => resolveExtends(configFile, child, configEnv)), Match.orElse(() => Effect$1.succeed(child)));
|
|
2005
|
-
const isCiEnvironment = Config.
|
|
2053
|
+
const isCiEnvironment = Config.String("CI").pipe(Effect$1.map((value) => Match.value(value.trim().toLowerCase()).pipe(Match.when("", () => false), Match.when("0", () => false), Match.when("false", () => false), Match.orElse(() => true))), Effect$1.orElseSucceed(() => false));
|
|
2006
2054
|
function loadOptionsFromConfigFile(cliOptions, configEnv) {
|
|
2007
2055
|
return findConfigFile(cliOptions["configFile"]).pipe(Effect$1.flatMap((configFile) => Match.value(configFile).pipe(Match.when(void 0, () => Effect$1.succeed({})), Match.orElse((found) => readConfigModule(found, configEnv).pipe(Effect$1.flatMap((child) => resolveChildExtends(found, child, configEnv)))))));
|
|
2008
2056
|
}
|
|
@@ -2014,7 +2062,7 @@ function readConfig(cliOptions, invocation) {
|
|
|
2014
2062
|
isDryRun: cliOptions["dryRunOnly"] === true,
|
|
2015
2063
|
isCi: yield* isCiEnvironment
|
|
2016
2064
|
};
|
|
2017
|
-
const cliRecord = yield* S.
|
|
2065
|
+
const cliRecord = yield* S.decodeEffect(ConfigDocumentSchema)(cliOptions).pipe(Effect$1.orDie);
|
|
2018
2066
|
const fileRecord = yield* loadOptionsFromConfigFile(cliRecord, configEnv);
|
|
2019
2067
|
const fileOptions = yield* Result.match(S.decodeUnknownResult(ConfigDocumentSchema)(fileRecord), {
|
|
2020
2068
|
onFailure: (cause) => Effect$1.fail(ConfigFileInvalidError.make({
|
|
@@ -2046,9 +2094,13 @@ const PluginDescriptorSchema = Schema.Union([Schema.Struct({
|
|
|
2046
2094
|
const PluginModuleSchema = Schema.Struct({ strykerPlugins: Schema.Array(PluginDescriptorSchema) });
|
|
2047
2095
|
const isShouldIgnore = (value) => typeof value === "function";
|
|
2048
2096
|
const ignoreNothing = () => void 0;
|
|
2097
|
+
const shouldIgnoreArbitrary = Schema.link()(Schema.Null, {
|
|
2098
|
+
decode: SchemaGetter.transform(() => ignoreNothing),
|
|
2099
|
+
encode: SchemaGetter.transform(() => null)
|
|
2100
|
+
});
|
|
2049
2101
|
const IgnorerEntrySchema = Schema.Struct({
|
|
2050
2102
|
name: Schema.String,
|
|
2051
|
-
shouldIgnore: Schema.declare(isShouldIgnore, {
|
|
2103
|
+
shouldIgnore: Schema.declare(isShouldIgnore, { toCodecArbitrary: () => shouldIgnoreArbitrary })
|
|
2052
2104
|
});
|
|
2053
2105
|
const IgnorerModuleSchema = Schema.Struct({ strykerIgnorers: Schema.Array(IgnorerEntrySchema) });
|
|
2054
2106
|
const SchemaValidationContributionSchema = Schema.Struct({ strykerValidationSchema: Schema.Record(Schema.String, Schema.Unknown) });
|
|
@@ -2436,8 +2488,8 @@ const initFromPhaseSpan = (span) => {
|
|
|
2436
2488
|
};
|
|
2437
2489
|
};
|
|
2438
2490
|
const environmentTraceInit = () => Effect$1.gen(function* () {
|
|
2439
|
-
const traceparent = yield* Config.
|
|
2440
|
-
const tracestate = yield* Config.
|
|
2491
|
+
const traceparent = yield* Config.String("TRACEPARENT").pipe(Effect$1.option);
|
|
2492
|
+
const tracestate = yield* Config.String("TRACESTATE").pipe(Effect$1.option);
|
|
2441
2493
|
return {
|
|
2442
2494
|
...traceparentInit(Option.getOrUndefined(traceparent)),
|
|
2443
2495
|
...tracestateInit(Option.getOrUndefined(tracestate))
|
|
@@ -2532,104 +2584,98 @@ const completeDryRunPassed = (raw) => Effect$1.gen(function* () {
|
|
|
2532
2584
|
timeOverhead: Duration.millis(overheadMillis)
|
|
2533
2585
|
};
|
|
2534
2586
|
});
|
|
2535
|
-
const dryRunCell =
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
const
|
|
2543
|
-
const
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
}).pipe(Effect$1.mapError(missingWorkerEntry("dryRun", "test runner", runnerLabel)), Effect$1.flatMap(({ spawn }) => makeChildProcessTestRunner({
|
|
2551
|
-
options: command.options,
|
|
2552
|
-
fileDescriptions: command.project.fileDescriptions,
|
|
2553
|
-
sandboxWorkingDirectory: command.sandbox.workingDirectory,
|
|
2554
|
-
workerEntrypoint: spawn.entrypoint,
|
|
2555
|
-
idGenerator
|
|
2556
|
-
})));
|
|
2557
|
-
});
|
|
2558
|
-
const runner = yield* buildTestRunner({
|
|
2587
|
+
const dryRunCell = Sandwich.read((command) => Effect$1.gen(function* () {
|
|
2588
|
+
yield* Scope.Scope;
|
|
2589
|
+
const idGenerator = yield* IdGenerator;
|
|
2590
|
+
const { files, testFiles } = buildDryRunFiles(command);
|
|
2591
|
+
const dryRunTimeout = command.options.dryRunTimeoutMinutes * 60 * 1e3;
|
|
2592
|
+
yield* Effect$1.logInfo("Starting dry run");
|
|
2593
|
+
const { rawResult, capabilities, gross } = yield* Effect$1.scoped(Effect$1.gen(function* () {
|
|
2594
|
+
const childRunnerEffect = Effect$1.suspend(() => {
|
|
2595
|
+
const runnerConfigured = command.options.testRunner;
|
|
2596
|
+
const runnerLabel = Match.value(runnerConfigured).pipe(Match.when(isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
|
|
2597
|
+
return resolveConfiguredWorkerSpawn({
|
|
2598
|
+
loaded: command.loadedPlugins,
|
|
2599
|
+
kind: "TestRunner",
|
|
2600
|
+
configured: runnerConfigured
|
|
2601
|
+
}).pipe(Effect$1.mapError(missingWorkerEntry("dryRun", "test runner", runnerLabel)), Effect$1.flatMap(({ spawn }) => makeChildProcessTestRunner({
|
|
2559
2602
|
options: command.options,
|
|
2560
2603
|
fileDescriptions: command.project.fileDescriptions,
|
|
2561
2604
|
sandboxWorkingDirectory: command.sandbox.workingDirectory,
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
return StageError.make({
|
|
2605
|
+
workerEntrypoint: spawn.entrypoint,
|
|
2606
|
+
idGenerator
|
|
2607
|
+
})));
|
|
2608
|
+
});
|
|
2609
|
+
const runner = yield* buildTestRunner({
|
|
2610
|
+
options: command.options,
|
|
2611
|
+
fileDescriptions: command.project.fileDescriptions,
|
|
2612
|
+
sandboxWorkingDirectory: command.sandbox.workingDirectory,
|
|
2613
|
+
idGenerator,
|
|
2614
|
+
retire: Effect$1.void,
|
|
2615
|
+
testFiles: testFiles ?? []
|
|
2616
|
+
}, childRunnerEffect);
|
|
2617
|
+
const extra = Option.match(Option.fromUndefinedOr(testFiles), {
|
|
2618
|
+
onNone: () => ({}),
|
|
2619
|
+
onSome: (files) => ({ testFiles: files })
|
|
2620
|
+
});
|
|
2621
|
+
const timed = yield* Effect$1.timed(runner.dryRun({
|
|
2622
|
+
timeout: dryRunTimeout,
|
|
2623
|
+
coverageAnalysis: command.options.coverageAnalysis,
|
|
2624
|
+
disableBail: command.options.disableBail,
|
|
2625
|
+
files,
|
|
2626
|
+
...extra
|
|
2627
|
+
}).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
2628
|
+
stage: "dryRun",
|
|
2629
|
+
reason: "Dry run failed",
|
|
2630
|
+
cause
|
|
2631
|
+
}))));
|
|
2632
|
+
const gross = timed[0];
|
|
2633
|
+
return {
|
|
2634
|
+
rawResult: timed[1],
|
|
2635
|
+
capabilities: yield* runner.capabilities.pipe(Effect$1.mapError((cause) => StageError.make({
|
|
2594
2636
|
stage: "dryRun",
|
|
2595
|
-
reason: "
|
|
2637
|
+
reason: "Failed to get test runner capabilities",
|
|
2596
2638
|
cause
|
|
2597
|
-
})
|
|
2598
|
-
}));
|
|
2599
|
-
return {
|
|
2600
|
-
prev: command,
|
|
2601
|
-
rawResult,
|
|
2602
|
-
capabilities,
|
|
2639
|
+
}))),
|
|
2603
2640
|
gross
|
|
2604
2641
|
};
|
|
2605
|
-
})
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
encode: (outcome) => outcome,
|
|
2609
|
-
write: (outcome, raw) => withPhaseSpan("dryRun", {}, () => Effect$1.gen(function* () {
|
|
2610
|
-
const env = yield* RunEnvironment;
|
|
2611
|
-
const now = yield* Clock.currentTimeMillis;
|
|
2612
|
-
const queue = yield* RunEvents;
|
|
2613
|
-
yield* Queue.offer(queue, PhaseEntered.make({
|
|
2614
|
-
phase: "dry-run",
|
|
2615
|
-
elapsedMs: now - env.runStartedAt
|
|
2616
|
-
}));
|
|
2617
|
-
const out = outcome;
|
|
2618
|
-
if (Result.isFailure(out)) {
|
|
2619
|
-
const err = out.failure;
|
|
2620
|
-
return yield* StageError.make({
|
|
2621
|
-
stage: err.stage,
|
|
2622
|
-
reason: err.reason,
|
|
2623
|
-
cause: err
|
|
2624
|
-
});
|
|
2625
|
-
}
|
|
2626
|
-
return yield* Match.value(out.success).pipe(Match.tag("DryRunFailed", (decision) => Effect$1.fail(StageError.make({
|
|
2642
|
+
})).pipe(Effect$1.mapError((cause) => {
|
|
2643
|
+
if (S.is(StageError)(cause)) return cause;
|
|
2644
|
+
return StageError.make({
|
|
2627
2645
|
stage: "dryRun",
|
|
2628
|
-
reason: "
|
|
2629
|
-
cause
|
|
2630
|
-
})
|
|
2631
|
-
}))
|
|
2632
|
-
|
|
2646
|
+
reason: "Dry run failed to start test runner",
|
|
2647
|
+
cause
|
|
2648
|
+
});
|
|
2649
|
+
}));
|
|
2650
|
+
return {
|
|
2651
|
+
prev: command,
|
|
2652
|
+
rawResult,
|
|
2653
|
+
capabilities,
|
|
2654
|
+
gross
|
|
2655
|
+
};
|
|
2656
|
+
})).decode(Sandwich.pure((raw) => Match.value(raw.rawResult).pipe(Match.when(isCompleteDryRun, (complete) => decodeCompleteDryRun(complete, raw.prev.options.allowEmpty)), Match.when(isFailedDryRun, (failed) => decodeFailedDryRun(failed, raw.prev.options.allowEmpty)), Match.orElse((timedOut) => decodeTimedOutDryRun(timedOut, raw.prev.options.allowEmpty))))).decide(dryRun).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((outcome, raw) => withPhaseSpan("dryRun", {}, () => Effect$1.gen(function* () {
|
|
2657
|
+
const env = yield* RunEnvironment;
|
|
2658
|
+
const now = yield* Clock.currentTimeMillis;
|
|
2659
|
+
const queue = yield* RunEvents;
|
|
2660
|
+
yield* Queue.offer(queue, PhaseEntered.make({
|
|
2661
|
+
phase: "dry-run",
|
|
2662
|
+
elapsedMs: now - env.runStartedAt
|
|
2663
|
+
}));
|
|
2664
|
+
const out = outcome;
|
|
2665
|
+
if (Result.isFailure(out)) {
|
|
2666
|
+
const err = out.failure;
|
|
2667
|
+
return yield* StageError.make({
|
|
2668
|
+
stage: err.stage,
|
|
2669
|
+
reason: err.reason,
|
|
2670
|
+
cause: err
|
|
2671
|
+
});
|
|
2672
|
+
}
|
|
2673
|
+
return yield* Match.value(out.success).pipe(Match.tag("DryRunFailed", (decision) => Effect$1.fail(StageError.make({
|
|
2674
|
+
stage: "dryRun",
|
|
2675
|
+
reason: "There were failed tests in the initial test run.",
|
|
2676
|
+
cause: decision
|
|
2677
|
+
}))), Match.tag("DryRunPassed", () => completeDryRunPassed(raw)), Match.exhaustive);
|
|
2678
|
+
})));
|
|
2633
2679
|
//#endregion
|
|
2634
2680
|
//#region src/plan-instrumentation.workflow.ts
|
|
2635
2681
|
var InstrumentError = class extends S.TaggedError()("InstrumentError", {
|
|
@@ -2846,118 +2892,8 @@ const decide = (command) => Option.match(Option.fromUndefinedOr(command.report),
|
|
|
2846
2892
|
});
|
|
2847
2893
|
const admitIncrementalReport = Workflow.total(AdmitIncrementalReportCommand, (command) => Result.succeed(decide(command)));
|
|
2848
2894
|
//#endregion
|
|
2849
|
-
//#region package.json
|
|
2850
|
-
var package_default = {
|
|
2851
|
-
name: "@systemfsoftware/stryker-js",
|
|
2852
|
-
version: "10.0.0",
|
|
2853
|
-
repository: {
|
|
2854
|
-
"type": "git",
|
|
2855
|
-
"url": "git+https://github.com/systemfsoftware/stryker-js-effect.git",
|
|
2856
|
-
"directory": "packages/stryker-js"
|
|
2857
|
-
},
|
|
2858
|
-
homepage: "https://github.com/systemfsoftware/stryker-js-effect",
|
|
2859
|
-
bugs: { "url": "https://github.com/systemfsoftware/stryker-js-effect/issues" },
|
|
2860
|
-
description: "The Stryker mutation testing tool — the stryker executable, the run engine, and the configuration surface.",
|
|
2861
|
-
type: "module",
|
|
2862
|
-
files: ["dist"],
|
|
2863
|
-
bin: { "stryker": "./dist/main.mjs" },
|
|
2864
|
-
scripts: {
|
|
2865
|
-
"clean": "rimraf dist",
|
|
2866
|
-
"build": "pnpm run typecheck && rimraf dist && tsdown --config tsdown.bin.config.ts && tsdown --config tsdown.config.ts",
|
|
2867
|
-
"typecheck": "tsc --noEmit --incremental && tsc -p tsconfig.node.json --noEmit",
|
|
2868
|
-
"test": "vitest run",
|
|
2869
|
-
"mutation": "stryker run",
|
|
2870
|
-
"attw": "attw --pack .",
|
|
2871
|
-
"lint": "f=${OXLINT_FORMAT:-${AGENT:+agent}}; oxlint . --format=${f:-default}",
|
|
2872
|
-
"api:check": "api-extractor run",
|
|
2873
|
-
"api:update": "api-extractor run --local",
|
|
2874
|
-
"lint:tsgo": "effect-tsgo diagnostics --project tsconfig.json --format ${TSGO_FORMAT:-text}"
|
|
2875
|
-
},
|
|
2876
|
-
license: "Apache-2.0",
|
|
2877
|
-
engines: { "node": ">=22.18.0" },
|
|
2878
|
-
dependencies: {
|
|
2879
|
-
"@effect/opentelemetry": "4.0.0-rc.112",
|
|
2880
|
-
"@effect/platform-node": "catalog:",
|
|
2881
|
-
"@effect/platform-node-shared": "catalog:",
|
|
2882
|
-
"@noble/hashes": "catalog:",
|
|
2883
|
-
"@opentelemetry/api": "^1.9.0",
|
|
2884
|
-
"@opentelemetry/exporter-metrics-otlp-http": "^0.208.0",
|
|
2885
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.208.0",
|
|
2886
|
-
"@opentelemetry/sdk-metrics": "^2.2.0",
|
|
2887
|
-
"@opentelemetry/sdk-trace-base": "^2.2.0",
|
|
2888
|
-
"@systemfsoftware/effect-cell-types": "catalog:"
|
|
2889
|
-
},
|
|
2890
|
-
peerDependencies: { "effect": "catalog:" },
|
|
2891
|
-
devDependencies: {
|
|
2892
|
-
"@effect/tsgo": "catalog:",
|
|
2893
|
-
"@effect/vitest": "catalog:",
|
|
2894
|
-
"@microsoft/api-extractor": "catalog:",
|
|
2895
|
-
"@oxc-parser/binding-wasm32-wasi": "catalog:",
|
|
2896
|
-
"@std/jsonc": "catalog:",
|
|
2897
|
-
"@systemfsoftware/all": "catalog:",
|
|
2898
|
-
"@systemfsoftware/arethetypeswrong-cli": "catalog:",
|
|
2899
|
-
"@systemfsoftware/effect-gherkin-spec": "catalog:",
|
|
2900
|
-
"@systemfsoftware/effect-schema-law": "catalog:",
|
|
2901
|
-
"@systemfsoftware/effect-schema-vite": "catalog:",
|
|
2902
|
-
"@systemfsoftware/stryker-config": "workspace:^",
|
|
2903
|
-
"@systemfsoftware/stryker-ignorer-effect-schema-declarations": "catalog:stryker",
|
|
2904
|
-
"@systemfsoftware/stryker-ignorer-in-source-vitest-block": "catalog:stryker",
|
|
2905
|
-
"@systemfsoftware/stryker-ignorer-interface": "workspace:^",
|
|
2906
|
-
"@systemfsoftware/stryker-js": "catalog:stryker",
|
|
2907
|
-
"@systemfsoftware/stryker-js-html-reporter": "workspace:^",
|
|
2908
|
-
"@systemfsoftware/stryker-js-instrumenter": "workspace:^",
|
|
2909
|
-
"@systemfsoftware/stryker-js-plugin-interface": "workspace:^",
|
|
2910
|
-
"@systemfsoftware/stryker-js-plugin-runtime": "workspace:^",
|
|
2911
|
-
"@systemfsoftware/stryker-js-typescript-checker": "catalog:stryker",
|
|
2912
|
-
"@systemfsoftware/stryker-js-vitest-runner": "catalog:stryker",
|
|
2913
|
-
"@systemfsoftware/stryker-test-contribution": "catalog:stryker",
|
|
2914
|
-
"@systemfsoftware/tsconfig": "catalog:",
|
|
2915
|
-
"@systemfsoftware/tsdown-config": "workspace:^",
|
|
2916
|
-
"@systemfsoftware/vitest-config": "workspace:^",
|
|
2917
|
-
"@types/node": "catalog:",
|
|
2918
|
-
"@vitest/coverage-v8": "catalog:",
|
|
2919
|
-
"concurrently": "catalog:",
|
|
2920
|
-
"mutation-testing-elements": "catalog:stryker",
|
|
2921
|
-
"oxc-parser": "catalog:",
|
|
2922
|
-
"oxlint": "catalog:",
|
|
2923
|
-
"oxlint-tsgolint": "catalog:",
|
|
2924
|
-
"rimraf": "catalog:",
|
|
2925
|
-
"tsdown": "catalog:",
|
|
2926
|
-
"typescript": "catalog:",
|
|
2927
|
-
"vitest": "catalog:"
|
|
2928
|
-
},
|
|
2929
|
-
publishConfig: {
|
|
2930
|
-
"access": "public",
|
|
2931
|
-
"provenance": true,
|
|
2932
|
-
"exports": {
|
|
2933
|
-
".": {
|
|
2934
|
-
"types": "./dist/index.d.mts",
|
|
2935
|
-
"default": "./dist/index.mjs"
|
|
2936
|
-
},
|
|
2937
|
-
"./config": {
|
|
2938
|
-
"types": "./dist/config.d.mts",
|
|
2939
|
-
"default": "./dist/config.mjs"
|
|
2940
|
-
},
|
|
2941
|
-
"./events": {
|
|
2942
|
-
"types": "./dist/events.d.mts",
|
|
2943
|
-
"default": "./dist/events.mjs"
|
|
2944
|
-
},
|
|
2945
|
-
"./promises": {
|
|
2946
|
-
"types": "./dist/promises.d.mts",
|
|
2947
|
-
"default": "./dist/promises.mjs"
|
|
2948
|
-
},
|
|
2949
|
-
"./package.json": "./package.json"
|
|
2950
|
-
}
|
|
2951
|
-
},
|
|
2952
|
-
exports: { "./package.json": "./package.json" }
|
|
2953
|
-
};
|
|
2954
|
-
//#endregion
|
|
2955
|
-
//#region src/stryker-package.schema.ts
|
|
2956
|
-
const PackageJsonSchema = Schema.Struct({ version: Schema.String });
|
|
2957
|
-
//#endregion
|
|
2958
2895
|
//#region src/stryker-package.ts
|
|
2959
|
-
const
|
|
2960
|
-
const strykerVersion = Schema.decodeUnknownSync(PackageJsonSchema)(rawPackageJson).version;
|
|
2896
|
+
const strykerVersion = "10.1.0";
|
|
2961
2897
|
//#endregion
|
|
2962
2898
|
//#region src/incremental-report.cell.ts
|
|
2963
2899
|
const parseAndDecodeIncrementalReport = S.decodeUnknownResult(S.fromJsonString(IncrementalReportSchema));
|
|
@@ -2968,7 +2904,7 @@ const readIncrementalReportRaw = (input) => {
|
|
|
2968
2904
|
contents: void 0
|
|
2969
2905
|
});
|
|
2970
2906
|
return Effect$1.gen(function* () {
|
|
2971
|
-
const contents = yield* (yield* FileSystem.FileSystem).readFileString(input.incrementalFile).pipe(Effect$1.
|
|
2907
|
+
const contents = yield* (yield* FileSystem.FileSystem).readFileString(input.incrementalFile).pipe(Effect$1.tapError((error) => Match.value(error.reason).pipe(Match.tag("NotFound", () => Effect$1.logInfo(`No incremental result file found at ${input.incrementalFile}, a full mutation testing run will be performed.`)), Match.orElse(() => Effect$1.void))), Effect$1.catchTag("PlatformError", (error) => Match.value(error.reason).pipe(Match.tag("NotFound", () => Effect$1.undefined), Match.orElse(() => Effect$1.fail(error)))));
|
|
2972
2908
|
return {
|
|
2973
2909
|
incremental: true,
|
|
2974
2910
|
incrementalFile: input.incrementalFile,
|
|
@@ -2996,13 +2932,7 @@ const writeIncrementalReportOutcome = (outcome, raw) => Result.match(outcome, {
|
|
|
2996
2932
|
});
|
|
2997
2933
|
}), Match.exhaustive)
|
|
2998
2934
|
});
|
|
2999
|
-
const incrementalReportCell =
|
|
3000
|
-
read: readIncrementalReportRaw,
|
|
3001
|
-
decode: decodeIncrementalReportRaw,
|
|
3002
|
-
decide: admitIncrementalReport,
|
|
3003
|
-
encode: (outcome) => outcome,
|
|
3004
|
-
write: writeIncrementalReportOutcome
|
|
3005
|
-
});
|
|
2935
|
+
const incrementalReportCell = Sandwich.read(readIncrementalReportRaw).decode(Sandwich.pure(decodeIncrementalReportRaw)).decide(admitIncrementalReport).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write(writeIncrementalReportOutcome);
|
|
3006
2936
|
//#endregion
|
|
3007
2937
|
//#region src/Project.ts
|
|
3008
2938
|
const DEFAULT_GLOB$1 = "**/*.{js,ts,jsx,tsx,html,vue,mjs,mts,cts,cjs}";
|
|
@@ -3736,9 +3666,9 @@ const makeDisableTypeChecksPreprocessor = (options, impl) => (project) => Effect
|
|
|
3736
3666
|
const content = yield* Effect$1.map(impl(instrumenterFile), (instrumented) => instrumented.content).pipe(Effect$1.mapError((cause) => StrykerError.make({
|
|
3737
3667
|
message: "disableTypeChecks failed",
|
|
3738
3668
|
cause
|
|
3739
|
-
})), Effect$1.
|
|
3669
|
+
})), Effect$1.tapError(() => Effect$1.gen(function* () {
|
|
3740
3670
|
if (isWarningEnabled("preprocessorErrors", options.warnings)) yield* Effect$1.logWarning(`Unable to disable type checking for file "${name}". Shouldn't type checking be disabled for this file? Consider configuring a more restrictive "${optionsPath("disableTypeChecks")}" settings (or turn it completely off with \`false\`)`);
|
|
3741
|
-
})));
|
|
3671
|
+
})), Effect$1.orElseSucceed(() => void 0));
|
|
3742
3672
|
if (content !== void 0) return withContent(file, content);
|
|
3743
3673
|
})), Match.orElse(() => Effect$1.succeedNone)), { concurrency: 24 })).forEach(mergeUpdatedInto(project));
|
|
3744
3674
|
});
|
|
@@ -3885,7 +3815,7 @@ const directoryChain = (from, pathService) => {
|
|
|
3885
3815
|
return [from, ...directoryChain(parent, pathService)];
|
|
3886
3816
|
};
|
|
3887
3817
|
const binDirectoriesFrom = (from, pathService) => directoryChain(pathService.resolve(from), pathService).map((directory) => pathService.join(directory, "node_modules", ".bin"));
|
|
3888
|
-
const inheritedPath = () => Config.
|
|
3818
|
+
const inheritedPath = () => Config.String("PATH").pipe(Effect$1.option, Effect$1.map((value) => Option.getOrUndefined(value) ?? ""));
|
|
3889
3819
|
const failOnBuildFailure = (command, result) => Match.value(result.exitCode).pipe(Match.when((exitCode) => exitCode !== 0, (exitCode) => Effect$1.fail(StrykerError.make({ message: `Build command "${command}" failed with exit code ${String(exitCode)}.\n${result.stderr}` }))), Match.orElse(() => Effect$1.void));
|
|
3890
3820
|
const runBuildCommandIn = (command, workingDirectory) => Effect$1.gen(function* () {
|
|
3891
3821
|
const pathService = yield* Path.Path;
|
|
@@ -4012,7 +3942,7 @@ const linkNodeModules = (nodeModules, workingDirectory, basePath, pathService) =
|
|
|
4012
3942
|
const resolvedTo = pathService.resolve(pathService.join(basePath, nodeModules));
|
|
4013
3943
|
const resolvedFrom = pathService.join(workingDirectory, nodeModules);
|
|
4014
3944
|
yield* Effect$1.logDebug(`Create symlink from ${resolvedTo} to ${resolvedFrom}`);
|
|
4015
|
-
yield* symlinkJunction(resolvedTo, resolvedFrom).pipe(Effect$1.
|
|
3945
|
+
yield* symlinkJunction(resolvedTo, resolvedFrom).pipe(Effect$1.tapError(() => Effect$1.logWarning(`Unexpected error while trying to symlink "${nodeModules}" in sandbox directory.`)), Effect$1.catchTag("PlatformError", () => Effect$1.void));
|
|
4016
3946
|
});
|
|
4017
3947
|
const linkFoundNodeModules = (options, workingDirectory, basePath, pathService) => Effect$1.gen(function* () {
|
|
4018
3948
|
const nodeModulesList = yield* findNodeModulesList(basePath, options.tempDirName);
|
|
@@ -4050,90 +3980,84 @@ const makeSandbox = (input) => Effect$1.gen(function* () {
|
|
|
4050
3980
|
});
|
|
4051
3981
|
//#endregion
|
|
4052
3982
|
//#region src/run/instrument.cell.ts
|
|
4053
|
-
const instrumentCell =
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
3983
|
+
const instrumentCell = Sandwich.read((command) => Effect$1.gen(function* () {
|
|
3984
|
+
yield* Scope.Scope;
|
|
3985
|
+
const env = yield* RunEnvironment;
|
|
3986
|
+
const filesToMutate = yield* Effect$1.forEach([...MutableHashMap.values(command.project.filesToMutate)], (file) => toInstrumenterFile(file), { concurrency: 24 }).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
3987
|
+
stage: "instrument",
|
|
3988
|
+
reason: "Failed to read files to mutate",
|
|
3989
|
+
cause
|
|
3990
|
+
})));
|
|
3991
|
+
const instrumentResult = yield* instrument(filesToMutate, {
|
|
3992
|
+
ignorers: [...command.ignorers],
|
|
3993
|
+
excludedMutations: [...command.options.mutator.excludedMutations]
|
|
3994
|
+
}, env.basePath).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
3995
|
+
stage: "instrument",
|
|
3996
|
+
reason: "Instrumenter failed",
|
|
3997
|
+
cause
|
|
3998
|
+
})));
|
|
3999
|
+
const instrumentedProject = withInstrumentedFiles(command.project, instrumentResult.files);
|
|
4000
|
+
const basePath = env.basePath;
|
|
4001
|
+
let workingDirectory = command.temporaryDirectoryPath;
|
|
4002
|
+
let backupDirectory = "";
|
|
4003
|
+
if (command.options.inPlace) {
|
|
4004
|
+
workingDirectory = basePath;
|
|
4005
|
+
backupDirectory = command.temporaryDirectoryPath;
|
|
4006
|
+
}
|
|
4007
|
+
return {
|
|
4008
|
+
prev: command,
|
|
4009
|
+
filesToMutate,
|
|
4010
|
+
instrumentResult,
|
|
4011
|
+
instrumentedProject,
|
|
4012
|
+
sandbox: yield* makeSandbox({
|
|
4013
|
+
options: command.options,
|
|
4014
|
+
project: instrumentedProject,
|
|
4015
|
+
workingDirectory,
|
|
4016
|
+
backupDirectory,
|
|
4017
|
+
basePath
|
|
4018
|
+
}).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
4058
4019
|
stage: "instrument",
|
|
4059
|
-
reason: "
|
|
4020
|
+
reason: "Sandbox initialization failed",
|
|
4060
4021
|
cause
|
|
4061
|
-
})))
|
|
4062
|
-
|
|
4063
|
-
ignorers: [...command.ignorers],
|
|
4064
|
-
excludedMutations: [...command.options.mutator.excludedMutations]
|
|
4065
|
-
}, env.basePath).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
4022
|
+
}))),
|
|
4023
|
+
concurrency: yield* makeConcurrency(command.options).pipe(Effect$1.mapError((cause) => StageError.make({
|
|
4066
4024
|
stage: "instrument",
|
|
4067
|
-
reason: "
|
|
4025
|
+
reason: "Failed to compute concurrency",
|
|
4068
4026
|
cause
|
|
4069
|
-
})))
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
}),
|
|
4101
|
-
decode: (raw) => Result.succeed(InstrumentCommand.make({
|
|
4102
|
-
fileCount: raw.filesToMutate.length,
|
|
4103
|
-
inPlace: raw.prev.options.inPlace,
|
|
4104
|
-
pluginCount: raw.prev.loadedPlugins.pluginModulePaths.length
|
|
4105
|
-
})),
|
|
4106
|
-
decide: planInstrumentation,
|
|
4107
|
-
encode: (outcome) => outcome,
|
|
4108
|
-
write: (output, raw) => withPhaseSpan("instrument", { fileCount: raw.filesToMutate.length }, () => Effect$1.gen(function* () {
|
|
4109
|
-
const env = yield* RunEnvironment;
|
|
4110
|
-
const now = yield* Clock.currentTimeMillis;
|
|
4111
|
-
const queue = yield* RunEvents;
|
|
4112
|
-
yield* Queue.offer(queue, PhaseEntered.make({
|
|
4113
|
-
phase: "instrument",
|
|
4114
|
-
elapsedMs: now - env.runStartedAt
|
|
4115
|
-
}));
|
|
4116
|
-
const out = output;
|
|
4117
|
-
if (Result.isFailure(out)) {
|
|
4118
|
-
const err = out.failure;
|
|
4119
|
-
return yield* StageError.make({
|
|
4120
|
-
stage: err.stage,
|
|
4121
|
-
reason: err.reason,
|
|
4122
|
-
cause: err
|
|
4123
|
-
});
|
|
4027
|
+
})))
|
|
4028
|
+
};
|
|
4029
|
+
})).decode(Sandwich.pure((raw) => Result.succeed(InstrumentCommand.make({
|
|
4030
|
+
fileCount: raw.filesToMutate.length,
|
|
4031
|
+
inPlace: raw.prev.options.inPlace,
|
|
4032
|
+
pluginCount: raw.prev.loadedPlugins.pluginModulePaths.length
|
|
4033
|
+
})))).decide(planInstrumentation).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((output, raw) => withPhaseSpan("instrument", { fileCount: raw.filesToMutate.length }, () => Effect$1.gen(function* () {
|
|
4034
|
+
const env = yield* RunEnvironment;
|
|
4035
|
+
const now = yield* Clock.currentTimeMillis;
|
|
4036
|
+
const queue = yield* RunEvents;
|
|
4037
|
+
yield* Queue.offer(queue, PhaseEntered.make({
|
|
4038
|
+
phase: "instrument",
|
|
4039
|
+
elapsedMs: now - env.runStartedAt
|
|
4040
|
+
}));
|
|
4041
|
+
const out = output;
|
|
4042
|
+
if (Result.isFailure(out)) {
|
|
4043
|
+
const err = out.failure;
|
|
4044
|
+
return yield* StageError.make({
|
|
4045
|
+
stage: err.stage,
|
|
4046
|
+
reason: err.reason,
|
|
4047
|
+
cause: err
|
|
4048
|
+
});
|
|
4049
|
+
}
|
|
4050
|
+
return {
|
|
4051
|
+
...raw.prev,
|
|
4052
|
+
project: raw.instrumentedProject,
|
|
4053
|
+
mutants: raw.instrumentResult.mutants,
|
|
4054
|
+
sandbox: raw.sandbox,
|
|
4055
|
+
concurrency: {
|
|
4056
|
+
testRunners: raw.concurrency.testRunners,
|
|
4057
|
+
checkers: raw.concurrency.checkers
|
|
4124
4058
|
}
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
project: raw.instrumentedProject,
|
|
4128
|
-
mutants: raw.instrumentResult.mutants,
|
|
4129
|
-
sandbox: raw.sandbox,
|
|
4130
|
-
concurrency: {
|
|
4131
|
-
testRunners: raw.concurrency.testRunners,
|
|
4132
|
-
checkers: raw.concurrency.checkers
|
|
4133
|
-
}
|
|
4134
|
-
};
|
|
4135
|
-
}))
|
|
4136
|
-
});
|
|
4059
|
+
};
|
|
4060
|
+
})));
|
|
4137
4061
|
//#endregion
|
|
4138
4062
|
//#region src/MutationTest.schema.ts
|
|
4139
4063
|
var MutationTestCommand = class extends S.TaggedClass()("MutationTestCommand", {
|
|
@@ -4168,7 +4092,7 @@ const admitMutationTest = Workflow.make(MutationTestCommand, (command) => Match.
|
|
|
4168
4092
|
}, () => Result.succeed(MutationTestNoTests.make({}))), Match.orElse(() => Result.succeed(MutationTestProceed.make({})))));
|
|
4169
4093
|
//#endregion
|
|
4170
4094
|
//#region src/checker-mutant-wire.ts
|
|
4171
|
-
const CheckerMutantFromMutant = Mutant.pipe(S.decodeTo(CheckerMutantWire, SchemaTransformation.transform({
|
|
4095
|
+
const CheckerMutantFromMutant = Mutant.pipe(S.decodeTo(CheckerMutantWire, SchemaTransformation$1.transform({
|
|
4172
4096
|
decode: (m) => ({
|
|
4173
4097
|
id: m.id,
|
|
4174
4098
|
fileName: m.fileName,
|
|
@@ -4184,7 +4108,7 @@ const CheckerMutantFromMutant = Mutant.pipe(S.decodeTo(CheckerMutantWire, Schema
|
|
|
4184
4108
|
location: w.location
|
|
4185
4109
|
})
|
|
4186
4110
|
})));
|
|
4187
|
-
const wireRecordOf = (mutant) => Result.mapError(S.
|
|
4111
|
+
const wireRecordOf = (mutant) => Result.mapError(S.decodeResult(CheckerMutantFromMutant)(mutant), (error) => ({
|
|
4188
4112
|
id: mutant.id,
|
|
4189
4113
|
fileName: mutant.fileName,
|
|
4190
4114
|
reason: error.message
|
|
@@ -4501,35 +4425,29 @@ const logSkippedMutants = (checkerName, undescribable) => Match.value(undescriba
|
|
|
4501
4425
|
* that joins them back. The join is where the work is, and it is pure.
|
|
4502
4426
|
*/
|
|
4503
4427
|
const checkPlans = (checker, checkerName, plans, lookup) => {
|
|
4504
|
-
return
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
answers: { ...raw.answers }
|
|
4528
|
-
})),
|
|
4529
|
-
decide: admitCheckerAnswer,
|
|
4530
|
-
encode: (outcome) => outcome,
|
|
4531
|
-
write: (outcome, raw) => writeCheckerOutcome(plans, raw.checkerName, outcome)
|
|
4532
|
-
}).run({
|
|
4428
|
+
return Sandwich.read((command) => Effect$1.gen(function* () {
|
|
4429
|
+
const partitioned = Option.match(Option.fromUndefinedOr(command.lookup), {
|
|
4430
|
+
onSome: (known) => selectedFromLookup(command.plans, known),
|
|
4431
|
+
onNone: () => partitionMutantsForWire(command.plans)
|
|
4432
|
+
});
|
|
4433
|
+
yield* logSkippedMutants(command.checkerName, partitioned.undescribable);
|
|
4434
|
+
if (partitioned.undescribable.length > 0) yield* Metric.update(checkerMutantsSkipped, partitioned.undescribable.length);
|
|
4435
|
+
yield* Effect$1.annotateCurrentSpan({ "stryker.checker.skipped_mutants_count": partitioned.undescribable.length });
|
|
4436
|
+
const answers = yield* command.checker.check(command.checkerName, partitioned.wire);
|
|
4437
|
+
return {
|
|
4438
|
+
checkerName: command.checkerName,
|
|
4439
|
+
requestedIds: command.plans.map((plan) => plan.mutant.id),
|
|
4440
|
+
answers: {
|
|
4441
|
+
...compileErrorAnswersOf(partitioned.undescribable),
|
|
4442
|
+
...answers
|
|
4443
|
+
}
|
|
4444
|
+
};
|
|
4445
|
+
})).decode(Sandwich.pure((raw) => Result.succeed(CheckerCommand.make({
|
|
4446
|
+
checkerName: raw.checkerName,
|
|
4447
|
+
requestedIds: [...raw.requestedIds],
|
|
4448
|
+
phase: "check",
|
|
4449
|
+
answers: { ...raw.answers }
|
|
4450
|
+
})))).decide(admitCheckerAnswer).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((outcome, raw) => writeCheckerOutcome(plans, raw.checkerName, outcome)).run({
|
|
4533
4451
|
checker,
|
|
4534
4452
|
checkerName,
|
|
4535
4453
|
plans,
|
|
@@ -4540,31 +4458,25 @@ const checkPlans = (checker, checkerName, plans, lookup) => {
|
|
|
4540
4458
|
* Ask a checker how to group run plans, and get groups of run plans back.
|
|
4541
4459
|
*/
|
|
4542
4460
|
const groupPlans = (checker, checkerName, plans, lookup) => {
|
|
4543
|
-
return
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
idGroups: raw.idGroups.map((group) => [...group])
|
|
4563
|
-
})),
|
|
4564
|
-
decide: admitCheckerAnswer,
|
|
4565
|
-
encode: (outcome) => outcome,
|
|
4566
|
-
write: (outcome, raw) => writeGroupOutcome(plans, raw.checkerName, outcome)
|
|
4567
|
-
}).run({
|
|
4461
|
+
return Sandwich.read((command) => Effect$1.gen(function* () {
|
|
4462
|
+
const partitioned = Option.match(Option.fromUndefinedOr(command.lookup), {
|
|
4463
|
+
onSome: (known) => selectedFromLookup(command.plans, known),
|
|
4464
|
+
onNone: () => partitionMutantsForWire(command.plans)
|
|
4465
|
+
});
|
|
4466
|
+
yield* Effect$1.annotateCurrentSpan({ "stryker.checker.skipped_mutants_count": partitioned.undescribable.length });
|
|
4467
|
+
const undescribableIds = undescribableIdsOf(partitioned.undescribable);
|
|
4468
|
+
const withoutSkipped = (yield* command.checker.group(command.checkerName, partitioned.wire)).map((group) => group.filter((id) => !undescribableIds.has(id))).filter((group) => group.length > 0);
|
|
4469
|
+
return {
|
|
4470
|
+
checkerName: command.checkerName,
|
|
4471
|
+
requestedIds: command.plans.map((plan) => plan.mutant.id),
|
|
4472
|
+
idGroups: [...singletonGroupsOf(partitioned.undescribable), ...withoutSkipped]
|
|
4473
|
+
};
|
|
4474
|
+
})).decode(Sandwich.pure((raw) => Result.succeed(CheckerCommand.make({
|
|
4475
|
+
checkerName: raw.checkerName,
|
|
4476
|
+
requestedIds: [...raw.requestedIds],
|
|
4477
|
+
phase: "group",
|
|
4478
|
+
idGroups: raw.idGroups.map((group) => [...group])
|
|
4479
|
+
})))).decide(admitCheckerAnswer).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((outcome, raw) => writeGroupOutcome(plans, raw.checkerName, outcome)).run({
|
|
4568
4480
|
checker,
|
|
4569
4481
|
checkerName,
|
|
4570
4482
|
plans,
|
|
@@ -4800,7 +4712,7 @@ function embeddedConfig(report) {
|
|
|
4800
4712
|
}
|
|
4801
4713
|
function breakThreshold(thresholds) {
|
|
4802
4714
|
const ThresholdsBreakSchema = S.StructWithRest(S.Struct({ break: S.optional(S.Union([S.Finite, S.Null])) }), [S.Record(S.String, S.Unknown)]);
|
|
4803
|
-
const decoded = S.
|
|
4715
|
+
const decoded = S.decodeOption(ThresholdsBreakSchema)(thresholds);
|
|
4804
4716
|
return Option.getOrNull(Option.flatMap(decoded, (value) => Option.fromNullishOr(value.break)));
|
|
4805
4717
|
}
|
|
4806
4718
|
const actionableMutants = (files) => Object.entries(files).flatMap(([file, fileResult]) => fileResult.mutants.filter((mutant) => isActionableStatus(mutant.status)).map((mutant) => ({
|
|
@@ -4965,7 +4877,7 @@ const makeMutationReportingService = (input) => {
|
|
|
4965
4877
|
const resolved = yield* Effect$1.try(() => new URL(import.meta.resolve(`${specifier}/package.json`)));
|
|
4966
4878
|
const manifestPath = yield* pathService.fromFileUrl(resolved);
|
|
4967
4879
|
const text = yield* fs.readFileString(manifestPath);
|
|
4968
|
-
return Result.match(S.
|
|
4880
|
+
return Result.match(S.decodeResult(S.fromJsonString(ManifestSchema))(text), {
|
|
4969
4881
|
onFailure: () => Option.none(),
|
|
4970
4882
|
onSuccess: (manifest) => Option.some(manifest.version ?? "")
|
|
4971
4883
|
});
|
|
@@ -5215,160 +5127,177 @@ const reportDroppedMutants = (dropped) => Match.value(dropped.length).pipe(Match
|
|
|
5215
5127
|
yield* Metric.update(checkerMutantsSkipped, dropped.length);
|
|
5216
5128
|
yield* Effect$1.logWarning(`${dropped.length} mutant(s) cannot be described to a checker and were left out of the run (${droppedIdsOf(dropped)})`);
|
|
5217
5129
|
})));
|
|
5218
|
-
const
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5130
|
+
const hasStringReason = (r) => "reason" in r && typeof r.reason === "string";
|
|
5131
|
+
const reasonOf = (result) => Match.value(result).pipe(Match.when((r) => typeof r === "object" && r !== null, (r) => Match.value(r).pipe(Match.when(hasStringReason, (obj) => obj.reason), Match.orElse(() => void 0))), Match.orElse(() => void 0));
|
|
5132
|
+
const stopWallClock = (result) => {
|
|
5133
|
+
if (!wallClockTimeoutStopsRun(result.status, reasonOf(result))) return Effect$1.void;
|
|
5134
|
+
return Effect$1.fail(StageError.make({
|
|
5135
|
+
stage: "mutationTest",
|
|
5136
|
+
reason: WALL_CLOCK_TIMEOUT_REASON
|
|
5137
|
+
}));
|
|
5138
|
+
};
|
|
5139
|
+
const mutationTestCell$1 = Sandwich.read((command) => Effect$1.gen(function* () {
|
|
5140
|
+
yield* Scope.Scope;
|
|
5141
|
+
return { prev: command };
|
|
5142
|
+
})).decode(Sandwich.pure((raw) => Result.succeed(MutationTestCommand.make({
|
|
5143
|
+
dryRunOnly: raw.prev.options.dryRunOnly,
|
|
5144
|
+
allowEmpty: raw.prev.options.allowEmpty,
|
|
5145
|
+
testCount: raw.prev.dryRunResult.tests.length,
|
|
5146
|
+
isZero: raw.prev.dryRunResult.tests.length === 0
|
|
5147
|
+
})))).decide(admitMutationTest).encode(Sandwich.pure((outcome) => Result.succeed(outcome))).write((outcome, raw) => {
|
|
5148
|
+
const { dropped, plannable: plannableMutants } = partitionPlannable(raw.prev.mutants);
|
|
5149
|
+
return withPhaseSpan("mutationTest", {
|
|
5150
|
+
mutantCount: raw.prev.mutants.length,
|
|
5151
|
+
skippedMutantCount: dropped.length,
|
|
5152
|
+
testCount: raw.prev.dryRunResult.tests.length
|
|
5153
|
+
}, () => Effect$1.gen(function* () {
|
|
5154
|
+
yield* reportDroppedMutants(dropped);
|
|
5155
|
+
const decision = yield* Result.match(outcome, {
|
|
5156
|
+
onFailure: (err) => Effect$1.fail(StageError.make({
|
|
5157
|
+
stage: err.stage,
|
|
5158
|
+
reason: err.reason,
|
|
5159
|
+
cause: err
|
|
5160
|
+
})),
|
|
5161
|
+
onSuccess: (d) => Effect$1.succeed(d)
|
|
5162
|
+
});
|
|
5163
|
+
return yield* Match.value(decision).pipe(Match.tag("MutationTestDryRunOnly", () => Effect$1.gen(function* () {
|
|
5164
|
+
const env = yield* RunEnvironment;
|
|
5165
|
+
const queue = yield* RunEvents;
|
|
5166
|
+
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5167
|
+
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5168
|
+
phase: "mutation-test",
|
|
5169
|
+
elapsedMs: nowEmit - env.runStartedAt
|
|
5170
|
+
}));
|
|
5171
|
+
yield* Effect$1.logInfo("The dry-run has been completed successfully. No mutations have been executed.");
|
|
5172
|
+
return {
|
|
5173
|
+
results: [],
|
|
5174
|
+
verdict: null
|
|
5175
|
+
};
|
|
5176
|
+
})), Match.tag("MutationTestNoTests", () => Effect$1.gen(function* () {
|
|
5177
|
+
const env = yield* RunEnvironment;
|
|
5178
|
+
const queue = yield* RunEvents;
|
|
5179
|
+
const now = yield* Clock.currentTimeMillis;
|
|
5180
|
+
const elapsed = Duration.millis(now - env.runStartedAt);
|
|
5181
|
+
yield* Effect$1.logInfo(`Done in ${Duration.format(elapsed)}.`);
|
|
5182
|
+
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5183
|
+
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5184
|
+
phase: "mutation-test",
|
|
5185
|
+
elapsedMs: nowEmit - env.runStartedAt
|
|
5186
|
+
}));
|
|
5187
|
+
return {
|
|
5188
|
+
results: [],
|
|
5189
|
+
verdict: null
|
|
5190
|
+
};
|
|
5191
|
+
})), Match.tag("MutationTestProceed", () => Effect$1.gen(function* () {
|
|
5192
|
+
const prev = raw.prev;
|
|
5193
|
+
const env = yield* RunEnvironment;
|
|
5194
|
+
yield* Effect$1.gen(function* () {
|
|
5250
5195
|
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5251
|
-
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5252
|
-
phase: "mutation-test",
|
|
5253
|
-
elapsedMs: nowEmit - env.runStartedAt
|
|
5254
|
-
}));
|
|
5255
|
-
yield* Effect$1.logInfo("The dry-run has been completed successfully. No mutations have been executed.");
|
|
5256
|
-
return {
|
|
5257
|
-
results: [],
|
|
5258
|
-
verdict: null
|
|
5259
|
-
};
|
|
5260
|
-
})), Match.tag("MutationTestNoTests", () => Effect$1.gen(function* () {
|
|
5261
|
-
const env = yield* RunEnvironment;
|
|
5262
5196
|
const queue = yield* RunEvents;
|
|
5263
|
-
const now = yield* Clock.currentTimeMillis;
|
|
5264
|
-
const elapsed = Duration.millis(now - env.runStartedAt);
|
|
5265
|
-
yield* Effect$1.logInfo(`Done in ${Duration.format(elapsed)}.`);
|
|
5266
|
-
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5267
5197
|
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5268
5198
|
phase: "mutation-test",
|
|
5269
5199
|
elapsedMs: nowEmit - env.runStartedAt
|
|
5270
5200
|
}));
|
|
5201
|
+
});
|
|
5202
|
+
const idGenerator = yield* IdGenerator;
|
|
5203
|
+
const checkerPool = yield* makeCheckerPool(prev, idGenerator, env.basePath);
|
|
5204
|
+
const testRunnerContext = {
|
|
5205
|
+
options: prev.options,
|
|
5206
|
+
fileDescriptions: prev.project.fileDescriptions,
|
|
5207
|
+
sandboxWorkingDirectory: prev.sandbox.workingDirectory,
|
|
5208
|
+
idGenerator,
|
|
5209
|
+
retire: Effect$1.void,
|
|
5210
|
+
testFiles: prev.project.testFiles.map((file) => prev.sandbox.sandboxFileFor(file))
|
|
5211
|
+
};
|
|
5212
|
+
const testRunnerPool = yield* Pool.make({
|
|
5213
|
+
acquire: buildTestRunner(testRunnerContext, Effect$1.suspend(() => {
|
|
5214
|
+
const runnerConfigured = prev.options.testRunner;
|
|
5215
|
+
const runnerLabel = Match.value(runnerConfigured).pipe(Match.when(isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
|
|
5216
|
+
return resolveConfiguredWorkerSpawn({
|
|
5217
|
+
loaded: prev.loadedPlugins,
|
|
5218
|
+
kind: "TestRunner",
|
|
5219
|
+
configured: runnerConfigured
|
|
5220
|
+
}).pipe(Effect$1.mapError(missingWorkerEntry("mutationTest", "test runner", runnerLabel)), Effect$1.flatMap(({ spawn }) => makeChildProcessTestRunner({
|
|
5221
|
+
options: prev.options,
|
|
5222
|
+
fileDescriptions: prev.project.fileDescriptions,
|
|
5223
|
+
sandboxWorkingDirectory: prev.sandbox.workingDirectory,
|
|
5224
|
+
workerEntrypoint: spawn.entrypoint,
|
|
5225
|
+
idGenerator
|
|
5226
|
+
})));
|
|
5227
|
+
})),
|
|
5228
|
+
size: prev.concurrency.testRunners
|
|
5229
|
+
});
|
|
5230
|
+
const reporting = makeMutationReportingService({
|
|
5231
|
+
reporterStage: prev.reporterStage,
|
|
5232
|
+
options: prev.options,
|
|
5233
|
+
project: prev.project,
|
|
5234
|
+
testCoverage: prev.testCoverage,
|
|
5235
|
+
runId: env.runId,
|
|
5236
|
+
resolvedMode: env.resolvedMode,
|
|
5237
|
+
sandboxDirectory: prev.sandbox.workingDirectory,
|
|
5238
|
+
basePath: env.basePath
|
|
5239
|
+
});
|
|
5240
|
+
const sandboxFileByName = Object.fromEntries([...MutableHashMap.keys(prev.project.filesToMutate)].map((name) => [name, prev.sandbox.sandboxFileFor(name)]));
|
|
5241
|
+
const currentRelativeFiles = yield* readCurrentRelativeFiles(prev.project, env.basePath);
|
|
5242
|
+
const incremental = incrementalDiff({
|
|
5243
|
+
currentMutants: plannableMutants,
|
|
5244
|
+
testCoverage: prev.testCoverage,
|
|
5245
|
+
incrementalReport: prev.project.incrementalReport,
|
|
5246
|
+
currentRelativeFiles,
|
|
5247
|
+
basePath: env.basePath,
|
|
5248
|
+
force: prev.options.force
|
|
5249
|
+
});
|
|
5250
|
+
const rememberedResults = rememberedResultsOf(plannableMutants, incremental.remembered);
|
|
5251
|
+
yield* Effect$1.when(Effect$1.logInfo(`Incremental mode: reusing ${rememberedResults.length} mutant result(s), running ${incremental.mutants.length} mutant(s).`), Effect$1.succeed(rememberedResults.length > 0));
|
|
5252
|
+
const { runPlans, earlyResults: noCoverageResults } = partitionRunPlans(yield* decidePlans(incremental.mutants, prev.testCoverage, {
|
|
5253
|
+
disableBail: prev.options.disableBail,
|
|
5254
|
+
timeoutMS: prev.options.timeoutMS,
|
|
5255
|
+
timeoutFactor: prev.options.timeoutFactor,
|
|
5256
|
+
ignoreStatic: prev.options.ignoreStatic
|
|
5257
|
+
}, Duration.toMillis(prev.timeOverhead), void 0, sandboxFileByName));
|
|
5258
|
+
const sortedPlans = sortRunPlans(runPlans);
|
|
5259
|
+
const allPlansForReporter = [...sortedPlans];
|
|
5260
|
+
yield* offerReporterEvent(prev.reporterStage, MutationTestingPlanReady.make({
|
|
5261
|
+
total: allPlansForReporter.length + noCoverageResults.length + rememberedResults.length,
|
|
5262
|
+
plans: allPlansForReporter.map((plan) => ({
|
|
5263
|
+
mutantId: plan.mutant.id,
|
|
5264
|
+
plan: plan.plan,
|
|
5265
|
+
netTime: plan.netTime,
|
|
5266
|
+
reloadEnvironment: plan.runOptions.reloadEnvironment
|
|
5267
|
+
}))
|
|
5268
|
+
})).pipe(Effect$1.ignoreCause);
|
|
5269
|
+
{
|
|
5270
|
+
const queue2 = yield* RunEvents;
|
|
5271
|
+
yield* Queue.offer(queue2, PlanKnown.make({ total: allPlansForReporter.length + noCoverageResults.length }));
|
|
5272
|
+
}
|
|
5273
|
+
const { passedPlans, checkerResults } = yield* checkPlansWithConfiguredCheckers(checkerPool, sortedPlans, reporting);
|
|
5274
|
+
const testRunnerStream = Stream.fromIterable(passedPlans);
|
|
5275
|
+
const plannedTotal = allPlansForReporter.length + noCoverageResults.length + rememberedResults.length;
|
|
5276
|
+
const pathService = yield* Path.Path;
|
|
5277
|
+
const progressQueue = yield* RunEvents;
|
|
5278
|
+
const completedRef = yield* Ref.make(0);
|
|
5279
|
+
const preparedStreamableOf = (result) => {
|
|
5280
|
+
if (!isMutantStatus(result.status)) return;
|
|
5271
5281
|
return {
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
})), Match.tag("MutationTestProceed", () => Effect$1.gen(function* () {
|
|
5276
|
-
const prev = raw.prev;
|
|
5277
|
-
const env = yield* RunEnvironment;
|
|
5278
|
-
yield* Effect$1.gen(function* () {
|
|
5279
|
-
const nowEmit = yield* Clock.currentTimeMillis;
|
|
5280
|
-
const queue = yield* RunEvents;
|
|
5281
|
-
yield* Queue.offer(queue, PhaseEntered.make({
|
|
5282
|
-
phase: "mutation-test",
|
|
5283
|
-
elapsedMs: nowEmit - env.runStartedAt
|
|
5284
|
-
}));
|
|
5285
|
-
});
|
|
5286
|
-
const idGenerator = yield* IdGenerator;
|
|
5287
|
-
const checkerPool = yield* makeCheckerPool(prev, idGenerator, env.basePath);
|
|
5288
|
-
const testRunnerContext = {
|
|
5289
|
-
options: prev.options,
|
|
5290
|
-
fileDescriptions: prev.project.fileDescriptions,
|
|
5291
|
-
sandboxWorkingDirectory: prev.sandbox.workingDirectory,
|
|
5292
|
-
idGenerator,
|
|
5293
|
-
retire: Effect$1.void,
|
|
5294
|
-
testFiles: prev.project.testFiles.map((file) => prev.sandbox.sandboxFileFor(file))
|
|
5295
|
-
};
|
|
5296
|
-
const testRunnerPool = yield* Pool.make({
|
|
5297
|
-
acquire: buildTestRunner(testRunnerContext, Effect$1.suspend(() => {
|
|
5298
|
-
const runnerConfigured = prev.options.testRunner;
|
|
5299
|
-
const runnerLabel = Match.value(runnerConfigured).pipe(Match.when(isCustomTestRunner, (runner) => runner.plugin), Match.orElse((name) => name));
|
|
5300
|
-
return resolveConfiguredWorkerSpawn({
|
|
5301
|
-
loaded: prev.loadedPlugins,
|
|
5302
|
-
kind: "TestRunner",
|
|
5303
|
-
configured: runnerConfigured
|
|
5304
|
-
}).pipe(Effect$1.mapError(missingWorkerEntry("mutationTest", "test runner", runnerLabel)), Effect$1.flatMap(({ spawn }) => makeChildProcessTestRunner({
|
|
5305
|
-
options: prev.options,
|
|
5306
|
-
fileDescriptions: prev.project.fileDescriptions,
|
|
5307
|
-
sandboxWorkingDirectory: prev.sandbox.workingDirectory,
|
|
5308
|
-
workerEntrypoint: spawn.entrypoint,
|
|
5309
|
-
idGenerator
|
|
5310
|
-
})));
|
|
5311
|
-
})),
|
|
5312
|
-
size: prev.concurrency.testRunners
|
|
5313
|
-
});
|
|
5314
|
-
const reporting = makeMutationReportingService({
|
|
5315
|
-
reporterStage: prev.reporterStage,
|
|
5316
|
-
options: prev.options,
|
|
5317
|
-
project: prev.project,
|
|
5318
|
-
testCoverage: prev.testCoverage,
|
|
5319
|
-
runId: env.runId,
|
|
5320
|
-
resolvedMode: env.resolvedMode,
|
|
5321
|
-
sandboxDirectory: prev.sandbox.workingDirectory,
|
|
5322
|
-
basePath: env.basePath
|
|
5323
|
-
});
|
|
5324
|
-
const sandboxFileByName = Object.fromEntries([...MutableHashMap.keys(prev.project.filesToMutate)].map((name) => [name, prev.sandbox.sandboxFileFor(name)]));
|
|
5325
|
-
const currentRelativeFiles = yield* readCurrentRelativeFiles(prev.project, env.basePath);
|
|
5326
|
-
const incremental = incrementalDiff({
|
|
5327
|
-
currentMutants: plannableMutants,
|
|
5328
|
-
testCoverage: prev.testCoverage,
|
|
5329
|
-
incrementalReport: prev.project.incrementalReport,
|
|
5330
|
-
currentRelativeFiles,
|
|
5331
|
-
basePath: env.basePath,
|
|
5332
|
-
force: prev.options.force
|
|
5333
|
-
});
|
|
5334
|
-
const rememberedResults = rememberedResultsOf(plannableMutants, incremental.remembered);
|
|
5335
|
-
yield* Effect$1.when(Effect$1.logInfo(`Incremental mode: reusing ${rememberedResults.length} mutant result(s), running ${incremental.mutants.length} mutant(s).`), Effect$1.succeed(rememberedResults.length > 0));
|
|
5336
|
-
const { runPlans, earlyResults: noCoverageResults } = partitionRunPlans(yield* decidePlans(incremental.mutants, prev.testCoverage, {
|
|
5337
|
-
disableBail: prev.options.disableBail,
|
|
5338
|
-
timeoutMS: prev.options.timeoutMS,
|
|
5339
|
-
timeoutFactor: prev.options.timeoutFactor,
|
|
5340
|
-
ignoreStatic: prev.options.ignoreStatic
|
|
5341
|
-
}, Duration.toMillis(prev.timeOverhead), void 0, sandboxFileByName));
|
|
5342
|
-
const sortedPlans = sortRunPlans(runPlans);
|
|
5343
|
-
const allPlansForReporter = [...sortedPlans];
|
|
5344
|
-
yield* offerReporterEvent(prev.reporterStage, MutationTestingPlanReady.make({
|
|
5345
|
-
total: allPlansForReporter.length + noCoverageResults.length + rememberedResults.length,
|
|
5346
|
-
plans: allPlansForReporter.map((plan) => ({
|
|
5347
|
-
mutantId: plan.mutant.id,
|
|
5348
|
-
plan: plan.plan,
|
|
5349
|
-
netTime: plan.netTime,
|
|
5350
|
-
reloadEnvironment: plan.runOptions.reloadEnvironment
|
|
5351
|
-
}))
|
|
5352
|
-
})).pipe(Effect$1.ignoreCause);
|
|
5353
|
-
{
|
|
5354
|
-
const queue2 = yield* RunEvents;
|
|
5355
|
-
yield* Queue.offer(queue2, PlanKnown.make({ total: allPlansForReporter.length + noCoverageResults.length }));
|
|
5356
|
-
}
|
|
5357
|
-
const { passedPlans, checkerResults } = yield* checkPlansWithConfiguredCheckers(checkerPool, sortedPlans, reporting);
|
|
5358
|
-
const testRunnerStream = Stream.fromIterable(passedPlans);
|
|
5359
|
-
const plannedTotal = allPlansForReporter.length + noCoverageResults.length + rememberedResults.length;
|
|
5360
|
-
const pathService = yield* Path.Path;
|
|
5361
|
-
const progressQueue = yield* RunEvents;
|
|
5362
|
-
const completedRef = yield* Ref.make(0);
|
|
5363
|
-
const preparedStreamableOf = (result) => {
|
|
5364
|
-
if (!isMutantStatus(result.status)) return;
|
|
5365
|
-
return {
|
|
5366
|
-
status: result.status,
|
|
5367
|
-
file: reportFileName(pathService.relative(env.basePath, result.fileName)),
|
|
5368
|
-
location: toSchemaLocation(result.location)
|
|
5369
|
-
};
|
|
5282
|
+
status: result.status,
|
|
5283
|
+
file: reportFileName(pathService.relative(env.basePath, result.fileName)),
|
|
5284
|
+
location: toSchemaLocation(result.location)
|
|
5370
5285
|
};
|
|
5371
|
-
|
|
5286
|
+
};
|
|
5287
|
+
const toStreamEvent = (result, completed, prepared) => MutantTested.make({
|
|
5288
|
+
id: result.id,
|
|
5289
|
+
status: prepared.status,
|
|
5290
|
+
file: prepared.file,
|
|
5291
|
+
location: prepared.location,
|
|
5292
|
+
mutator: result.mutatorName,
|
|
5293
|
+
replacement: result.replacement,
|
|
5294
|
+
completed,
|
|
5295
|
+
total: plannedTotal
|
|
5296
|
+
});
|
|
5297
|
+
const offerFinished = (result, prepared) => Effect$1.gen(function* () {
|
|
5298
|
+
if (prepared === void 0) return;
|
|
5299
|
+
const completed = yield* Ref.updateAndGet(completedRef, (n) => n + 1);
|
|
5300
|
+
yield* Queue.offer(progressQueue, RunMutantTested.make({
|
|
5372
5301
|
id: result.id,
|
|
5373
5302
|
status: prepared.status,
|
|
5374
5303
|
file: prepared.file,
|
|
@@ -5377,90 +5306,85 @@ const mutationTestCell$1 = Cell.layer({
|
|
|
5377
5306
|
replacement: result.replacement,
|
|
5378
5307
|
completed,
|
|
5379
5308
|
total: plannedTotal
|
|
5380
|
-
});
|
|
5381
|
-
const offerFinished = (result, prepared) => Effect$1.gen(function* () {
|
|
5382
|
-
if (prepared === void 0) return;
|
|
5383
|
-
const completed = yield* Ref.updateAndGet(completedRef, (n) => n + 1);
|
|
5384
|
-
yield* Queue.offer(progressQueue, RunMutantTested.make({
|
|
5385
|
-
id: result.id,
|
|
5386
|
-
status: prepared.status,
|
|
5387
|
-
file: prepared.file,
|
|
5388
|
-
location: prepared.location,
|
|
5389
|
-
mutator: result.mutatorName,
|
|
5390
|
-
replacement: result.replacement,
|
|
5391
|
-
completed,
|
|
5392
|
-
total: plannedTotal
|
|
5393
|
-
}));
|
|
5394
|
-
return completed;
|
|
5395
|
-
});
|
|
5396
|
-
const reportStreamTested = (result, completed, prepared) => offerReporterEvent(prev.reporterStage, toStreamEvent(result, completed, prepared)).pipe(Effect$1.catchCause((cause) => Effect$1.logWarning("Reporter stream failed handling mutantTested", cause)));
|
|
5397
|
-
const offerStreamTested = (result, completed, prepared) => Option.match(Option.all([Option.fromNullishOr(completed), Option.fromNullishOr(prepared)]), {
|
|
5398
|
-
onNone: () => Effect$1.void,
|
|
5399
|
-
onSome: ([done, streamable]) => reportStreamTested(result, done, streamable)
|
|
5400
|
-
});
|
|
5401
|
-
const announceSettledMutant = (result) => Effect$1.gen(function* () {
|
|
5402
|
-
const prepared = preparedStreamableOf(result);
|
|
5403
|
-
const completed = yield* offerFinished(result, prepared);
|
|
5404
|
-
yield* offerStreamTested(result, completed, prepared);
|
|
5405
|
-
});
|
|
5406
|
-
yield* Effect$1.forEach([
|
|
5407
|
-
...rememberedResults,
|
|
5408
|
-
...noCoverageResults,
|
|
5409
|
-
...checkerResults
|
|
5410
|
-
], announceSettledMutant, {
|
|
5411
|
-
concurrency: 1,
|
|
5412
|
-
discard: true
|
|
5413
|
-
});
|
|
5414
|
-
const completedMutants = yield* Ref.make([
|
|
5415
|
-
...rememberedResults,
|
|
5416
|
-
...noCoverageResults,
|
|
5417
|
-
...checkerResults
|
|
5418
|
-
]);
|
|
5419
|
-
const checkpointGate = yield* Semaphore.make(1);
|
|
5420
|
-
yield* reporting.checkpoint(yield* Ref.get(completedMutants)).pipe(Effect$1.catchCause((cause) => Effect$1.logWarning("Failed to persist the mutation checkpoint", cause)));
|
|
5421
|
-
const persist = (result) => checkpointGate.withPermits(1)(Effect$1.gen(function* () {
|
|
5422
|
-
const next = yield* Ref.updateAndGet(completedMutants, (prev) => [...prev, result]);
|
|
5423
|
-
yield* reporting.checkpoint(next).pipe(Effect$1.catchCause((cause) => Effect$1.logWarning("Failed to persist the mutation checkpoint", cause)));
|
|
5424
5309
|
}));
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
const
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5310
|
+
return completed;
|
|
5311
|
+
});
|
|
5312
|
+
const reportStreamTested = (result, completed, prepared) => offerReporterEvent(prev.reporterStage, toStreamEvent(result, completed, prepared)).pipe(Effect$1.tapCause((cause) => Effect$1.logWarning("Reporter stream failed handling mutantTested", cause)), Effect$1.ignoreCause);
|
|
5313
|
+
const offerStreamTested = (result, completed, prepared) => Option.match(Option.all([Option.fromNullishOr(completed), Option.fromNullishOr(prepared)]), {
|
|
5314
|
+
onNone: () => Effect$1.void,
|
|
5315
|
+
onSome: ([done, streamable]) => reportStreamTested(result, done, streamable)
|
|
5316
|
+
});
|
|
5317
|
+
const announceSettledMutant = (result) => Effect$1.gen(function* () {
|
|
5318
|
+
const prepared = preparedStreamableOf(result);
|
|
5319
|
+
const completed = yield* offerFinished(result, prepared);
|
|
5320
|
+
yield* offerStreamTested(result, completed, prepared);
|
|
5321
|
+
});
|
|
5322
|
+
yield* Effect$1.forEach([
|
|
5323
|
+
...rememberedResults,
|
|
5324
|
+
...noCoverageResults,
|
|
5325
|
+
...checkerResults
|
|
5326
|
+
], announceSettledMutant, {
|
|
5327
|
+
concurrency: 1,
|
|
5328
|
+
discard: true
|
|
5329
|
+
});
|
|
5330
|
+
const completedMutants = yield* Ref.make([
|
|
5331
|
+
...rememberedResults,
|
|
5332
|
+
...noCoverageResults,
|
|
5333
|
+
...checkerResults
|
|
5334
|
+
]);
|
|
5335
|
+
const checkpointGate = yield* Semaphore.make(1);
|
|
5336
|
+
yield* reporting.checkpoint(yield* Ref.get(completedMutants)).pipe(Effect$1.tapCause((cause) => Effect$1.logWarning("Failed to persist the mutation checkpoint", cause)), Effect$1.ignoreCause);
|
|
5337
|
+
const persist = (result) => checkpointGate.withPermits(1)(Effect$1.gen(function* () {
|
|
5338
|
+
const next = yield* Ref.updateAndGet(completedMutants, (prev) => [...prev, result]);
|
|
5339
|
+
yield* reporting.checkpoint(next).pipe(Effect$1.tapCause((cause) => Effect$1.logWarning("Failed to persist the mutation checkpoint", cause)), Effect$1.ignoreCause);
|
|
5340
|
+
}));
|
|
5341
|
+
const runResults = yield* withPhaseSpan("mutationTest.batch", {
|
|
5342
|
+
total: plannedTotal,
|
|
5343
|
+
testRunners: prev.concurrency.testRunners
|
|
5344
|
+
}, () => Stream.mapEffect(testRunnerStream, (plan) => Effect$1.scoped(Effect$1.gen(function* () {
|
|
5345
|
+
const pool = testRunnerPool;
|
|
5346
|
+
const runner = yield* Pool.get(pool);
|
|
5347
|
+
const result = yield* runner.mutantRun(plan.runOptions).pipe(Effect$1.withSpan("stryker.testRunner.mutantRun", { attributes: {
|
|
5348
|
+
"stryker.mutant.id": plan.mutant.id,
|
|
5349
|
+
"stryker.mutant.mutator": plan.mutant.mutatorName,
|
|
5350
|
+
"stryker.mutant.file": plan.mutant.fileName
|
|
5351
|
+
} }), Effect$1.tap((runResult) => Effect$1.annotateCurrentSpan({ "stryker.mutant.status": runResult.status })), Effect$1.catchTags({
|
|
5352
|
+
OutOfMemoryError: (error) => invalidateSlot(pool, runner, error),
|
|
5353
|
+
ChildProcessCrashedError: (error) => invalidateSlot(pool, runner, error)
|
|
5354
|
+
}));
|
|
5355
|
+
if (invalidatesRunnerPool(result.status, reasonOf(result))) return yield* invalidateSlot(pool, runner, ChildProcessCrashedError.make({
|
|
5356
|
+
pid: 0,
|
|
5357
|
+
exit: {
|
|
5358
|
+
_tag: "Signal",
|
|
5359
|
+
signal: "SIGKILL"
|
|
5360
|
+
},
|
|
5361
|
+
cause: "wall-clock timeout"
|
|
5362
|
+
}));
|
|
5363
|
+
yield* stopWallClock(result);
|
|
5364
|
+
const reported = yield* reporting.reportMutantRunResult(toReportedMutant(plan.mutant), result);
|
|
5365
|
+
const prepared = preparedStreamableOf(reported);
|
|
5366
|
+
const finished = yield* offerFinished(reported, prepared);
|
|
5367
|
+
yield* offerStreamTested(reported, finished, prepared);
|
|
5368
|
+
yield* persist(reported);
|
|
5369
|
+
return reported;
|
|
5370
|
+
})), { concurrency: Math.max(1, prev.concurrency.testRunners) }).pipe(Stream.runCollect, Effect$1.map((chunk) => [...chunk])));
|
|
5371
|
+
const allResults = [
|
|
5372
|
+
...rememberedResults,
|
|
5373
|
+
...noCoverageResults,
|
|
5374
|
+
...checkerResults,
|
|
5375
|
+
...runResults
|
|
5376
|
+
];
|
|
5377
|
+
const outcomeResult = yield* reporting.reportAll(allResults);
|
|
5378
|
+
const doneNow = yield* Clock.currentTimeMillis;
|
|
5379
|
+
const elapsed = Duration.millis(doneNow - env.runStartedAt);
|
|
5380
|
+
yield* Effect$1.logInfo(`Done in ${Duration.format(elapsed)}.`);
|
|
5381
|
+
return outcomeResult;
|
|
5382
|
+
})), Match.exhaustive);
|
|
5383
|
+
})).pipe(Effect$1.mapError((cause) => Match.value(cause).pipe(Match.tag("StageError", (stage) => stage), Match.tag("ChildProcessCrashedError", "OutOfMemoryError", "PlatformError", "TestRunnerFailed", () => StageError.make({
|
|
5384
|
+
stage: "mutationTest",
|
|
5385
|
+
reason: "Mutation testing failed",
|
|
5386
|
+
cause
|
|
5387
|
+
})), Match.exhaustive)));
|
|
5464
5388
|
});
|
|
5465
5389
|
//#endregion
|
|
5466
5390
|
//#region src/reporter-output.ts
|
|
@@ -5475,7 +5399,7 @@ const write = (stdio, channel, chunks) => Stream.run(Stream.fromIterable(chunks)
|
|
|
5475
5399
|
* that cannot compose Effects — its writes fire inside a synchronous for-await).
|
|
5476
5400
|
* Write errors are ignored like a broken pipe on a stream handle.
|
|
5477
5401
|
*
|
|
5478
|
-
* Note: effect 4.0.0-rc.
|
|
5402
|
+
* Note: effect 4.0.0-rc.116 exports the runner as `Effect.runPromise`; there is no
|
|
5479
5403
|
* `Runtime.runPromise` in this version (verified against the installed source) —
|
|
5480
5404
|
* do not invent that import.
|
|
5481
5405
|
*/
|
|
@@ -5887,7 +5811,7 @@ const rememberTerminalReport = (seen, event) => {
|
|
|
5887
5811
|
};
|
|
5888
5812
|
}), Match.orElse(() => void 0));
|
|
5889
5813
|
};
|
|
5890
|
-
const decodeClearTextReport = (terminal) => S.
|
|
5814
|
+
const decodeClearTextReport = (terminal) => S.decodeEffect(ClearTextReportCommand)({
|
|
5891
5815
|
_tag: "ClearTextReportCommand",
|
|
5892
5816
|
report: terminal.report,
|
|
5893
5817
|
metrics: terminal.metrics
|
|
@@ -6329,13 +6253,7 @@ const writePrepare = (outcome, raw) => withPhaseSpan("prepare", {}, (span) => Ef
|
|
|
6329
6253
|
reporterStage
|
|
6330
6254
|
};
|
|
6331
6255
|
}));
|
|
6332
|
-
const prepareCell =
|
|
6333
|
-
read: readPrepare,
|
|
6334
|
-
decode: decodePrepare,
|
|
6335
|
-
decide: planPrepare,
|
|
6336
|
-
encode: encodePrepareDecision,
|
|
6337
|
-
write: writePrepare
|
|
6338
|
-
});
|
|
6256
|
+
const prepareCell = Sandwich.read(readPrepare).decode(Sandwich.pure(decodePrepare)).decide(planPrepare).encode(Sandwich.pure((outcome) => Result.succeed(encodePrepareDecision(outcome)))).write(writePrepare);
|
|
6339
6257
|
//#endregion
|
|
6340
6258
|
//#region src/Run.ts
|
|
6341
6259
|
const RUN_EVENTS_QUEUE_BOUND = 256;
|
|
@@ -6385,7 +6303,7 @@ const framedEventOf = (decision) => Option.match(decision, {
|
|
|
6385
6303
|
onSome: (d) => Match.value(d).pipe(Match.tag("EventFramed", (framed) => Result.succeed(framed.event)), Match.tag("EventSuppressed", () => Result.fail(void 0)), Match.exhaustive)
|
|
6386
6304
|
});
|
|
6387
6305
|
var RunEventDrain = class extends Context.Service()("@systemfsoftware/stryker-js/run-event-stream/RunEventDrain") {};
|
|
6388
|
-
const drainOf = (stdio, framed) => Stream.run(framed, stdio.stdout({ endOnDone: true })).pipe(Effect$1.withSpan("stryker.output.drain"), Effect$1.
|
|
6306
|
+
const drainOf = (stdio, framed) => Stream.run(framed, stdio.stdout({ endOnDone: true })).pipe(Effect$1.withSpan("stryker.output.drain"), Effect$1.tapCause((cause) => Effect$1.logError("stryker.output.drain_failed", cause)), Effect$1.ignoreCause);
|
|
6389
6307
|
const RunEventDrainLive = Layer.effect(RunEventDrain, Effect$1.gen(function* () {
|
|
6390
6308
|
const stdio = yield* Stdio.Stdio;
|
|
6391
6309
|
return RunEventDrain.of({
|
|
@@ -6552,7 +6470,7 @@ const RunEventDrainFileLive = Layer.effect(RunEventDrain, Effect$1.gen(function*
|
|
|
6552
6470
|
drainFramed: (framed) => Effect$1.gen(function* () {
|
|
6553
6471
|
const fileName = yield* Ref.get(fileNameRef);
|
|
6554
6472
|
yield* drainStdoutAndFile(fs, path, stdio, fileName, framed);
|
|
6555
|
-
}).pipe(Effect$1.
|
|
6473
|
+
}).pipe(Effect$1.tapCause((cause) => Effect$1.logError("stryker.output.drain_file_failed", cause)), Effect$1.ignoreCause),
|
|
6556
6474
|
setProgressStreamFile: (fileName) => Ref.set(fileNameRef, fileName)
|
|
6557
6475
|
});
|
|
6558
6476
|
}));
|