as-test 0.2.0 → 0.3.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/.github/workflows/as-test.yml +3 -0
- package/CHANGELOG.md +4 -1
- package/README.md +73 -67
- package/as-test.config.json +7 -10
- package/assembly/__tests__/array.spec.ts +19 -0
- package/assembly/__tests__/math.spec.ts +16 -0
- package/assembly/__tests__/sleep.spec.ts +28 -0
- package/assembly/index.ts +181 -165
- package/assembly/src/expectation.ts +119 -112
- package/assembly/src/log.ts +19 -0
- package/assembly/src/suite.ts +99 -0
- package/assembly/src/tests.ts +10 -0
- package/assembly/tsconfig.json +1 -1
- package/assembly/util/helpers.ts +0 -33
- package/assembly/util/term.ts +55 -0
- package/assets/img/download.png +0 -0
- package/bin/about.js +135 -0
- package/bin/build.js +72 -131
- package/bin/index.js +70 -112
- package/bin/init.js +211 -39
- package/bin/reporter.js +1 -0
- package/bin/run.js +226 -68
- package/bin/types.js +25 -31
- package/bin/util.js +44 -20
- package/cli/build.ts +70 -109
- package/cli/index.ts +148 -159
- package/cli/init.ts +235 -34
- package/cli/reporter.ts +1 -0
- package/cli/run.ts +266 -57
- package/cli/types.ts +6 -11
- package/cli/util.ts +35 -0
- package/package.json +6 -2
- package/run/package.json +27 -0
- package/tests/array.run.js +7 -0
- package/tests/math.run.js +7 -0
- package/tests/sleep.run.js +7 -0
- package/transform/lib/coverage.js +325 -319
- package/transform/lib/index.js +51 -31
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/mock.js +61 -55
- package/transform/lib/mock.js.map +1 -1
- package/transform/package.json +1 -1
- package/transform/src/index.ts +22 -3
- package/transform/src/mock.ts +1 -1
- package/asconfig.json +0 -31
- package/assembly/__tests__/example.spec.ts +0 -79
- package/assembly/reporters/tap.ts +0 -30
- package/assembly/src/group.ts +0 -44
- package/assembly/src/node.ts +0 -13
- package/test.config.json +0 -0
- package/tests/test.tap +0 -14
- package/unision +0 -38
- package/unision.pub +0 -1
- package/utils.ts +0 -1
package/assembly/index.ts
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import { rainbow } from "as-rainbow";
|
|
2
|
-
import {
|
|
2
|
+
import { Suite } from "./src/suite";
|
|
3
3
|
import { Expectation } from "./src/expectation";
|
|
4
|
-
import { formatTime } from "./util/helpers";
|
|
5
4
|
import { stringify } from "as-console/stringify";
|
|
6
5
|
import { __COVER, __HASHES, __POINTS } from "as-test/assembly/coverage";
|
|
7
|
-
import {
|
|
6
|
+
import { JSON } from "json-as";
|
|
7
|
+
import { term, TermLine } from "./util/term";
|
|
8
|
+
import { Log } from "./src/log";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
* Enumeration representing the verdict of a test case.
|
|
11
|
-
*/
|
|
12
|
-
export enum Verdict {
|
|
13
|
-
Unreachable,
|
|
14
|
-
Ok,
|
|
15
|
-
Fail,
|
|
16
|
-
}
|
|
10
|
+
let entrySuites: Suite[] = [];
|
|
17
11
|
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
const FILE = isDefined(ENTRY_FILE) ? ENTRY_FILE : "unknown";
|
|
18
14
|
// Globals
|
|
19
|
-
|
|
20
|
-
let
|
|
21
|
-
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
@global let suites: Suite[] = [];
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
@global let depth: i32 = -1;
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
@global let current_suite: Suite | null = null;
|
|
21
|
+
// @ts-ignore
|
|
22
22
|
let before_all_callback: (() => void) | null = null;
|
|
23
|
+
// @ts-ignore
|
|
23
24
|
let after_all_callback: (() => void) | null = null;
|
|
24
25
|
|
|
25
26
|
export let before_each_callback: (() => void) | null = null;
|
|
@@ -41,10 +42,21 @@ let __test_options!: RunOptions;
|
|
|
41
42
|
* ```
|
|
42
43
|
*/
|
|
43
44
|
export function describe(description: string, callback: () => void): void {
|
|
44
|
-
const
|
|
45
|
+
const suite = new Suite(description, callback, "describe");
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
if (depth >= 0) {
|
|
48
|
+
const _suite = suites[depth];
|
|
49
|
+
if (_suite.depth == depth) {
|
|
50
|
+
_suite.addSuite(suite);
|
|
51
|
+
} else {
|
|
52
|
+
suite.depth = ++depth;
|
|
53
|
+
suites.push(suite);
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
suite.file = FILE;
|
|
57
|
+
entrySuites.push(suite);
|
|
58
|
+
suites.push(suite);
|
|
59
|
+
}
|
|
48
60
|
}
|
|
49
61
|
|
|
50
62
|
/**
|
|
@@ -62,10 +74,21 @@ export function describe(description: string, callback: () => void): void {
|
|
|
62
74
|
* ```
|
|
63
75
|
*/
|
|
64
76
|
export function test(description: string, callback: () => void): void {
|
|
65
|
-
const
|
|
77
|
+
const suite = new Suite(description, callback, "test");
|
|
66
78
|
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
if (depth >= 0) {
|
|
80
|
+
const _suite = suites[depth];
|
|
81
|
+
if (_suite.depth == depth) {
|
|
82
|
+
_suite.addSuite(suite);
|
|
83
|
+
} else {
|
|
84
|
+
suite.depth = ++depth;
|
|
85
|
+
suites.push(suite);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
suite.file = FILE;
|
|
89
|
+
entrySuites.push(suite);
|
|
90
|
+
suites.push(suite);
|
|
91
|
+
}
|
|
69
92
|
}
|
|
70
93
|
|
|
71
94
|
/**
|
|
@@ -83,10 +106,21 @@ export function test(description: string, callback: () => void): void {
|
|
|
83
106
|
* ```
|
|
84
107
|
*/
|
|
85
108
|
export function it(description: string, callback: () => void): void {
|
|
86
|
-
const
|
|
109
|
+
const suite = new Suite(description, callback, "it");
|
|
87
110
|
|
|
88
|
-
|
|
89
|
-
|
|
111
|
+
if (depth >= 0) {
|
|
112
|
+
const _suite = suites[depth];
|
|
113
|
+
if (_suite.depth == depth) {
|
|
114
|
+
_suite.addSuite(suite);
|
|
115
|
+
} else {
|
|
116
|
+
suite.depth = ++depth;
|
|
117
|
+
suites.push(suite);
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
suite.file = FILE;
|
|
121
|
+
entrySuites.push(suite);
|
|
122
|
+
suites.push(suite);
|
|
123
|
+
}
|
|
90
124
|
}
|
|
91
125
|
|
|
92
126
|
/**
|
|
@@ -108,10 +142,13 @@ export function it(description: string, callback: () => void): void {
|
|
|
108
142
|
* ```
|
|
109
143
|
*/
|
|
110
144
|
export function expect<T>(value: T): Expectation<T> {
|
|
111
|
-
const
|
|
112
|
-
|
|
145
|
+
const test = new Expectation<T>(value);
|
|
146
|
+
|
|
147
|
+
if (current_suite) {
|
|
148
|
+
current_suite!.addExpectation(test);
|
|
149
|
+
}
|
|
113
150
|
|
|
114
|
-
return
|
|
151
|
+
return test;
|
|
115
152
|
}
|
|
116
153
|
|
|
117
154
|
/**
|
|
@@ -133,9 +170,11 @@ export function log<T>(data: T): void {
|
|
|
133
170
|
const lines = formatted.split("\n");
|
|
134
171
|
for (let i = 0; i < lines.length; i++) {
|
|
135
172
|
const line = unchecked(lines[i]);
|
|
136
|
-
|
|
173
|
+
if (current_suite) {
|
|
174
|
+
current_suite!.addLog(new Log(line));
|
|
175
|
+
}
|
|
137
176
|
}
|
|
138
|
-
|
|
177
|
+
term.write("\n");
|
|
139
178
|
}
|
|
140
179
|
}
|
|
141
180
|
|
|
@@ -176,7 +215,7 @@ export function afterEach(callback: () => void): void {
|
|
|
176
215
|
}
|
|
177
216
|
|
|
178
217
|
/**
|
|
179
|
-
* Overrides all references to an existing function to instead point to
|
|
218
|
+
* Overrides all references to an existing function in local scope to instead point to new function
|
|
180
219
|
* @param {string} fn - name of function to override
|
|
181
220
|
* @param {() => returnType} callback - the function to substitute it with
|
|
182
221
|
*/
|
|
@@ -185,6 +224,18 @@ export function mockFn<returnType>(
|
|
|
185
224
|
callback: (...args: any[]) => returnType,
|
|
186
225
|
): void {}
|
|
187
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Unmock all references to an existing function to instead point to the original function
|
|
229
|
+
* @param {string} fn - name of function to override
|
|
230
|
+
*/
|
|
231
|
+
export function unmockFn(fn: string): void {}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Re-mock all references to an existing function to instead point to the declared function
|
|
235
|
+
* @param {string} fn - name of function to override
|
|
236
|
+
*/
|
|
237
|
+
export function remockFn(fn: string): void {}
|
|
238
|
+
|
|
188
239
|
/**
|
|
189
240
|
* Class defining options that can be passed to the `run` function.
|
|
190
241
|
*
|
|
@@ -218,153 +269,118 @@ class RunOptions {
|
|
|
218
269
|
* ```
|
|
219
270
|
*/
|
|
220
271
|
export function run(options: RunOptions = new RunOptions()): void {
|
|
272
|
+
// const buf = new ArrayBuffer(20);
|
|
273
|
+
// const bytes = process.stdin.read(buf);
|
|
274
|
+
// const stdinLn = term.write(String.UTF8.decodeUnsafe(changetype<usize>(buf), bytes) + "\n");
|
|
221
275
|
__test_options = options;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
),
|
|
226
|
-
);
|
|
227
|
-
console.log(
|
|
228
|
-
rainbow.boldMk(
|
|
229
|
-
rainbow.blueBright(`| _ || __| ___|_ _|| __|| __||_ _|`),
|
|
230
|
-
),
|
|
276
|
+
const time = new Time();
|
|
277
|
+
const fileLn = term.write(
|
|
278
|
+
`${rainbow.bgCyanBright(" FILE ")} ${rainbow.dimMk(FILE)}\n`,
|
|
231
279
|
);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
280
|
+
term.write("\n");
|
|
281
|
+
time.start = performance.now();
|
|
282
|
+
for (let i = 0; i < entrySuites.length; i++) {
|
|
283
|
+
// @ts-ignore
|
|
284
|
+
const suite = unchecked(entrySuites[i]);
|
|
285
|
+
suites = [suite];
|
|
286
|
+
|
|
287
|
+
current_suite = suite;
|
|
288
|
+
depth = -1;
|
|
289
|
+
current_suite = null;
|
|
290
|
+
|
|
291
|
+
suite.run();
|
|
292
|
+
|
|
293
|
+
suites = [];
|
|
294
|
+
depth = -1;
|
|
295
|
+
current_suite = null;
|
|
296
|
+
}
|
|
297
|
+
time.end = performance.now();
|
|
298
|
+
fileLn.edit(
|
|
299
|
+
`${rainbow.bgCyanBright(" FILE ")} ${rainbow.dimMk(FILE)} ${rainbow.dimMk(time.format())}`,
|
|
244
300
|
);
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
301
|
+
const reportText = JSON.stringify(entrySuites);
|
|
302
|
+
const chunk_size = 48;
|
|
303
|
+
let chunks = reportText.length / chunk_size;
|
|
304
|
+
let index = 0;
|
|
305
|
+
term.write("\x1B[8m\n").clear(); // Hide text (so that the cursor doesn't flash for a moment)
|
|
306
|
+
while (chunks--) {
|
|
307
|
+
term
|
|
308
|
+
.write(
|
|
309
|
+
"READ_LINE" +
|
|
310
|
+
reportText.slice(index, (index += chunk_size)) +
|
|
311
|
+
"END_LINE\n",
|
|
312
|
+
)
|
|
313
|
+
.clear(); // Write a line and then clear it, making it invisible
|
|
253
314
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const start = performance.now();
|
|
260
|
-
for (let i = 0; i < groups.length; i++) {
|
|
261
|
-
if (before_all_callback) before_all_callback();
|
|
262
|
-
const suite = unchecked(groups[i]);
|
|
263
|
-
suite.run();
|
|
264
|
-
for (let i = 0; i < suite.results.length; i++) {
|
|
265
|
-
const expectation = unchecked(suite.results[i]);
|
|
266
|
-
const verdict = expectation.verdict;
|
|
267
|
-
tests++;
|
|
268
|
-
if (verdict == Verdict.Ok) {
|
|
269
|
-
suite.passed++;
|
|
270
|
-
} else if (verdict == Verdict.Fail) {
|
|
271
|
-
suite.verdict = Verdict.Fail;
|
|
272
|
-
suite.failed++;
|
|
273
|
-
failed_tests++;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
if (suite.verdict == Verdict.Unreachable) {
|
|
277
|
-
suite.verdict = Verdict.Ok;
|
|
278
|
-
console.log(
|
|
279
|
-
rainbow.bgGreenBright(" PASS ") +
|
|
280
|
-
" " +
|
|
281
|
-
rainbow.dimMk(suite.description) +
|
|
282
|
-
"\n",
|
|
283
|
-
);
|
|
284
|
-
} else {
|
|
285
|
-
failed++;
|
|
286
|
-
const txt =
|
|
287
|
-
rainbow.bgRed(" FAIL ") + " " + rainbow.dimMk(suite.description) + "\n";
|
|
288
|
-
failed_suite_logs += txt;
|
|
289
|
-
console.log(txt);
|
|
290
|
-
}
|
|
315
|
+
if (index < reportText.length) {
|
|
316
|
+
term.write("READ_LINE" + reportText.slice(index) + "END_LINE\n").clear();
|
|
317
|
+
}
|
|
318
|
+
term.write("\x1B[0m\n").clear(); // Un-hide text
|
|
319
|
+
}
|
|
291
320
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
321
|
+
export class Result {
|
|
322
|
+
public name: string;
|
|
323
|
+
public arg1: i32;
|
|
324
|
+
public arg2: i32;
|
|
325
|
+
constructor(name: string, arg1: i32, arg2: i32) {
|
|
326
|
+
this.name = name;
|
|
327
|
+
this.arg1 = arg1;
|
|
328
|
+
this.arg2 = arg2;
|
|
329
|
+
}
|
|
330
|
+
display(): string {
|
|
331
|
+
let out = "";
|
|
332
|
+
out += `${rainbow.boldMk(this.name)} `;
|
|
333
|
+
if (this.arg1) {
|
|
334
|
+
out += `${rainbow.boldMk(rainbow.red(this.arg1.toString() + " " + "failed"))}`;
|
|
335
|
+
} else {
|
|
336
|
+
out += `${rainbow.boldMk(rainbow.green("0 failed"))}`;
|
|
296
337
|
}
|
|
297
|
-
|
|
338
|
+
out += ` ${this.arg1 + this.arg2} total\n`;
|
|
339
|
+
return out;
|
|
340
|
+
}
|
|
341
|
+
serialize(): string {
|
|
342
|
+
return JSON.stringify(this);
|
|
298
343
|
}
|
|
344
|
+
}
|
|
345
|
+
|
|
299
346
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
347
|
+
@json
|
|
348
|
+
export class Time {
|
|
349
|
+
start: f64 = 0;
|
|
350
|
+
end: f64 = 0;
|
|
351
|
+
format(): string {
|
|
352
|
+
return formatTime(this.end - this.start);
|
|
305
353
|
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
class Unit {
|
|
357
|
+
name: string;
|
|
358
|
+
divisor: number;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function formatTime(time: f64): string {
|
|
362
|
+
if (time < 0) return "0.00μs";
|
|
363
|
+
|
|
364
|
+
const us = time * 1000;
|
|
306
365
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
":" +
|
|
322
|
-
point.line.toString() +
|
|
323
|
-
":" +
|
|
324
|
-
point.column.toString();
|
|
325
|
-
const type = point.type;
|
|
326
|
-
const hash = point.hash;
|
|
327
|
-
table.push([rainbow.underlineMk(reference), type, "#" + hash]);
|
|
366
|
+
const units: Unit[] = [
|
|
367
|
+
{ name: "μs", divisor: 1 },
|
|
368
|
+
{ name: "ms", divisor: 1000 },
|
|
369
|
+
{ name: "s", divisor: 1000 * 1000 },
|
|
370
|
+
{ name: "m", divisor: 60 * 1000 * 1000 },
|
|
371
|
+
{ name: "h", divisor: 60 * 60 * 1000 * 1000 },
|
|
372
|
+
{ name: "d", divisor: 24 * 60 * 60 * 1000 * 1000 },
|
|
373
|
+
];
|
|
374
|
+
|
|
375
|
+
for (let i = units.length - 1; i >= 0; i--) {
|
|
376
|
+
const unit = units[i];
|
|
377
|
+
if (us >= unit.divisor) {
|
|
378
|
+
const value = (Math.round((us / unit.divisor) * 100) / 100).toString();
|
|
379
|
+
return `${value}${unit.name}`;
|
|
328
380
|
}
|
|
329
|
-
console.log(rainbow.dimMk(createTable(table)) + "\n");
|
|
330
381
|
}
|
|
331
382
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const ms = performance.now() - start;
|
|
336
|
-
console.log(
|
|
337
|
-
rainbow.boldMk("Test Suites: ") +
|
|
338
|
-
(failed
|
|
339
|
-
? rainbow.boldMk(rainbow.red(failed.toString() + " failed"))
|
|
340
|
-
: rainbow.boldMk(rainbow.green("0 failed"))) +
|
|
341
|
-
", " +
|
|
342
|
-
suites.toString() +
|
|
343
|
-
" total",
|
|
344
|
-
);
|
|
345
|
-
console.log(
|
|
346
|
-
rainbow.boldMk("Tests: ") +
|
|
347
|
-
(failed_tests
|
|
348
|
-
? rainbow.boldMk(rainbow.red(failed_tests.toString() + " failed"))
|
|
349
|
-
: rainbow.boldMk(rainbow.green("0 failed"))) +
|
|
350
|
-
", " +
|
|
351
|
-
tests.toString() +
|
|
352
|
-
" total",
|
|
353
|
-
);
|
|
354
|
-
// @ts-ignore
|
|
355
|
-
if (isDefined(COVERAGE_USE))
|
|
356
|
-
console.log(
|
|
357
|
-
rainbow.boldMk("Coverage: ") +
|
|
358
|
-
(__HASHES().size
|
|
359
|
-
? rainbow.boldMk(rainbow.red(__HASHES().size.toString() + " failed"))
|
|
360
|
-
: rainbow.boldMk(rainbow.green("0 failed"))) +
|
|
361
|
-
", " +
|
|
362
|
-
__POINTS().toString() +
|
|
363
|
-
" total",
|
|
364
|
-
);
|
|
365
|
-
console.log(rainbow.boldMk("Snapshots: ") + "0 total");
|
|
366
|
-
console.log(rainbow.boldMk("Time: ") + formatTime(ms));
|
|
367
|
-
if (failed) {
|
|
368
|
-
process.exit(1);
|
|
369
|
-
}
|
|
383
|
+
const _us = (Math.round(us * 100) / 100).toString();
|
|
384
|
+
|
|
385
|
+
return `${_us}μs`;
|
|
370
386
|
}
|