mirror of
https://github.com/oven-sh/bun
synced 2026-02-03 23:48:52 +00:00
Compare commits
12 Commits
dylan/pyth
...
nektro-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11ba4971b0 | ||
|
|
cfb30c5989 | ||
|
|
1887f073b7 | ||
|
|
f1125d1827 | ||
|
|
69c2ee0abd | ||
|
|
700c922e0c | ||
|
|
fa0a8f393c | ||
|
|
3cdf1f27d9 | ||
|
|
4d8bf16ed9 | ||
|
|
cf9f9b4658 | ||
|
|
dd94e5359e | ||
|
|
198c645097 |
@@ -18,6 +18,7 @@ steps:
|
||||
# macOS aarch64
|
||||
- key: "darwin-aarch64"
|
||||
group: ":darwin: aarch64"
|
||||
skip: true
|
||||
steps:
|
||||
- key: "darwin-aarch64-build-deps"
|
||||
label: ":darwin: aarch64 - build-deps"
|
||||
@@ -118,6 +119,7 @@ steps:
|
||||
# macOS x64
|
||||
- key: "darwin-x64"
|
||||
group: ":darwin: x64"
|
||||
skip: true
|
||||
steps:
|
||||
- key: "darwin-x64-build-deps"
|
||||
label: ":darwin: x64 - build-deps"
|
||||
@@ -218,6 +220,7 @@ steps:
|
||||
# Linux aarch64
|
||||
- key: "linux-aarch64"
|
||||
group: ":linux: aarch64"
|
||||
skip: true
|
||||
steps:
|
||||
- key: "linux-aarch64-build-deps"
|
||||
label: ":linux: aarch64 - build-deps"
|
||||
@@ -393,6 +396,7 @@ steps:
|
||||
- key: "linux-x64-test-debian-12"
|
||||
label: ":debian: 12 x64 - test-bun"
|
||||
if: "build.branch != 'main'"
|
||||
skip: true
|
||||
parallelism: 5
|
||||
soft_fail:
|
||||
- exit_status: 2
|
||||
@@ -451,6 +455,7 @@ steps:
|
||||
- key: "linux-x64-test-ubuntu-2004"
|
||||
label: ":ubuntu: 20.04 x64 - test-bun"
|
||||
if: "build.branch != 'main'"
|
||||
skip: true
|
||||
parallelism: 5
|
||||
soft_fail:
|
||||
- exit_status: 2
|
||||
@@ -477,9 +482,41 @@ steps:
|
||||
command:
|
||||
- "./scripts/runner.node.mjs --step linux-x64-build-bun"
|
||||
|
||||
- key: "linux-x64-test-ubuntu-2204-nodejs"
|
||||
label: ":node: :ubuntu: 22.04 x64 - test-nodejs"
|
||||
if: "build.branch != 'main'"
|
||||
parallelism: 1
|
||||
soft_fail:
|
||||
- exit_status: 2
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: 1
|
||||
limit: 1
|
||||
- exit_status: -1
|
||||
limit: 3
|
||||
- exit_status: 255
|
||||
limit: 3
|
||||
- signal_reason: agent_stop
|
||||
limit: 3
|
||||
- signal: SIGTERM
|
||||
limit: 3
|
||||
depends_on:
|
||||
- "linux-x64-build-bun"
|
||||
agents:
|
||||
robobun: "true"
|
||||
os: "linux"
|
||||
arch: "x64"
|
||||
distro: "ubuntu"
|
||||
release: "22.04"
|
||||
command:
|
||||
- "git clone https://github.com/nodejs/node ~/node"
|
||||
- "git -C ~/node checkout v22.5.1"
|
||||
- "./scripts/runner.node.mjs --nodejs"
|
||||
|
||||
# Linux x64-baseline
|
||||
- key: "linux-x64-baseline"
|
||||
group: ":linux: x64-baseline"
|
||||
skip: true
|
||||
steps:
|
||||
- key: "linux-x64-baseline-build-deps"
|
||||
label: ":linux: x64-baseline - build-deps"
|
||||
@@ -611,6 +648,7 @@ steps:
|
||||
# Windows x64
|
||||
- key: "windows-x64"
|
||||
group: ":windows: x64"
|
||||
skip: true
|
||||
steps:
|
||||
- key: "windows-x64-build-deps"
|
||||
label: ":windows: x64 - build-deps"
|
||||
@@ -696,6 +734,7 @@ steps:
|
||||
# Windows x64-baseline
|
||||
- key: "windows-x64-baseline"
|
||||
group: ":windows: x64-baseline"
|
||||
skip: true
|
||||
steps:
|
||||
- key: "windows-x64-baseline-build-deps"
|
||||
label: ":windows: x64-baseline - build-deps"
|
||||
|
||||
@@ -21,8 +21,7 @@ import {
|
||||
} from "node:fs";
|
||||
import { spawn, spawnSync } from "node:child_process";
|
||||
import { tmpdir, hostname, userInfo, homedir } from "node:os";
|
||||
import { join, basename, dirname, relative } from "node:path";
|
||||
import { normalize as normalizeWindows } from "node:path/win32";
|
||||
import { join, basename, dirname, relative, win32 } from "node:path";
|
||||
import { isIP } from "node:net";
|
||||
import { parseArgs } from "node:util";
|
||||
|
||||
@@ -36,7 +35,6 @@ const isWindows = process.platform === "win32";
|
||||
|
||||
const isGitHubAction = !!process.env["GITHUB_ACTIONS"];
|
||||
const isBuildKite = !!process.env["BUILDKITE"];
|
||||
const isBuildKiteTestSuite = !!process.env["BUILDKITE_ANALYTICS_TOKEN"];
|
||||
const isCI = !!process.env["CI"] || isGitHubAction || isBuildKite;
|
||||
|
||||
const isAWS =
|
||||
@@ -55,6 +53,7 @@ const gitRef = getGitRef();
|
||||
const cwd = dirname(import.meta.dirname);
|
||||
const testsPath = join(cwd, "test");
|
||||
const tmpPath = getTmpdir();
|
||||
const nodeTestsPath = join(homedir(), "node", "test", "parallel");
|
||||
|
||||
const { values: options, positionals: filters } = parseArgs({
|
||||
allowPositionals: true,
|
||||
@@ -93,6 +92,10 @@ const { values: options, positionals: filters } = parseArgs({
|
||||
type: "string",
|
||||
default: undefined,
|
||||
},
|
||||
["nodejs"]: {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -221,6 +224,11 @@ async function runTests() {
|
||||
|
||||
if (results.every(({ ok }) => ok)) {
|
||||
for (const testPath of tests) {
|
||||
if (options["nodejs"]) {
|
||||
const testPathFull = join(nodeTestsPath, testPath);
|
||||
await runTest(`node/test/parallel/${testPath}`, async () => spawnBunTest(execPath, testPathFull));
|
||||
continue;
|
||||
}
|
||||
const title = relative(cwd, join(testsPath, testPath)).replace(/\\/g, "/");
|
||||
await runTest(title, async () => spawnBunTest(execPath, join("test", testPath)));
|
||||
}
|
||||
@@ -233,6 +241,8 @@ async function runTests() {
|
||||
reportOutputToGitHubAction("failing_tests", markdown);
|
||||
}
|
||||
|
||||
if (!isCI) console.log("-------");
|
||||
if (!isCI) console.log("passing", results.length - failedTests.length, "/", results.length);
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -387,6 +397,8 @@ async function spawnSafe(options) {
|
||||
error = "timeout";
|
||||
} else {
|
||||
error = signalCode;
|
||||
if (!isCI) console.log();
|
||||
if (!isCI) onExit(signalCode);
|
||||
}
|
||||
} else if (exitCode === 1) {
|
||||
const match = buffer.match(/\x1b\[31m\s(\d+) fail/);
|
||||
@@ -527,12 +539,14 @@ async function spawnBun(execPath, { args, cwd, timeout, env, stdout, stderr }) {
|
||||
* @returns {Promise<TestResult>}
|
||||
*/
|
||||
async function spawnBunTest(execPath, testPath) {
|
||||
if (options["nodejs"] && !isCI) console.log(testPath);
|
||||
const timeout = getTestTimeout(testPath);
|
||||
const perTestTimeout = Math.ceil(timeout / 2);
|
||||
const isReallyTest = isTestStrict(testPath);
|
||||
const { ok, error, stdout } = await spawnBun(execPath, {
|
||||
args: ["test", `--timeout=${perTestTimeout}`, testPath],
|
||||
args: isReallyTest ? ["test", `--timeout=${perTestTimeout}`, testPath] : [testPath],
|
||||
cwd: cwd,
|
||||
timeout,
|
||||
timeout: isReallyTest ? timeout : 1_000,
|
||||
env: {
|
||||
GITHUB_ACTIONS: "true", // always true so annotations are parsed
|
||||
},
|
||||
@@ -780,7 +794,7 @@ function getTmpdir() {
|
||||
if (/cygwin|cygdrive/i.test(tmpdir) || !/^[a-z]/i.test(tmpdir)) {
|
||||
continue;
|
||||
}
|
||||
return normalizeWindows(tmpdir);
|
||||
return win32.normalize(tmpdir);
|
||||
}
|
||||
const appData = process.env["LOCALAPPDATA"];
|
||||
if (appData) {
|
||||
@@ -811,6 +825,15 @@ function isJavaScript(path) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isTest(path) {
|
||||
if (options["nodejs"]) return true;
|
||||
return isTestStrict(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isTestStrict(path) {
|
||||
return isJavaScript(path) && /\.test|spec\./.test(basename(path));
|
||||
}
|
||||
|
||||
@@ -828,6 +851,226 @@ function isHidden(path) {
|
||||
*/
|
||||
function getTests(cwd) {
|
||||
function* getFiles(cwd, path) {
|
||||
if (options["nodejs"]) {
|
||||
const dirname = join(cwd, path);
|
||||
console.log(dirname);
|
||||
for (const entry of readdirSync(dirname, { encoding: "utf-8", withFileTypes: true })) {
|
||||
const { name } = entry;
|
||||
const filename = join(path, name);
|
||||
if (!isCI) {
|
||||
// skip these in debug mode so its easier to comment out individual ones to test
|
||||
// guards in this list should only be moved here once theyre 100% passing
|
||||
}
|
||||
if (filename.startsWith("test-abortcontroller")) continue;
|
||||
if (filename.startsWith("test-aborted")) continue;
|
||||
if (filename.startsWith("test-abortsignal")) continue;
|
||||
if (filename.startsWith("test-accessor")) continue;
|
||||
if (filename.startsWith("test-arm")) continue;
|
||||
if (filename.startsWith("test-assert")) continue;
|
||||
if (filename.startsWith("test-async")) continue;
|
||||
if (filename.startsWith("test-atomics")) continue;
|
||||
if (filename.startsWith("test-bad")) continue;
|
||||
if (filename.startsWith("test-bash")) continue;
|
||||
if (filename.startsWith("test-beforeexit")) continue;
|
||||
if (filename.startsWith("test-benchmark")) continue;
|
||||
if (filename.startsWith("test-binding")) continue;
|
||||
if (filename.startsWith("test-blob")) continue;
|
||||
if (filename.startsWith("test-blocklist")) continue;
|
||||
if (filename.startsWith("test-bootstrap")) continue;
|
||||
if (filename.startsWith("test-broadcastchannel")) continue;
|
||||
if (filename.startsWith("test-btoa")) continue;
|
||||
if (filename.startsWith("test-buffer")) continue;
|
||||
if (filename.startsWith("test-c-")) continue;
|
||||
if (filename.startsWith("test-child")) continue;
|
||||
if (filename.startsWith("test-cli-")) continue;
|
||||
if (filename.startsWith("test-client")) continue;
|
||||
if (filename.startsWith("test-cluster")) continue;
|
||||
if (filename.startsWith("test-code")) continue;
|
||||
if (filename.startsWith("test-common")) continue;
|
||||
if (filename.startsWith("test-compile")) continue;
|
||||
if (filename.startsWith("test-compression")) continue;
|
||||
if (filename.startsWith("test-console")) continue;
|
||||
if (filename.startsWith("test-constants")) continue;
|
||||
if (filename.startsWith("test-corepack")) continue;
|
||||
if (filename.startsWith("test-coverage")) continue;
|
||||
if (filename.startsWith("test-crypto")) continue;
|
||||
if (filename.startsWith("test-cwd")) continue;
|
||||
if (filename.startsWith("test-datetime")) continue;
|
||||
if (filename.startsWith("test-debugger")) continue;
|
||||
if (filename.startsWith("test-delayed")) continue;
|
||||
if (filename.startsWith("test-destroy")) continue;
|
||||
if (filename.startsWith("test-dgram")) continue;
|
||||
if (filename.startsWith("test-diagnostics")) continue;
|
||||
if (filename.startsWith("test-directory")) continue;
|
||||
if (filename.startsWith("test-disable")) continue;
|
||||
if (filename.startsWith("test-dns")) continue;
|
||||
if (filename.startsWith("test-domain")) continue;
|
||||
if (filename.startsWith("test-domexception")) continue;
|
||||
if (filename.startsWith("test-dotenv")) continue;
|
||||
if (filename.startsWith("test-double")) continue;
|
||||
if (filename.startsWith("test-dsa")) continue;
|
||||
if (filename.startsWith("test-dummy")) continue;
|
||||
if (filename.startsWith("test-emit")) continue;
|
||||
if (filename.startsWith("test-env")) continue;
|
||||
if (filename.startsWith("test-err-")) continue;
|
||||
if (filename.startsWith("test-error-")) continue;
|
||||
if (filename.startsWith("test-errors-")) continue;
|
||||
if (filename.startsWith("test-eslint")) continue;
|
||||
if (filename.startsWith("test-eval")) continue;
|
||||
if (filename.startsWith("test-event-")) continue;
|
||||
if (filename.startsWith("test-eventemitter")) continue;
|
||||
if (filename.startsWith("test-events-")) continue;
|
||||
if (filename.startsWith("test-eventsource")) continue;
|
||||
if (filename.startsWith("test-eventtarget")) continue;
|
||||
if (filename.startsWith("test-exception")) continue;
|
||||
if (filename.startsWith("test-experimental")) continue;
|
||||
if (filename.startsWith("test-fetch")) continue;
|
||||
if (filename.startsWith("test-file-")) continue;
|
||||
if (filename.startsWith("test-file.")) continue;
|
||||
if (filename.startsWith("test-filehandle")) continue;
|
||||
if (filename.startsWith("test-finalization")) continue;
|
||||
if (filename.startsWith("test-fixed")) continue;
|
||||
if (filename.startsWith("test-force")) continue;
|
||||
if (filename.startsWith("test-freelist")) continue;
|
||||
if (filename.startsWith("test-freeze")) continue;
|
||||
if (filename.startsWith("test-fs")) continue;
|
||||
if (filename.startsWith("test-gc")) continue;
|
||||
if (filename.startsWith("test-global")) continue;
|
||||
if (filename.startsWith("test-h2")) continue;
|
||||
if (filename.startsWith("test-handle")) continue;
|
||||
if (filename.startsWith("test-heap-")) continue;
|
||||
if (filename.startsWith("test-heapdump")) continue;
|
||||
if (filename.startsWith("test-heapsnapshot")) continue;
|
||||
if (filename.startsWith("test-http-")) continue;
|
||||
if (filename.startsWith("test-http.")) continue;
|
||||
if (filename.startsWith("test-http2")) continue;
|
||||
if (filename.startsWith("test-https")) continue;
|
||||
if (filename.startsWith("test-icu")) continue;
|
||||
if (filename.startsWith("test-inspect-")) continue;
|
||||
if (filename.startsWith("test-inspector")) continue;
|
||||
if (filename.startsWith("test-instanceof")) continue;
|
||||
if (filename.startsWith("test-internal")) continue;
|
||||
if (filename.startsWith("test-intl")) continue;
|
||||
if (filename.startsWith("test-js")) continue;
|
||||
if (filename.startsWith("test-kill")) continue;
|
||||
if (filename.startsWith("test-listen")) continue;
|
||||
if (filename.startsWith("test-macos")) continue;
|
||||
if (filename.startsWith("test-math")) continue;
|
||||
if (filename.startsWith("test-memory")) continue;
|
||||
if (filename.startsWith("test-messagechannel")) continue;
|
||||
if (filename.startsWith("test-messageevent")) continue;
|
||||
if (filename.startsWith("test-messageport")) continue;
|
||||
if (filename.startsWith("test-messaging")) continue;
|
||||
if (filename.startsWith("test-microtask")) continue;
|
||||
if (filename.startsWith("test-mime")) continue;
|
||||
if (filename.startsWith("test-module")) continue;
|
||||
if (filename.startsWith("test-navigator")) continue;
|
||||
if (filename.startsWith("test-net")) continue;
|
||||
if (filename.startsWith("test-next")) continue;
|
||||
if (filename.startsWith("test-no")) continue;
|
||||
if (filename.startsWith("test-npm")) continue;
|
||||
if (filename.startsWith("test-openssl")) continue;
|
||||
if (filename.startsWith("test-options")) continue;
|
||||
if (filename.startsWith("test-os")) continue;
|
||||
if (filename.startsWith("test-outgoing")) continue;
|
||||
if (filename.startsWith("test-parse")) continue;
|
||||
if (filename.startsWith("test-path")) continue;
|
||||
if (filename.startsWith("test-pending")) continue;
|
||||
if (filename.startsWith("test-perf-")) continue;
|
||||
if (filename.startsWith("test-performance-")) continue;
|
||||
if (filename.startsWith("test-performanceobserver-")) continue;
|
||||
if (filename.startsWith("test-performanceobserver.")) continue;
|
||||
if (filename.startsWith("test-permission")) continue;
|
||||
if (filename.startsWith("test-pipe")) continue;
|
||||
if (filename.startsWith("test-preload")) continue;
|
||||
if (filename.startsWith("test-primitive")) continue;
|
||||
if (filename.startsWith("test-primordials")) continue;
|
||||
if (filename.startsWith("test-priority")) continue;
|
||||
if (filename.startsWith("test-process")) continue;
|
||||
if (filename.startsWith("test-promise")) continue;
|
||||
if (filename.startsWith("test-punycode")) continue;
|
||||
if (filename.startsWith("test-querystring")) continue;
|
||||
if (filename.startsWith("test-queue")) continue;
|
||||
if (filename.startsWith("test-quic")) continue;
|
||||
if (filename.startsWith("test-readable")) continue;
|
||||
if (filename.startsWith("test-readline")) continue;
|
||||
if (filename.startsWith("test-ref")) continue;
|
||||
if (filename.startsWith("test-regression")) continue;
|
||||
if (filename.startsWith("test-release")) continue;
|
||||
if (filename.startsWith("test-repl")) continue;
|
||||
if (filename.startsWith("test-require")) continue;
|
||||
if (filename.startsWith("test-resource")) continue;
|
||||
if (filename.startsWith("test-runner")) continue;
|
||||
if (filename.startsWith("test-safe")) continue;
|
||||
if (filename.startsWith("test-security")) continue;
|
||||
if (filename.startsWith("test-set")) continue;
|
||||
if (filename.startsWith("test-shadow")) continue;
|
||||
if (filename.startsWith("test-sigint")) continue;
|
||||
if (filename.startsWith("test-signal")) continue;
|
||||
if (filename.startsWith("test-single")) continue;
|
||||
if (filename.startsWith("test-snapshot")) continue;
|
||||
if (filename.startsWith("test-socket-")) continue;
|
||||
if (filename.startsWith("test-socketaddress")) continue;
|
||||
if (filename.startsWith("test-source")) continue;
|
||||
if (filename.startsWith("test-spawn")) continue;
|
||||
if (filename.startsWith("test-sqlite")) continue;
|
||||
if (filename.startsWith("test-stack")) continue;
|
||||
if (filename.startsWith("test-startup")) continue;
|
||||
if (filename.startsWith("test-stdin")) continue;
|
||||
if (filename.startsWith("test-stdio")) continue;
|
||||
if (filename.startsWith("test-stdout")) continue;
|
||||
if (filename.startsWith("test-strace")) continue;
|
||||
if (filename.startsWith("test-stream-")) continue;
|
||||
if (filename.startsWith("test-stream2-")) continue;
|
||||
if (filename.startsWith("test-stream3-")) continue;
|
||||
if (filename.startsWith("test-streams")) continue;
|
||||
if (filename.startsWith("test-string-")) continue;
|
||||
if (filename.startsWith("test-stringbytes")) continue;
|
||||
if (filename.startsWith("test-structuredClone")) continue;
|
||||
if (filename.startsWith("test-sync")) continue;
|
||||
if (filename.startsWith("test-sys")) continue;
|
||||
if (filename.startsWith("test-tcp")) continue;
|
||||
if (filename.startsWith("test-throw")) continue;
|
||||
if (filename.startsWith("test-tick")) continue;
|
||||
if (filename.startsWith("test-timers")) continue;
|
||||
if (filename.startsWith("test-tls")) continue;
|
||||
if (filename.startsWith("test-tojson")) continue;
|
||||
if (filename.startsWith("test-trace")) continue;
|
||||
if (filename.startsWith("test-tracing")) continue;
|
||||
if (filename.startsWith("test-tty-")) continue;
|
||||
if (filename.startsWith("test-ttywrap")) continue;
|
||||
if (filename.startsWith("test-tz")) continue;
|
||||
if (filename.startsWith("test-unhandled")) continue;
|
||||
if (filename.startsWith("test-unicode")) continue;
|
||||
if (filename.startsWith("test-url")) continue;
|
||||
if (filename.startsWith("test-utf8")) continue;
|
||||
if (filename.startsWith("test-util")) continue;
|
||||
if (filename.startsWith("test-uv")) continue;
|
||||
if (filename.startsWith("test-v8")) continue;
|
||||
if (filename.startsWith("test-validators")) continue;
|
||||
if (filename.startsWith("test-vfs")) continue;
|
||||
if (filename.startsWith("test-vm")) continue;
|
||||
if (filename.startsWith("test-warn")) continue;
|
||||
if (filename.startsWith("test-watch")) continue;
|
||||
if (filename.startsWith("test-weakref")) continue;
|
||||
if (filename.startsWith("test-webcrypto")) continue;
|
||||
if (filename.startsWith("test-websocket")) continue;
|
||||
if (filename.startsWith("test-webstorage")) continue;
|
||||
if (filename.startsWith("test-webstream")) continue;
|
||||
if (filename.startsWith("test-whatwg")) continue;
|
||||
if (filename.startsWith("test-windows")) continue;
|
||||
if (filename.startsWith("test-worker")) continue;
|
||||
if (filename.startsWith("test-wrap")) continue;
|
||||
if (filename.startsWith("test-x509")) continue;
|
||||
if (filename.startsWith("test-zlib")) continue;
|
||||
|
||||
if (filename.startsWith("test-")) {
|
||||
yield filename;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const dirname = join(cwd, path);
|
||||
for (const entry of readdirSync(dirname, { encoding: "utf-8", withFileTypes: true })) {
|
||||
const { name } = entry;
|
||||
@@ -842,6 +1085,9 @@ function getTests(cwd) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (options["nodejs"]) {
|
||||
return [...getFiles(nodeTestsPath, "")].sort();
|
||||
}
|
||||
return [...getFiles(cwd, "")].sort();
|
||||
}
|
||||
|
||||
@@ -1711,6 +1957,7 @@ async function getDoomsdayDate() {
|
||||
* @param {string} signal
|
||||
*/
|
||||
async function beforeExit(signal) {
|
||||
if (!isCI) return onExit(signal);
|
||||
const endOfWorld = await getDoomsdayDate();
|
||||
if (endOfWorld) {
|
||||
const timeMin = 10 * 1000;
|
||||
|
||||
@@ -3443,8 +3443,8 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
|
||||
PropertyAttribute::Accessor | 0);
|
||||
|
||||
// TODO: this should be usable on the lookup table. it crashed las time i tried it
|
||||
putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "onmessage"_s), JSC::CustomGetterSetter::create(vm, globalOnMessage, setGlobalOnMessage), 0);
|
||||
putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "onerror"_s), JSC::CustomGetterSetter::create(vm, globalOnError, setGlobalOnError), 0);
|
||||
putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "onmessage"_s), JSC::CustomGetterSetter::create(vm, globalOnMessage, setGlobalOnMessage), (unsigned)PropertyAttribute::DontEnum);
|
||||
putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "onerror"_s), JSC::CustomGetterSetter::create(vm, globalOnError, setGlobalOnError), (unsigned)PropertyAttribute::DontEnum);
|
||||
|
||||
// ----- Extensions to Built-in objects -----
|
||||
|
||||
|
||||
6
test/node.js/.gitignore
vendored
6
test/node.js/.gitignore
vendored
@@ -1,6 +0,0 @@
|
||||
# Paths copied from Node.js repository
|
||||
upstream/
|
||||
|
||||
# Paths for test runner
|
||||
summary/
|
||||
summary.md
|
||||
@@ -1 +0,0 @@
|
||||
upstream/
|
||||
@@ -1,2 +0,0 @@
|
||||
[test]
|
||||
preload = ["./common/preload.js"]
|
||||
@@ -1,273 +0,0 @@
|
||||
import { expect } from "bun:test";
|
||||
|
||||
function deepEqual(actual, expected, message) {
|
||||
if (isIgnored(expected, message)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
expect(actual).toEqual(expected);
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function deepStrictEqual(actual, expected, message) {
|
||||
if (isIgnored(expected, message)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
expect(actual).toStrictEqual(expected);
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function doesNotMatch(string, regexp, message) {
|
||||
if (isIgnored(regexp, message)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
expect(string).not.toMatch(regexp);
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function doesNotReject(asyncFn, error, message) {
|
||||
if (isIgnored(error, message)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
expect(asyncFn).rejects.toThrow(error);
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function doesNotThrow(fn, error, message) {
|
||||
if (isIgnored(error, message)) {
|
||||
return;
|
||||
}
|
||||
todo("doesNotThrow");
|
||||
}
|
||||
|
||||
function equal(actual, expected, message) {
|
||||
if (isIgnored(expected, message)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
expect(actual).toBe(expected);
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function fail(actual, expected, message, operator, stackStartFn) {
|
||||
if (isIgnored(expected, message)) {
|
||||
return;
|
||||
}
|
||||
todo("fail");
|
||||
}
|
||||
|
||||
function ifError(value) {
|
||||
if (isIgnored(value)) {
|
||||
return;
|
||||
}
|
||||
todo("ifError");
|
||||
}
|
||||
|
||||
function match(string, regexp, message) {
|
||||
if (isIgnored(regexp, message)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
expect(string).toMatch(regexp);
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function notDeepEqual(actual, expected, message) {
|
||||
if (isIgnored(expected, message)) {
|
||||
return;
|
||||
}
|
||||
todo("notDeepEqual");
|
||||
}
|
||||
|
||||
function notDeepStrictEqual(actual, expected, message) {
|
||||
if (isIgnored(expected, message)) {
|
||||
return;
|
||||
}
|
||||
todo("notDeepStrictEqual");
|
||||
}
|
||||
|
||||
function notEqual(actual, expected, message) {
|
||||
if (isIgnored(expected, message)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
expect(actual).not.toBe(expected);
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function notStrictEqual(actual, expected, message) {
|
||||
if (isIgnored(expected, message)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
expect(actual).not.toStrictEqual(expected);
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function ok(value, message) {
|
||||
if (isIgnored(message)) {
|
||||
return;
|
||||
}
|
||||
equal(!!value, true, message);
|
||||
}
|
||||
|
||||
function rejects(asyncFn, error, message) {
|
||||
if (isIgnored(error, message)) {
|
||||
return;
|
||||
}
|
||||
todo("rejects");
|
||||
}
|
||||
|
||||
function strictEqual(actual, expected, message) {
|
||||
if (isIgnored(expected, message)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
expect(actual).toBe(expected);
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function throws(fn, error, message) {
|
||||
try {
|
||||
let result;
|
||||
try {
|
||||
result = fn();
|
||||
} catch (cause) {
|
||||
const matcher = toErrorMatcher(error);
|
||||
expect(cause).toEqual(matcher);
|
||||
return;
|
||||
}
|
||||
expect(result).toBe("Expected function to throw an error, instead it returned");
|
||||
} catch (cause) {
|
||||
throwError(cause, message);
|
||||
}
|
||||
}
|
||||
|
||||
function toErrorMatcher(expected) {
|
||||
let message;
|
||||
if (typeof expected === "string") {
|
||||
message = expected;
|
||||
} else if (expected instanceof RegExp) {
|
||||
message = expected.source;
|
||||
} else if (typeof expected === "object") {
|
||||
message = expected.message;
|
||||
}
|
||||
|
||||
for (const [expected, actual] of similarErrors) {
|
||||
if (message && expected.test(message)) {
|
||||
message = actual;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
return expect.anything();
|
||||
}
|
||||
|
||||
if (typeof expected === "object") {
|
||||
return expect.objectContaining({
|
||||
...expected,
|
||||
message: expect.stringMatching(message),
|
||||
});
|
||||
}
|
||||
|
||||
return expect.stringMatching(message);
|
||||
}
|
||||
|
||||
const similarErrors = [
|
||||
[/Invalid typed array length/i, /length too large/i],
|
||||
[/Unknown encoding/i, /Invalid encoding/i],
|
||||
[
|
||||
/The ".*" argument must be of type string or an instance of Buffer or ArrayBuffer/i,
|
||||
/Invalid input, must be a string, Buffer, or ArrayBuffer/i,
|
||||
],
|
||||
[/The ".*" argument must be an instance of Buffer or Uint8Array./i, /Expected Buffer/i],
|
||||
[/The ".*" argument must be an instance of Array./i, /Argument must be an array/i],
|
||||
[/The value of ".*" is out of range./i, /Offset is out of bounds/i],
|
||||
[/Attempt to access memory outside buffer bounds/i, /Out of bounds access/i],
|
||||
];
|
||||
|
||||
const ignoredExpectations = [
|
||||
// Reason: Bun has a nicer format for `Buffer.inspect()`.
|
||||
/^<Buffer /,
|
||||
];
|
||||
|
||||
function isIgnored(...expectations) {
|
||||
for (const expected of expectations) {
|
||||
let query;
|
||||
if (typeof expected === "string") {
|
||||
query = expected;
|
||||
} else if (expected instanceof RegExp) {
|
||||
query = expected.source;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
for (const pattern of ignoredExpectations) {
|
||||
if (pattern.test(query)) {
|
||||
console.warn("Ignoring expectation:", expected);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function throwError(error, message) {
|
||||
if (isIgnored(error, message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof message === "string") {
|
||||
const gray = "\x1b[90m";
|
||||
const reset = "\x1b[0m";
|
||||
error.message += `\n${gray}note: ${message}${reset}`;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
function todo(name) {
|
||||
throw new Error(`TODO: ${name}`);
|
||||
}
|
||||
|
||||
export default ok;
|
||||
export {
|
||||
deepEqual,
|
||||
deepStrictEqual,
|
||||
doesNotMatch,
|
||||
doesNotReject,
|
||||
doesNotThrow,
|
||||
equal,
|
||||
fail,
|
||||
ifError,
|
||||
match,
|
||||
notDeepEqual,
|
||||
notDeepStrictEqual,
|
||||
notEqual,
|
||||
notStrictEqual,
|
||||
ok,
|
||||
rejects,
|
||||
strictEqual,
|
||||
throws,
|
||||
};
|
||||
@@ -1,122 +0,0 @@
|
||||
// https://github.com/nodejs/node/blob/c975384264dc553de62398be814d0c66fc1fc1fb/test/common/index.js
|
||||
|
||||
import { inspect } from "bun";
|
||||
import { expect, afterAll } from "bun:test";
|
||||
|
||||
const hasIntl = true;
|
||||
const hasCrypto = true;
|
||||
const hasOpenSSL3 = false;
|
||||
const hasOpenSSL31 = false;
|
||||
const hasQuic = false;
|
||||
|
||||
const { platform, env } = process;
|
||||
const isWindows = platform === "win32";
|
||||
const isSunOS = platform === "sunos";
|
||||
const isFreeBSD = platform === "freebsd";
|
||||
const isOpenBSD = platform === "openbsd";
|
||||
const isLinux = platform === "linux";
|
||||
const isOSX = platform === "darwin";
|
||||
const isAsan = false;
|
||||
const isPi = false;
|
||||
const isDumbTerminal = env.TERM === "dumb";
|
||||
|
||||
function mustCall(fn, n = 1) {
|
||||
const callSite = getCallSite(mustCall);
|
||||
|
||||
let calls = 0;
|
||||
const mustCallFn = function (...args) {
|
||||
calls++;
|
||||
return fn.apply(this, args);
|
||||
};
|
||||
|
||||
afterAll(() => {
|
||||
if (calls !== n) {
|
||||
throw new Error(`function should be called exactly ${n} times:\n ${callSite}`);
|
||||
}
|
||||
});
|
||||
|
||||
return mustCallFn;
|
||||
}
|
||||
|
||||
function mustNotCall() {
|
||||
const callSite = getCallSite(mustNotCall);
|
||||
|
||||
return function mustNotCall(...args) {
|
||||
const argsInfo = args.length > 0 ? `\ncalled with arguments: ${args.map(arg => inspect(arg)).join(", ")}` : "";
|
||||
assert.fail(`${msg || "function should not have been called"} at ${callSite}` + argsInfo);
|
||||
};
|
||||
}
|
||||
|
||||
function printSkipMessage(message) {
|
||||
console.warn(message);
|
||||
}
|
||||
|
||||
function skip(message) {
|
||||
printSkipMessage(message);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
function expectsError(validator, exact) {
|
||||
return mustCall((...args) => {
|
||||
if (args.length !== 1) {
|
||||
// Do not use `assert.strictEqual()` to prevent `inspect` from
|
||||
// always being called.
|
||||
assert.fail(`Expected one argument, got ${inspect(args)}`);
|
||||
}
|
||||
const error = args.pop();
|
||||
// The error message should be non-enumerable
|
||||
assert.strictEqual(Object.prototype.propertyIsEnumerable.call(error, "message"), false);
|
||||
|
||||
assert.throws(() => {
|
||||
throw error;
|
||||
}, validator);
|
||||
return true;
|
||||
}, exact);
|
||||
}
|
||||
|
||||
function expectWarning(name, code, message) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
function invalidArgTypeHelper(input) {
|
||||
return ` Received: ${inspect(input)}`;
|
||||
}
|
||||
|
||||
function getCallSite(fn) {
|
||||
const originalStackFormatter = Error.prepareStackTrace;
|
||||
Error.prepareStackTrace = (_, stack) => `${stack[0].getFileName()}:${stack[0].getLineNumber()}`;
|
||||
const error = new Error();
|
||||
Error.captureStackTrace(error, fn);
|
||||
error.stack; // With the V8 Error API, the stack is not formatted until it is accessed
|
||||
Error.prepareStackTrace = originalStackFormatter;
|
||||
return error.stack;
|
||||
}
|
||||
|
||||
export {
|
||||
hasIntl,
|
||||
hasCrypto,
|
||||
hasOpenSSL3,
|
||||
hasOpenSSL31,
|
||||
hasQuic,
|
||||
// ...
|
||||
isWindows,
|
||||
isSunOS,
|
||||
isFreeBSD,
|
||||
isOpenBSD,
|
||||
isLinux,
|
||||
isOSX,
|
||||
isAsan,
|
||||
isPi,
|
||||
// ...
|
||||
isDumbTerminal,
|
||||
// ...
|
||||
mustCall,
|
||||
mustNotCall,
|
||||
printSkipMessage,
|
||||
skip,
|
||||
expectsError,
|
||||
expectWarning,
|
||||
// ...
|
||||
inspect,
|
||||
invalidArgTypeHelper,
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
const { mock } = require("bun:test");
|
||||
const assert = require("./assert");
|
||||
|
||||
mock.module("assert", () => {
|
||||
return assert;
|
||||
});
|
||||
|
||||
mock.module("internal/test/binding", () => {
|
||||
return {};
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
const isBun = !!process.isBun;
|
||||
const os = process.platform === "win32" ? "windows" : process.platform;
|
||||
const arch = process.arch === "arm64" ? "aarch64" : process.arch;
|
||||
const version = isBun ? Bun.version : process.versions.node;
|
||||
const revision = isBun ? Bun.revision : undefined;
|
||||
const baseline = (() => {
|
||||
if (!isBun || arch !== "x64") {
|
||||
return undefined;
|
||||
}
|
||||
const { stdout } = spawnSync(process.execPath, ["--print", "Bun.unsafe.segfault()"], {
|
||||
encoding: "utf8",
|
||||
timeout: 5_000,
|
||||
});
|
||||
if (stdout.includes("baseline")) {
|
||||
return true;
|
||||
}
|
||||
return undefined;
|
||||
})();
|
||||
const name = baseline ? `bun-${os}-${arch}-baseline` : `${isBun ? "bun" : "node"}-${os}-${arch}`;
|
||||
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
name,
|
||||
os,
|
||||
arch,
|
||||
version,
|
||||
revision,
|
||||
baseline,
|
||||
}),
|
||||
);
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "node runner.mjs --exec-path $(which bun-debug || which bun)"
|
||||
}
|
||||
}
|
||||
@@ -1,433 +0,0 @@
|
||||
import { parseArgs } from "node:util";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, writeFileSync, appendFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, join } from "node:path";
|
||||
import readline from "node:readline/promises";
|
||||
|
||||
const testPath = new URL("./", import.meta.url);
|
||||
const nodePath = new URL("upstream/", testPath);
|
||||
const nodeTestPath = new URL("test/", nodePath);
|
||||
const metadataScriptPath = new URL("metadata.mjs", testPath);
|
||||
const testJsonPath = new URL("tests.json", testPath);
|
||||
const summariesPath = new URL("summary/", testPath);
|
||||
const summaryMdPath = new URL("summary.md", testPath);
|
||||
const cwd = new URL("../../", testPath);
|
||||
|
||||
async function main() {
|
||||
const { values, positionals } = parseArgs({
|
||||
allowPositionals: true,
|
||||
options: {
|
||||
help: {
|
||||
type: "boolean",
|
||||
short: "h",
|
||||
},
|
||||
baseline: {
|
||||
type: "boolean",
|
||||
},
|
||||
interactive: {
|
||||
type: "boolean",
|
||||
short: "i",
|
||||
},
|
||||
"exec-path": {
|
||||
type: "string",
|
||||
},
|
||||
pull: {
|
||||
type: "boolean",
|
||||
},
|
||||
summary: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (values.help) {
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.summary) {
|
||||
printSummary();
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.pull) {
|
||||
pullTests(true);
|
||||
return;
|
||||
}
|
||||
|
||||
pullTests();
|
||||
const summary = await runTests(values, positionals);
|
||||
const regressedTests = appendSummary(summary);
|
||||
printSummary(summary, regressedTests);
|
||||
|
||||
process.exit(regressedTests?.length ? 1 : 0);
|
||||
}
|
||||
|
||||
function printHelp() {
|
||||
console.log(`Usage: ${process.argv0} ${basename(import.meta.filename)} [options]`);
|
||||
console.log();
|
||||
console.log("Options:");
|
||||
console.log(" -h, --help Show this help message");
|
||||
console.log(" -e, --exec-path Path to the bun executable to run");
|
||||
console.log(" -i, --interactive Pause and wait for input after a failing test");
|
||||
console.log(" -s, --summary Print a summary of the tests (does not run tests)");
|
||||
}
|
||||
|
||||
function pullTests(force) {
|
||||
if (!force && existsSync(nodeTestPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Pulling tests...");
|
||||
const { status, error, stderr } = spawnSync(
|
||||
"git",
|
||||
["submodule", "update", "--init", "--recursive", "--progress", "--depth=1", "--checkout", "upstream"],
|
||||
{
|
||||
cwd: testPath,
|
||||
stdio: "inherit",
|
||||
},
|
||||
);
|
||||
|
||||
if (error || status !== 0) {
|
||||
throw error || new Error(stderr);
|
||||
}
|
||||
|
||||
for (const { filename, status } of getTests(nodeTestPath)) {
|
||||
if (status === "TODO") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const src = new URL(filename, nodeTestPath);
|
||||
const dst = new URL(filename, testPath);
|
||||
|
||||
try {
|
||||
writeFileSync(dst, readFileSync(src));
|
||||
} catch (error) {
|
||||
if (error.code === "ENOENT") {
|
||||
mkdirSync(new URL(".", dst), { recursive: true });
|
||||
writeFileSync(dst, readFileSync(src));
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function runTests(options, filters) {
|
||||
const { interactive } = options;
|
||||
const bunPath = process.isBun ? process.execPath : "bun";
|
||||
const execPath = options["exec-path"] || bunPath;
|
||||
|
||||
let reader;
|
||||
if (interactive) {
|
||||
reader = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
}
|
||||
|
||||
const results = [];
|
||||
const tests = getTests(testPath);
|
||||
for (const { label, filename, status: filter } of tests) {
|
||||
if (filters?.length && !filters.some(filter => label?.includes(filter))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (filter !== "OK") {
|
||||
results.push({ label, filename, status: filter });
|
||||
continue;
|
||||
}
|
||||
|
||||
const { pathname: filePath } = new URL(filename, testPath);
|
||||
const tmp = tmpdirSync();
|
||||
const timestamp = Date.now();
|
||||
const {
|
||||
status: exitCode,
|
||||
signal: signalCode,
|
||||
error: spawnError,
|
||||
} = spawnSync(execPath, ["test", filePath], {
|
||||
cwd: testPath,
|
||||
stdio: "inherit",
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
HOME: tmp,
|
||||
TMPDIR: tmp,
|
||||
TZ: "Etc/UTC",
|
||||
FORCE_COLOR: "1",
|
||||
BUN_DEBUG_QUIET_LOGS: "1",
|
||||
BUN_GARBAGE_COLLECTOR_LEVEL: "1",
|
||||
BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0",
|
||||
GITHUB_ACTIONS: "false", // disable for now
|
||||
},
|
||||
timeout: 30_000,
|
||||
});
|
||||
|
||||
const duration = Math.ceil(Date.now() - timestamp);
|
||||
const status = exitCode === 0 ? "PASS" : "FAIL";
|
||||
let error;
|
||||
if (signalCode) {
|
||||
error = signalCode;
|
||||
} else if (spawnError) {
|
||||
const { message } = spawnError;
|
||||
if (message.includes("timed out") || message.includes("timeout")) {
|
||||
error = "TIMEOUT";
|
||||
} else {
|
||||
error = message;
|
||||
}
|
||||
} else if (exitCode !== 0) {
|
||||
error = `code ${exitCode}`;
|
||||
}
|
||||
results.push({ label, filename, status, error, timestamp, duration });
|
||||
|
||||
if (reader && status === "FAIL") {
|
||||
const answer = await reader.question("Continue? [Y/n] ");
|
||||
if (answer.toUpperCase() !== "Y") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reader?.close();
|
||||
return {
|
||||
v: 1,
|
||||
metadata: getMetadata(execPath),
|
||||
tests: results,
|
||||
};
|
||||
}
|
||||
|
||||
function getTests(filePath) {
|
||||
const tests = [];
|
||||
const testData = JSON.parse(readFileSync(testJsonPath, "utf8"));
|
||||
|
||||
for (const filename of readdirSync(filePath, { recursive: true })) {
|
||||
if (!isJavaScript(filename) || !isTest(filename)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let match;
|
||||
for (const { label, pattern, skip: skipList = [], todo: todoList = [] } of testData) {
|
||||
if (!filename.startsWith(pattern)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (skipList.some(({ file }) => filename.endsWith(file))) {
|
||||
tests.push({ label, filename, status: "SKIP" });
|
||||
} else if (todoList.some(({ file }) => filename.endsWith(file))) {
|
||||
tests.push({ label, filename, status: "TODO" });
|
||||
} else {
|
||||
tests.push({ label, filename, status: "OK" });
|
||||
}
|
||||
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
tests.push({ filename, status: "TODO" });
|
||||
}
|
||||
}
|
||||
|
||||
return tests;
|
||||
}
|
||||
|
||||
function appendSummary(summary) {
|
||||
const { metadata, tests, ...extra } = summary;
|
||||
const { name } = metadata;
|
||||
|
||||
const summaryPath = new URL(`${name}.json`, summariesPath);
|
||||
const summaryData = {
|
||||
metadata,
|
||||
tests: tests.map(({ label, filename, status, error }) => ({ label, filename, status, error })),
|
||||
...extra,
|
||||
};
|
||||
|
||||
const regressedTests = [];
|
||||
if (existsSync(summaryPath)) {
|
||||
const previousData = JSON.parse(readFileSync(summaryPath, "utf8"));
|
||||
const { v } = previousData;
|
||||
if (v === 1) {
|
||||
const { tests: previousTests } = previousData;
|
||||
for (const { label, filename, status, error } of tests) {
|
||||
if (status !== "FAIL") {
|
||||
continue;
|
||||
}
|
||||
const previousTest = previousTests.find(({ filename: file }) => file === filename);
|
||||
if (previousTest) {
|
||||
const { status: previousStatus } = previousTest;
|
||||
if (previousStatus !== "FAIL") {
|
||||
regressedTests.push({ label, filename, error });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (regressedTests.length) {
|
||||
return regressedTests;
|
||||
}
|
||||
|
||||
const summaryText = JSON.stringify(summaryData, null, 2);
|
||||
try {
|
||||
writeFileSync(summaryPath, summaryText);
|
||||
} catch (error) {
|
||||
if (error.code === "ENOENT") {
|
||||
mkdirSync(summariesPath, { recursive: true });
|
||||
writeFileSync(summaryPath, summaryText);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function printSummary(summaryData, regressedTests) {
|
||||
let metadataInfo = {};
|
||||
let testInfo = {};
|
||||
let labelInfo = {};
|
||||
let errorInfo = {};
|
||||
|
||||
const summaryList = [];
|
||||
if (summaryData) {
|
||||
summaryList.push(summaryData);
|
||||
} else {
|
||||
for (const filename of readdirSync(summariesPath)) {
|
||||
if (!filename.endsWith(".json")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const summaryPath = new URL(filename, summariesPath);
|
||||
const summaryData = JSON.parse(readFileSync(summaryPath, "utf8"));
|
||||
summaryList.push(summaryData);
|
||||
}
|
||||
}
|
||||
|
||||
for (const summaryData of summaryList) {
|
||||
const { v, metadata, tests } = summaryData;
|
||||
if (v !== 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { name, version, revision } = metadata;
|
||||
if (revision) {
|
||||
metadataInfo[name] =
|
||||
`${version}-[\`${revision.slice(0, 7)}\`](https://github.com/oven-sh/bun/commit/${revision})`;
|
||||
} else {
|
||||
metadataInfo[name] = `${version}`;
|
||||
}
|
||||
|
||||
for (const test of tests) {
|
||||
const { label, filename, status, error } = test;
|
||||
if (label) {
|
||||
labelInfo[label] ||= { pass: 0, fail: 0, skip: 0, todo: 0, total: 0 };
|
||||
labelInfo[label][status.toLowerCase()] += 1;
|
||||
labelInfo[label].total += 1;
|
||||
}
|
||||
testInfo[name] ||= { pass: 0, fail: 0, skip: 0, todo: 0, total: 0 };
|
||||
testInfo[name][status.toLowerCase()] += 1;
|
||||
testInfo[name].total += 1;
|
||||
if (status === "FAIL") {
|
||||
errorInfo[filename] ||= {};
|
||||
errorInfo[filename][name] = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let summaryMd = `## Node.js tests
|
||||
`;
|
||||
|
||||
if (!summaryData) {
|
||||
summaryMd += `
|
||||
| Platform | Conformance | Passed | Failed | Skipped | Total |
|
||||
| - | - | - | - | - | - |
|
||||
`;
|
||||
|
||||
for (const [name, { pass, fail, skip, total }] of Object.entries(testInfo)) {
|
||||
testInfo[name].coverage = (((pass + fail + skip) / total) * 100).toFixed(2);
|
||||
testInfo[name].conformance = ((pass / total) * 100).toFixed(2);
|
||||
}
|
||||
|
||||
for (const [name, { conformance, pass, fail, skip, total }] of Object.entries(testInfo)) {
|
||||
summaryMd += `| \`${name}\` ${metadataInfo[name]} | ${conformance} % | ${pass} | ${fail} | ${skip} | ${total} |\n`;
|
||||
}
|
||||
}
|
||||
|
||||
summaryMd += `
|
||||
| API | Conformance | Passed | Failed | Skipped | Total |
|
||||
| - | - | - | - | - | - |
|
||||
`;
|
||||
|
||||
for (const [label, { pass, fail, skip, total }] of Object.entries(labelInfo)) {
|
||||
labelInfo[label].coverage = (((pass + fail + skip) / total) * 100).toFixed(2);
|
||||
labelInfo[label].conformance = ((pass / total) * 100).toFixed(2);
|
||||
}
|
||||
|
||||
for (const [label, { conformance, pass, fail, skip, total }] of Object.entries(labelInfo)) {
|
||||
summaryMd += `| \`${label}\` | ${conformance} % | ${pass} | ${fail} | ${skip} | ${total} |\n`;
|
||||
}
|
||||
|
||||
if (!summaryData) {
|
||||
writeFileSync(summaryMdPath, summaryMd);
|
||||
}
|
||||
|
||||
const githubSummaryPath = process.env.GITHUB_STEP_SUMMARY;
|
||||
if (githubSummaryPath) {
|
||||
appendFileSync(githubSummaryPath, summaryMd);
|
||||
}
|
||||
|
||||
console.log("=".repeat(process.stdout.columns));
|
||||
console.log("Summary by platform:");
|
||||
console.table(testInfo);
|
||||
console.log("Summary by label:");
|
||||
console.table(labelInfo);
|
||||
if (regressedTests?.length) {
|
||||
const isTty = process.stdout.isTTY;
|
||||
if (isTty) {
|
||||
process.stdout.write("\x1b[31m");
|
||||
}
|
||||
const { name } = summaryData.metadata;
|
||||
console.log(`Regressions found in ${regressedTests.length} tests for ${name}:`);
|
||||
console.table(regressedTests);
|
||||
if (isTty) {
|
||||
process.stdout.write("\x1b[0m");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isJavaScript(filename) {
|
||||
return /\.(m|c)?js$/.test(filename);
|
||||
}
|
||||
|
||||
function isTest(filename) {
|
||||
return /^test-/.test(basename(filename));
|
||||
}
|
||||
|
||||
function getMetadata(execPath) {
|
||||
const { pathname: filePath } = metadataScriptPath;
|
||||
const { status: exitCode, stdout } = spawnSync(execPath, [filePath], {
|
||||
cwd,
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
BUN_DEBUG_QUIET_LOGS: "1",
|
||||
},
|
||||
timeout: 5_000,
|
||||
});
|
||||
|
||||
if (exitCode === 0) {
|
||||
try {
|
||||
return JSON.parse(stdout);
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
os: process.platform,
|
||||
arch: process.arch,
|
||||
};
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,166 +0,0 @@
|
||||
[
|
||||
{
|
||||
"label": "node:buffer",
|
||||
"pattern": "parallel/test-buffer",
|
||||
"skip": [
|
||||
{
|
||||
"file": "backing-arraybuffer.js",
|
||||
"reason": "Internal binding checks if the buffer is on the heap"
|
||||
}
|
||||
],
|
||||
"todo": [
|
||||
{
|
||||
"file": "constants.js",
|
||||
"reason": "Hangs"
|
||||
},
|
||||
{
|
||||
"file": "tostring-rangeerror.js",
|
||||
"reason": "Hangs"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "node:path",
|
||||
"pattern": "parallel/test-path"
|
||||
},
|
||||
{
|
||||
"label": "node:child_process",
|
||||
"pattern": "parallel/test-child-process"
|
||||
},
|
||||
{
|
||||
"label": "node:async_hooks",
|
||||
"pattern": "parallel/test-async-hooks"
|
||||
},
|
||||
{
|
||||
"label": "node:crypto",
|
||||
"pattern": "parallel/test-crypto"
|
||||
},
|
||||
{
|
||||
"label": "node:dgram",
|
||||
"pattern": "parallel/test-dgram"
|
||||
},
|
||||
{
|
||||
"label": "node:diagnostics_channel",
|
||||
"pattern": "parallel/test-diagnostics-channel"
|
||||
},
|
||||
{
|
||||
"label": "node:fs",
|
||||
"pattern": "parallel/test-fs"
|
||||
},
|
||||
{
|
||||
"label": "node:dns",
|
||||
"pattern": "parallel/test-dns"
|
||||
},
|
||||
{
|
||||
"label": "node:domain",
|
||||
"pattern": "parallel/test-domain"
|
||||
},
|
||||
{
|
||||
"label": "node:events",
|
||||
"pattern": "parallel/test-event-emitter"
|
||||
},
|
||||
{
|
||||
"label": "node:http",
|
||||
"pattern": "parallel/test-http"
|
||||
},
|
||||
{
|
||||
"label": "node:http2",
|
||||
"pattern": "parallel/test-http2"
|
||||
},
|
||||
{
|
||||
"label": "node:https",
|
||||
"pattern": "parallel/test-https"
|
||||
},
|
||||
{
|
||||
"label": "node:net",
|
||||
"pattern": "parallel/test-net"
|
||||
},
|
||||
{
|
||||
"label": "node:os",
|
||||
"pattern": "parallel/test-os"
|
||||
},
|
||||
{
|
||||
"label": "process",
|
||||
"pattern": "parallel/test-process"
|
||||
},
|
||||
{
|
||||
"label": "node:stream",
|
||||
"pattern": "parallel/test-stream"
|
||||
},
|
||||
{
|
||||
"label": "node:stream",
|
||||
"pattern": "parallel/test-readable"
|
||||
},
|
||||
{
|
||||
"label": "node:timers",
|
||||
"pattern": "parallel/test-timers"
|
||||
},
|
||||
{
|
||||
"label": "node:timers",
|
||||
"pattern": "parallel/test-next-tick"
|
||||
},
|
||||
{
|
||||
"label": "node:tls",
|
||||
"pattern": "parallel/test-tls"
|
||||
},
|
||||
{
|
||||
"label": "node:tty",
|
||||
"pattern": "parallel/test-tty"
|
||||
},
|
||||
{
|
||||
"label": "node:url",
|
||||
"pattern": "parallel/test-url"
|
||||
},
|
||||
{
|
||||
"label": "node:util",
|
||||
"pattern": "parallel/test-util"
|
||||
},
|
||||
{
|
||||
"label": "node:trace_events",
|
||||
"pattern": "parallel/test-trace-events"
|
||||
},
|
||||
{
|
||||
"label": "node:vm",
|
||||
"pattern": "parallel/test-vm"
|
||||
},
|
||||
{
|
||||
"label": "node:zlib",
|
||||
"pattern": "parallel/test-zlib"
|
||||
},
|
||||
{
|
||||
"label": "node:worker_threads",
|
||||
"pattern": "parallel/test-worker"
|
||||
},
|
||||
{
|
||||
"label": "node:readline",
|
||||
"pattern": "parallel/test-readline"
|
||||
},
|
||||
{
|
||||
"label": "web:crypto",
|
||||
"pattern": "parallel/test-webcrypto"
|
||||
},
|
||||
{
|
||||
"label": "web:streams",
|
||||
"pattern": "parallel/test-webstream"
|
||||
},
|
||||
{
|
||||
"label": "web:streams",
|
||||
"pattern": "parallel/test-whatwg-webstreams"
|
||||
},
|
||||
{
|
||||
"label": "web:encoding",
|
||||
"pattern": "parallel/test-whatwg-encoding"
|
||||
},
|
||||
{
|
||||
"label": "web:url",
|
||||
"pattern": "parallel/test-whatwg-url"
|
||||
},
|
||||
{
|
||||
"label": "web:websocket",
|
||||
"pattern": "parallel/test-websocket"
|
||||
},
|
||||
{
|
||||
"label": "web:performance",
|
||||
"pattern": "parallel/test-performance"
|
||||
}
|
||||
]
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"include": [".", "../../packages/bun-types/index.d.ts"],
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"module": "ESNext",
|
||||
"target": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
"allowImportingTsExtensions": true,
|
||||
"experimentalDecorators": true,
|
||||
"noEmit": true,
|
||||
"composite": true,
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "preserve",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowJs": true,
|
||||
"resolveJsonModule": true,
|
||||
"noImplicitThis": false,
|
||||
"paths": {
|
||||
"assert": ["./common/assert.js"]
|
||||
}
|
||||
},
|
||||
"exclude": []
|
||||
}
|
||||
Reference in New Issue
Block a user