gofront 1.8.0 → 1.9.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/README.md +3 -3
- package/package.json +6 -5
- package/src/backend/js/expressions.js +1157 -408
- package/src/backend/js/index.js +327 -153
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +559 -2552
- package/src/backend/js/statements.js +670 -158
- package/src/backend/js/stdlib/index.js +45 -93
- package/src/backend/js/templ.js +32 -45
- package/src/backend/js/type-info.js +298 -19
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +91 -170
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +490 -965
- package/src/backend/wasm/emit-builtins.js +884 -256
- package/src/backend/wasm/emit-exprs.js +185 -77
- package/src/backend/wasm/emit-maps.js +17 -367
- package/src/backend/wasm/emit-shared.js +4 -1
- package/src/backend/wasm/emit-stmts.js +524 -240
- package/src/backend/wasm/emit.js +176 -38
- package/src/backend/wasm/globals.js +48 -8
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +44 -530
- package/src/backend/wasm/method-expr.js +12 -1
- package/src/backend/wasm/module-emitter.js +299 -770
- package/src/backend/wasm/monomorph.js +139 -8
- package/src/backend/wasm/natives.js +600 -0
- package/src/backend/wasm/prescan.js +5 -153
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -32
- package/src/backend/wasm/types.js +97 -20
- package/src/backend/wasm/variadic.js +9 -4
- package/src/cli/cli-core.js +5 -1
- package/src/cli/test-runner.js +115 -342
- package/src/compiler.js +113 -130
- package/src/lexer/lexer.js +106 -11
- package/src/lexer/templ-lexer.js +61 -18
- package/src/lexer/tokens.js +1 -0
- package/src/link/stdlib.js +355 -132
- package/src/link/type-names.js +204 -0
- package/src/link/wasm.js +30 -6
- package/src/lower/bounds.js +153 -0
- package/src/lower/captures.js +92 -33
- package/src/lower/embedding.js +62 -5
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +929 -0
- package/src/lower/functions.js +225 -7
- package/src/lower/gen-types.js +293 -0
- package/src/lower/index.js +14 -2
- package/src/lower/json-codecs.js +334 -245
- package/src/lower/ownership.js +25 -7
- package/src/lower/reachability.js +69 -51
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +30 -5
- package/src/parser/expressions.js +111 -57
- package/src/parser/statements.js +108 -0
- package/src/parser/templ.js +44 -5
- package/src/parser/types.js +12 -0
- package/src/resolver.js +1 -2
- package/src/typechecker/assignability.js +214 -19
- package/src/typechecker/const-fold.js +70 -27
- package/src/typechecker/constants.js +156 -8
- package/src/typechecker/expressions.js +490 -108
- package/src/typechecker/index.js +346 -42
- package/src/typechecker/init-order.js +136 -40
- package/src/typechecker/operand-text.js +41 -0
- package/src/typechecker/resolve.js +490 -65
- package/src/typechecker/statements.js +288 -27
- package/src/typechecker/stdlib/excluded.js +9 -5
- package/src/typechecker/stdlib/index.js +25 -9
- package/src/typechecker/termination.js +10 -1
- package/src/typechecker/types.js +287 -575
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +171 -38
- package/stdlib/internal/jsonrt/enc.go +186 -36
- package/stdlib/internal/jsonrt/scanner.go +17 -8
- package/stdlib/io/io.go +157 -1
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +16 -14
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +391 -452
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +235 -50
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +141 -3
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/fmt-runtime.js +0 -573
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -119
- package/src/backend/js/stdlib/builder.js +0 -98
- package/src/backend/js/stdlib/bytes.js +0 -368
- package/src/backend/js/stdlib/errors.js +0 -45
- package/src/backend/js/stdlib/fmt.js +0 -517
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -1167
- package/src/backend/js/stdlib/maps.js +0 -37
- package/src/backend/js/stdlib/math.js +0 -85
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -34
- package/src/backend/js/stdlib/slices.js +0 -107
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -79
- package/src/backend/js/stdlib/strings.js +0 -301
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -41
- package/src/backend/js/stdlib/time.js +0 -152
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/stdlib/bytes.js +0 -6716
- package/src/backend/wasm/stdlib/core.js +0 -10278
- package/src/backend/wasm/stdlib/io.js +0 -3578
- package/src/backend/wasm/stdlib/packages.js +0 -2402
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -2229
- package/src/typechecker/stdlib/core.js +0 -1079
- package/src/typechecker/stdlib/extended.js +0 -1210
- package/stdlib/bytes/iter.go +0 -192
- package/stdlib/bytes/search.go +0 -240
- package/stdlib/bytes/split.go +0 -218
- package/stdlib/errors/overlay.go +0 -12
- package/stdlib/maps/iter.go +0 -65
- package/stdlib/slices/extra.go +0 -73
- package/stdlib/slices/iter.go +0 -113
- package/stdlib/strings/extra.go +0 -35
- package/stdlib/strings/iter.go +0 -122
- package/stdlib/sync/extra.go +0 -105
- package/stdlib/unicode/utf8/bytes.go +0 -239
package/src/cli/test-runner.js
CHANGED
|
@@ -6,7 +6,6 @@ import { statSync } from "node:fs";
|
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { basename, dirname, join, resolve } from "node:path";
|
|
8
8
|
import { pathToFileURL } from "node:url";
|
|
9
|
-
import { HELPER_SPRINTF, HELPER_TESTING } from "../backend/js/runtime.js";
|
|
10
9
|
import {
|
|
11
10
|
compilePackageTests,
|
|
12
11
|
compilePackageTestsWasm,
|
|
@@ -97,6 +96,19 @@ export function discoverTests(programs) {
|
|
|
97
96
|
return testNames;
|
|
98
97
|
}
|
|
99
98
|
|
|
99
|
+
// The `async func Test…` names (js packages only).
|
|
100
|
+
export function discoverAsyncTests(programs) {
|
|
101
|
+
const names = [];
|
|
102
|
+
for (const p of programs) {
|
|
103
|
+
if (p._filename && !p._filename.endsWith("_test.go")) continue;
|
|
104
|
+
for (const d of p.decls) {
|
|
105
|
+
if (isTestFunc(d) && (d.async || d.isAsync) && !names.includes(d.name))
|
|
106
|
+
names.push(d.name);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return names;
|
|
110
|
+
}
|
|
111
|
+
|
|
100
112
|
export function discoverBenchmarks(programs) {
|
|
101
113
|
const benchNames = [];
|
|
102
114
|
for (const p of programs) {
|
|
@@ -120,15 +132,53 @@ export function discoverTestMain(programs) {
|
|
|
120
132
|
return null;
|
|
121
133
|
}
|
|
122
134
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
// The Go source of the driver the runner compiles with a package's tests (see
|
|
136
|
+
// `testDriver` in compileFiles; it is never written to disk). `target` is the
|
|
137
|
+
// package's target: a `js` package is driven asynchronously so that async
|
|
138
|
+
// tests and subtests can be awaited; a TestMain gets the M and runs it
|
|
139
|
+
// itself.
|
|
140
|
+
export function generateTestDriver(
|
|
141
|
+
pkgName,
|
|
142
|
+
target,
|
|
143
|
+
{ testNames, benchNames, testMain, asyncTests = [] },
|
|
144
|
+
) {
|
|
145
|
+
if (testMain && asyncTests.length > 0) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`async test functions cannot be combined with TestMain (${asyncTests.join(", ")}): remove TestMain or make the tests synchronous`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const entries = (names, _type) =>
|
|
151
|
+
names.map((n) => `\t\t{Name: ${JSON.stringify(n)}, F: ${n}},`).join("\n");
|
|
152
|
+
const table = (type, names) =>
|
|
153
|
+
names.length === 0
|
|
154
|
+
? `[]testing.${type}{}`
|
|
155
|
+
: `[]testing.${type}{\n${entries(names)}\n\t}`;
|
|
156
|
+
const make = `\tm := testing.GofrontMain(${JSON.stringify(pkgName)}, run, bench, verbose, ${table("GofrontTest", testNames)}, ${table("GofrontBenchmark", benchNames)})`;
|
|
157
|
+
let body;
|
|
158
|
+
let head = "func";
|
|
159
|
+
if (testMain) {
|
|
160
|
+
body = `\tTestMain(m)\n\treturn m.ExitCode()`;
|
|
161
|
+
} else if (target === "js") {
|
|
162
|
+
head = "async func";
|
|
163
|
+
body = "\treturn await m.RunAsync()";
|
|
164
|
+
} else {
|
|
165
|
+
body = "\treturn m.Run()";
|
|
166
|
+
}
|
|
167
|
+
return `package ${pkgName}
|
|
168
|
+
|
|
169
|
+
import "testing"
|
|
170
|
+
|
|
171
|
+
${head} GofrontRunTests(run, bench string, verbose bool) int {
|
|
172
|
+
${make}
|
|
173
|
+
${body}
|
|
174
|
+
}
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// The module the test child process runs: the compiled package (with its
|
|
179
|
+
// driver), then one call to GofrontRunTests. Everything else (running,
|
|
180
|
+
// filtering, reporting) happens inside the package.
|
|
181
|
+
export function generateTestHarness(bundleJs, options = {}) {
|
|
132
182
|
const verbose = Boolean(options.verbose);
|
|
133
183
|
const dom = Boolean(options.dom);
|
|
134
184
|
const color = Boolean(options.color);
|
|
@@ -138,14 +188,12 @@ export function generateTestHarness(bundleJs, testNames, options = {}) {
|
|
|
138
188
|
const jsdomSpec = options.jsdomPath
|
|
139
189
|
? pathToFileURL(options.jsdomPath).href
|
|
140
190
|
: "jsdom";
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
]),
|
|
148
|
-
];
|
|
191
|
+
const run = options.run ?? "";
|
|
192
|
+
const bench = options.bench
|
|
193
|
+
? options.bench === true
|
|
194
|
+
? "."
|
|
195
|
+
: options.bench
|
|
196
|
+
: "";
|
|
149
197
|
|
|
150
198
|
return `
|
|
151
199
|
${
|
|
@@ -177,14 +225,12 @@ globalThis.customElements = __dom.window.customElements;
|
|
|
177
225
|
globalThis.document = globalThis.document ?? null;
|
|
178
226
|
`
|
|
179
227
|
}
|
|
180
|
-
|
|
228
|
+
// The package line and colours the testing package prints come from here.
|
|
229
|
+
process.env.GOFRONT_TEST_LABEL = ${JSON.stringify(pkgName)};
|
|
230
|
+
process.env.GOFRONT_TEST_COLOR = ${color ? '"1"' : '"0"'};
|
|
181
231
|
${
|
|
182
232
|
options.wasmBytes
|
|
183
|
-
? `
|
|
184
|
-
// ── WASM module (tests run inside app.wasm; *testing.T stays in JS) ──
|
|
185
|
-
${HELPER_SPRINTF}
|
|
186
|
-
${HELPER_TESTING}
|
|
187
|
-
globalThis.__GOFRONT_WASM_BYTES = Uint8Array.from(atob(${JSON.stringify(Buffer.from(options.wasmBytes).toString("base64"))}), (c) => c.charCodeAt(0));
|
|
233
|
+
? `globalThis.__GOFRONT_WASM_BYTES = Uint8Array.from(atob(${JSON.stringify(Buffer.from(options.wasmBytes).toString("base64"))}), (c) => c.charCodeAt(0));
|
|
188
234
|
`
|
|
189
235
|
: ""
|
|
190
236
|
}
|
|
@@ -192,313 +238,13 @@ globalThis.__GOFRONT_WASM_BYTES = Uint8Array.from(atob(${JSON.stringify(Buffer.f
|
|
|
192
238
|
${bundleJs}
|
|
193
239
|
// ─────────────────────────────
|
|
194
240
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const benchFilter = ${benchRegex ? `new RegExp(${JSON.stringify(benchRegex)})` : "null"};
|
|
201
|
-
const verbose = ${verbose};
|
|
202
|
-
const pkgName = ${JSON.stringify(pkgName)};
|
|
203
|
-
const paint = ${color}
|
|
204
|
-
? (code) => (s) => "\\x1b[" + code + "m" + s + "\\x1b[0m"
|
|
205
|
-
: () => (s) => s;
|
|
206
|
-
const red = paint(31), green = paint(32), yellow = paint(33), dim = paint(2), bold = paint(1);
|
|
207
|
-
const PASS = green("PASS"), FAIL = bold(red("FAIL")), SKIP = yellow("SKIP");
|
|
208
|
-
const okLine = (name, t) => console.log(green("ok ") + "\\t" + name + "\\t" + dim(t + "s"));
|
|
209
|
-
|
|
210
|
-
const testsToRun = runFilter
|
|
211
|
-
? allTests.filter((name) => runFilter.test(name))
|
|
212
|
-
: allTests;
|
|
213
|
-
|
|
214
|
-
const benchesToRun = benchFilter
|
|
215
|
-
? allBenchmarks.filter((name) => benchFilter.test(name))
|
|
216
|
-
: [];
|
|
217
|
-
|
|
218
|
-
if (testsToRun.length === 0 && benchesToRun.length === 0) {
|
|
219
|
-
if (allTests.length > 0 && runFilter) {
|
|
220
|
-
console.log(yellow("testing: warning: no tests to run matching " + ${JSON.stringify(runRegex)}));
|
|
221
|
-
}
|
|
222
|
-
if (allBenchmarks.length > 0 && benchFilter) {
|
|
223
|
-
console.log(yellow("testing: warning: no benchmarks to run matching " + ${JSON.stringify(benchRegex)}));
|
|
224
|
-
}
|
|
225
|
-
console.log(PASS);
|
|
226
|
-
okLine(pkgName, "0.000");
|
|
227
|
-
process.exit(0);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const now = () => (typeof performance !== "undefined" ? performance.now() : Date.now());
|
|
231
|
-
|
|
232
|
-
// Go-style streaming report. In non-verbose mode only failures and skips are
|
|
233
|
-
// shown, so the "=== RUN" header is emitted late for failures.
|
|
234
|
-
const report = (t) => {
|
|
235
|
-
const elapsed = dim("(" + ((now() - t._start) / 1000).toFixed(2) + "s)");
|
|
236
|
-
if (t.skipped) {
|
|
237
|
-
console.log("--- " + SKIP + ": " + t._name + " " + elapsed);
|
|
238
|
-
for (const log of t._logs) console.log(" " + log);
|
|
239
|
-
} else if (t.failed) {
|
|
240
|
-
if (!verbose) console.log(dim("=== RUN ") + t._name);
|
|
241
|
-
for (const log of t._logs) console.log(" " + red(log));
|
|
242
|
-
console.log("--- " + FAIL + ": " + t._name + " " + elapsed);
|
|
243
|
-
} else if (verbose) {
|
|
244
|
-
for (const log of t._logs) console.log(" " + log);
|
|
245
|
-
console.log("--- " + PASS + ": " + t._name + " " + elapsed);
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
const reportBenchmark = (b) => {
|
|
250
|
-
if (b.skipped) {
|
|
251
|
-
console.log("--- " + SKIP + ": " + b._name);
|
|
252
|
-
for (const log of b._logs) console.log(" " + log);
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
if (b.failed) {
|
|
256
|
-
console.log("--- " + FAIL + ": " + b._name);
|
|
257
|
-
for (const log of b._logs) console.log(" " + red(log));
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
const elapsedNs = Number(b.Elapsed());
|
|
261
|
-
const nsPerOp = b.N > 0 ? (elapsedNs / b.N).toFixed(0) : "0";
|
|
262
|
-
let line = \`\${b._name.padEnd(20)}\\t\${String(b.N).padStart(8)}\\t\${nsPerOp.padStart(10)} ns/op\`;
|
|
263
|
-
if (b._bytes > 0n && elapsedNs > 0) {
|
|
264
|
-
const mbPerSec = (Number(b._bytes * BigInt(b.N)) / (elapsedNs / 1e9) / (1024 * 1024)).toFixed(2);
|
|
265
|
-
line += \`\\t\${mbPerSec.padStart(8)} MB/s\`;
|
|
266
|
-
}
|
|
267
|
-
console.log(line);
|
|
268
|
-
for (const log of b._logs) console.log(" " + log);
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
// FailNow/SkipNow are control flow; anything else is a panic → failure.
|
|
272
|
-
const recordTestError = (t, e) => {
|
|
273
|
-
if (e instanceof __GoFront_FailNow || e instanceof __GoFront_SkipNow) return;
|
|
274
|
-
t.Fail();
|
|
275
|
-
t.Log("panic: " + (e?.message ?? String(e)));
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
globalThis.__onSubtestStart = (name) => {
|
|
279
|
-
if (verbose) console.log(dim("=== RUN ") + name);
|
|
280
|
-
};
|
|
281
|
-
globalThis.__onSubtestEnd = report;
|
|
282
|
-
|
|
283
|
-
const __testRegistry = {
|
|
284
|
-
${allFuncNames.map((n) => ` ${JSON.stringify(n)}: typeof ${n} !== "undefined" ? ${n} : null`).join(",\n")}
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
function runAll() {
|
|
288
|
-
let totalFailures = 0;
|
|
289
|
-
let totalSkipped = 0;
|
|
290
|
-
const suiteStart = now();
|
|
291
|
-
|
|
292
|
-
const finish = () => {
|
|
293
|
-
const suiteElapsed = ((now() - suiteStart) / 1000).toFixed(3);
|
|
294
|
-
if (totalFailures > 0) {
|
|
295
|
-
console.log(FAIL);
|
|
296
|
-
console.log(FAIL + "\\t" + pkgName + "\\t" + dim(suiteElapsed + "s"));
|
|
297
|
-
return 1;
|
|
298
|
-
} else {
|
|
299
|
-
console.log(PASS);
|
|
300
|
-
okLine(pkgName, suiteElapsed);
|
|
301
|
-
return 0;
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
const runOneTest = (name) => {
|
|
306
|
-
const fn = __testRegistry[name] ?? (typeof globalThis[name] === "function" ? globalThis[name] : null);
|
|
307
|
-
if (typeof fn !== "function") {
|
|
308
|
-
console.error(red("testing: cannot find test function " + name));
|
|
309
|
-
totalFailures++;
|
|
310
|
-
return null;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const t = new __GoFront_T(name);
|
|
314
|
-
if (verbose) console.log(dim("=== RUN ") + name);
|
|
315
|
-
|
|
316
|
-
let res;
|
|
317
|
-
try {
|
|
318
|
-
res = fn(t);
|
|
319
|
-
} catch (e) {
|
|
320
|
-
recordTestError(t, e);
|
|
321
|
-
t._runCleanups();
|
|
322
|
-
if (t.skipped) totalSkipped++;
|
|
323
|
-
else if (t.failed) totalFailures++;
|
|
324
|
-
report(t);
|
|
325
|
-
return null;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (res && typeof res.then === "function") {
|
|
329
|
-
return res
|
|
330
|
-
.catch((e) => { recordTestError(t, e); })
|
|
331
|
-
.finally(() => {
|
|
332
|
-
t._runCleanups();
|
|
333
|
-
if (t.skipped) totalSkipped++;
|
|
334
|
-
else if (t.failed) totalFailures++;
|
|
335
|
-
report(t);
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
t._runCleanups();
|
|
340
|
-
if (t.skipped) totalSkipped++;
|
|
341
|
-
else if (t.failed) totalFailures++;
|
|
342
|
-
report(t);
|
|
343
|
-
return null;
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
const runOneBench = (name) => {
|
|
347
|
-
const fn = __testRegistry[name] ?? (typeof globalThis[name] === "function" ? globalThis[name] : null);
|
|
348
|
-
if (typeof fn !== "function") {
|
|
349
|
-
console.error(red("testing: cannot find benchmark function " + name));
|
|
350
|
-
totalFailures++;
|
|
351
|
-
return null;
|
|
352
|
-
}
|
|
353
|
-
if (verbose) console.log(dim("=== RUN ") + name);
|
|
354
|
-
const b = new __GoFront_B(name);
|
|
355
|
-
b._benchDurationNs = 1e8; // 100ms
|
|
356
|
-
const runIters = () => {
|
|
357
|
-
b.N = 1;
|
|
358
|
-
b.ResetTimer();
|
|
359
|
-
const res = fn(b);
|
|
360
|
-
if (res && typeof res.then === "function") {
|
|
361
|
-
return res.then(() => loopBench(b, fn));
|
|
362
|
-
}
|
|
363
|
-
return loopBench(b, fn);
|
|
364
|
-
};
|
|
365
|
-
const loopBench = (b, fn) => {
|
|
366
|
-
if (!b._loopStarted && !b.failed && !b.skipped) {
|
|
367
|
-
b.StopTimer();
|
|
368
|
-
b._runCleanups();
|
|
369
|
-
let n = 1;
|
|
370
|
-
while (!b.failed && !b.skipped) {
|
|
371
|
-
const elapsedNs = Number(b.Elapsed());
|
|
372
|
-
if (elapsedNs >= b._benchDurationNs || n >= 1e9) break;
|
|
373
|
-
let nextN;
|
|
374
|
-
if (elapsedNs === 0) nextN = n * 100;
|
|
375
|
-
else nextN = Math.max(n + 1, Math.min(1e9, Math.floor(n * (b._benchDurationNs / elapsedNs) * 1.2)));
|
|
376
|
-
if (nextN <= n) break;
|
|
377
|
-
n = nextN;
|
|
378
|
-
const nextB = new __GoFront_B(name);
|
|
379
|
-
nextB._benchDurationNs = b._benchDurationNs;
|
|
380
|
-
nextB.N = n;
|
|
381
|
-
nextB.ResetTimer();
|
|
382
|
-
const res = fn(nextB);
|
|
383
|
-
if (res && typeof res.then === "function") {
|
|
384
|
-
return res.then(() => {
|
|
385
|
-
nextB.StopTimer();
|
|
386
|
-
nextB._runCleanups();
|
|
387
|
-
b.N = nextB.N;
|
|
388
|
-
b._elapsedMs = nextB._elapsedMs;
|
|
389
|
-
b._timerRunning = false;
|
|
390
|
-
b.failed = nextB.failed;
|
|
391
|
-
b.skipped = nextB.skipped;
|
|
392
|
-
b._logs = nextB._logs;
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
nextB.StopTimer();
|
|
396
|
-
nextB._runCleanups();
|
|
397
|
-
b.N = nextB.N;
|
|
398
|
-
b._elapsedMs = nextB._elapsedMs;
|
|
399
|
-
b._timerRunning = false;
|
|
400
|
-
b.failed = nextB.failed;
|
|
401
|
-
b.skipped = nextB.skipped;
|
|
402
|
-
b._logs = nextB._logs;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
|
|
407
|
-
let res;
|
|
408
|
-
try {
|
|
409
|
-
res = runIters();
|
|
410
|
-
} catch (e) {
|
|
411
|
-
recordTestError(b, e);
|
|
412
|
-
b._runCleanups();
|
|
413
|
-
if (b.failed) totalFailures++;
|
|
414
|
-
else if (b.skipped) totalSkipped++;
|
|
415
|
-
reportBenchmark(b);
|
|
416
|
-
return null;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if (res && typeof res.then === "function") {
|
|
420
|
-
return res
|
|
421
|
-
.catch((e) => { recordTestError(b, e); })
|
|
422
|
-
.finally(() => {
|
|
423
|
-
b._runCleanups();
|
|
424
|
-
if (b.failed) totalFailures++;
|
|
425
|
-
else if (b.skipped) totalSkipped++;
|
|
426
|
-
reportBenchmark(b);
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
b._runCleanups();
|
|
431
|
-
if (b.failed) totalFailures++;
|
|
432
|
-
else if (b.skipped) totalSkipped++;
|
|
433
|
-
reportBenchmark(b);
|
|
434
|
-
return null;
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
let ti = 0;
|
|
438
|
-
while (ti < testsToRun.length) {
|
|
439
|
-
const p = runOneTest(testsToRun[ti++]);
|
|
440
|
-
if (p) {
|
|
441
|
-
return p.then(async () => {
|
|
442
|
-
while (ti < testsToRun.length) {
|
|
443
|
-
const nextP = runOneTest(testsToRun[ti++]);
|
|
444
|
-
if (nextP) await nextP;
|
|
445
|
-
}
|
|
446
|
-
for (const bName of benchesToRun) {
|
|
447
|
-
const nextP = runOneBench(bName);
|
|
448
|
-
if (nextP) await nextP;
|
|
449
|
-
}
|
|
450
|
-
return finish();
|
|
451
|
-
});
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
let bi = 0;
|
|
456
|
-
while (bi < benchesToRun.length) {
|
|
457
|
-
const p = runOneBench(benchesToRun[bi++]);
|
|
458
|
-
if (p) {
|
|
459
|
-
return p.then(async () => {
|
|
460
|
-
while (bi < benchesToRun.length) {
|
|
461
|
-
const nextP = runOneBench(benchesToRun[bi++]);
|
|
462
|
-
if (nextP) await nextP;
|
|
463
|
-
}
|
|
464
|
-
return finish();
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
return finish();
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
if (testMainName) {
|
|
473
|
-
const mainFn = __testRegistry[testMainName] ?? (typeof globalThis[testMainName] === "function" ? globalThis[testMainName] : null);
|
|
474
|
-
if (typeof mainFn === "function") {
|
|
475
|
-
let exitCode = 0;
|
|
476
|
-
const m = new __GoFront_M(() => {
|
|
477
|
-
const res = runAll();
|
|
478
|
-
if (res && typeof res.then === "function") {
|
|
479
|
-
return res.then((code) => { exitCode = code; return code; });
|
|
480
|
-
}
|
|
481
|
-
exitCode = res;
|
|
482
|
-
return exitCode;
|
|
483
|
-
});
|
|
484
|
-
try {
|
|
485
|
-
const res = mainFn(m);
|
|
486
|
-
if (res && typeof res.then === "function") await res;
|
|
487
|
-
} catch (e) {
|
|
488
|
-
console.error(red("panic in TestMain: " + (e?.message ?? String(e))));
|
|
489
|
-
process.exit(1);
|
|
490
|
-
}
|
|
491
|
-
if (m._promise) await m._promise;
|
|
492
|
-
process.exit(exitCode);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
const res = runAll();
|
|
497
|
-
const exitCode = res && typeof res.then === "function" ? await res : res;
|
|
498
|
-
process.exit(exitCode);
|
|
241
|
+
let __exitCode = 1;
|
|
242
|
+
try {
|
|
243
|
+
__exitCode = Number(await GofrontRunTests(${JSON.stringify(run)}, ${JSON.stringify(bench)}, ${verbose}));
|
|
244
|
+
} catch (e) {
|
|
245
|
+
console.error("panic: " + (e?.message ?? String(e)));
|
|
499
246
|
}
|
|
500
|
-
|
|
501
|
-
__runGoFrontSuite();
|
|
247
|
+
process.exit(__exitCode);
|
|
502
248
|
`;
|
|
503
249
|
}
|
|
504
250
|
|
|
@@ -613,10 +359,16 @@ function reportBuildFailure(err, resolvedDir, options) {
|
|
|
613
359
|
|
|
614
360
|
// `both` packages run twice (JS and wasm) so the two backends are kept in
|
|
615
361
|
// agreement; output of both runs is concatenated.
|
|
616
|
-
async function runDualTarget(
|
|
362
|
+
async function runDualTarget(
|
|
363
|
+
compiled,
|
|
364
|
+
resolvedDir,
|
|
365
|
+
runHarness,
|
|
366
|
+
compileOptions,
|
|
367
|
+
options,
|
|
368
|
+
) {
|
|
617
369
|
let wasmCompiled;
|
|
618
370
|
try {
|
|
619
|
-
wasmCompiled = compilePackageTestsWasm(resolvedDir,
|
|
371
|
+
wasmCompiled = compilePackageTestsWasm(resolvedDir, compileOptions);
|
|
620
372
|
} catch (err) {
|
|
621
373
|
return reportBuildFailure(err, resolvedDir, options);
|
|
622
374
|
}
|
|
@@ -654,18 +406,35 @@ export async function runTests(targetDir, options = {}) {
|
|
|
654
406
|
return reportEmptyTests(basename(resolvedDir), "no test files", options);
|
|
655
407
|
}
|
|
656
408
|
|
|
409
|
+
// The driver is generated while the package compiles, once its files are
|
|
410
|
+
// parsed and its target is known.
|
|
411
|
+
let testNames = [];
|
|
412
|
+
let benchNames = [];
|
|
413
|
+
let testMain = null;
|
|
414
|
+
const compileOptions = {
|
|
415
|
+
...options,
|
|
416
|
+
testDriver: (programs, target) => {
|
|
417
|
+
testNames = discoverTests(programs);
|
|
418
|
+
benchNames = discoverBenchmarks(programs);
|
|
419
|
+
testMain = discoverTestMain(programs);
|
|
420
|
+
if (testNames.length === 0 && benchNames.length === 0 && !testMain)
|
|
421
|
+
return null;
|
|
422
|
+
return generateTestDriver(programs[0].pkg.name, target, {
|
|
423
|
+
testNames,
|
|
424
|
+
benchNames,
|
|
425
|
+
testMain,
|
|
426
|
+
asyncTests: discoverAsyncTests(programs),
|
|
427
|
+
});
|
|
428
|
+
},
|
|
429
|
+
};
|
|
657
430
|
let compiled;
|
|
658
431
|
try {
|
|
659
|
-
compiled = compilePackageTests(resolvedDir,
|
|
432
|
+
compiled = compilePackageTests(resolvedDir, compileOptions);
|
|
660
433
|
} catch (err) {
|
|
661
434
|
return reportBuildFailure(err, resolvedDir, options);
|
|
662
435
|
}
|
|
663
436
|
|
|
664
|
-
const { pkgName, js
|
|
665
|
-
const testNames = discoverTests(programs);
|
|
666
|
-
const benchNames = discoverBenchmarks(programs);
|
|
667
|
-
const testMain = discoverTestMain(programs);
|
|
668
|
-
|
|
437
|
+
const { pkgName, js } = compiled;
|
|
669
438
|
if (testNames.length === 0 && benchNames.length === 0 && !testMain) {
|
|
670
439
|
return reportEmptyTests(pkgName, "no tests to run", options);
|
|
671
440
|
}
|
|
@@ -673,10 +442,8 @@ export async function runTests(targetDir, options = {}) {
|
|
|
673
442
|
const runHarness = (bundleJs, label, wasmBytes) =>
|
|
674
443
|
spawnTestRunner(
|
|
675
444
|
resolvedDir,
|
|
676
|
-
generateTestHarness(bundleJs,
|
|
445
|
+
generateTestHarness(bundleJs, {
|
|
677
446
|
...options,
|
|
678
|
-
benchNames,
|
|
679
|
-
testMain,
|
|
680
447
|
pkgName: label,
|
|
681
448
|
jsdomPath,
|
|
682
449
|
wasmBytes,
|
|
@@ -696,7 +463,13 @@ export async function runTests(targetDir, options = {}) {
|
|
|
696
463
|
}
|
|
697
464
|
}
|
|
698
465
|
if (compiled.target === "both") {
|
|
699
|
-
return runDualTarget(
|
|
466
|
+
return runDualTarget(
|
|
467
|
+
compiled,
|
|
468
|
+
resolvedDir,
|
|
469
|
+
runHarness,
|
|
470
|
+
compileOptions,
|
|
471
|
+
options,
|
|
472
|
+
);
|
|
700
473
|
}
|
|
701
474
|
return runHarness(js, pkgName, compiled.wasm ?? null);
|
|
702
475
|
}
|