as-test 1.1.0 → 1.1.2
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 +17 -3
- package/README.md +14 -7
- package/as-test.config.schema.json +142 -142
- package/assembly/__fuzz__/math.fuzz.ts +22 -0
- package/assembly/__fuzz__/seed-perf.fuzz.ts +4 -2
- package/assembly/__fuzz__/string.fuzz.ts +31 -0
- package/assembly/index.ts +6 -9
- package/assembly/src/expectation.ts +99 -42
- package/assembly/src/fuzz.ts +44 -23
- package/assembly/util/format.ts +113 -0
- package/assembly/util/helpers.ts +7 -13
- package/assembly/util/json.ts +2 -2
- package/assembly/util/wipc.ts +5 -3
- package/bin/build-worker-pool.js +7 -1
- package/bin/commands/build-core.js +6 -1
- package/bin/commands/build.js +1 -1
- package/bin/commands/clean-core.js +61 -16
- package/bin/commands/clean.js +11 -3
- package/bin/commands/fuzz-core.js +2 -2
- package/bin/commands/run-core.js +35 -24
- package/bin/commands/web-runner-source.js +14 -14
- package/bin/commands/web-session.js +6 -1
- package/bin/crash-store.js +3 -1
- package/bin/index.js +303 -124
- package/bin/reporters/default.js +175 -33
- package/bin/util.js +36 -11
- package/bin/wipc.js +7 -2
- package/lib/build/index.js +93 -25
- package/lib/src/index.ts +115 -36
- package/package.json +1 -3
- package/transform/lib/coverage.js +3 -1
|
@@ -62,6 +62,7 @@ export class Expectation<T> extends Tests {
|
|
|
62
62
|
instr: string,
|
|
63
63
|
left: string,
|
|
64
64
|
right: string,
|
|
65
|
+
message: string = "",
|
|
65
66
|
): void {
|
|
66
67
|
if (this._skip) {
|
|
67
68
|
this.verdict = "skip";
|
|
@@ -77,7 +78,8 @@ export class Expectation<T> extends Tests {
|
|
|
77
78
|
this.instr = instr;
|
|
78
79
|
this.left = left;
|
|
79
80
|
this.right = right;
|
|
80
|
-
|
|
81
|
+
const resolvedMessage = message.length ? message : this._message;
|
|
82
|
+
this.message = isFail ? resolvedMessage : "";
|
|
81
83
|
if (isFail) {
|
|
82
84
|
sendAssertionFailure(this._snapshotKey, instr, left, right, this.message);
|
|
83
85
|
// @ts-ignore
|
|
@@ -103,7 +105,7 @@ export class Expectation<T> extends Tests {
|
|
|
103
105
|
/**
|
|
104
106
|
* Tests if a == null
|
|
105
107
|
*/
|
|
106
|
-
toBeNull(): void {
|
|
108
|
+
toBeNull(message: string = ""): void {
|
|
107
109
|
const passed =
|
|
108
110
|
(isNullable<T>() && changetype<usize>(this._left) == 0) ||
|
|
109
111
|
(isInteger<T>() && nameof<T>() == "usize" && this._left == 0);
|
|
@@ -117,13 +119,14 @@ export class Expectation<T> extends Tests {
|
|
|
117
119
|
visualize<T>(
|
|
118
120
|
load<T>(changetype<usize>(this), offsetof<Expectation<T>>("_right")),
|
|
119
121
|
),
|
|
122
|
+
message,
|
|
120
123
|
);
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
/**
|
|
124
127
|
* Tests if a > b
|
|
125
128
|
*/
|
|
126
|
-
toBeGreaterThan(value: T): void {
|
|
129
|
+
toBeGreaterThan(value: T, message: string = ""): void {
|
|
127
130
|
if (!isInteger<T>() && !isFloat<T>())
|
|
128
131
|
ERROR("toBeGreaterThan() can only be used on number types!");
|
|
129
132
|
|
|
@@ -139,13 +142,14 @@ export class Expectation<T> extends Tests {
|
|
|
139
142
|
visualize<T>(
|
|
140
143
|
load<T>(changetype<usize>(this), offsetof<Expectation<T>>("_right")),
|
|
141
144
|
),
|
|
145
|
+
message,
|
|
142
146
|
);
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
/**
|
|
146
150
|
* Tests if a >= b
|
|
147
151
|
*/
|
|
148
|
-
toBeGreaterOrEqualTo(value: T): void {
|
|
152
|
+
toBeGreaterOrEqualTo(value: T, message: string = ""): void {
|
|
149
153
|
if (!isInteger<T>() && !isFloat<T>())
|
|
150
154
|
ERROR("toBeGreaterOrEqualTo() can only be used on number types!");
|
|
151
155
|
|
|
@@ -161,13 +165,14 @@ export class Expectation<T> extends Tests {
|
|
|
161
165
|
visualize<T>(
|
|
162
166
|
load<T>(changetype<usize>(this), offsetof<Expectation<T>>("_right")),
|
|
163
167
|
),
|
|
168
|
+
message,
|
|
164
169
|
);
|
|
165
170
|
}
|
|
166
171
|
|
|
167
172
|
/**
|
|
168
173
|
* Tests if a < b
|
|
169
174
|
*/
|
|
170
|
-
toBeLessThan(value: T): void {
|
|
175
|
+
toBeLessThan(value: T, message: string = ""): void {
|
|
171
176
|
if (!isInteger<T>() && !isFloat<T>())
|
|
172
177
|
ERROR("toBeLessThan() can only be used on number types!");
|
|
173
178
|
|
|
@@ -183,13 +188,14 @@ export class Expectation<T> extends Tests {
|
|
|
183
188
|
visualize<T>(
|
|
184
189
|
load<T>(changetype<usize>(this), offsetof<Expectation<T>>("_right")),
|
|
185
190
|
),
|
|
191
|
+
message,
|
|
186
192
|
);
|
|
187
193
|
}
|
|
188
194
|
|
|
189
195
|
/**
|
|
190
196
|
* Tests if a <= b
|
|
191
197
|
*/
|
|
192
|
-
toBeLessThanOrEqualTo(value: T): void {
|
|
198
|
+
toBeLessThanOrEqualTo(value: T, message: string = ""): void {
|
|
193
199
|
if (!isInteger<T>() && !isFloat<T>())
|
|
194
200
|
ERROR("toBeLessThanOrEqualTo() can only be used on number types!");
|
|
195
201
|
|
|
@@ -205,93 +211,127 @@ export class Expectation<T> extends Tests {
|
|
|
205
211
|
visualize<T>(
|
|
206
212
|
load<T>(changetype<usize>(this), offsetof<Expectation<T>>("_right")),
|
|
207
213
|
),
|
|
214
|
+
message,
|
|
208
215
|
);
|
|
209
216
|
}
|
|
210
217
|
|
|
211
218
|
/**
|
|
212
219
|
* Tests if a is string
|
|
213
220
|
*/
|
|
214
|
-
toBeString(): void {
|
|
215
|
-
this._resolve(
|
|
221
|
+
toBeString(message: string = ""): void {
|
|
222
|
+
this._resolve(
|
|
223
|
+
isString<T>(),
|
|
224
|
+
"toBeString",
|
|
225
|
+
q(nameof<T>()),
|
|
226
|
+
q("string"),
|
|
227
|
+
message,
|
|
228
|
+
);
|
|
216
229
|
}
|
|
217
230
|
|
|
218
231
|
/**
|
|
219
232
|
* Tests if a is boolean
|
|
220
233
|
*/
|
|
221
|
-
toBeBoolean(): void {
|
|
222
|
-
this._resolve(
|
|
234
|
+
toBeBoolean(message: string = ""): void {
|
|
235
|
+
this._resolve(
|
|
236
|
+
isBoolean<T>(),
|
|
237
|
+
"toBeBoolean",
|
|
238
|
+
q(nameof<T>()),
|
|
239
|
+
q("boolean"),
|
|
240
|
+
message,
|
|
241
|
+
);
|
|
223
242
|
}
|
|
224
243
|
|
|
225
244
|
/**
|
|
226
245
|
* Tests if a is array
|
|
227
246
|
*/
|
|
228
|
-
toBeArray(): void {
|
|
229
|
-
this._resolve(
|
|
247
|
+
toBeArray(message: string = ""): void {
|
|
248
|
+
this._resolve(
|
|
249
|
+
isArray<T>(),
|
|
250
|
+
"toBeArray",
|
|
251
|
+
q(nameof<T>()),
|
|
252
|
+
q("Array<any>"),
|
|
253
|
+
message,
|
|
254
|
+
);
|
|
230
255
|
}
|
|
231
256
|
|
|
232
257
|
/**
|
|
233
258
|
* Tests if a is number
|
|
234
259
|
*/
|
|
235
|
-
toBeNumber(): void {
|
|
260
|
+
toBeNumber(message: string = ""): void {
|
|
236
261
|
this._resolve(
|
|
237
262
|
isFloat<T>() || isInteger<T>(),
|
|
238
263
|
"toBeNumber",
|
|
239
264
|
q(nameof<T>()),
|
|
240
265
|
q("number"),
|
|
266
|
+
message,
|
|
241
267
|
);
|
|
242
268
|
}
|
|
243
269
|
|
|
244
270
|
/**
|
|
245
271
|
* Tests if a is integer
|
|
246
272
|
*/
|
|
247
|
-
toBeInteger(): void {
|
|
248
|
-
this._resolve(
|
|
273
|
+
toBeInteger(message: string = ""): void {
|
|
274
|
+
this._resolve(
|
|
275
|
+
isInteger<T>(),
|
|
276
|
+
"toBeInteger",
|
|
277
|
+
q(nameof<T>()),
|
|
278
|
+
q("integer"),
|
|
279
|
+
message,
|
|
280
|
+
);
|
|
249
281
|
}
|
|
250
282
|
|
|
251
283
|
/**
|
|
252
284
|
* Tests if a is float
|
|
253
285
|
*/
|
|
254
|
-
toBeFloat(): void {
|
|
255
|
-
this._resolve(
|
|
286
|
+
toBeFloat(message: string = ""): void {
|
|
287
|
+
this._resolve(
|
|
288
|
+
isFloat<T>(),
|
|
289
|
+
"toBeFloat",
|
|
290
|
+
q(nameof<T>()),
|
|
291
|
+
q("float"),
|
|
292
|
+
message,
|
|
293
|
+
);
|
|
256
294
|
}
|
|
257
295
|
|
|
258
296
|
/**
|
|
259
297
|
* Tests if a is finite
|
|
260
298
|
*/
|
|
261
|
-
toBeFinite(): void {
|
|
299
|
+
toBeFinite(message: string = ""): void {
|
|
262
300
|
// @ts-ignore
|
|
263
301
|
const passed = (isFloat<T>() || isInteger<T>()) && isFinite(this._left);
|
|
264
|
-
this._resolve(passed, "toBeFinite", q("Infinity"), q("Finite"));
|
|
302
|
+
this._resolve(passed, "toBeFinite", q("Infinity"), q("Finite"), message);
|
|
265
303
|
}
|
|
266
304
|
|
|
267
305
|
/**
|
|
268
306
|
* Tests if a value is truthy
|
|
269
307
|
*/
|
|
270
|
-
toBeTruthy(): void {
|
|
308
|
+
toBeTruthy(message: string = ""): void {
|
|
271
309
|
this._resolve(
|
|
272
310
|
isTruthy<T>(this._left),
|
|
273
311
|
"toBeTruthy",
|
|
274
312
|
q("falsy"),
|
|
275
313
|
q("truthy"),
|
|
314
|
+
message,
|
|
276
315
|
);
|
|
277
316
|
}
|
|
278
317
|
|
|
279
318
|
/**
|
|
280
319
|
* Tests if a value is falsy
|
|
281
320
|
*/
|
|
282
|
-
toBeFalsy(): void {
|
|
321
|
+
toBeFalsy(message: string = ""): void {
|
|
283
322
|
this._resolve(
|
|
284
323
|
!isTruthy<T>(this._left),
|
|
285
324
|
"toBeFalsy",
|
|
286
325
|
q("truthy"),
|
|
287
326
|
q("falsy"),
|
|
327
|
+
message,
|
|
288
328
|
);
|
|
289
329
|
}
|
|
290
330
|
|
|
291
331
|
/**
|
|
292
332
|
* Tests if a floating-point number is close to expected
|
|
293
333
|
*/
|
|
294
|
-
toBeCloseTo(expected: T, precision: i32 = 2): void {
|
|
334
|
+
toBeCloseTo(expected: T, precision: i32 = 2, message: string = ""): void {
|
|
295
335
|
if (!isFloat<T>() && !isInteger<T>())
|
|
296
336
|
ERROR("toBeCloseTo() can only be used on number types!");
|
|
297
337
|
const factor = Math.pow(10, precision as f64);
|
|
@@ -302,67 +342,80 @@ export class Expectation<T> extends Tests {
|
|
|
302
342
|
"toBeCloseTo",
|
|
303
343
|
visualize<T>(this._left),
|
|
304
344
|
visualize<T>(expected),
|
|
345
|
+
message,
|
|
305
346
|
);
|
|
306
347
|
}
|
|
307
348
|
|
|
308
349
|
/**
|
|
309
350
|
* Tests if a string contains substring
|
|
310
351
|
*/
|
|
311
|
-
toMatch(value: string): void {
|
|
352
|
+
toMatch(value: string, message: string = ""): void {
|
|
312
353
|
if (!isString<T>()) ERROR("toMatch() can only be used on string types!");
|
|
313
354
|
// @ts-ignore
|
|
314
355
|
const passed = this._left.indexOf(value) >= 0;
|
|
315
356
|
// @ts-ignore
|
|
316
|
-
this._resolve(
|
|
357
|
+
this._resolve(
|
|
358
|
+
passed,
|
|
359
|
+
"toMatch",
|
|
360
|
+
q(this._left as string),
|
|
361
|
+
q(value),
|
|
362
|
+
message,
|
|
363
|
+
);
|
|
317
364
|
}
|
|
318
365
|
|
|
319
366
|
/**
|
|
320
367
|
* Tests if a string starts with the provided prefix.
|
|
321
368
|
*/
|
|
322
|
-
toStartWith(value: string): void {
|
|
369
|
+
toStartWith(value: string, message: string = ""): void {
|
|
323
370
|
if (!isString<T>())
|
|
324
371
|
ERROR("toStartWith() can only be used on string types!");
|
|
325
372
|
// @ts-ignore
|
|
326
373
|
const left = this._left as string;
|
|
327
374
|
const passed = left.indexOf(value) == 0;
|
|
328
|
-
this._resolve(passed, "toStartWith", q(left), q(value));
|
|
375
|
+
this._resolve(passed, "toStartWith", q(left), q(value), message);
|
|
329
376
|
}
|
|
330
377
|
|
|
331
378
|
/**
|
|
332
379
|
* Tests if a string ends with the provided suffix.
|
|
333
380
|
*/
|
|
334
|
-
toEndWith(value: string): void {
|
|
381
|
+
toEndWith(value: string, message: string = ""): void {
|
|
335
382
|
if (!isString<T>()) ERROR("toEndWith() can only be used on string types!");
|
|
336
383
|
// @ts-ignore
|
|
337
384
|
const left = this._left as string;
|
|
338
385
|
const idx = left.lastIndexOf(value);
|
|
339
386
|
const passed = idx >= 0 && idx + value.length == left.length;
|
|
340
|
-
this._resolve(passed, "toEndWith", q(left), q(value));
|
|
387
|
+
this._resolve(passed, "toEndWith", q(left), q(value), message);
|
|
341
388
|
}
|
|
342
389
|
|
|
343
390
|
/**
|
|
344
391
|
* Tests if an array has length x
|
|
345
392
|
*/
|
|
346
|
-
toHaveLength(value: i32): void {
|
|
393
|
+
toHaveLength(value: i32, message: string = ""): void {
|
|
347
394
|
// @ts-ignore
|
|
348
395
|
const leftLen = this._left.length as i32;
|
|
349
396
|
// @ts-ignore
|
|
350
397
|
const passed = isArray<T>() && leftLen == value;
|
|
351
|
-
this._resolve(
|
|
398
|
+
this._resolve(
|
|
399
|
+
passed,
|
|
400
|
+
"toHaveLength",
|
|
401
|
+
leftLen.toString(),
|
|
402
|
+
value.toString(),
|
|
403
|
+
message,
|
|
404
|
+
);
|
|
352
405
|
}
|
|
353
406
|
|
|
354
407
|
/**
|
|
355
408
|
* Tests if an array or string contains a value
|
|
356
409
|
*/
|
|
357
410
|
// @ts-ignore
|
|
358
|
-
toContain(value: valueof<T
|
|
411
|
+
toContain(value: valueof<T>, message: string = ""): void {
|
|
359
412
|
if (isString<T>()) {
|
|
360
413
|
// @ts-ignore
|
|
361
414
|
const left = this._left as string;
|
|
362
415
|
// @ts-ignore
|
|
363
416
|
const needle = value as string;
|
|
364
417
|
const passed = left.indexOf(needle) >= 0;
|
|
365
|
-
this._resolve(passed, "toContain", q(left), q(needle));
|
|
418
|
+
this._resolve(passed, "toContain", q(left), q(needle), message);
|
|
366
419
|
return;
|
|
367
420
|
}
|
|
368
421
|
|
|
@@ -374,6 +427,7 @@ export class Expectation<T> extends Tests {
|
|
|
374
427
|
"toContain",
|
|
375
428
|
stringifyValue<T>(this._left),
|
|
376
429
|
stringifyValue<valueof<T>>(value),
|
|
430
|
+
message,
|
|
377
431
|
);
|
|
378
432
|
return;
|
|
379
433
|
}
|
|
@@ -385,28 +439,28 @@ export class Expectation<T> extends Tests {
|
|
|
385
439
|
* Alias for toContain().
|
|
386
440
|
*/
|
|
387
441
|
// @ts-ignore
|
|
388
|
-
toContains(value: valueof<T
|
|
389
|
-
this.toContain(value);
|
|
442
|
+
toContains(value: valueof<T>, message: string = ""): void {
|
|
443
|
+
this.toContain(value, message);
|
|
390
444
|
}
|
|
391
445
|
|
|
392
446
|
/**
|
|
393
447
|
* Tests if serialized value matches stored snapshot.
|
|
394
448
|
*/
|
|
395
|
-
toMatchSnapshot(name: string = ""): void {
|
|
449
|
+
toMatchSnapshot(name: string = "", message: string = ""): void {
|
|
396
450
|
let key = name.length
|
|
397
451
|
? namedSnapshotKey(this._snapshotKey, name)
|
|
398
452
|
: nextUnnamedSnapshotKey(this._snapshotKey);
|
|
399
453
|
|
|
400
454
|
const actual = stringifyValue<T>(this._left);
|
|
401
455
|
const res = snapshotAssert(key, actual);
|
|
402
|
-
this._resolve(res.ok, "toMatchSnapshot", actual, res.expected);
|
|
456
|
+
this._resolve(res.ok, "toMatchSnapshot", actual, res.expected, message);
|
|
403
457
|
}
|
|
404
458
|
|
|
405
459
|
/**
|
|
406
460
|
* Delegates throw assertions to try-as when available.
|
|
407
461
|
* If try-as is unavailable, this matcher is disabled and warns once.
|
|
408
462
|
*/
|
|
409
|
-
toThrow(): void {
|
|
463
|
+
toThrow(message: string = ""): void {
|
|
410
464
|
// @ts-ignore
|
|
411
465
|
if (!isDefined(AS_TEST_TRY_AS)) {
|
|
412
466
|
if (!warnedToThrowDisabled) {
|
|
@@ -415,7 +469,7 @@ export class Expectation<T> extends Tests {
|
|
|
415
469
|
);
|
|
416
470
|
warnedToThrowDisabled = true;
|
|
417
471
|
}
|
|
418
|
-
this._resolve(true, "toThrow", q("disabled"), q("disabled"));
|
|
472
|
+
this._resolve(true, "toThrow", q("disabled"), q("disabled"), message);
|
|
419
473
|
return;
|
|
420
474
|
}
|
|
421
475
|
|
|
@@ -425,13 +479,13 @@ export class Expectation<T> extends Tests {
|
|
|
425
479
|
// @ts-ignore
|
|
426
480
|
__ExceptionState.Failures--;
|
|
427
481
|
}
|
|
428
|
-
this._resolve(passed, "toThrow", q("throws"), q("throws"));
|
|
482
|
+
this._resolve(passed, "toThrow", q("throws"), q("throws"), message);
|
|
429
483
|
}
|
|
430
484
|
|
|
431
485
|
/**
|
|
432
486
|
* Tests for equality
|
|
433
487
|
*/
|
|
434
|
-
toBe(equals: T): void {
|
|
488
|
+
toBe(equals: T, message: string = ""): void {
|
|
435
489
|
const passed = this._left === equals;
|
|
436
490
|
|
|
437
491
|
this._resolve(
|
|
@@ -439,32 +493,35 @@ export class Expectation<T> extends Tests {
|
|
|
439
493
|
"toBe",
|
|
440
494
|
stringifyValue<T>(this._left),
|
|
441
495
|
stringifyValue<T>(equals),
|
|
496
|
+
message,
|
|
442
497
|
);
|
|
443
498
|
}
|
|
444
499
|
|
|
445
500
|
/**
|
|
446
501
|
* Tests for deep equality
|
|
447
502
|
*/
|
|
448
|
-
toEqual(equals: T): void {
|
|
503
|
+
toEqual(equals: T, message: string = ""): void {
|
|
449
504
|
const passed = valueEquals<T>(this._left, equals, false);
|
|
450
505
|
this._resolve(
|
|
451
506
|
passed,
|
|
452
507
|
"toEqual",
|
|
453
508
|
stringifyValue<T>(this._left),
|
|
454
509
|
stringifyValue<T>(equals),
|
|
510
|
+
message,
|
|
455
511
|
);
|
|
456
512
|
}
|
|
457
513
|
|
|
458
514
|
/**
|
|
459
515
|
* Tests for strict deep equality
|
|
460
516
|
*/
|
|
461
|
-
toStrictEqual(equals: T): void {
|
|
517
|
+
toStrictEqual(equals: T, message: string = ""): void {
|
|
462
518
|
const passed = valueEquals<T>(this._left, equals, true);
|
|
463
519
|
this._resolve(
|
|
464
520
|
passed,
|
|
465
521
|
"toStrictEqual",
|
|
466
522
|
stringifyValue<T>(this._left),
|
|
467
523
|
stringifyValue<T>(equals),
|
|
524
|
+
message,
|
|
468
525
|
);
|
|
469
526
|
}
|
|
470
527
|
}
|
package/assembly/src/fuzz.ts
CHANGED
|
@@ -79,14 +79,24 @@ export class FuzzSeed {
|
|
|
79
79
|
|
|
80
80
|
i8(options: IntegerOptions<i8> | null = null): i8 {
|
|
81
81
|
if (options == null) {
|
|
82
|
-
return this.nextI8InRange(
|
|
82
|
+
return this.nextI8InRange(
|
|
83
|
+
i8.MIN_VALUE,
|
|
84
|
+
i8.MAX_VALUE,
|
|
85
|
+
EMPTY_I8_EXCLUDE,
|
|
86
|
+
false,
|
|
87
|
+
);
|
|
83
88
|
}
|
|
84
89
|
return this.nextI8InRange(options.min, options.max, options.exclude, true);
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
u8(options: IntegerOptions<u8> | null = null): u8 {
|
|
88
93
|
if (options == null) {
|
|
89
|
-
return this.nextU8InRange(
|
|
94
|
+
return this.nextU8InRange(
|
|
95
|
+
u8.MIN_VALUE,
|
|
96
|
+
u8.MAX_VALUE,
|
|
97
|
+
EMPTY_U8_EXCLUDE,
|
|
98
|
+
false,
|
|
99
|
+
);
|
|
90
100
|
}
|
|
91
101
|
return this.nextU8InRange(options.min, options.max, options.exclude, true);
|
|
92
102
|
}
|
|
@@ -186,7 +196,9 @@ export class FuzzSeed {
|
|
|
186
196
|
if (!exclude.length) {
|
|
187
197
|
for (let i = 0; i < length; i++) {
|
|
188
198
|
unchecked(
|
|
189
|
-
(out[i] = <u8>
|
|
199
|
+
(out[i] = <u8>(
|
|
200
|
+
unchecked(include[this.nextRange(0, include.length - 1)])
|
|
201
|
+
)),
|
|
190
202
|
);
|
|
191
203
|
}
|
|
192
204
|
return out;
|
|
@@ -299,7 +311,9 @@ export class FuzzSeed {
|
|
|
299
311
|
return <i32>this.nextU32();
|
|
300
312
|
}
|
|
301
313
|
if (!exclude.length) {
|
|
302
|
-
return max <= min
|
|
314
|
+
return max <= min
|
|
315
|
+
? min
|
|
316
|
+
: min + <i32>(this.nextU32() % <u32>(max - min + 1));
|
|
303
317
|
}
|
|
304
318
|
for (let attempts = 0; attempts < 1024; attempts++) {
|
|
305
319
|
const value =
|
|
@@ -324,12 +338,16 @@ export class FuzzSeed {
|
|
|
324
338
|
const right = <i32>max;
|
|
325
339
|
if (!exclude.length) {
|
|
326
340
|
return <i8>(
|
|
327
|
-
right <= left
|
|
341
|
+
(right <= left
|
|
342
|
+
? left
|
|
343
|
+
: left + <i32>(this.nextU32() % <u32>(right - left + 1)))
|
|
328
344
|
);
|
|
329
345
|
}
|
|
330
346
|
for (let attempts = 0; attempts < 1024; attempts++) {
|
|
331
347
|
const value = <i8>(
|
|
332
|
-
right <= left
|
|
348
|
+
(right <= left
|
|
349
|
+
? left
|
|
350
|
+
: left + <i32>(this.nextU32() % <u32>(right - left + 1)))
|
|
333
351
|
);
|
|
334
352
|
if (!containsValue<i8>(exclude, value)) return value;
|
|
335
353
|
}
|
|
@@ -350,11 +368,13 @@ export class FuzzSeed {
|
|
|
350
368
|
const left = <u32>min;
|
|
351
369
|
const right = <u32>max;
|
|
352
370
|
if (!exclude.length) {
|
|
353
|
-
return <u8>(
|
|
371
|
+
return <u8>(
|
|
372
|
+
(right <= left ? left : left + (this.nextU32() % (right - left + 1)))
|
|
373
|
+
);
|
|
354
374
|
}
|
|
355
375
|
for (let attempts = 0; attempts < 1024; attempts++) {
|
|
356
376
|
const value = <u8>(
|
|
357
|
-
right <= left ? left : left + (this.nextU32() % (right - left + 1))
|
|
377
|
+
(right <= left ? left : left + (this.nextU32() % (right - left + 1)))
|
|
358
378
|
);
|
|
359
379
|
if (!containsValue<u8>(exclude, value)) return value;
|
|
360
380
|
}
|
|
@@ -376,12 +396,16 @@ export class FuzzSeed {
|
|
|
376
396
|
const right = <i32>max;
|
|
377
397
|
if (!exclude.length) {
|
|
378
398
|
return <i16>(
|
|
379
|
-
right <= left
|
|
399
|
+
(right <= left
|
|
400
|
+
? left
|
|
401
|
+
: left + <i32>(this.nextU32() % <u32>(right - left + 1)))
|
|
380
402
|
);
|
|
381
403
|
}
|
|
382
404
|
for (let attempts = 0; attempts < 1024; attempts++) {
|
|
383
405
|
const value = <i16>(
|
|
384
|
-
right <= left
|
|
406
|
+
(right <= left
|
|
407
|
+
? left
|
|
408
|
+
: left + <i32>(this.nextU32() % <u32>(right - left + 1)))
|
|
385
409
|
);
|
|
386
410
|
if (!containsValue<i16>(exclude, value)) return value;
|
|
387
411
|
}
|
|
@@ -402,11 +426,13 @@ export class FuzzSeed {
|
|
|
402
426
|
const left = <u32>min;
|
|
403
427
|
const right = <u32>max;
|
|
404
428
|
if (!exclude.length) {
|
|
405
|
-
return <u16>(
|
|
429
|
+
return <u16>(
|
|
430
|
+
(right <= left ? left : left + (this.nextU32() % (right - left + 1)))
|
|
431
|
+
);
|
|
406
432
|
}
|
|
407
433
|
for (let attempts = 0; attempts < 1024; attempts++) {
|
|
408
434
|
const value = <u16>(
|
|
409
|
-
right <= left ? left : left + (this.nextU32() % (right - left + 1))
|
|
435
|
+
(right <= left ? left : left + (this.nextU32() % (right - left + 1)))
|
|
410
436
|
);
|
|
411
437
|
if (!containsValue<u16>(exclude, value)) return value;
|
|
412
438
|
}
|
|
@@ -448,9 +474,7 @@ export class FuzzSeed {
|
|
|
448
474
|
const left = this.toOrderedU64(min);
|
|
449
475
|
const right = this.toOrderedU64(max);
|
|
450
476
|
if (!exclude.length) {
|
|
451
|
-
return this.fromOrderedU64(
|
|
452
|
-
left + this.nextU64Offset(left, right),
|
|
453
|
-
);
|
|
477
|
+
return this.fromOrderedU64(left + this.nextU64Offset(left, right));
|
|
454
478
|
}
|
|
455
479
|
for (let attempts = 0; attempts < 1024; attempts++) {
|
|
456
480
|
const value = this.fromOrderedU64(left + this.nextU64Offset(left, right));
|
|
@@ -529,7 +553,7 @@ export class FuzzSeed {
|
|
|
529
553
|
}
|
|
530
554
|
|
|
531
555
|
private toOrderedU64(value: i64): u64 {
|
|
532
|
-
return <u64>value ^ I64_SIGN_MASK;
|
|
556
|
+
return (<u64>value) ^ I64_SIGN_MASK;
|
|
533
557
|
}
|
|
534
558
|
|
|
535
559
|
private fromOrderedU64(value: u64): i64 {
|
|
@@ -543,13 +567,11 @@ const DIGIT_ALPHABET: i32[] = rangeChars(48, 57);
|
|
|
543
567
|
const HEX_ALPHABET: i32[] = DIGIT_ALPHABET.concat(rangeChars(97, 102));
|
|
544
568
|
const ALNUM_ALPHABET: i32[] = ALPHA_ALPHABET.concat(DIGIT_ALPHABET);
|
|
545
569
|
const BASE64_ALPHABET: i32[] = ALPHA_ALPHABET.concat(DIGIT_ALPHABET).concat([
|
|
546
|
-
43,
|
|
547
|
-
47,
|
|
548
|
-
61,
|
|
570
|
+
43, 47, 61,
|
|
549
571
|
]);
|
|
550
|
-
const IDENTIFIER_ALPHABET: i32[] = [95]
|
|
551
|
-
|
|
552
|
-
);
|
|
572
|
+
const IDENTIFIER_ALPHABET: i32[] = [95]
|
|
573
|
+
.concat(ALPHA_ALPHABET)
|
|
574
|
+
.concat(DIGIT_ALPHABET);
|
|
553
575
|
const WHITESPACE_ALPHABET: i32[] = [9, 10, 13, 32];
|
|
554
576
|
|
|
555
577
|
export abstract class FuzzerBase {
|
|
@@ -1113,7 +1135,6 @@ function removeFirst(values: i32[], needle: i32): void {
|
|
|
1113
1135
|
if (index >= 0) values.splice(index, 1);
|
|
1114
1136
|
}
|
|
1115
1137
|
|
|
1116
|
-
|
|
1117
1138
|
function validateLengthRange(label: string, min: i32, max: i32): void {
|
|
1118
1139
|
if (min < 0 || max < 0) panic();
|
|
1119
1140
|
if (max < min) panic();
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export function formatValue<T>(value: T, deep: boolean = false): string {
|
|
2
|
+
if (isNullable<T>() && changetype<usize>(value) == <usize>0) {
|
|
3
|
+
return "null";
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
if (isString<T>()) {
|
|
7
|
+
const text = value as string;
|
|
8
|
+
return deep ? "'" + text + "'" : text;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (isBoolean<T>() || isInteger<T>() || isFloat<T>()) {
|
|
12
|
+
// @ts-expect-error: primitive formatting
|
|
13
|
+
return value.toString();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (isArray<T>()) {
|
|
17
|
+
// @ts-expect-error: array-like handling
|
|
18
|
+
const values = value as valueof<T>[];
|
|
19
|
+
if (!values.length) return "[]";
|
|
20
|
+
let out = "[";
|
|
21
|
+
for (let i = 0; i < values.length; i++) {
|
|
22
|
+
if (i) out += ", ";
|
|
23
|
+
out += formatValue<valueof<T>>(unchecked(values[i]), true);
|
|
24
|
+
}
|
|
25
|
+
out += "]";
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (value instanceof Map) {
|
|
30
|
+
// @ts-expect-error: generic runtime access
|
|
31
|
+
const keys = value.keys();
|
|
32
|
+
if (!keys.length) return "Map(0) {}";
|
|
33
|
+
// @ts-expect-error: generic runtime access
|
|
34
|
+
const values = value.values();
|
|
35
|
+
let out = "Map(" + keys.length.toString() + ") { ";
|
|
36
|
+
for (let i = 0; i < keys.length; i++) {
|
|
37
|
+
if (i) out += ", ";
|
|
38
|
+
out += formatValue(
|
|
39
|
+
changetype<valueof<typeof keys>>(unchecked(keys[i])),
|
|
40
|
+
true,
|
|
41
|
+
);
|
|
42
|
+
out += " => ";
|
|
43
|
+
out += formatValue(
|
|
44
|
+
changetype<valueof<typeof values>>(unchecked(values[i])),
|
|
45
|
+
true,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
out += " }";
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (value instanceof Set) {
|
|
53
|
+
// @ts-expect-error: generic runtime access
|
|
54
|
+
const values = value.values();
|
|
55
|
+
if (!values.length) return "Set(0) {}";
|
|
56
|
+
let out = "Set(" + values.length.toString() + ") { ";
|
|
57
|
+
for (let i = 0; i < values.length; i++) {
|
|
58
|
+
if (i) out += ", ";
|
|
59
|
+
out += formatValue(
|
|
60
|
+
changetype<valueof<typeof values>>(unchecked(values[i])),
|
|
61
|
+
true,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
out += " }";
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (isManaged<T>()) {
|
|
69
|
+
// @ts-expect-error: custom serializer when provided
|
|
70
|
+
if (isDefined(value.__as_test_json)) {
|
|
71
|
+
// @ts-expect-error: dynamic method dispatch
|
|
72
|
+
return value.__as_test_json();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return nameof<T>();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@inline
|
|
81
|
+
export function colorText(format: i32[], text: string): string {
|
|
82
|
+
return `\u001b[${format[0].toString()}m${text}\u001b[${format[1].toString()}m`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@inline
|
|
87
|
+
export function red(text: string): string {
|
|
88
|
+
return colorText([31, 39], text);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@inline
|
|
93
|
+
export function green(text: string): string {
|
|
94
|
+
return colorText([32, 39], text);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@inline
|
|
99
|
+
export function bgRed(text: string): string {
|
|
100
|
+
return colorText([41, 49], text);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@inline
|
|
105
|
+
export function bgGreen(text: string): string {
|
|
106
|
+
return colorText([42, 49], text);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@inline
|
|
111
|
+
export function bold(text: string): string {
|
|
112
|
+
return colorText([1, 22], text);
|
|
113
|
+
}
|