as-test 1.0.12 → 1.0.13
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 +5 -0
- package/README.md +13 -0
- package/bin/commands/fuzz-core.js +43 -12
- package/bin/commands/fuzz.js +2 -1
- package/bin/commands/run-core.js +144 -3
- package/bin/commands/run.js +2 -1
- package/bin/commands/test.js +3 -1
- package/bin/index.js +100 -27
- package/bin/reporters/default.js +18 -8
- package/bin/util.js +1 -1
- package/package.json +8 -8
- package/transform/lib/builder.js +14 -15
- package/transform/lib/coverage.js +11 -12
- package/transform/lib/index.js +0 -1
- package/transform/lib/linker.js +3 -4
- package/transform/lib/location.js +0 -1
- package/transform/lib/log.js +0 -1
- package/transform/lib/mock.js +15 -9
- package/transform/lib/range.js +0 -1
- package/transform/lib/types.js +0 -1
- package/transform/lib/util.js +0 -1
- package/transform/lib/visitor.js +64 -65
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 2025-05-03 - v1.0.13
|
|
4
|
+
|
|
5
|
+
- feat: add `--fuzzer` / `--fuzzers` filtering for `ast fuzz` and `ast test --fuzz`, accept `--suite` / `--suites` as fuzz aliases, and include target-specific repro commands in fuzz failure output.
|
|
6
|
+
- feat: add `--suite` / `--suites` filtering for `ast run` and `ast test`, and print suite-specific repro commands on failing test assertions.
|
|
7
|
+
|
|
3
8
|
## 2026-04-28 - v1.0.12
|
|
4
9
|
|
|
5
10
|
- perf: faster seed generation
|
package/README.md
CHANGED
|
@@ -134,6 +134,13 @@ Run one matching file:
|
|
|
134
134
|
npx ast test math
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
Re-run one suite inside a matching file:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npx ast run math --suite array-check
|
|
141
|
+
npx ast run math --suite array-manipulation/array-check
|
|
142
|
+
```
|
|
143
|
+
|
|
137
144
|
You do not need to learn every CLI flag to get started. Most projects can begin with `npx ast test`, then add more configuration only when they need it.
|
|
138
145
|
|
|
139
146
|
## Mocking
|
|
@@ -286,6 +293,12 @@ Run only fuzzers:
|
|
|
286
293
|
npx ast fuzz
|
|
287
294
|
```
|
|
288
295
|
|
|
296
|
+
Run one matching fuzz target:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
npx ast fuzz string --fuzzer ascii-strings-survive-concatenation-boundaries
|
|
300
|
+
```
|
|
301
|
+
|
|
289
302
|
Run tests and fuzzers together:
|
|
290
303
|
|
|
291
304
|
```bash
|
|
@@ -9,7 +9,7 @@ const DEFAULT_CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json");
|
|
|
9
9
|
const MAGIC = Buffer.from("WIPC");
|
|
10
10
|
const HEADER_SIZE = 9;
|
|
11
11
|
const MAX_DEFAULT_SEED = 0x7fffffff;
|
|
12
|
-
export async function fuzz(configPath = DEFAULT_CONFIG_PATH, selectors = [], modeName, overrides = {}) {
|
|
12
|
+
export async function fuzz(configPath = DEFAULT_CONFIG_PATH, selectors = [], modeName, overrides = {}, fuzzerSelectors = []) {
|
|
13
13
|
const loadedConfig = loadConfig(configPath, false);
|
|
14
14
|
const mode = applyMode(loadedConfig, modeName);
|
|
15
15
|
const config = resolveFuzzConfig(loadedConfig.fuzz, overrides);
|
|
@@ -25,7 +25,7 @@ export async function fuzz(configPath = DEFAULT_CONFIG_PATH, selectors = [], mod
|
|
|
25
25
|
await build(configPath, [file], modeName, { coverage: false }, { target: "bindings", args: ["--use", "AS_TEST_FUZZ=1"], kind: "fuzz" });
|
|
26
26
|
const buildFinishedAt = Date.now();
|
|
27
27
|
const buildTime = buildFinishedAt - buildStartedAt;
|
|
28
|
-
results.push(await runFuzzTarget(file, mode.config.outDir, duplicateBasenames, config, buildStartedAt, buildFinishedAt, buildTime, modeName));
|
|
28
|
+
results.push(await runFuzzTarget(file, mode.config.outDir, duplicateBasenames, config, fuzzerSelectors, buildStartedAt, buildFinishedAt, buildTime, modeName));
|
|
29
29
|
}
|
|
30
30
|
return results;
|
|
31
31
|
}
|
|
@@ -69,7 +69,7 @@ function encodeRunsOverrideKind(kind) {
|
|
|
69
69
|
return 4;
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
async function runFuzzTarget(file, outDir, duplicateBasenames, config, buildStartedAt, buildFinishedAt, buildTime, modeName) {
|
|
72
|
+
async function runFuzzTarget(file, outDir, duplicateBasenames, config, fuzzerSelectors, buildStartedAt, buildFinishedAt, buildTime, modeName) {
|
|
73
73
|
const startedAt = Date.now();
|
|
74
74
|
const artifact = resolveArtifactFileName(file, duplicateBasenames, modeName);
|
|
75
75
|
const wasmPath = path.resolve(process.cwd(), outDir, artifact);
|
|
@@ -210,7 +210,10 @@ async function runFuzzTarget(file, outDir, duplicateBasenames, config, buildStar
|
|
|
210
210
|
};
|
|
211
211
|
}
|
|
212
212
|
const crashFiles = [];
|
|
213
|
-
|
|
213
|
+
const selectedFuzzers = fuzzerSelectors.length
|
|
214
|
+
? filterSelectedFuzzers(report.fuzzers, fuzzerSelectors, file)
|
|
215
|
+
: report.fuzzers;
|
|
216
|
+
for (const fuzzer of selectedFuzzers) {
|
|
214
217
|
if (fuzzer.failed <= 0 && fuzzer.crashed <= 0)
|
|
215
218
|
continue;
|
|
216
219
|
const firstFailureSeed = typeof fuzzer.failures?.[0]?.seed == "number"
|
|
@@ -222,7 +225,7 @@ async function runFuzzTarget(file, outDir, duplicateBasenames, config, buildStar
|
|
|
222
225
|
entryKey: buildFuzzFailureEntryKey(file, fuzzer.name, modeName ?? "default"),
|
|
223
226
|
mode: modeName ?? "default",
|
|
224
227
|
seed: firstFailureSeed,
|
|
225
|
-
reproCommand: buildFuzzReproCommand(file, firstFailureSeed, modeName ?? "default", 1),
|
|
228
|
+
reproCommand: buildFuzzReproCommand(file, firstFailureSeed, modeName ?? "default", fuzzer.selector, 1),
|
|
226
229
|
error: fuzzer.failure?.message ||
|
|
227
230
|
`fuzz failure in ${fuzzer.name} after ${fuzzer.runs} runs`,
|
|
228
231
|
stdout: passthrough.stdout,
|
|
@@ -237,21 +240,49 @@ async function runFuzzTarget(file, outDir, duplicateBasenames, config, buildStar
|
|
|
237
240
|
file,
|
|
238
241
|
target: path.basename(file),
|
|
239
242
|
modeName: modeName ?? "default",
|
|
240
|
-
runs:
|
|
241
|
-
crashes:
|
|
243
|
+
runs: selectedFuzzers.reduce((sum, item) => sum + item.runs, 0),
|
|
244
|
+
crashes: selectedFuzzers.reduce((sum, item) => sum + item.crashed, 0),
|
|
242
245
|
crashFiles,
|
|
243
246
|
seed: config.seed,
|
|
244
247
|
time: Date.now() - startedAt,
|
|
245
248
|
buildTime,
|
|
246
249
|
buildStartedAt,
|
|
247
250
|
buildFinishedAt,
|
|
248
|
-
fuzzers:
|
|
251
|
+
fuzzers: selectedFuzzers,
|
|
249
252
|
};
|
|
250
253
|
}
|
|
251
|
-
function
|
|
254
|
+
function filterSelectedFuzzers(fuzzers, selectors, file) {
|
|
255
|
+
const annotated = fuzzers.map((fuzzer) => ({
|
|
256
|
+
...fuzzer,
|
|
257
|
+
selector: slugifyFuzzerSelector(fuzzer.name),
|
|
258
|
+
}));
|
|
259
|
+
const selected = new Set();
|
|
260
|
+
for (const selector of selectors) {
|
|
261
|
+
const slug = slugifyFuzzerSelector(selector);
|
|
262
|
+
if (!slug.length)
|
|
263
|
+
continue;
|
|
264
|
+
const matches = annotated.filter((fuzzer) => fuzzer.selector == slug);
|
|
265
|
+
if (!matches.length) {
|
|
266
|
+
throw new Error(`No fuzz targets matched "${selector}" in ${path.basename(file)}.`);
|
|
267
|
+
}
|
|
268
|
+
for (const match of matches) {
|
|
269
|
+
selected.add(match.selector);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return annotated.filter((fuzzer) => selected.has(fuzzer.selector ?? ""));
|
|
273
|
+
}
|
|
274
|
+
function slugifyFuzzerSelector(value) {
|
|
275
|
+
return value
|
|
276
|
+
.trim()
|
|
277
|
+
.toLowerCase()
|
|
278
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
279
|
+
.replace(/^-+|-+$/g, "");
|
|
280
|
+
}
|
|
281
|
+
function buildFuzzReproCommand(file, seed, modeName, fuzzer, runs) {
|
|
252
282
|
const modeArg = modeName != "default" ? ` --mode ${modeName}` : "";
|
|
283
|
+
const fuzzerArg = fuzzer?.length ? ` --fuzzer ${fuzzer}` : "";
|
|
253
284
|
const runsArg = typeof runs == "number" ? ` --runs ${runs}` : "";
|
|
254
|
-
return `ast fuzz ${file}${modeArg} --seed ${seed}${runsArg}`;
|
|
285
|
+
return `ast fuzz ${file}${modeArg}${fuzzerArg} --seed ${seed}${runsArg}`;
|
|
255
286
|
}
|
|
256
287
|
function buildFuzzFailureEntryKey(file, name, modeName) {
|
|
257
288
|
return `${path.basename(file).replace(/\.ts$/, "")}.${sanitizeEntryName(modeName)}.${sanitizeEntryName(name)}`;
|
|
@@ -324,12 +355,12 @@ function captureFrames(onFrame) {
|
|
|
324
355
|
}
|
|
325
356
|
});
|
|
326
357
|
process.stdin.read = ((size) => {
|
|
327
|
-
const max =
|
|
358
|
+
const max = size == null ? 0 : Number(size);
|
|
328
359
|
if (max > 0 && replies.length) {
|
|
329
360
|
return dequeueReply(max);
|
|
330
361
|
}
|
|
331
362
|
if (originalRead) {
|
|
332
|
-
return originalRead(size);
|
|
363
|
+
return originalRead(size === null ? undefined : size);
|
|
333
364
|
}
|
|
334
365
|
return null;
|
|
335
366
|
});
|
package/bin/commands/fuzz.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export async function executeFuzzCommand(rawArgs, configPath, selectedModes, deps) {
|
|
2
2
|
const commandArgs = deps.resolveCommandArgs(rawArgs, "fuzz");
|
|
3
|
+
const fuzzerSelectors = deps.resolveFuzzerSelectors(rawArgs, "fuzz");
|
|
3
4
|
const listFlags = deps.resolveListFlags(rawArgs, "fuzz");
|
|
4
5
|
const modeTargets = deps.resolveExecutionModes(configPath, selectedModes);
|
|
5
6
|
if (listFlags.list || listFlags.listModes) {
|
|
6
7
|
await deps.listExecutionPlan("fuzz", configPath, commandArgs, modeTargets, listFlags);
|
|
7
8
|
return;
|
|
8
9
|
}
|
|
9
|
-
await deps.runFuzzModes(configPath, commandArgs, modeTargets, rawArgs);
|
|
10
|
+
await deps.runFuzzModes(configPath, commandArgs, fuzzerSelectors, modeTargets, rawArgs);
|
|
10
11
|
}
|
package/bin/commands/run-core.js
CHANGED
|
@@ -327,6 +327,9 @@ function formatReadableLog(file, suites, modeName, buildCommand, runCommand, sna
|
|
|
327
327
|
lines.push("", "Failures:");
|
|
328
328
|
for (const failure of failures) {
|
|
329
329
|
lines.push(`FAIL ${failure.title}${failure.where.length ? ` (${failure.where})` : ""}`);
|
|
330
|
+
if (failure.suitePath.length) {
|
|
331
|
+
lines.push(`Repro: ${buildSuiteReproCommand(file, failure.suitePath, modeName)}`);
|
|
332
|
+
}
|
|
330
333
|
if (failure.message.length)
|
|
331
334
|
lines.push(`Message: ${failure.message}`);
|
|
332
335
|
if (failure.left.length)
|
|
@@ -352,6 +355,139 @@ function formatInvocation(invocation) {
|
|
|
352
355
|
.map((part) => (/[\s"'\\]/.test(part) ? JSON.stringify(part) : part))
|
|
353
356
|
.join(" ");
|
|
354
357
|
}
|
|
358
|
+
function filterSelectedSuites(suites, selectors, file, modeName) {
|
|
359
|
+
const annotated = annotateSuitePaths(suites, []);
|
|
360
|
+
const matches = resolveSuiteSelectionMatches(annotated, selectors, file);
|
|
361
|
+
const selected = new Set(matches.map((match) => match.resolvedPath));
|
|
362
|
+
return cloneSelectedSuites(annotated, selected, file, modeName);
|
|
363
|
+
}
|
|
364
|
+
function annotateSuitePaths(suites, pathParts) {
|
|
365
|
+
return suites.map((suite) => annotateSuiteNode(suite, pathParts));
|
|
366
|
+
}
|
|
367
|
+
function annotateSuiteNode(suite, pathParts) {
|
|
368
|
+
const description = String(suite?.description ?? "unknown");
|
|
369
|
+
const slug = slugifySelectorSegment(description);
|
|
370
|
+
const nextParts = [...pathParts, slug];
|
|
371
|
+
const nextSuites = Array.isArray(suite?.suites)
|
|
372
|
+
? suite.suites
|
|
373
|
+
: [];
|
|
374
|
+
const annotatedSuites = annotateSuitePaths(nextSuites, nextParts);
|
|
375
|
+
return {
|
|
376
|
+
...suite,
|
|
377
|
+
path: nextParts.join("/"),
|
|
378
|
+
suites: annotatedSuites,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function resolveSuiteSelectionMatches(suites, selectors, file) {
|
|
382
|
+
const matches = [];
|
|
383
|
+
for (const selector of selectors) {
|
|
384
|
+
const normalized = selector.trim();
|
|
385
|
+
if (!normalized.length)
|
|
386
|
+
continue;
|
|
387
|
+
if (normalized.includes("/")) {
|
|
388
|
+
const resolved = resolveExplicitSuitePath(suites, normalized);
|
|
389
|
+
if (!resolved) {
|
|
390
|
+
throw new Error(`No suites matched "${selector}" in ${path.basename(file)}.`);
|
|
391
|
+
}
|
|
392
|
+
matches.push({
|
|
393
|
+
kind: "path",
|
|
394
|
+
raw: selector,
|
|
395
|
+
resolvedPath: resolved.path,
|
|
396
|
+
depth: resolved.depth,
|
|
397
|
+
});
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
const resolved = resolveBareSuiteSelector(suites, normalized);
|
|
401
|
+
if (!resolved) {
|
|
402
|
+
throw new Error(`No suites matched "${selector}" in ${path.basename(file)}.`);
|
|
403
|
+
}
|
|
404
|
+
matches.push({
|
|
405
|
+
kind: "bare",
|
|
406
|
+
raw: selector,
|
|
407
|
+
resolvedPath: resolved.path,
|
|
408
|
+
depth: resolved.depth,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
return matches;
|
|
412
|
+
}
|
|
413
|
+
function resolveExplicitSuitePath(suites, selector) {
|
|
414
|
+
const normalized = selector
|
|
415
|
+
.split("/")
|
|
416
|
+
.map((part) => slugifySelectorSegment(part))
|
|
417
|
+
.filter((part) => part.length)
|
|
418
|
+
.join("/");
|
|
419
|
+
if (!normalized.length)
|
|
420
|
+
return null;
|
|
421
|
+
let match = null;
|
|
422
|
+
walkSuites(suites, (suite, depth) => {
|
|
423
|
+
if (suite.path == normalized) {
|
|
424
|
+
match = { path: suite.path, depth };
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
return false;
|
|
428
|
+
});
|
|
429
|
+
return match;
|
|
430
|
+
}
|
|
431
|
+
function resolveBareSuiteSelector(suites, selector) {
|
|
432
|
+
const slug = slugifySelectorSegment(selector);
|
|
433
|
+
if (!slug.length)
|
|
434
|
+
return null;
|
|
435
|
+
const matches = [];
|
|
436
|
+
walkSuites(suites, (suite, depth) => {
|
|
437
|
+
const leaf = String(suite.path ?? "").split("/").pop() ?? "";
|
|
438
|
+
if (leaf == slug) {
|
|
439
|
+
matches.push({ path: String(suite.path), depth });
|
|
440
|
+
}
|
|
441
|
+
return false;
|
|
442
|
+
});
|
|
443
|
+
if (!matches.length)
|
|
444
|
+
return null;
|
|
445
|
+
matches.sort((a, b) => a.depth - b.depth || a.path.localeCompare(b.path));
|
|
446
|
+
const shallowest = matches[0];
|
|
447
|
+
const ambiguous = matches.filter((match) => match.depth == shallowest.depth);
|
|
448
|
+
if (ambiguous.length > 1) {
|
|
449
|
+
throw new Error(`Suite selector "${selector}" is ambiguous. Matches: ${ambiguous.map((match) => match.path).join(", ")}`);
|
|
450
|
+
}
|
|
451
|
+
return shallowest;
|
|
452
|
+
}
|
|
453
|
+
function walkSuites(suites, visitor, depth = 0) {
|
|
454
|
+
for (const suite of suites) {
|
|
455
|
+
if (visitor(suite, depth))
|
|
456
|
+
return true;
|
|
457
|
+
const childSuites = Array.isArray(suite?.suites) ? suite.suites : [];
|
|
458
|
+
if (walkSuites(childSuites, visitor, depth + 1))
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
function cloneSelectedSuites(suites, selected, file, modeName) {
|
|
464
|
+
const out = [];
|
|
465
|
+
for (const suite of suites) {
|
|
466
|
+
const childSuites = Array.isArray(suite.suites) ? suite.suites : [];
|
|
467
|
+
const selectedChildren = cloneSelectedSuites(childSuites, selected, file, modeName);
|
|
468
|
+
const keep = selected.has(String(suite.path ?? "")) || selectedChildren.length > 0;
|
|
469
|
+
if (!keep)
|
|
470
|
+
continue;
|
|
471
|
+
out.push({
|
|
472
|
+
...suite,
|
|
473
|
+
file,
|
|
474
|
+
modeName,
|
|
475
|
+
suites: selectedChildren,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
return out;
|
|
479
|
+
}
|
|
480
|
+
function slugifySelectorSegment(value) {
|
|
481
|
+
return value
|
|
482
|
+
.trim()
|
|
483
|
+
.toLowerCase()
|
|
484
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
485
|
+
.replace(/^-+|-+$/g, "");
|
|
486
|
+
}
|
|
487
|
+
function buildSuiteReproCommand(file, suitePath, modeName) {
|
|
488
|
+
const modeArg = modeName && modeName != "default" ? ` --mode ${modeName}` : "";
|
|
489
|
+
return `ast run ${file}${modeArg} --suite ${suitePath}`;
|
|
490
|
+
}
|
|
355
491
|
function collectReadableFailures(suites, file, pathParts) {
|
|
356
492
|
const out = [];
|
|
357
493
|
for (const suite of suites) {
|
|
@@ -372,6 +508,7 @@ function collectReadableFailures(suites, file, pathParts) {
|
|
|
372
508
|
message: String(test.message ?? ""),
|
|
373
509
|
left: JSON.stringify(test.left ?? ""),
|
|
374
510
|
right: JSON.stringify(test.right ?? ""),
|
|
511
|
+
suitePath: String(suiteAny.path ?? ""),
|
|
375
512
|
});
|
|
376
513
|
}
|
|
377
514
|
const childSuites = Array.isArray(suiteAny.suites)
|
|
@@ -492,6 +629,9 @@ export async function run(flags = {}, configPath = DEFAULT_CONFIG_PATH, selector
|
|
|
492
629
|
throw new Error(`Failed to run ${path.basename(file)} in mode ${modeLabel} with ${details}`);
|
|
493
630
|
}
|
|
494
631
|
const normalized = normalizeReport(report);
|
|
632
|
+
const selectedSuites = options.suiteSelectors?.length
|
|
633
|
+
? filterSelectedSuites(normalized.suites, options.suiteSelectors, file, options.modeName ?? "default")
|
|
634
|
+
: normalized.suites;
|
|
495
635
|
snapshotStore.flush();
|
|
496
636
|
snapshotSummary.matched += snapshotStore.matched;
|
|
497
637
|
snapshotSummary.created += snapshotStore.created;
|
|
@@ -500,7 +640,7 @@ export async function run(flags = {}, configPath = DEFAULT_CONFIG_PATH, selector
|
|
|
500
640
|
reports.push({
|
|
501
641
|
file,
|
|
502
642
|
modeName: options.modeName ?? "default",
|
|
503
|
-
suites:
|
|
643
|
+
suites: selectedSuites,
|
|
504
644
|
coverage: normalized.coverage,
|
|
505
645
|
runCommand: runCommandForLog,
|
|
506
646
|
snapshotSummary: {
|
|
@@ -1665,8 +1805,9 @@ async function runProcess(invocation, specFile, crashDir, modeName, snapshots, s
|
|
|
1665
1805
|
if (stderrPendingLine.length && !shouldSuppressWasiWarningLine(stderrPendingLine)) {
|
|
1666
1806
|
stderrBuffer += stderrPendingLine;
|
|
1667
1807
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1808
|
+
const processSpawnError = spawnError;
|
|
1809
|
+
if (processSpawnError) {
|
|
1810
|
+
const errorText = processSpawnError.stack ?? processSpawnError.message;
|
|
1670
1811
|
persistCrashRecord(crashDir, {
|
|
1671
1812
|
kind: "test",
|
|
1672
1813
|
file: specFile,
|
package/bin/commands/run.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { createRunReporter, run } from "./run-core.js";
|
|
2
2
|
export async function executeRunCommand(rawArgs, flags, configPath, selectedModes, deps) {
|
|
3
3
|
const commandArgs = deps.resolveCommandArgs(rawArgs, "run");
|
|
4
|
+
const suiteSelectors = deps.resolveSuiteSelectors(rawArgs, "run");
|
|
4
5
|
const listFlags = deps.resolveListFlags(rawArgs, "run");
|
|
5
6
|
const featureToggles = deps.resolveFeatureToggles(rawArgs, "run");
|
|
6
7
|
const runFlags = {
|
|
@@ -20,5 +21,5 @@ export async function executeRunCommand(rawArgs, flags, configPath, selectedMode
|
|
|
20
21
|
await deps.listExecutionPlan("run", configPath, commandArgs, modeTargets, listFlags);
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
|
-
await deps.runRuntimeModes(runFlags, configPath, commandArgs, modeTargets);
|
|
24
|
+
await deps.runRuntimeModes(runFlags, configPath, commandArgs, suiteSelectors, modeTargets);
|
|
24
25
|
}
|
package/bin/commands/test.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export async function executeTestCommand(rawArgs, flags, configPath, selectedModes, deps) {
|
|
2
2
|
const commandArgs = deps.resolveCommandArgs(rawArgs, "test");
|
|
3
|
+
const suiteSelectors = deps.resolveSuiteSelectors(rawArgs, "test");
|
|
4
|
+
const fuzzerSelectors = deps.resolveFuzzerSelectors(rawArgs, "test");
|
|
3
5
|
const listFlags = deps.resolveListFlags(rawArgs, "test");
|
|
4
6
|
const featureToggles = deps.resolveFeatureToggles(rawArgs, "test");
|
|
5
7
|
const buildFeatureToggles = {
|
|
@@ -25,5 +27,5 @@ export async function executeTestCommand(rawArgs, flags, configPath, selectedMod
|
|
|
25
27
|
await deps.listExecutionPlan("test", configPath, commandArgs, modeTargets, listFlags, fuzzEnabled);
|
|
26
28
|
return;
|
|
27
29
|
}
|
|
28
|
-
await deps.runTestModes(runFlags, configPath, commandArgs, modeTargets, buildFeatureToggles, fuzzEnabled, fuzzOverrides);
|
|
30
|
+
await deps.runTestModes(runFlags, configPath, commandArgs, suiteSelectors, fuzzerSelectors, modeTargets, buildFeatureToggles, fuzzEnabled, fuzzOverrides);
|
|
29
31
|
}
|