as-test 0.4.4 → 0.5.1

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.
Files changed (67) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +196 -82
  3. package/as-test.config.schema.json +137 -0
  4. package/assembly/coverage.ts +19 -0
  5. package/assembly/index.ts +172 -85
  6. package/assembly/src/expectation.ts +263 -199
  7. package/assembly/src/log.ts +1 -9
  8. package/assembly/src/suite.ts +61 -25
  9. package/assembly/src/tests.ts +2 -0
  10. package/assembly/util/wipc.ts +286 -0
  11. package/bin/build.js +86 -41
  12. package/bin/index.js +337 -68
  13. package/bin/init.js +441 -183
  14. package/bin/reporter.js +1 -1
  15. package/bin/reporters/default.js +379 -0
  16. package/bin/reporters/types.js +1 -0
  17. package/bin/run.js +882 -194
  18. package/bin/types.js +14 -7
  19. package/bin/util.js +54 -3
  20. package/package.json +34 -16
  21. package/transform/lib/builder.js +169 -169
  22. package/transform/lib/builder.js.map +1 -1
  23. package/transform/lib/coverage.js +47 -1
  24. package/transform/lib/coverage.js.map +1 -1
  25. package/transform/lib/index.js +70 -0
  26. package/transform/lib/index.js.map +1 -1
  27. package/transform/lib/location.js +20 -0
  28. package/transform/lib/location.js.map +1 -0
  29. package/transform/lib/log.js +118 -0
  30. package/transform/lib/log.js.map +1 -0
  31. package/transform/lib/mock.js +2 -2
  32. package/transform/lib/mock.js.map +1 -1
  33. package/transform/lib/util.js +3 -3
  34. package/transform/lib/util.js.map +1 -1
  35. package/.github/workflows/as-test.yml +0 -26
  36. package/.prettierrc +0 -3
  37. package/as-test.config.json +0 -19
  38. package/assembly/__tests__/array.spec.ts +0 -25
  39. package/assembly/__tests__/math.spec.ts +0 -16
  40. package/assembly/__tests__/mock.spec.ts +0 -22
  41. package/assembly/__tests__/mock.ts +0 -7
  42. package/assembly/__tests__/sleep.spec.ts +0 -28
  43. package/assembly/tsconfig.json +0 -97
  44. package/assets/img/screenshot.png +0 -0
  45. package/cli/build.ts +0 -117
  46. package/cli/index.ts +0 -190
  47. package/cli/init.ts +0 -247
  48. package/cli/reporter.ts +0 -1
  49. package/cli/run.ts +0 -286
  50. package/cli/tsconfig.json +0 -9
  51. package/cli/types.ts +0 -29
  52. package/cli/util.ts +0 -65
  53. package/run/package.json +0 -27
  54. package/tests/array.run.js +0 -7
  55. package/tests/math.run.js +0 -7
  56. package/tests/mock.run.js +0 -14
  57. package/tests/sleep.run.js +0 -7
  58. package/transform/src/builder.ts +0 -1474
  59. package/transform/src/coverage.ts +0 -580
  60. package/transform/src/index.ts +0 -73
  61. package/transform/src/linker.ts +0 -41
  62. package/transform/src/mock.ts +0 -163
  63. package/transform/src/range.ts +0 -12
  64. package/transform/src/types.ts +0 -35
  65. package/transform/src/util.ts +0 -81
  66. package/transform/src/visitor.ts +0 -744
  67. package/transform/tsconfig.json +0 -10
package/assembly/index.ts CHANGED
@@ -1,11 +1,16 @@
1
- import { rainbow } from "as-rainbow";
2
1
  import { Suite } from "./src/suite";
3
2
  import { Expectation } from "./src/expectation";
4
3
  import { stringify } from "as-console/stringify";
5
- import { __COVER, __HASHES, __POINTS } from "as-test/assembly/coverage";
4
+ import {
5
+ __COVER,
6
+ __POINTS,
7
+ __UNCOVERED,
8
+ __ALL_POINTS,
9
+ CoverPoint,
10
+ } from "as-test/assembly/coverage";
6
11
  import { JSON } from "json-as";
7
- import { term } from "./util/term";
8
12
  import { Log } from "./src/log";
13
+ import { sendFileEnd, sendFileStart, sendReport } from "./util/wipc";
9
14
 
10
15
  let entrySuites: Suite[] = [];
11
16
 
@@ -46,21 +51,7 @@ let __test_options!: RunOptions;
46
51
  * ```
47
52
  */
48
53
  export function describe(description: string, callback: () => void): void {
49
- const suite = new Suite(description, callback, "describe");
50
-
51
- if (depth >= 0) {
52
- const _suite = suites[depth];
53
- if (_suite.depth == depth) {
54
- _suite.addSuite(suite);
55
- } else {
56
- suite.depth = ++depth;
57
- suites.push(suite);
58
- }
59
- } else {
60
- suite.file = FILE;
61
- entrySuites.push(suite);
62
- suites.push(suite);
63
- }
54
+ registerSuite(description, callback, "describe");
64
55
  }
65
56
 
66
57
  /**
@@ -78,21 +69,7 @@ export function describe(description: string, callback: () => void): void {
78
69
  * ```
79
70
  */
80
71
  export function test(description: string, callback: () => void): void {
81
- const suite = new Suite(description, callback, "test");
82
-
83
- if (depth >= 0) {
84
- const _suite = suites[depth];
85
- if (_suite.depth == depth) {
86
- _suite.addSuite(suite);
87
- } else {
88
- suite.depth = ++depth;
89
- suites.push(suite);
90
- }
91
- } else {
92
- suite.file = FILE;
93
- entrySuites.push(suite);
94
- suites.push(suite);
95
- }
72
+ registerSuite(description, callback, "test");
96
73
  }
97
74
 
98
75
  /**
@@ -110,21 +87,28 @@ export function test(description: string, callback: () => void): void {
110
87
  * ```
111
88
  */
112
89
  export function it(description: string, callback: () => void): void {
113
- const suite = new Suite(description, callback, "it");
90
+ registerSuite(description, callback, "it");
91
+ }
114
92
 
115
- if (depth >= 0) {
116
- const _suite = suites[depth];
117
- if (_suite.depth == depth) {
118
- _suite.addSuite(suite);
119
- } else {
120
- suite.depth = ++depth;
121
- suites.push(suite);
122
- }
123
- } else {
124
- suite.file = FILE;
125
- entrySuites.push(suite);
126
- suites.push(suite);
127
- }
93
+ /**
94
+ * Creates a skipped test group.
95
+ */
96
+ export function xdescribe(description: string, callback: () => void): void {
97
+ registerSuite(description, callback, "xdescribe");
98
+ }
99
+
100
+ /**
101
+ * Creates a skipped test case.
102
+ */
103
+ export function xtest(description: string, callback: () => void): void {
104
+ registerSuite(description, callback, "xtest");
105
+ }
106
+
107
+ /**
108
+ * Creates a skipped test case alias.
109
+ */
110
+ export function xit(description: string, callback: () => void): void {
111
+ registerSuite(description, callback, "xit");
128
112
  }
129
113
 
130
114
  /**
@@ -145,8 +129,12 @@ export function it(description: string, callback: () => void): void {
145
129
  * });
146
130
  * ```
147
131
  */
148
- export function expect<T>(value: T): Expectation<T> {
149
- const test = new Expectation<T>(value);
132
+ export function expect<T>(
133
+ value: T,
134
+ message: string = "",
135
+ location: string = "",
136
+ ): Expectation<T> {
137
+ const test = new Expectation<T>(value, message, snapshotKey(), location);
150
138
 
151
139
  if (current_suite) {
152
140
  current_suite!.addExpectation(test);
@@ -155,6 +143,17 @@ export function expect<T>(value: T): Expectation<T> {
155
143
  return test;
156
144
  }
157
145
 
146
+ /**
147
+ * Creates a skipped expectation.
148
+ */
149
+ export function xexpect<T>(
150
+ value: T,
151
+ message: string = "",
152
+ location: string = "",
153
+ ): Expectation<T> {
154
+ return expect<T>(value, message, location).skip();
155
+ }
156
+
158
157
  /**
159
158
  * Formats and prints content to the terminal
160
159
  * Can be disabled like so:
@@ -168,17 +167,26 @@ export function expect<T>(value: T): Expectation<T> {
168
167
  * @param {T} data - The data to format and print
169
168
  */
170
169
  export function log<T>(data: T): void {
171
- if (!__test_options.log) return;
172
- const formatted = stringify(data);
173
- if (formatted) {
174
- const lines = formatted.split("\n");
175
- for (let i = 0; i < lines.length; i++) {
176
- const line = unchecked(lines[i]);
177
- if (current_suite) {
178
- current_suite!.addLog(new Log(line));
179
- }
170
+ if (!__as_test_log_is_enabled()) return;
171
+ __as_test_log_serialized(__as_test_log_default<T>(data));
172
+ }
173
+
174
+ export function __as_test_log_default<T>(data: T): string {
175
+ return stringify(data);
176
+ }
177
+
178
+ export function __as_test_log_is_enabled(): bool {
179
+ return __test_options.log;
180
+ }
181
+
182
+ export function __as_test_log_serialized(formatted: string): void {
183
+ if (!formatted) return;
184
+ const lines = formatted.split("\n");
185
+ for (let i = 0; i < lines.length; i++) {
186
+ const line = unchecked(lines[i]);
187
+ if (current_suite) {
188
+ current_suite!.addLog(new Log(line));
180
189
  }
181
- term.write("\n");
182
190
  }
183
191
  }
184
192
 
@@ -263,15 +271,10 @@ class RunOptions {
263
271
  * ```
264
272
  */
265
273
  export function run(options: RunOptions = new RunOptions()): void {
266
- // const buf = new ArrayBuffer(20);
267
- // const bytes = process.stdin.read(buf);
268
- // const stdinLn = term.write(String.UTF8.decodeUnsafe(changetype<usize>(buf), bytes) + "\n");
269
274
  __test_options = options;
270
275
  const time = new Time();
271
- const fileLn = term.write(
272
- `${rainbow.bgCyanBright(" FILE ")} ${rainbow.dimMk(FILE)}\n`,
273
- );
274
- term.write("\n");
276
+ let fileVerdict = "none";
277
+ sendFileStart(FILE);
275
278
  time.start = performance.now();
276
279
  for (let i = 0; i < entrySuites.length; i++) {
277
280
  // @ts-ignore
@@ -283,33 +286,117 @@ export function run(options: RunOptions = new RunOptions()): void {
283
286
  current_suite = null;
284
287
 
285
288
  suite.run();
289
+ if (suite.verdict == "fail") {
290
+ fileVerdict = "fail";
291
+ } else if (fileVerdict != "fail" && suite.verdict == "ok") {
292
+ fileVerdict = "ok";
293
+ } else if (fileVerdict == "none" && suite.verdict == "skip") {
294
+ fileVerdict = "skip";
295
+ }
286
296
 
287
297
  suites = [];
288
298
  depth = -1;
289
299
  current_suite = null;
290
300
  }
291
301
  time.end = performance.now();
292
- fileLn.edit(
293
- `${rainbow.bgCyanBright(" FILE ")} ${rainbow.dimMk(FILE)} ${rainbow.dimMk(time.format())}`,
294
- );
295
- const reportText = JSON.stringify(entrySuites);
296
- const chunk_size = 48;
297
- let chunks = reportText.length / chunk_size;
298
- let index = 0;
299
- term.write("\x1B[8m\n").clear(); // Hide text (so that the cursor doesn't flash for a moment)
300
- while (chunks--) {
301
- term
302
- .write(
303
- "READ_LINE" +
304
- reportText.slice(index, (index += chunk_size)) +
305
- "END_LINE\n",
306
- )
307
- .clear(); // Write a line and then clear it, making it invisible
302
+ sendFileEnd(FILE, fileVerdict, time.format());
303
+ const report = new FileReport();
304
+ report.suites = entrySuites;
305
+ report.coverage = collectCoverage();
306
+ sendReport(JSON.stringify(report));
307
+ }
308
+
309
+ function registerSuite(
310
+ description: string,
311
+ callback: () => void,
312
+ kind: string,
313
+ ): void {
314
+ const suite = new Suite(description, callback, kind);
315
+ if (depth >= 0) {
316
+ const _suite = suites[depth];
317
+ if (_suite.depth == depth) {
318
+ _suite.addSuite(suite);
319
+ return;
320
+ }
321
+ suite.depth = ++depth;
322
+ suites.push(suite);
323
+ return;
308
324
  }
309
- if (index < reportText.length) {
310
- term.write("READ_LINE" + reportText.slice(index) + "END_LINE\n").clear();
325
+
326
+ suite.file = FILE;
327
+ entrySuites.push(suite);
328
+ suites.push(suite);
329
+ }
330
+
331
+
332
+ @json
333
+ class CoverageReport {
334
+ total: i32 = 0;
335
+ covered: i32 = 0;
336
+ uncovered: i32 = 0;
337
+ percent: f64 = 100.0;
338
+ points: CoveragePointReport[] = [];
339
+ }
340
+
341
+
342
+ @json
343
+ class CoveragePointReport {
344
+ hash: string = "";
345
+ file: string = "";
346
+ line: i32 = 0;
347
+ column: i32 = 0;
348
+ type: string = "";
349
+ executed: bool = false;
350
+ }
351
+
352
+
353
+ @json
354
+ class FileReport {
355
+ suites: Suite[] = [];
356
+ coverage: CoverageReport = new CoverageReport();
357
+ }
358
+
359
+ function collectCoverage(): CoverageReport {
360
+ const out = new CoverageReport();
361
+ out.total = __POINTS();
362
+ out.uncovered = __UNCOVERED();
363
+ out.covered = out.total - out.uncovered;
364
+ if (out.total <= 0) {
365
+ out.percent = 100.0;
366
+ } else {
367
+ out.percent = (<f64>out.covered * 100.0) / <f64>out.total;
368
+ }
369
+
370
+ const points = __ALL_POINTS();
371
+ for (let i = 0; i < points.length; i++) {
372
+ const point = unchecked(points[i]);
373
+ out.points.push(toCoveragePointReport(point));
374
+ }
375
+ return out;
376
+ }
377
+
378
+ function toCoveragePointReport(point: CoverPoint): CoveragePointReport {
379
+ const out = new CoveragePointReport();
380
+ out.hash = point.hash;
381
+ out.file = point.file;
382
+ out.line = point.line;
383
+ out.column = point.column;
384
+ out.type = point.type;
385
+ out.executed = point.executed;
386
+ return out;
387
+ }
388
+
389
+ function snapshotKey(): string {
390
+ if (!current_suite) return FILE + "::global::0";
391
+ const suite = current_suite!;
392
+ const parts = new Array<string>();
393
+ let cursor: Suite | null = suite;
394
+ while (cursor) {
395
+ parts.unshift(cursor.description);
396
+ cursor = cursor.parent;
311
397
  }
312
- term.write("\x1B[0m\n").clear(); // Un-hide text
398
+ const path = parts.join(" > ");
399
+ return FILE + "::" + path + "::" + suite.tests.length.toString();
313
400
  }
314
401
 
315
402
  export class Result {