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.
- package/CHANGELOG.md +46 -0
- package/README.md +196 -82
- package/as-test.config.schema.json +137 -0
- package/assembly/coverage.ts +19 -0
- package/assembly/index.ts +172 -85
- package/assembly/src/expectation.ts +263 -199
- package/assembly/src/log.ts +1 -9
- package/assembly/src/suite.ts +61 -25
- package/assembly/src/tests.ts +2 -0
- package/assembly/util/wipc.ts +286 -0
- package/bin/build.js +86 -41
- package/bin/index.js +337 -68
- package/bin/init.js +441 -183
- package/bin/reporter.js +1 -1
- package/bin/reporters/default.js +379 -0
- package/bin/reporters/types.js +1 -0
- package/bin/run.js +882 -194
- package/bin/types.js +14 -7
- package/bin/util.js +54 -3
- package/package.json +34 -16
- package/transform/lib/builder.js +169 -169
- package/transform/lib/builder.js.map +1 -1
- package/transform/lib/coverage.js +47 -1
- package/transform/lib/coverage.js.map +1 -1
- package/transform/lib/index.js +70 -0
- package/transform/lib/index.js.map +1 -1
- package/transform/lib/location.js +20 -0
- package/transform/lib/location.js.map +1 -0
- package/transform/lib/log.js +118 -0
- package/transform/lib/log.js.map +1 -0
- package/transform/lib/mock.js +2 -2
- package/transform/lib/mock.js.map +1 -1
- package/transform/lib/util.js +3 -3
- package/transform/lib/util.js.map +1 -1
- package/.github/workflows/as-test.yml +0 -26
- package/.prettierrc +0 -3
- package/as-test.config.json +0 -19
- package/assembly/__tests__/array.spec.ts +0 -25
- package/assembly/__tests__/math.spec.ts +0 -16
- package/assembly/__tests__/mock.spec.ts +0 -22
- package/assembly/__tests__/mock.ts +0 -7
- package/assembly/__tests__/sleep.spec.ts +0 -28
- package/assembly/tsconfig.json +0 -97
- package/assets/img/screenshot.png +0 -0
- package/cli/build.ts +0 -117
- package/cli/index.ts +0 -190
- package/cli/init.ts +0 -247
- package/cli/reporter.ts +0 -1
- package/cli/run.ts +0 -286
- package/cli/tsconfig.json +0 -9
- package/cli/types.ts +0 -29
- package/cli/util.ts +0 -65
- package/run/package.json +0 -27
- package/tests/array.run.js +0 -7
- package/tests/math.run.js +0 -7
- package/tests/mock.run.js +0 -14
- package/tests/sleep.run.js +0 -7
- package/transform/src/builder.ts +0 -1474
- package/transform/src/coverage.ts +0 -580
- package/transform/src/index.ts +0 -73
- package/transform/src/linker.ts +0 -41
- package/transform/src/mock.ts +0 -163
- package/transform/src/range.ts +0 -12
- package/transform/src/types.ts +0 -35
- package/transform/src/util.ts +0 -81
- package/transform/src/visitor.ts +0 -744
- package/transform/tsconfig.json +0 -10
package/bin/init.js
CHANGED
|
@@ -2,213 +2,471 @@ import chalk from "chalk";
|
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import { createInterface } from "readline";
|
|
5
|
-
import { loadConfig } from "./util.js";
|
|
5
|
+
import { getCliVersion, loadConfig } from "./util.js";
|
|
6
6
|
const TARGETS = ["wasi", "bindings"];
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const EXAMPLE_MODES = ["minimal", "full", "none"];
|
|
8
|
+
export async function init(rawArgs) {
|
|
9
|
+
const options = parseInitArgs(rawArgs);
|
|
10
|
+
const root = path.resolve(process.cwd(), options.dir);
|
|
11
|
+
const rl = options.yes
|
|
12
|
+
? null
|
|
13
|
+
: createInterface({
|
|
14
|
+
input: process.stdin,
|
|
15
|
+
output: process.stdout,
|
|
16
|
+
});
|
|
17
|
+
try {
|
|
18
|
+
console.log(chalk.bold(`as-test init v${getCliVersion()}`) + "\n");
|
|
19
|
+
const target = options.target ??
|
|
20
|
+
(await askChoice("Select target", TARGETS, rl, "wasi"));
|
|
21
|
+
const example = options.example ??
|
|
22
|
+
(await askChoice("Select example mode", EXAMPLE_MODES, rl, "minimal"));
|
|
23
|
+
printPlan(root, target, example);
|
|
24
|
+
if (!options.yes) {
|
|
25
|
+
const cont = (await ask("Continue? [Y/n] ", rl)).toLowerCase().trim();
|
|
26
|
+
if (["n", "no"].includes(cont)) {
|
|
27
|
+
console.log("Exiting.");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const summary = applyInit(root, target, example, options.force);
|
|
32
|
+
printSummary(summary);
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
rl?.close();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function parseInitArgs(rawArgs) {
|
|
39
|
+
const options = {
|
|
40
|
+
yes: false,
|
|
41
|
+
force: false,
|
|
42
|
+
dir: ".",
|
|
43
|
+
};
|
|
44
|
+
const positional = [];
|
|
45
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
46
|
+
const arg = rawArgs[i];
|
|
47
|
+
if (arg == "--yes" || arg == "-y") {
|
|
48
|
+
options.yes = true;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (arg == "--force") {
|
|
52
|
+
options.force = true;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (arg == "--target") {
|
|
56
|
+
const next = rawArgs[i + 1];
|
|
57
|
+
if (next && !next.startsWith("-")) {
|
|
58
|
+
options.target = parseTarget(next);
|
|
59
|
+
i++;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
throw new Error("--target requires a value: wasi|bindings");
|
|
63
|
+
}
|
|
64
|
+
if (arg.startsWith("--target=")) {
|
|
65
|
+
options.target = parseTarget(arg.slice("--target=".length));
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (arg == "--example") {
|
|
69
|
+
const next = rawArgs[i + 1];
|
|
70
|
+
if (next && !next.startsWith("-")) {
|
|
71
|
+
options.example = parseExampleMode(next);
|
|
72
|
+
i++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
throw new Error("--example requires a value: minimal|full|none");
|
|
76
|
+
}
|
|
77
|
+
if (arg.startsWith("--example=")) {
|
|
78
|
+
options.example = parseExampleMode(arg.slice("--example=".length));
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (arg == "--dir") {
|
|
82
|
+
const next = rawArgs[i + 1];
|
|
83
|
+
if (next && !next.startsWith("-")) {
|
|
84
|
+
options.dir = next;
|
|
85
|
+
i++;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
throw new Error("--dir requires a path value");
|
|
89
|
+
}
|
|
90
|
+
if (arg.startsWith("--dir=")) {
|
|
91
|
+
options.dir = arg.slice("--dir=".length);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (arg.startsWith("-")) {
|
|
95
|
+
throw new Error(`Unknown init flag: ${arg}`);
|
|
96
|
+
}
|
|
97
|
+
positional.push(arg);
|
|
98
|
+
}
|
|
99
|
+
// First positional argument is always the target directory.
|
|
100
|
+
if (positional.length > 0) {
|
|
101
|
+
options.dir = positional.shift();
|
|
102
|
+
}
|
|
103
|
+
if (!options.target && positional.length > 0 && isTarget(positional[0])) {
|
|
104
|
+
options.target = positional.shift();
|
|
105
|
+
}
|
|
106
|
+
if (!options.example && positional.length > 0 && isExampleMode(positional[0])) {
|
|
107
|
+
options.example = positional.shift();
|
|
108
|
+
}
|
|
109
|
+
if (positional.length > 0) {
|
|
110
|
+
throw new Error(`Unknown init argument(s): ${positional.join(", ")}. Usage: init [dir] [--target wasi|bindings] [--example minimal|full|none] [--yes] [--force] [--dir <path>]`);
|
|
111
|
+
}
|
|
112
|
+
return options;
|
|
113
|
+
}
|
|
114
|
+
function parseTarget(value) {
|
|
115
|
+
if (!isTarget(value)) {
|
|
116
|
+
throw new Error(`Invalid target "${value}". Expected wasi|bindings`);
|
|
117
|
+
}
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
function parseExampleMode(value) {
|
|
121
|
+
if (!isExampleMode(value)) {
|
|
122
|
+
throw new Error(`Invalid example mode "${value}". Expected minimal|full|none`);
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
function isTarget(value) {
|
|
127
|
+
return TARGETS.includes(value);
|
|
128
|
+
}
|
|
129
|
+
function isExampleMode(value) {
|
|
130
|
+
return EXAMPLE_MODES.includes(value);
|
|
131
|
+
}
|
|
132
|
+
function printPlan(root, target, example) {
|
|
133
|
+
console.log(chalk.dim("Planned changes:\n"));
|
|
134
|
+
console.log(chalk.dim(` target: ${target}`));
|
|
135
|
+
console.log(chalk.dim(` example: ${example}`));
|
|
136
|
+
console.log(chalk.dim(` root: ${root}\n`));
|
|
137
|
+
console.log(chalk.dim(" directories:"));
|
|
138
|
+
console.log(chalk.dim(" .as-test/build"));
|
|
139
|
+
console.log(chalk.dim(" .as-test/logs"));
|
|
140
|
+
console.log(chalk.dim(" .as-test/coverage"));
|
|
141
|
+
console.log(chalk.dim(" .as-test/snapshots"));
|
|
142
|
+
console.log(chalk.dim(" assembly/__tests__"));
|
|
143
|
+
if (target == "wasi" || target == "bindings") {
|
|
144
|
+
console.log(chalk.dim(" .as-test/runners"));
|
|
145
|
+
}
|
|
146
|
+
console.log(chalk.dim("\n files:"));
|
|
147
|
+
console.log(chalk.dim(" as-test.config.json"));
|
|
148
|
+
if (example != "none") {
|
|
149
|
+
console.log(chalk.dim(" assembly/__tests__/example.spec.ts"));
|
|
150
|
+
}
|
|
151
|
+
if (target == "wasi") {
|
|
152
|
+
console.log(chalk.dim(" .as-test/runners/default.wasi.js"));
|
|
153
|
+
}
|
|
154
|
+
if (target == "bindings") {
|
|
155
|
+
console.log(chalk.dim(" .as-test/runners/default.run.js"));
|
|
156
|
+
}
|
|
157
|
+
console.log(chalk.dim(" package.json"));
|
|
158
|
+
console.log("");
|
|
159
|
+
}
|
|
160
|
+
function applyInit(root, target, example, force) {
|
|
161
|
+
const summary = {
|
|
162
|
+
created: [],
|
|
163
|
+
updated: [],
|
|
164
|
+
skipped: [],
|
|
165
|
+
};
|
|
166
|
+
ensureDir(root, ".as-test/build", summary);
|
|
167
|
+
ensureDir(root, ".as-test/logs", summary);
|
|
168
|
+
ensureDir(root, ".as-test/coverage", summary);
|
|
169
|
+
ensureDir(root, ".as-test/snapshots", summary);
|
|
170
|
+
ensureDir(root, "assembly/__tests__", summary);
|
|
171
|
+
if (target == "wasi" || target == "bindings") {
|
|
172
|
+
ensureDir(root, ".as-test/runners", summary);
|
|
173
|
+
}
|
|
174
|
+
const configPath = path.join(root, "as-test.config.json");
|
|
175
|
+
const config = loadConfig(configPath, false);
|
|
176
|
+
config.$schema = "./node_modules/as-test/as-test.config.schema.json";
|
|
177
|
+
config.buildOptions.target = target;
|
|
178
|
+
if (target == "wasi") {
|
|
179
|
+
config.runOptions.runtime.cmd = "node ./.as-test/runners/default.wasi.js <file>";
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
config.runOptions.runtime.cmd = "node ./.as-test/runners/default.run.js <file>";
|
|
183
|
+
}
|
|
184
|
+
writeJson(configPath, config, summary, "as-test.config.json");
|
|
185
|
+
if (example != "none") {
|
|
186
|
+
const examplePath = path.join(root, "assembly/__tests__/example.spec.ts");
|
|
187
|
+
const content = example == "minimal" ? buildMinimalExampleSpec() : buildFullExampleSpec();
|
|
188
|
+
writeManagedFile(examplePath, content, force, summary, "assembly/__tests__/example.spec.ts");
|
|
189
|
+
}
|
|
190
|
+
if (target == "wasi") {
|
|
191
|
+
const runnerPath = path.join(root, ".as-test/runners/default.wasi.js");
|
|
192
|
+
writeManagedFile(runnerPath, buildWasiRunner(), force, summary, ".as-test/runners/default.wasi.js");
|
|
193
|
+
}
|
|
194
|
+
if (target == "bindings") {
|
|
195
|
+
const runnerPath = path.join(root, ".as-test/runners/default.run.js");
|
|
196
|
+
writeManagedFile(runnerPath, buildBindingsRunner(), force, summary, ".as-test/runners/default.run.js");
|
|
197
|
+
}
|
|
198
|
+
const pkgPath = path.join(root, "package.json");
|
|
199
|
+
const pkg = existsSync(pkgPath)
|
|
200
|
+
? JSON.parse(readFileSync(pkgPath, "utf8"))
|
|
201
|
+
: {};
|
|
202
|
+
if (!pkg.scripts || typeof pkg.scripts != "object") {
|
|
203
|
+
pkg.scripts = {};
|
|
204
|
+
}
|
|
205
|
+
const scripts = pkg.scripts;
|
|
206
|
+
if (!scripts.test) {
|
|
207
|
+
scripts.test = "as-test test";
|
|
208
|
+
}
|
|
209
|
+
if (!pkg.type) {
|
|
210
|
+
pkg.type = "module";
|
|
211
|
+
}
|
|
212
|
+
if (!pkg.devDependencies || typeof pkg.devDependencies != "object") {
|
|
213
|
+
pkg.devDependencies = {};
|
|
214
|
+
}
|
|
215
|
+
const devDependencies = pkg.devDependencies;
|
|
216
|
+
if (!devDependencies["as-test"]) {
|
|
217
|
+
devDependencies["as-test"] = "^" + getCliVersion();
|
|
218
|
+
}
|
|
219
|
+
if (target == "wasi" && !devDependencies["@assemblyscript/wasi-shim"]) {
|
|
220
|
+
devDependencies["@assemblyscript/wasi-shim"] = "^0.1.0";
|
|
221
|
+
}
|
|
222
|
+
if (target == "bindings" && !pkg.type) {
|
|
223
|
+
pkg.type = "module";
|
|
224
|
+
}
|
|
225
|
+
writeJson(pkgPath, pkg, summary, "package.json");
|
|
226
|
+
return summary;
|
|
227
|
+
}
|
|
228
|
+
function ensureDir(root, rel, summary) {
|
|
229
|
+
const full = path.join(root, rel);
|
|
230
|
+
if (existsSync(full))
|
|
231
|
+
return;
|
|
232
|
+
mkdirSync(full, { recursive: true });
|
|
233
|
+
summary.created.push(rel + "/");
|
|
234
|
+
}
|
|
235
|
+
function writeJson(fullPath, value, summary, displayPath) {
|
|
236
|
+
const rel = displayPath ??
|
|
237
|
+
path.relative(process.cwd(), fullPath) ??
|
|
238
|
+
path.basename(fullPath);
|
|
239
|
+
const existed = existsSync(fullPath);
|
|
240
|
+
const data = JSON.stringify(value, null, 2) + "\n";
|
|
241
|
+
writeFileSync(fullPath, data);
|
|
242
|
+
if (existed)
|
|
243
|
+
summary.updated.push(rel);
|
|
244
|
+
else
|
|
245
|
+
summary.created.push(rel);
|
|
246
|
+
}
|
|
247
|
+
function writeManagedFile(fullPath, data, force, summary, displayPath) {
|
|
248
|
+
const rel = displayPath ??
|
|
249
|
+
path.relative(process.cwd(), fullPath) ??
|
|
250
|
+
path.basename(fullPath);
|
|
251
|
+
const existed = existsSync(fullPath);
|
|
252
|
+
if (existed && !force) {
|
|
253
|
+
summary.skipped.push(rel);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (!existsSync(path.dirname(fullPath))) {
|
|
257
|
+
mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
258
|
+
}
|
|
259
|
+
writeFileSync(fullPath, data);
|
|
260
|
+
if (existed)
|
|
261
|
+
summary.updated.push(rel);
|
|
262
|
+
else
|
|
263
|
+
summary.created.push(rel);
|
|
264
|
+
}
|
|
265
|
+
function printSummary(summary) {
|
|
266
|
+
console.log("");
|
|
267
|
+
if (summary.created.length) {
|
|
268
|
+
console.log(chalk.bold("Created:"));
|
|
269
|
+
for (const item of summary.created) {
|
|
270
|
+
console.log(` + ${item}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (summary.updated.length) {
|
|
274
|
+
console.log(chalk.bold("Updated:"));
|
|
275
|
+
for (const item of summary.updated) {
|
|
276
|
+
console.log(` ~ ${item}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (summary.skipped.length) {
|
|
280
|
+
console.log(chalk.bold("Skipped (exists, use --force to overwrite):"));
|
|
281
|
+
for (const item of summary.skipped) {
|
|
282
|
+
console.log(` = ${item}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
console.log("\nNow, install dependencies and run " + chalk.bold("as-test test") + "\n");
|
|
286
|
+
}
|
|
287
|
+
function ask(question, face) {
|
|
288
|
+
if (!face) {
|
|
289
|
+
throw new Error("interactive input is unavailable; pass --yes with options");
|
|
290
|
+
}
|
|
291
|
+
return new Promise((res) => {
|
|
292
|
+
face.question(question, (answer) => {
|
|
293
|
+
res(answer);
|
|
294
|
+
});
|
|
11
295
|
});
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
├── 📂 build/
|
|
29
|
-
├── 📂 logs/
|
|
30
|
-
├── 📂 tests/
|
|
31
|
-
│ └── 📃 as-test.run.js
|
|
32
|
-
├── ⚙️ as-test.config.json
|
|
33
|
-
└── ⚙️ package.json\n`));
|
|
34
|
-
const cont = (await ask(chalk.dim(" -> "), rl)).toLowerCase().trim();
|
|
35
|
-
if (cont == "n" || cont == "no") {
|
|
36
|
-
console.log("Exiting.");
|
|
37
|
-
process.exit(0);
|
|
38
|
-
}
|
|
39
|
-
let config = loadConfig(path.join(process.cwd(), "./as-test.config.json"));
|
|
40
|
-
if (target == "wasi" && config.buildOptions.target != "wasi") {
|
|
41
|
-
config.buildOptions.target = "wasi";
|
|
42
|
-
config.runOptions.runtime.name = "wasmtime";
|
|
43
|
-
config.runOptions.runtime.run = "wasmtime <file>";
|
|
44
|
-
}
|
|
45
|
-
else if (target == "bindings" && config.buildOptions.target != "bindings") {
|
|
46
|
-
config.buildOptions.target = "bindings";
|
|
47
|
-
config.runOptions.runtime.name = "node";
|
|
48
|
-
config.runOptions.runtime.run = "node ./tests/<name>.run.js";
|
|
49
|
-
}
|
|
50
|
-
writeFile("./as-test.config.json", JSON.stringify(config, null, 2));
|
|
51
|
-
writeFile("./assembly/__tests__/example.spec.ts", `import {
|
|
52
|
-
describe,
|
|
53
|
-
expect,
|
|
54
|
-
test,
|
|
55
|
-
beforeAll,
|
|
56
|
-
afterAll,
|
|
57
|
-
mockFn,
|
|
58
|
-
log,
|
|
59
|
-
run,
|
|
60
|
-
it
|
|
61
|
-
} from "as-test";
|
|
296
|
+
}
|
|
297
|
+
async function askChoice(label, choices, face, fallback) {
|
|
298
|
+
if (!face) {
|
|
299
|
+
return fallback;
|
|
300
|
+
}
|
|
301
|
+
const answer = (await ask(`${label} [${choices.join("/")}] (${fallback}) -> `, face))
|
|
302
|
+
.trim()
|
|
303
|
+
.toLowerCase();
|
|
304
|
+
if (!answer.length)
|
|
305
|
+
return fallback;
|
|
306
|
+
if (choices.includes(answer))
|
|
307
|
+
return answer;
|
|
308
|
+
throw new Error(`Invalid choice "${answer}" for ${label}`);
|
|
309
|
+
}
|
|
310
|
+
function buildMinimalExampleSpec() {
|
|
311
|
+
return `import { describe, expect, test, run } from "as-test";
|
|
62
312
|
|
|
63
|
-
|
|
64
|
-
|
|
313
|
+
describe("example", () => {
|
|
314
|
+
test("adds numbers", () => {
|
|
315
|
+
expect(1 + 2).toBe(3);
|
|
316
|
+
});
|
|
65
317
|
});
|
|
66
318
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
319
|
+
run();
|
|
320
|
+
`;
|
|
321
|
+
}
|
|
322
|
+
function buildFullExampleSpec() {
|
|
323
|
+
return `import { afterAll, beforeAll, describe, expect, it, log, run, test } from "as-test";
|
|
70
324
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
console.log("[MOCKED]: " + data + "\\n");
|
|
325
|
+
beforeAll(() => {
|
|
326
|
+
log("setup");
|
|
74
327
|
});
|
|
75
328
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const start = Date.now();
|
|
79
|
-
sleep(1);
|
|
80
|
-
expect(Date.now() - start).toBeGreaterOrEqualTo(1);
|
|
81
|
-
});
|
|
82
|
-
test("10ms", () => {
|
|
83
|
-
const start = Date.now();
|
|
84
|
-
sleep(10);
|
|
85
|
-
expect(Date.now() - start).toBeGreaterOrEqualTo(10);
|
|
86
|
-
});
|
|
87
|
-
test("1s", () => {
|
|
88
|
-
const start = Date.now();
|
|
89
|
-
sleep(1000);
|
|
90
|
-
expect(Date.now() - start).toBeGreaterOrEqualTo(1000);
|
|
91
|
-
});
|
|
92
|
-
test("5s", () => {
|
|
93
|
-
const start = Date.now();
|
|
94
|
-
log("Sleeping...");
|
|
95
|
-
sleep(5000);
|
|
96
|
-
log("Done!");
|
|
97
|
-
expect(Date.now() - start).toBeGreaterOrEqualTo(5000);
|
|
98
|
-
});
|
|
329
|
+
afterAll(() => {
|
|
330
|
+
log("teardown");
|
|
99
331
|
});
|
|
100
332
|
|
|
101
|
-
describe("
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
test("Subtraction", () => {
|
|
107
|
-
expect(1 - 2).toBe(-1);
|
|
108
|
-
});
|
|
333
|
+
describe("math", () => {
|
|
334
|
+
test("addition", () => {
|
|
335
|
+
expect(2 + 2).toBe(4);
|
|
336
|
+
});
|
|
109
337
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
test("Type checking", () => {
|
|
116
|
-
expect("hello").toBeString();
|
|
117
|
-
expect(true).toBeBoolean();
|
|
118
|
-
expect(10.5).toBeNumber();
|
|
119
|
-
});
|
|
338
|
+
test("comparisons", () => {
|
|
339
|
+
expect(10).toBeGreaterThan(2);
|
|
340
|
+
expect(2).toBeLessThan(10);
|
|
341
|
+
});
|
|
120
342
|
});
|
|
121
343
|
|
|
122
|
-
|
|
344
|
+
describe("strings", () => {
|
|
345
|
+
it("contains", () => {
|
|
346
|
+
expect("assemblyscript").toContain("script");
|
|
347
|
+
});
|
|
123
348
|
|
|
124
|
-
|
|
125
|
-
test("
|
|
126
|
-
|
|
127
|
-
|
|
349
|
+
test("prefix", () => {
|
|
350
|
+
expect("as-test").toStartWith("as");
|
|
351
|
+
});
|
|
352
|
+
});
|
|
128
353
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
354
|
+
run();
|
|
355
|
+
`;
|
|
356
|
+
}
|
|
357
|
+
function buildWasiRunner() {
|
|
358
|
+
return `import { readFileSync } from "fs";
|
|
359
|
+
import { WASI } from "wasi";
|
|
132
360
|
|
|
133
|
-
|
|
361
|
+
const originalEmitWarning = process.emitWarning.bind(process);
|
|
362
|
+
process.emitWarning = ((warning, ...args) => {
|
|
363
|
+
const type = typeof args[0] == "string" ? args[0] : "";
|
|
364
|
+
const name = typeof warning?.name == "string" ? warning.name : type;
|
|
365
|
+
const message =
|
|
366
|
+
typeof warning == "string" ? warning : String(warning?.message ?? "");
|
|
367
|
+
if (
|
|
368
|
+
name == "ExperimentalWarning" &&
|
|
369
|
+
message.includes("WASI is an experimental feature")
|
|
370
|
+
) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
return originalEmitWarning(warning, ...args);
|
|
134
374
|
});
|
|
135
375
|
|
|
136
|
-
|
|
376
|
+
const wasmPath = process.argv[2];
|
|
377
|
+
if (!wasmPath) {
|
|
378
|
+
process.stderr.write("usage: node ./.as-test/runners/default.wasi.js <file.wasm>\\n");
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
137
381
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
writeFile("./tests/example.run.js", `import { readFileSync } from "fs";
|
|
146
|
-
import { instantiate } from "../build/example.spec.js";
|
|
382
|
+
try {
|
|
383
|
+
const wasi = new WASI({
|
|
384
|
+
version: "preview1",
|
|
385
|
+
args: [wasmPath],
|
|
386
|
+
env: process.env,
|
|
387
|
+
preopens: {},
|
|
388
|
+
});
|
|
147
389
|
|
|
148
|
-
const binary = readFileSync(
|
|
149
|
-
const module = new WebAssembly.Module(binary);
|
|
390
|
+
const binary = readFileSync(wasmPath);
|
|
391
|
+
const module = new WebAssembly.Module(binary);
|
|
392
|
+
const instance = new WebAssembly.Instance(module, {
|
|
393
|
+
wasi_snapshot_preview1: wasi.wasiImport,
|
|
394
|
+
});
|
|
395
|
+
wasi.start(instance);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
process.stderr.write("failed to run WASI module: " + String(error) + "\\n");
|
|
398
|
+
process.exit(1);
|
|
399
|
+
}
|
|
400
|
+
`;
|
|
401
|
+
}
|
|
402
|
+
function buildBindingsRunner() {
|
|
403
|
+
return `import fs from "fs";
|
|
404
|
+
import path from "path";
|
|
405
|
+
import { pathToFileURL } from "url";
|
|
150
406
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
pkg.scripts["test"] = "as-test run";
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
pkg.scripts["test"] = "as-test test";
|
|
169
|
-
}
|
|
170
|
-
if (!pkg["devDependencies"])
|
|
171
|
-
pkg["devDependencies"] = {};
|
|
172
|
-
if (!pkg["devDependencies"]["as-test"])
|
|
173
|
-
pkg["devDependencies"]["as-test"] = "^0.3.5";
|
|
174
|
-
if (target == "bindings") {
|
|
175
|
-
pkg["type"] = "module";
|
|
407
|
+
let patched = false;
|
|
408
|
+
|
|
409
|
+
function readExact(length) {
|
|
410
|
+
const out = Buffer.alloc(length);
|
|
411
|
+
let offset = 0;
|
|
412
|
+
while (offset < length) {
|
|
413
|
+
let read = 0;
|
|
414
|
+
try {
|
|
415
|
+
read = fs.readSync(0, out, offset, length - offset, null);
|
|
416
|
+
} catch (error) {
|
|
417
|
+
if (error && error.code === "EAGAIN") {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
throw error;
|
|
176
421
|
}
|
|
177
|
-
|
|
178
|
-
|
|
422
|
+
if (!read) break;
|
|
423
|
+
offset += read;
|
|
424
|
+
}
|
|
425
|
+
const view = out.subarray(0, offset);
|
|
426
|
+
return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
|
|
179
427
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
});
|
|
185
|
-
});
|
|
428
|
+
|
|
429
|
+
function writeRaw(data) {
|
|
430
|
+
const view = Buffer.from(data);
|
|
431
|
+
fs.writeSync(1, view);
|
|
186
432
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
433
|
+
|
|
434
|
+
function withNodeIo(imports = {}) {
|
|
435
|
+
if (!patched) {
|
|
436
|
+
patched = true;
|
|
437
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
438
|
+
process.stdout.write = (chunk, ...args) => {
|
|
439
|
+
if (chunk instanceof ArrayBuffer) {
|
|
440
|
+
writeRaw(chunk);
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
return originalWrite(chunk, ...args);
|
|
444
|
+
};
|
|
445
|
+
process.stdin.read = (size) => readExact(Number(size ?? 0));
|
|
446
|
+
}
|
|
447
|
+
return imports;
|
|
194
448
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
449
|
+
|
|
450
|
+
const wasmPathArg = process.argv[2];
|
|
451
|
+
if (!wasmPathArg) {
|
|
452
|
+
process.stderr.write("usage: node ./.as-test/runners/default.run.js <file.wasm>\\n");
|
|
453
|
+
process.exit(1);
|
|
200
454
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
455
|
+
|
|
456
|
+
const wasmPath = path.resolve(process.cwd(), wasmPathArg);
|
|
457
|
+
const jsPath = wasmPath.replace(/\\.wasm$/, ".js");
|
|
458
|
+
|
|
459
|
+
try {
|
|
460
|
+
const binary = fs.readFileSync(wasmPath);
|
|
461
|
+
const module = new WebAssembly.Module(binary);
|
|
462
|
+
const mod = await import(pathToFileURL(jsPath).href);
|
|
463
|
+
if (typeof mod.instantiate !== "function") {
|
|
464
|
+
throw new Error("bindings helper missing instantiate export");
|
|
465
|
+
}
|
|
466
|
+
mod.instantiate(module, withNodeIo({}));
|
|
467
|
+
} catch (error) {
|
|
468
|
+
process.stderr.write("failed to run bindings module: " + String(error) + "\\n");
|
|
469
|
+
process.exit(1);
|
|
470
|
+
}
|
|
471
|
+
`;
|
|
214
472
|
}
|
package/bin/reporter.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { createReporter } from "./reporters/default.js";
|