as-test 1.0.6 → 1.0.9
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 +13 -0
- package/README.md +45 -0
- package/as-test.config.schema.json +39 -0
- package/assembly/__fuzz__/string.fuzz.ts +1 -1
- package/assembly/as-test.intellisense.d.ts +60 -0
- package/assembly/index.ts +32 -3
- package/assembly/src/fuzz.ts +55 -14
- package/assembly/util/wipc.ts +14 -4
- package/bin/commands/fuzz-core.js +30 -2
- package/bin/commands/init-core.js +129 -19
- package/bin/commands/run-core.js +215 -21
- package/bin/commands/web-runner-source.js +86 -13
- package/bin/coverage-points.js +173 -0
- package/bin/index.js +62 -4
- package/bin/reporters/default.js +103 -4
- package/bin/types.js +9 -0
- package/bin/util.js +16 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 2026-03-31 - v1.0.7
|
|
6
|
+
|
|
7
|
+
### Coverage
|
|
8
|
+
|
|
9
|
+
- feat: make CLI coverage output easier to scan with a summarized coverage block, per-file breakdown, grouped uncovered points, clickable `file:line:column` locations, trimmed source snippets, aligned gap columns, source-aware labels such as `Function`, `Method`, `Constructor`, `Property`, and `Call`, and coverage-point ignore rules for labels, names, locations, and snippets.
|
|
10
|
+
|
|
11
|
+
### Fuzzing
|
|
12
|
+
|
|
13
|
+
- feat: allow `fuzz(...)` and `xfuzz(...)` targets to override their own operation count with an optional third argument, so one file can mix short smoke fuzzers and heavier targets without changing the global `fuzz.runs` config.
|
|
14
|
+
- feat: make `--runs` / `--fuzz-runs` accept absolute and relative overrides such as `500`, `1.5x`, `+10%`, and `+100000`, applying them to each fuzzer's effective run count for that command.
|
|
15
|
+
|
|
3
16
|
## 2026-03-31 - v1.0.6
|
|
4
17
|
|
|
5
18
|
### Fuzzing
|
package/README.md
CHANGED
|
@@ -83,6 +83,23 @@ Minimal `as-test.config.json`:
|
|
|
83
83
|
}
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
Coverage point filtering is configurable when you want to ignore known-noisy gaps:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"coverage": {
|
|
91
|
+
"enabled": true,
|
|
92
|
+
"include": ["assembly/src/**/*.ts"],
|
|
93
|
+
"ignore": {
|
|
94
|
+
"labels": ["Call"],
|
|
95
|
+
"names": ["panic", "serialize"],
|
|
96
|
+
"locations": ["assembly/src/fuzz.ts:38:*"],
|
|
97
|
+
"snippets": ["*message: string*"]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
86
103
|
## Writing Tests
|
|
87
104
|
|
|
88
105
|
Tests usually live in `assembly/__tests__/*.spec.ts`.
|
|
@@ -218,6 +235,34 @@ fuzz("bounded integer addition", (left: i32, right: i32): bool => {
|
|
|
218
235
|
});
|
|
219
236
|
```
|
|
220
237
|
|
|
238
|
+
Pass a third argument to override the operation count for one target without changing the global fuzz config:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
fuzz("hot path stays stable", (): void => {
|
|
242
|
+
expect(1 + 1).toBe(2);
|
|
243
|
+
}, 250);
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Or pass it as the second argument to `.generate(...)`:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
fuzz("ascii strings survive concatenation boundaries", (input: string): bool => {
|
|
250
|
+
expect(input.length <= 40).toBe(true);
|
|
251
|
+
return true;
|
|
252
|
+
}).generate((seed: FuzzSeed, run: (input: string) => bool): void => {
|
|
253
|
+
run(seed.string({ charset: "ascii", min: 0, max: 40 }));
|
|
254
|
+
}, 250);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
You can still override fuzz runs from the CLI when you want to force a different count for the current command:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
npx ast fuzz --runs 500
|
|
261
|
+
npx ast fuzz --runs 1.5x
|
|
262
|
+
npx ast fuzz --runs +10%
|
|
263
|
+
npx ast fuzz --runs +100000
|
|
264
|
+
```
|
|
265
|
+
|
|
221
266
|
If you used `npx ast init` with a fuzzer example, the config is already there. Otherwise, add a `fuzz` block to `as-test.config.json` so `npx ast fuzz` knows what to build:
|
|
222
267
|
|
|
223
268
|
```json
|
|
@@ -121,6 +121,45 @@
|
|
|
121
121
|
"type": "string"
|
|
122
122
|
},
|
|
123
123
|
"default": []
|
|
124
|
+
},
|
|
125
|
+
"ignore": {
|
|
126
|
+
"type": "object",
|
|
127
|
+
"description": "Ignore specific coverage points by derived label, symbol name, location, or source snippet.",
|
|
128
|
+
"additionalProperties": true,
|
|
129
|
+
"properties": {
|
|
130
|
+
"labels": {
|
|
131
|
+
"type": "array",
|
|
132
|
+
"description": "Ignore all points whose rendered label matches, such as Call, Method, Constructor, Property, or Function.",
|
|
133
|
+
"items": {
|
|
134
|
+
"type": "string"
|
|
135
|
+
},
|
|
136
|
+
"default": []
|
|
137
|
+
},
|
|
138
|
+
"names": {
|
|
139
|
+
"type": "array",
|
|
140
|
+
"description": "Ignore declarations or calls whose extracted symbol name matches a glob pattern.",
|
|
141
|
+
"items": {
|
|
142
|
+
"type": "string"
|
|
143
|
+
},
|
|
144
|
+
"default": []
|
|
145
|
+
},
|
|
146
|
+
"locations": {
|
|
147
|
+
"type": "array",
|
|
148
|
+
"description": "Ignore points whose file:line:column location matches a glob pattern.",
|
|
149
|
+
"items": {
|
|
150
|
+
"type": "string"
|
|
151
|
+
},
|
|
152
|
+
"default": []
|
|
153
|
+
},
|
|
154
|
+
"snippets": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"description": "Ignore points whose trimmed source snippet matches a glob pattern.",
|
|
157
|
+
"items": {
|
|
158
|
+
"type": "string"
|
|
159
|
+
},
|
|
160
|
+
"default": []
|
|
161
|
+
}
|
|
162
|
+
}
|
|
124
163
|
}
|
|
125
164
|
}
|
|
126
165
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
|
|
3
|
+
declare module "as-test" {
|
|
4
|
+
export interface IntellisenseIntegerOptions {
|
|
5
|
+
min?: number;
|
|
6
|
+
max?: number;
|
|
7
|
+
exclude?: number[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface IntellisenseFloatOptions {
|
|
11
|
+
min?: number;
|
|
12
|
+
max?: number;
|
|
13
|
+
exclude?: number[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface IntellisenseBytesOptions {
|
|
17
|
+
min?: number;
|
|
18
|
+
max?: number;
|
|
19
|
+
include?: number[];
|
|
20
|
+
exclude?: number[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface IntellisenseStringOptions {
|
|
24
|
+
charset?:
|
|
25
|
+
| "ascii"
|
|
26
|
+
| "alpha"
|
|
27
|
+
| "alnum"
|
|
28
|
+
| "digit"
|
|
29
|
+
| "hex"
|
|
30
|
+
| "base64"
|
|
31
|
+
| "identifier"
|
|
32
|
+
| "whitespace"
|
|
33
|
+
| "custom";
|
|
34
|
+
min?: number;
|
|
35
|
+
max?: number;
|
|
36
|
+
include?: number[];
|
|
37
|
+
exclude?: number[];
|
|
38
|
+
prefix?: string;
|
|
39
|
+
suffix?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface IntellisenseArrayOptions {
|
|
43
|
+
min?: number;
|
|
44
|
+
max?: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface FuzzSeed {
|
|
48
|
+
i32(options?: IntellisenseIntegerOptions): number;
|
|
49
|
+
u32(options?: IntellisenseIntegerOptions): number;
|
|
50
|
+
f32(options?: IntellisenseFloatOptions): number;
|
|
51
|
+
f64(options?: IntellisenseFloatOptions): number;
|
|
52
|
+
bytes(options?: IntellisenseBytesOptions): Uint8Array;
|
|
53
|
+
buffer(options?: IntellisenseBytesOptions): ArrayBuffer;
|
|
54
|
+
string(options?: IntellisenseStringOptions): string;
|
|
55
|
+
array<T>(
|
|
56
|
+
item: (seed: FuzzSeed) => T,
|
|
57
|
+
options?: IntellisenseArrayOptions,
|
|
58
|
+
): Array<T>;
|
|
59
|
+
}
|
|
60
|
+
}
|
package/assembly/index.ts
CHANGED
|
@@ -169,8 +169,9 @@ export function xit(description: string, callback: () => void): void {
|
|
|
169
169
|
export function fuzz<T extends Function>(
|
|
170
170
|
description: string,
|
|
171
171
|
callback: T,
|
|
172
|
+
operations: i32 = 0,
|
|
172
173
|
): FuzzerBase {
|
|
173
|
-
const entry = createFuzzer(description, callback);
|
|
174
|
+
const entry = createFuzzer(description, callback, false, operations);
|
|
174
175
|
entryFuzzers.push(entry);
|
|
175
176
|
return entry;
|
|
176
177
|
}
|
|
@@ -178,8 +179,9 @@ export function fuzz<T extends Function>(
|
|
|
178
179
|
export function xfuzz<T extends Function>(
|
|
179
180
|
description: string,
|
|
180
181
|
callback: T,
|
|
182
|
+
operations: i32 = 0,
|
|
181
183
|
): FuzzerBase {
|
|
182
|
-
const entry = createFuzzer(description, callback, true);
|
|
184
|
+
const entry = createFuzzer(description, callback, true, operations);
|
|
183
185
|
entryFuzzers.push(entry);
|
|
184
186
|
return entry;
|
|
185
187
|
}
|
|
@@ -421,6 +423,8 @@ function containsOnlySuites(values: Suite[]): bool {
|
|
|
421
423
|
class FuzzConfig {
|
|
422
424
|
runs: i32 = 1000;
|
|
423
425
|
seed: u64 = 1337;
|
|
426
|
+
runsOverrideKind: i32 = 0;
|
|
427
|
+
runsOverrideValue: f64 = 0.0;
|
|
424
428
|
}
|
|
425
429
|
|
|
426
430
|
class FuzzReport {
|
|
@@ -444,7 +448,10 @@ function runFuzzers(): void {
|
|
|
444
448
|
for (let i = 0; i < entryFuzzers.length; i++) {
|
|
445
449
|
const fuzzer = unchecked(entryFuzzers[i]);
|
|
446
450
|
prepareFuzzIteration();
|
|
447
|
-
const result = fuzzer.run(
|
|
451
|
+
const result = fuzzer.run(
|
|
452
|
+
config.seed,
|
|
453
|
+
resolveFuzzerRuns(fuzzer, config),
|
|
454
|
+
);
|
|
448
455
|
report.fuzzers.push(result);
|
|
449
456
|
}
|
|
450
457
|
sendReport(report.serialize());
|
|
@@ -455,9 +462,31 @@ function requestFuzzConfig(): FuzzConfig {
|
|
|
455
462
|
const reply = requestHostFuzzConfig();
|
|
456
463
|
out.runs = reply.runs;
|
|
457
464
|
out.seed = reply.seed;
|
|
465
|
+
out.runsOverrideKind = reply.runsOverrideKind;
|
|
466
|
+
out.runsOverrideValue = reply.runsOverrideValue;
|
|
458
467
|
return out;
|
|
459
468
|
}
|
|
460
469
|
|
|
470
|
+
function resolveFuzzerRuns(fuzzer: FuzzerBase, config: FuzzConfig): i32 {
|
|
471
|
+
const baseRuns = fuzzer.runsOr(config.runs);
|
|
472
|
+
const resolved = applyFuzzRunsOverride(
|
|
473
|
+
baseRuns,
|
|
474
|
+
config.runsOverrideKind,
|
|
475
|
+
config.runsOverrideValue,
|
|
476
|
+
);
|
|
477
|
+
return resolved > 0 ? resolved : 1;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function applyFuzzRunsOverride(baseRuns: i32, kind: i32, value: f64): i32 {
|
|
481
|
+
if (kind == 1) return <i32>value;
|
|
482
|
+
if (kind == 2) return <i32>Math.round(<f64>baseRuns * value);
|
|
483
|
+
if (kind == 3) return baseRuns + <i32>value;
|
|
484
|
+
if (kind == 4) {
|
|
485
|
+
return baseRuns + <i32>Math.round((<f64>baseRuns * value) / 100.0);
|
|
486
|
+
}
|
|
487
|
+
return baseRuns;
|
|
488
|
+
}
|
|
489
|
+
|
|
461
490
|
function registerSuite(
|
|
462
491
|
description: string,
|
|
463
492
|
callback: () => void,
|
package/assembly/src/fuzz.ts
CHANGED
|
@@ -186,15 +186,22 @@ export class FuzzSeed {
|
|
|
186
186
|
export abstract class FuzzerBase {
|
|
187
187
|
public name: string;
|
|
188
188
|
public skipped: bool;
|
|
189
|
-
|
|
189
|
+
public operations: i32;
|
|
190
|
+
constructor(name: string, skipped: bool = false, operations: i32 = 0) {
|
|
190
191
|
this.name = name;
|
|
191
192
|
this.skipped = skipped;
|
|
193
|
+
this.operations = operations > 0 ? operations : 0;
|
|
192
194
|
}
|
|
193
195
|
|
|
194
|
-
generate<T extends Function>(_generator: T): this {
|
|
196
|
+
generate<T extends Function>(_generator: T, operations: i32 = 0): this {
|
|
197
|
+
if (operations > 0) this.operations = operations;
|
|
195
198
|
return this;
|
|
196
199
|
}
|
|
197
200
|
|
|
201
|
+
runsOr(defaultRuns: i32): i32 {
|
|
202
|
+
return this.operations > 0 ? this.operations : defaultRuns;
|
|
203
|
+
}
|
|
204
|
+
|
|
198
205
|
abstract run(seed: u64, runs: i32): FuzzerResult;
|
|
199
206
|
}
|
|
200
207
|
|
|
@@ -377,19 +384,25 @@ export class Fuzzer0<R> extends FuzzerBase {
|
|
|
377
384
|
name: string,
|
|
378
385
|
private callback: () => R,
|
|
379
386
|
skipped: bool = false,
|
|
387
|
+
operations: i32 = 0,
|
|
380
388
|
) {
|
|
381
|
-
super(name, skipped);
|
|
389
|
+
super(name, skipped, operations);
|
|
382
390
|
this.returnsBool = !isVoid<R>();
|
|
383
391
|
}
|
|
384
392
|
|
|
385
|
-
generate<T extends Function>(generator: T): this {
|
|
393
|
+
generate<T extends Function>(generator: T, operations: i32 = 0): this {
|
|
386
394
|
this.generator =
|
|
387
395
|
changetype<(seed: FuzzSeed, run: () => R) => void>(generator);
|
|
396
|
+
if (operations > 0) this.operations = operations;
|
|
388
397
|
return this;
|
|
389
398
|
}
|
|
390
399
|
|
|
391
|
-
generateTyped(
|
|
400
|
+
generateTyped(
|
|
401
|
+
generator: (seed: FuzzSeed, run: () => R) => void,
|
|
402
|
+
operations: i32 = 0,
|
|
403
|
+
): this {
|
|
392
404
|
this.generator = generator;
|
|
405
|
+
if (operations > 0) this.operations = operations;
|
|
393
406
|
return this;
|
|
394
407
|
}
|
|
395
408
|
|
|
@@ -431,19 +444,25 @@ export class Fuzzer1<A, R> extends FuzzerBase {
|
|
|
431
444
|
name: string,
|
|
432
445
|
private callback: (a: A) => R,
|
|
433
446
|
skipped: bool = false,
|
|
447
|
+
operations: i32 = 0,
|
|
434
448
|
) {
|
|
435
|
-
super(name, skipped);
|
|
449
|
+
super(name, skipped, operations);
|
|
436
450
|
this.returnsBool = !isVoid<R>();
|
|
437
451
|
}
|
|
438
452
|
|
|
439
|
-
generate<T extends Function>(generator: T): this {
|
|
453
|
+
generate<T extends Function>(generator: T, operations: i32 = 0): this {
|
|
440
454
|
this.generator =
|
|
441
455
|
changetype<(seed: FuzzSeed, run: (a: A) => R) => void>(generator);
|
|
456
|
+
if (operations > 0) this.operations = operations;
|
|
442
457
|
return this;
|
|
443
458
|
}
|
|
444
459
|
|
|
445
|
-
generateTyped(
|
|
460
|
+
generateTyped(
|
|
461
|
+
generator: (seed: FuzzSeed, run: (a: A) => R) => void,
|
|
462
|
+
operations: i32 = 0,
|
|
463
|
+
): this {
|
|
446
464
|
this.generator = generator;
|
|
465
|
+
if (operations > 0) this.operations = operations;
|
|
447
466
|
return this;
|
|
448
467
|
}
|
|
449
468
|
|
|
@@ -494,21 +513,25 @@ export class Fuzzer2<A, B, R> extends FuzzerBase {
|
|
|
494
513
|
name: string,
|
|
495
514
|
private callback: (a: A, b: B) => R,
|
|
496
515
|
skipped: bool = false,
|
|
516
|
+
operations: i32 = 0,
|
|
497
517
|
) {
|
|
498
|
-
super(name, skipped);
|
|
518
|
+
super(name, skipped, operations);
|
|
499
519
|
this.returnsBool = !isVoid<R>();
|
|
500
520
|
}
|
|
501
521
|
|
|
502
|
-
generate<T extends Function>(generator: T): this {
|
|
522
|
+
generate<T extends Function>(generator: T, operations: i32 = 0): this {
|
|
503
523
|
this.generator =
|
|
504
524
|
changetype<(seed: FuzzSeed, run: (a: A, b: B) => R) => void>(generator);
|
|
525
|
+
if (operations > 0) this.operations = operations;
|
|
505
526
|
return this;
|
|
506
527
|
}
|
|
507
528
|
|
|
508
529
|
generateTyped(
|
|
509
530
|
generator: (seed: FuzzSeed, run: (a: A, b: B) => R) => void,
|
|
531
|
+
operations: i32 = 0,
|
|
510
532
|
): this {
|
|
511
533
|
this.generator = generator;
|
|
534
|
+
if (operations > 0) this.operations = operations;
|
|
512
535
|
return this;
|
|
513
536
|
}
|
|
514
537
|
|
|
@@ -559,20 +582,24 @@ export class Fuzzer3<A, B, C, R> extends FuzzerBase {
|
|
|
559
582
|
name: string,
|
|
560
583
|
private callback: (a: A, b: B, c: C) => R,
|
|
561
584
|
skipped: bool = false,
|
|
585
|
+
operations: i32 = 0,
|
|
562
586
|
) {
|
|
563
|
-
super(name, skipped);
|
|
587
|
+
super(name, skipped, operations);
|
|
564
588
|
this.returnsBool = !isVoid<R>();
|
|
565
589
|
}
|
|
566
590
|
|
|
567
|
-
generate<T extends Function>(generator: T): this {
|
|
591
|
+
generate<T extends Function>(generator: T, operations: i32 = 0): this {
|
|
568
592
|
this.generator = changetype<usize>(generator);
|
|
593
|
+
if (operations > 0) this.operations = operations;
|
|
569
594
|
return this;
|
|
570
595
|
}
|
|
571
596
|
|
|
572
597
|
generateTyped(
|
|
573
598
|
generator: (seed: FuzzSeed, run: (a: A, b: B, c: C) => R) => void,
|
|
599
|
+
operations: i32 = 0,
|
|
574
600
|
): this {
|
|
575
601
|
this.generator = changetype<usize>(generator);
|
|
602
|
+
if (operations > 0) this.operations = operations;
|
|
576
603
|
return this;
|
|
577
604
|
}
|
|
578
605
|
|
|
@@ -629,16 +656,23 @@ export function createFuzzer<T extends Function>(
|
|
|
629
656
|
name: string,
|
|
630
657
|
callback: T,
|
|
631
658
|
skipped: bool = false,
|
|
659
|
+
operations: i32 = 0,
|
|
632
660
|
): FuzzerBase {
|
|
633
661
|
const length = callback.length;
|
|
634
662
|
if (length == 0) {
|
|
635
|
-
return new Fuzzer0<usize>(
|
|
663
|
+
return new Fuzzer0<usize>(
|
|
664
|
+
name,
|
|
665
|
+
changetype<() => usize>(callback),
|
|
666
|
+
skipped,
|
|
667
|
+
operations,
|
|
668
|
+
);
|
|
636
669
|
}
|
|
637
670
|
if (length == 1) {
|
|
638
671
|
return new Fuzzer1<usize, usize>(
|
|
639
672
|
name,
|
|
640
673
|
changetype<(a: usize) => usize>(callback),
|
|
641
674
|
skipped,
|
|
675
|
+
operations,
|
|
642
676
|
);
|
|
643
677
|
}
|
|
644
678
|
if (length == 2) {
|
|
@@ -646,6 +680,7 @@ export function createFuzzer<T extends Function>(
|
|
|
646
680
|
name,
|
|
647
681
|
changetype<(a: usize, b: usize) => usize>(callback),
|
|
648
682
|
skipped,
|
|
683
|
+
operations,
|
|
649
684
|
);
|
|
650
685
|
}
|
|
651
686
|
if (length == 3) {
|
|
@@ -653,10 +688,16 @@ export function createFuzzer<T extends Function>(
|
|
|
653
688
|
name,
|
|
654
689
|
changetype<(a: usize, b: usize, c: usize) => usize>(callback),
|
|
655
690
|
skipped,
|
|
691
|
+
operations,
|
|
656
692
|
);
|
|
657
693
|
}
|
|
658
694
|
panic();
|
|
659
|
-
return new Fuzzer0<usize>(
|
|
695
|
+
return new Fuzzer0<usize>(
|
|
696
|
+
name,
|
|
697
|
+
changetype<() => usize>(callback),
|
|
698
|
+
skipped,
|
|
699
|
+
operations,
|
|
700
|
+
);
|
|
660
701
|
}
|
|
661
702
|
|
|
662
703
|
function buildAlphabet(options: StringOptions): i32[] {
|
package/assembly/util/wipc.ts
CHANGED
|
@@ -52,6 +52,8 @@ export class SnapshotReply {
|
|
|
52
52
|
export class FuzzConfigReply {
|
|
53
53
|
public runs: i32 = 1000;
|
|
54
54
|
public seed: u64 = 1337;
|
|
55
|
+
public runsOverrideKind: i32 = 0;
|
|
56
|
+
public runsOverrideValue: f64 = 0.0;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
export function sendAssertionFailure(
|
|
@@ -141,13 +143,21 @@ export function requestFuzzConfig(): FuzzConfigReply {
|
|
|
141
143
|
if (!body.length) {
|
|
142
144
|
return new FuzzConfigReply();
|
|
143
145
|
}
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
+
const first = body.indexOf("\n");
|
|
147
|
+
if (first < 0) return new FuzzConfigReply();
|
|
146
148
|
const reply = new FuzzConfigReply();
|
|
147
|
-
const
|
|
148
|
-
const
|
|
149
|
+
const second = body.indexOf("\n", first + 1);
|
|
150
|
+
const third = second >= 0 ? body.indexOf("\n", second + 1) : -1;
|
|
151
|
+
const runs = body.slice(0, first);
|
|
152
|
+
const seed =
|
|
153
|
+
second >= 0 ? body.slice(first + 1, second) : body.slice(first + 1);
|
|
154
|
+
const kind =
|
|
155
|
+
second >= 0 && third >= 0 ? body.slice(second + 1, third) : "";
|
|
156
|
+
const value = third >= 0 ? body.slice(third + 1) : "";
|
|
149
157
|
if (runs.length) reply.runs = I32.parseInt(runs);
|
|
150
158
|
if (seed.length) reply.seed = U64.parseInt(seed);
|
|
159
|
+
if (kind.length) reply.runsOverrideKind = I32.parseInt(kind);
|
|
160
|
+
if (value.length) reply.runsOverrideValue = parseFloat(value);
|
|
151
161
|
return reply;
|
|
152
162
|
}
|
|
153
163
|
|
|
@@ -29,12 +29,39 @@ export async function fuzz(configPath = DEFAULT_CONFIG_PATH, selectors = [], mod
|
|
|
29
29
|
return results;
|
|
30
30
|
}
|
|
31
31
|
function resolveFuzzConfig(raw, overrides) {
|
|
32
|
-
const config = Object.assign({}, raw
|
|
32
|
+
const config = Object.assign({}, raw);
|
|
33
|
+
if (typeof overrides.seed == "number") {
|
|
34
|
+
config.seed = overrides.seed;
|
|
35
|
+
}
|
|
36
|
+
if (typeof overrides.runs == "number") {
|
|
37
|
+
config.runs = overrides.runs;
|
|
38
|
+
}
|
|
39
|
+
config.runsOverrideKind = 0;
|
|
40
|
+
config.runsOverrideValue = 0;
|
|
41
|
+
if (overrides.runsOverride) {
|
|
42
|
+
config.runsOverrideKind = encodeRunsOverrideKind(overrides.runsOverride.kind);
|
|
43
|
+
config.runsOverrideValue = overrides.runsOverride.value;
|
|
44
|
+
if (overrides.runsOverride.kind == "set") {
|
|
45
|
+
config.runs = Math.max(1, Math.round(overrides.runsOverride.value));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
33
48
|
if (config.target != "bindings") {
|
|
34
49
|
throw new Error(`fuzz target must be "bindings"; received "${config.target}"`);
|
|
35
50
|
}
|
|
36
51
|
return config;
|
|
37
52
|
}
|
|
53
|
+
function encodeRunsOverrideKind(kind) {
|
|
54
|
+
switch (kind) {
|
|
55
|
+
case "set":
|
|
56
|
+
return 1;
|
|
57
|
+
case "scale":
|
|
58
|
+
return 2;
|
|
59
|
+
case "add":
|
|
60
|
+
return 3;
|
|
61
|
+
case "percent-add":
|
|
62
|
+
return 4;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
38
65
|
async function runFuzzTarget(file, outDir, duplicateBasenames, config, buildStartedAt, buildFinishedAt, buildTime, modeName) {
|
|
39
66
|
const startedAt = Date.now();
|
|
40
67
|
const artifact = resolveArtifactFileName(file, duplicateBasenames, modeName);
|
|
@@ -48,7 +75,8 @@ async function runFuzzTarget(file, outDir, duplicateBasenames, config, buildStar
|
|
|
48
75
|
if (type == 0x02) {
|
|
49
76
|
const event = JSON.parse(payload.toString("utf8"));
|
|
50
77
|
if (String(event.kind ?? "") == "fuzz:config") {
|
|
51
|
-
|
|
78
|
+
const resolved = config;
|
|
79
|
+
respond(`${config.runs}\n${config.seed}\n${resolved.runsOverrideKind ?? 0}\n${resolved.runsOverrideValue ?? 0}`);
|
|
52
80
|
}
|
|
53
81
|
else {
|
|
54
82
|
respond("");
|