as-test 1.1.1 → 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 +8 -3
- package/README.md +14 -7
- package/as-test.config.schema.json +142 -142
- package/assembly/__fuzz__/math.fuzz.ts +17 -14
- package/assembly/__fuzz__/seed-perf.fuzz.ts +4 -2
- package/assembly/index.ts +1 -4
- package/assembly/src/expectation.ts +7 -1
- package/assembly/src/fuzz.ts +44 -23
- package/assembly/util/format.ts +10 -1
- package/assembly/util/wipc.ts +1 -2
- 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 +3 -1
- package/bin/commands/clean.js +0 -37
- 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 +301 -123
- package/bin/reporters/default.js +175 -33
- package/bin/util.js +36 -11
- package/lib/build/index.js +74 -24
- package/lib/src/index.ts +96 -35
- package/package.json +1 -1
- package/transform/lib/coverage.js +3 -1
package/lib/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import os from "os";
|
|
|
6
6
|
import path from "path";
|
|
7
7
|
import type { Duplex } from "stream";
|
|
8
8
|
import { pathToFileURL } from "url";
|
|
9
|
-
import { WASI } from "wasi";
|
|
9
|
+
import type { WASI } from "wasi";
|
|
10
10
|
import { buildWebRunnerClientSource } from "./web-runner/client.js";
|
|
11
11
|
import { buildWebRunnerHtml } from "./web-runner/html.js";
|
|
12
12
|
import { buildWebRunnerWorkerSource } from "./web-runner/worker.js";
|
|
@@ -45,26 +45,22 @@ export async function instantiate(
|
|
|
45
45
|
): Promise<WebAssembly.Instance> {
|
|
46
46
|
validateImports(imports, "instantiate");
|
|
47
47
|
|
|
48
|
-
const wasmPath =
|
|
49
|
-
|
|
50
|
-
throw new Error(
|
|
51
|
-
"AS_TEST_WASM_PATH is not set; as-test must resolve the wasm artifact before launching the runner",
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
const target = (process.env.AS_TEST_RUNTIME_TARGET || "bindings") as RuntimeTarget;
|
|
48
|
+
const wasmPath = resolveWasmPath();
|
|
49
|
+
const target = resolveRuntimeTarget();
|
|
55
50
|
if (target == "wasi") {
|
|
56
51
|
return instantiateWasiInstance(wasmPath, imports);
|
|
57
52
|
}
|
|
58
53
|
if (target == "web") {
|
|
59
54
|
return instantiateWebInstance(wasmPath, imports);
|
|
60
55
|
}
|
|
61
|
-
const
|
|
56
|
+
const helperPath = resolveBindingsHelperPath(wasmPath);
|
|
57
|
+
const kind = resolveBindingsKind(helperPath);
|
|
62
58
|
|
|
63
59
|
if (kind == "raw") {
|
|
64
|
-
return instantiateRawInstance(wasmPath, imports);
|
|
60
|
+
return instantiateRawInstance(wasmPath, helperPath, imports);
|
|
65
61
|
}
|
|
66
62
|
if (kind == "esm") {
|
|
67
|
-
return instantiateEsmInstance(wasmPath, imports);
|
|
63
|
+
return instantiateEsmInstance(wasmPath, helperPath, imports);
|
|
68
64
|
}
|
|
69
65
|
if (kind == "none") {
|
|
70
66
|
return instantiateNoBindingsInstance(wasmPath, imports);
|
|
@@ -72,6 +68,64 @@ export async function instantiate(
|
|
|
72
68
|
throw new Error(`unsupported bindings kind "${kind}"`);
|
|
73
69
|
}
|
|
74
70
|
|
|
71
|
+
function resolveRuntimeTarget(): RuntimeTarget {
|
|
72
|
+
const envTarget = process.env.AS_TEST_RUNTIME_TARGET?.trim();
|
|
73
|
+
if (envTarget == "bindings" || envTarget == "wasi" || envTarget == "web") {
|
|
74
|
+
return envTarget;
|
|
75
|
+
}
|
|
76
|
+
const runnerPath = String(process.argv[1] ?? "");
|
|
77
|
+
if (runnerPath.includes(".wasi.")) return "wasi";
|
|
78
|
+
if (runnerPath.includes(".web.")) return "web";
|
|
79
|
+
return "bindings";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function resolveWasmPath(): string {
|
|
83
|
+
const envWasmPath = process.env.AS_TEST_WASM_PATH?.trim();
|
|
84
|
+
if (envWasmPath?.length) {
|
|
85
|
+
return path.resolve(envWasmPath);
|
|
86
|
+
}
|
|
87
|
+
const argWasmPath = process.argv[2]?.trim();
|
|
88
|
+
if (argWasmPath?.length) {
|
|
89
|
+
return path.resolve(argWasmPath);
|
|
90
|
+
}
|
|
91
|
+
const runnerPath = String(process.argv[1] ?? "");
|
|
92
|
+
const runnerName = path.basename(runnerPath || "runner.js");
|
|
93
|
+
throw new Error(
|
|
94
|
+
[
|
|
95
|
+
"No wasm artifact was provided for this runner.",
|
|
96
|
+
"",
|
|
97
|
+
`Direct usage: node .as-test/runners/${runnerName} .as-test/build/<artifact>.wasm`,
|
|
98
|
+
"Managed usage: bunx ast test --mode <mode>",
|
|
99
|
+
"",
|
|
100
|
+
"as-test normally sets AS_TEST_WASM_PATH automatically when it launches the runner.",
|
|
101
|
+
].join("\n"),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function resolveBindingsHelperPath(wasmPath: string): string {
|
|
106
|
+
const envHelperPath = process.env.AS_TEST_HELPER_PATH?.trim();
|
|
107
|
+
if (envHelperPath?.length) {
|
|
108
|
+
return path.resolve(envHelperPath);
|
|
109
|
+
}
|
|
110
|
+
const candidate = wasmPath.replace(/\.wasm$/i, ".js");
|
|
111
|
+
return fs.existsSync(candidate) ? candidate : "";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function resolveBindingsKind(helperPath: string): BindingsKind {
|
|
115
|
+
const envKind = process.env.AS_TEST_BINDINGS_KIND?.trim();
|
|
116
|
+
if (envKind == "raw" || envKind == "esm" || envKind == "none") {
|
|
117
|
+
return envKind;
|
|
118
|
+
}
|
|
119
|
+
if (!helperPath.length) {
|
|
120
|
+
return "none";
|
|
121
|
+
}
|
|
122
|
+
const source = fs.readFileSync(helperPath, "utf8");
|
|
123
|
+
if (/\bexport\s+(?:async\s+)?function\s+instantiate\b/.test(source)) {
|
|
124
|
+
return "raw";
|
|
125
|
+
}
|
|
126
|
+
return "esm";
|
|
127
|
+
}
|
|
128
|
+
|
|
75
129
|
function validateImports(
|
|
76
130
|
imports: WebAssembly.Imports,
|
|
77
131
|
fnName: string,
|
|
@@ -173,16 +227,18 @@ function mergeImports(...groups: unknown[]): AnyImports {
|
|
|
173
227
|
|
|
174
228
|
async function instantiateRawInstance(
|
|
175
229
|
wasmPath: string,
|
|
230
|
+
helperPath: string,
|
|
176
231
|
imports: WebAssembly.Imports,
|
|
177
232
|
): Promise<WebAssembly.Instance> {
|
|
178
233
|
validateImports(imports, "instantiateRawInstance");
|
|
179
|
-
const helperPath = process.env.AS_TEST_HELPER_PATH || "";
|
|
180
234
|
if (!helperPath.length) {
|
|
181
235
|
throw new Error("bindings kind is raw but AS_TEST_HELPER_PATH is not set");
|
|
182
236
|
}
|
|
183
237
|
const binary = fs.readFileSync(wasmPath);
|
|
184
238
|
const module = new WebAssembly.Module(binary);
|
|
185
|
-
const helper = (await import(
|
|
239
|
+
const helper = (await import(
|
|
240
|
+
`${pathToFileURL(helperPath).href}?t=${Date.now()}`
|
|
241
|
+
)) as {
|
|
186
242
|
instantiate?: (
|
|
187
243
|
module: WebAssembly.Module,
|
|
188
244
|
imports?: WebAssembly.Imports,
|
|
@@ -200,10 +256,10 @@ async function instantiateRawInstance(
|
|
|
200
256
|
|
|
201
257
|
async function instantiateEsmInstance(
|
|
202
258
|
wasmPath: string,
|
|
259
|
+
helperPath: string,
|
|
203
260
|
imports: WebAssembly.Imports,
|
|
204
261
|
): Promise<WebAssembly.Instance> {
|
|
205
262
|
validateImports(imports, "instantiateEsmInstance");
|
|
206
|
-
const helperPath = process.env.AS_TEST_HELPER_PATH || "";
|
|
207
263
|
if (!helperPath.length) {
|
|
208
264
|
throw new Error("bindings kind is esm but AS_TEST_HELPER_PATH is not set");
|
|
209
265
|
}
|
|
@@ -233,6 +289,7 @@ async function instantiateWasiInstance(
|
|
|
233
289
|
): Promise<WebAssembly.Instance> {
|
|
234
290
|
validateImports(imports, "instantiateWasiInstance");
|
|
235
291
|
suppressExperimentalWasiWarning();
|
|
292
|
+
const { WASI } = await import("wasi");
|
|
236
293
|
const binary = fs.readFileSync(wasmPath);
|
|
237
294
|
const module = new WebAssembly.Module(binary);
|
|
238
295
|
const wasi = new WASI({
|
|
@@ -259,7 +316,8 @@ async function instantiateWebInstance(
|
|
|
259
316
|
);
|
|
260
317
|
}
|
|
261
318
|
|
|
262
|
-
const bindingsKind = (process.env.AS_TEST_BINDINGS_KIND ||
|
|
319
|
+
const bindingsKind = (process.env.AS_TEST_BINDINGS_KIND ||
|
|
320
|
+
"raw") as BindingsKind;
|
|
263
321
|
const helperPath = process.env.AS_TEST_HELPER_PATH
|
|
264
322
|
? path.resolve(process.cwd(), process.env.AS_TEST_HELPER_PATH)
|
|
265
323
|
: wasmPath.replace(/\.wasm$/, ".js");
|
|
@@ -378,9 +436,11 @@ async function instantiateWebInstance(
|
|
|
378
436
|
if (message?.kind == "instantiated") {
|
|
379
437
|
if (resolved) return;
|
|
380
438
|
resolved = true;
|
|
381
|
-
resolve(
|
|
382
|
-
|
|
383
|
-
|
|
439
|
+
resolve(
|
|
440
|
+
createWebInstanceController(() => {
|
|
441
|
+
sendControl({ kind: "start" });
|
|
442
|
+
}),
|
|
443
|
+
);
|
|
384
444
|
return;
|
|
385
445
|
}
|
|
386
446
|
if (message?.kind == "done") {
|
|
@@ -477,9 +537,9 @@ async function instantiateWebInstance(
|
|
|
477
537
|
res.end(
|
|
478
538
|
html.replace(
|
|
479
539
|
"</body>",
|
|
480
|
-
|
|
540
|
+
" <script>window.__AS_TEST_ENV__ = " +
|
|
481
541
|
JSON.stringify(webRuntimeEnv) +
|
|
482
|
-
|
|
542
|
+
";</script>\n </body>",
|
|
483
543
|
),
|
|
484
544
|
);
|
|
485
545
|
return;
|
|
@@ -561,11 +621,7 @@ async function instantiateWebInstance(
|
|
|
561
621
|
});
|
|
562
622
|
socket.on("error", (error) => {
|
|
563
623
|
if (!finished) {
|
|
564
|
-
rejectOnce(
|
|
565
|
-
error instanceof Error
|
|
566
|
-
? error
|
|
567
|
-
: new Error(String(error)),
|
|
568
|
-
);
|
|
624
|
+
rejectOnce(error instanceof Error ? error : new Error(String(error)));
|
|
569
625
|
}
|
|
570
626
|
});
|
|
571
627
|
flushPendingFrames();
|
|
@@ -622,7 +678,9 @@ async function instantiateWebInstance(
|
|
|
622
678
|
return;
|
|
623
679
|
}
|
|
624
680
|
if (code && code != 0) {
|
|
625
|
-
rejectOnce(
|
|
681
|
+
rejectOnce(
|
|
682
|
+
new Error(formatBrowserExitError(code, browserStderr)),
|
|
683
|
+
);
|
|
626
684
|
return;
|
|
627
685
|
}
|
|
628
686
|
if (ready || wsSocket) {
|
|
@@ -631,9 +689,7 @@ async function instantiateWebInstance(
|
|
|
631
689
|
});
|
|
632
690
|
}
|
|
633
691
|
} catch (error) {
|
|
634
|
-
rejectOnce(
|
|
635
|
-
error instanceof Error ? error : new Error(String(error)),
|
|
636
|
-
);
|
|
692
|
+
rejectOnce(error instanceof Error ? error : new Error(String(error)));
|
|
637
693
|
}
|
|
638
694
|
});
|
|
639
695
|
});
|
|
@@ -680,7 +736,7 @@ function suppressExperimentalWasiWarning(): void {
|
|
|
680
736
|
? warning
|
|
681
737
|
: String(
|
|
682
738
|
warning && typeof warning == "object" && "message" in warning
|
|
683
|
-
? (warning as { message?: unknown }).message ?? ""
|
|
739
|
+
? ((warning as { message?: unknown }).message ?? "")
|
|
684
740
|
: "",
|
|
685
741
|
);
|
|
686
742
|
if (
|
|
@@ -831,7 +887,9 @@ function launchWebBrowser(
|
|
|
831
887
|
function openWithReusableBrowserWindow(url: string): ChildProcess | null {
|
|
832
888
|
if (process.platform != "darwin") return null;
|
|
833
889
|
if (!hasExecutable("osascript")) return null;
|
|
834
|
-
const browserApp = resolveMacBrowserAppName(
|
|
890
|
+
const browserApp = resolveMacBrowserAppName(
|
|
891
|
+
process.env.BROWSER?.trim() ?? "",
|
|
892
|
+
);
|
|
835
893
|
if (!browserApp) return null;
|
|
836
894
|
const script = buildMacBrowserOpenScript(browserApp, url);
|
|
837
895
|
if (!script.length) return null;
|
|
@@ -844,7 +902,9 @@ function openWithReusableBrowserWindow(url: string): ChildProcess | null {
|
|
|
844
902
|
|
|
845
903
|
function openWithSystemBrowser(url: string): ChildProcess | null {
|
|
846
904
|
if (process.env.BROWSER) {
|
|
847
|
-
return
|
|
905
|
+
return (
|
|
906
|
+
spawnBrowserCommand(process.env.BROWSER, url, false)?.process ?? null
|
|
907
|
+
);
|
|
848
908
|
}
|
|
849
909
|
if (process.platform == "darwin") {
|
|
850
910
|
if (!hasExecutable("open")) return null;
|
|
@@ -901,7 +961,7 @@ function buildMacBrowserOpenScript(appName: string, url: string): string[] {
|
|
|
901
961
|
return [
|
|
902
962
|
`tell application "${escapedApp}"`,
|
|
903
963
|
"activate",
|
|
904
|
-
|
|
964
|
+
"if (count of windows) = 0 then make new window",
|
|
905
965
|
`set URL of active tab of front window to "${escapedUrl}"`,
|
|
906
966
|
"end tell",
|
|
907
967
|
];
|
|
@@ -910,7 +970,7 @@ function buildMacBrowserOpenScript(appName: string, url: string): string[] {
|
|
|
910
970
|
return [
|
|
911
971
|
`tell application "${escapedApp}"`,
|
|
912
972
|
"activate",
|
|
913
|
-
|
|
973
|
+
"if (count of windows) = 0 then make new document",
|
|
914
974
|
`set URL of front document to "${escapedUrl}"`,
|
|
915
975
|
"end tell",
|
|
916
976
|
];
|
|
@@ -1256,7 +1316,8 @@ async function captureHelperInstance(
|
|
|
1256
1316
|
try {
|
|
1257
1317
|
await runHelper();
|
|
1258
1318
|
} finally {
|
|
1259
|
-
WebAssembly.instantiate =
|
|
1319
|
+
WebAssembly.instantiate =
|
|
1320
|
+
originalInstantiate as typeof WebAssembly.instantiate;
|
|
1260
1321
|
}
|
|
1261
1322
|
|
|
1262
1323
|
if (!instance) {
|
package/package.json
CHANGED
|
@@ -214,7 +214,9 @@ export class CoverageTransform extends Visitor {
|
|
|
214
214
|
const ifTrue = node.ifTrue;
|
|
215
215
|
const ifFalse = node.ifFalse;
|
|
216
216
|
const path = node.range.source.normalizedPath;
|
|
217
|
-
if (ifTrue
|
|
217
|
+
if (ifTrue &&
|
|
218
|
+
ifTrue.kind !== 31 &&
|
|
219
|
+
!isBuiltinStatement(ifTrue)) {
|
|
218
220
|
const trueLc = getLineCol(ifTrue);
|
|
219
221
|
const point = new CoverPoint();
|
|
220
222
|
point.line = trueLc?.line;
|