diff options
author | 2023-03-08 11:38:09 -0800 | |
---|---|---|
committer | 2023-03-08 11:38:09 -0800 | |
commit | ab02ab25b1ea37f2861099f91e3783591e08efdd (patch) | |
tree | b8a51acdc8ce63c01cdaa13d0a10b3c6d37ebb54 | |
parent | deb7a2b19225265ad8f847da300f9f6db7c5e8b3 (diff) | |
download | bun-ab02ab25b1ea37f2861099f91e3783591e08efdd.tar.gz bun-ab02ab25b1ea37f2861099f91e3783591e08efdd.tar.zst bun-ab02ab25b1ea37f2861099f91e3783591e08efdd.zip |
Improve test harness
-rw-r--r-- | .prettierignore | 1 | ||||
-rwxr-xr-x | test/bun.lockb | bin | 31909 -> 35688 bytes | |||
-rw-r--r-- | test/js/deno/.gitignore | 1 | ||||
-rw-r--r-- | test/js/deno/abort/abort-controller.test.ts | 97 | ||||
-rw-r--r-- | test/js/deno/fetch/body.test.ts | 90 | ||||
-rw-r--r-- | test/js/deno/harness.ts | 230 | ||||
-rw-r--r-- | test/js/deno/harness/assert.ts | 207 | ||||
-rw-r--r-- | test/js/deno/harness/fixture.ts | 26 | ||||
-rw-r--r-- | test/js/deno/harness/global.ts | 45 | ||||
-rw-r--r-- | test/js/deno/harness/util.ts | 5 | ||||
-rw-r--r-- | test/js/deno/html/blob.test.ts | 191 | ||||
-rw-r--r-- | test/js/deno/resources/tests.json | 7 | ||||
-rw-r--r-- | test/js/deno/scripts/postinstall.ts | 96 | ||||
-rw-r--r-- | test/package.json | 1 |
14 files changed, 615 insertions, 382 deletions
diff --git a/.prettierignore b/.prettierignore index 464309eab..21683c3e8 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,3 +8,4 @@ src/test/fixtures src/react-refresh.js test/snapshots test/snapshots-no-hmr +test/js/deno diff --git a/test/bun.lockb b/test/bun.lockb Binary files differindex f724750a9..b05324ca6 100755 --- a/test/bun.lockb +++ b/test/bun.lockb diff --git a/test/js/deno/.gitignore b/test/js/deno/.gitignore new file mode 100644 index 000000000..2fb5beae2 --- /dev/null +++ b/test/js/deno/.gitignore @@ -0,0 +1 @@ +*.deno.* diff --git a/test/js/deno/abort/abort-controller.test.ts b/test/js/deno/abort/abort-controller.test.ts index 3aae2b623..651cadf31 100644 --- a/test/js/deno/abort/abort-controller.test.ts +++ b/test/js/deno/abort/abort-controller.test.ts @@ -1,66 +1,59 @@ -// Updated: Wed, 08 Mar 2023 00:55:15 GMT -// URL: https://raw.githubusercontent.com/denoland/deno/main/cli/tests/unit/abort_controller_test.ts -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2018+ the Deno authors. All rights reserved. MIT license. +// https://raw.githubusercontent.com/denoland/deno/main/cli/tests/unit/abort_controller_test.ts import { assert, assertEquals } from "deno:harness"; - Deno.test(function basicAbortController() { - const controller = new AbortController(); - assert(controller); - const { signal } = controller; - assert(signal); - assertEquals(signal.aborted, false); - controller.abort(); - assertEquals(signal.aborted, true); + const controller = new AbortController(); + assert(controller); + const { signal } = controller; + assert(signal); + assertEquals(signal.aborted, false); + controller.abort(); + assertEquals(signal.aborted, true); }); - Deno.test(function signalCallsOnabort() { - const controller = new AbortController(); - const { signal } = controller; - let called = false; - signal.onabort = evt => { - assert(evt); - assertEquals(evt.type, "abort"); - called = true; - }; - controller.abort(); - assert(called); + const controller = new AbortController(); + const { signal } = controller; + let called = false; + signal.onabort = (evt)=>{ + assert(evt); + assertEquals(evt.type, "abort"); + called = true; + }; + controller.abort(); + assert(called); }); - Deno.test(function signalEventListener() { - const controller = new AbortController(); - const { signal } = controller; - let called = false; - signal.addEventListener("abort", function (ev) { - assert(this === signal); - assertEquals(ev.type, "abort"); - called = true; - }); - controller.abort(); - assert(called); + const controller = new AbortController(); + const { signal } = controller; + let called = false; + signal.addEventListener("abort", function(ev) { + assert(this === signal); + assertEquals(ev.type, "abort"); + called = true; + }); + controller.abort(); + assert(called); }); - Deno.test(function onlyAbortsOnce() { - const controller = new AbortController(); - const { signal } = controller; - let called = 0; - signal.addEventListener("abort", () => called++); - signal.onabort = () => { - called++; - }; - controller.abort(); - assertEquals(called, 2); - controller.abort(); - assertEquals(called, 2); + const controller = new AbortController(); + const { signal } = controller; + let called = 0; + signal.addEventListener("abort", ()=>called++); + signal.onabort = ()=>{ + called++; + }; + controller.abort(); + assertEquals(called, 2); + controller.abort(); + assertEquals(called, 2); }); - Deno.test(function controllerHasProperToString() { - const actual = Object.prototype.toString.call(new AbortController()); - assertEquals(actual, "[object AbortController]"); + const actual = Object.prototype.toString.call(new AbortController()); + assertEquals(actual, "[object AbortController]"); }); - Deno.test(function abortReason() { - const signal = AbortSignal.abort("hey!"); - assertEquals(signal.aborted, true); - assertEquals(signal.reason, "hey!"); + const signal = AbortSignal.abort("hey!"); + assertEquals(signal.aborted, true); + assertEquals(signal.reason, "hey!"); }); diff --git a/test/js/deno/fetch/body.test.ts b/test/js/deno/fetch/body.test.ts new file mode 100644 index 000000000..92ad70c0a --- /dev/null +++ b/test/js/deno/fetch/body.test.ts @@ -0,0 +1,90 @@ +// Copyright 2018+ the Deno authors. All rights reserved. MIT license. +// https://raw.githubusercontent.com/denoland/deno/main/cli/tests/unit/body_test.ts + +import { assert, assertEquals } from "deno:harness"; +function buildBody(body: any, headers?: Headers): Body { + const stub = new Request("http://foo/", { + body: body, + headers, + method: "POST" + }); + return stub as Body; +} +const intArrays = [ + Int8Array, + Int16Array, + Int32Array, + Uint8Array, + Uint16Array, + Uint32Array, + Uint8ClampedArray, + Float32Array, + Float64Array +]; +Deno.test(async function arrayBufferFromByteArrays() { + const buffer = new TextEncoder().encode("ahoyhoy8").buffer; + for (const type of intArrays){ + const body = buildBody(new type(buffer)); + const text = new TextDecoder("utf-8").decode(await body.arrayBuffer()); + assertEquals(text, "ahoyhoy8"); + } +}); +Deno.test({ + permissions: { + net: true + } +}, async function bodyMultipartFormData() { + const response = await fetch("http://localhost:4545/multipart_form_data.txt"); + assert(response.body instanceof ReadableStream); + const text = await response.text(); + const body = buildBody(text, response.headers); + const formData = await body.formData(); + assert(formData.has("field_1")); + assertEquals(formData.get("field_1")!.toString(), "value_1 \r\n"); + assert(formData.has("field_2")); +}); +Deno.test({ + permissions: { + net: true + } +}, async function bodyURLEncodedFormData() { + const response = await fetch("http://localhost:4545/subdir/form_urlencoded.txt"); + assert(response.body instanceof ReadableStream); + const text = await response.text(); + const body = buildBody(text, response.headers); + const formData = await body.formData(); + assert(formData.has("field_1")); + assertEquals(formData.get("field_1")!.toString(), "Hi"); + assert(formData.has("field_2")); + assertEquals(formData.get("field_2")!.toString(), "<Deno>"); +}); +Deno.test({ + permissions: {} +}, async function bodyURLSearchParams() { + const body = buildBody(new URLSearchParams({ + hello: "world" + })); + const text = await body.text(); + assertEquals(text, "hello=world"); +}); +Deno.test(async function bodyArrayBufferMultipleParts() { + const parts: Uint8Array[] = []; + let size = 0; + for(let i = 0; i <= 150000; i++){ + const part = new Uint8Array([ + 1 + ]); + parts.push(part); + size += part.length; + } + let offset = 0; + const stream = new ReadableStream({ + pull (controller) { + const chunk = parts[offset++]; + if (!chunk) return controller.close(); + controller.enqueue(chunk); + } + }); + const body = buildBody(stream); + assertEquals((await body.arrayBuffer()).byteLength, size); +}); diff --git a/test/js/deno/harness.ts b/test/js/deno/harness.ts index 167860d1f..8634d5261 100644 --- a/test/js/deno/harness.ts +++ b/test/js/deno/harness.ts @@ -1,226 +1,4 @@ -// Deno's test utilities implemented using expect(). -// https://github.com/denoland/deno/blob/main/cli/tests/unit/test_util.ts - -import { concatArrayBuffers } from "bun"; -import { it, expect } from "bun:test"; - -export function test(fn: () => void): void { - it(fn.name, fn); -} - -export function assert(condition: unknown, message?: string): asserts condition is true { - if (message) { - it(message, () => assert(condition)); - } else { - expect(condition).toBeTruthy(); - } -} - -export function assertFalse(condition: unknown, message?: string): asserts condition is false { - if (message) { - it(message, () => assertFalse(condition)); - } else { - expect(condition).toBeFalsy(); - } -} - -export function assertEquals(actual: unknown, expected: unknown, message?: string): void { - if (message) { - it(message, () => assertEquals(actual, expected)); - } else { - expect(actual).toEqual(expected); - } -} - -export function assertExists(value: unknown, message?: string): void { - if (message) { - it(message, () => assertExists(value)); - } else { - expect(value).toBeDefined(); - } -} - -export function assertNotEquals(actual: unknown, expected: unknown, message?: string): void { - if (message) { - it(message, () => assertNotEquals(actual, expected)); - } else { - expect(actual).not.toEqual(expected); - } -} - -export function assertStrictEquals(actual: unknown, expected: unknown, message?: string): void { - if (message) { - it(message, () => assertStrictEquals(actual, expected)); - } else { - expect(actual).toStrictEqual(expected); - } -} - -export function assertNotStrictEquals(actual: unknown, expected: unknown, message?: string): void { - if (message) { - it(message, () => assertNotStrictEquals(actual, expected)); - } else { - expect(actual).not.toStrictEqual(expected); - } -} - -export function assertAlmostEquals(actual: unknown, expected: number, epsilon: number = 1e-7, message?: string): void { - if (message) { - it(message, () => assertAlmostEquals(actual, expected)); - } else if (typeof actual === "number") { - // TODO: toBeCloseTo() - expect(Math.abs(actual - expected)).toBeLessThanOrEqual(epsilon); - } else { - expect(typeof actual).toBe("number"); - } -} - -export function assertInstanceOf(actual: unknown, expected: unknown, message?: string): void { - if (message) { - it(message, () => assertInstanceOf(actual, expected)); - } else if (typeof actual === "object") { - if (actual !== null) { - expect(actual).toHaveProperty("constructor", expected); - } else { - expect(actual).not.toBeNull(); - } - } else { - expect(typeof actual).toBe("object"); - } -} - -export function assertNotInstanceOf(actual: unknown, expected: unknown, message?: string): void { - if (message) { - it(message, () => assertNotInstanceOf(actual, expected)); - } else if (typeof actual === "object") { - if (actual !== null) { - expect(actual).not.toHaveProperty("constructor", expected); - } else { - expect(actual).not.toBeNull(); - } - } else { - expect(typeof actual).toBe("object"); - } -} - -export function assertStringIncludes(actual: unknown, expected: string, message?: string): void { - if (message) { - it(message, () => assertStringIncludes(actual, expected)); - } else if (typeof actual === "string") { - expect(actual).toContain(expected); - } else { - expect(typeof actual).toBe("string"); - } -} - -export function assertArrayIncludes(actual: unknown, expected: unknown[], message?: string): void { - if (message) { - it(message, () => assertArrayIncludes(actual, expected)); - } else if (Array.isArray(actual)) { - for (const value of expected) { - expect(actual).toContain(value); - } - } else { - expect(Array.isArray(actual)).toBe(true); - } -} - -export function assertMatch(actual: unknown, expected: RegExp, message?: string): void { - if (message) { - it(message, () => assertMatch(actual, expected)); - } else if (typeof actual === "string") { - expect(expected.test(actual)).toBe(true); - } else { - expect(typeof actual).toBe("string"); - } -} - -export function assertNotMatch(actual: unknown, expected: RegExp, message?: string): void { - if (message) { - it(message, () => assertNotMatch(actual, expected)); - } else if (typeof actual === "string") { - expect(expected.test(actual)).toBe(false); - } else { - expect(typeof actual).toBe("string"); - } -} - -export function assertObjectMatch(actual: unknown, expected: Record<PropertyKey, unknown>, message?: string): void { - if (message) { - it(message, () => assertObjectMatch(actual, expected)); - } else if (typeof actual === "object") { - // TODO: toMatchObject() - if (actual !== null) { - const expectedKeys = Object.keys(expected); - for (const key of Object.keys(actual)) { - if (!expectedKeys.includes(key)) { - // @ts-ignore - delete actual[key]; - } - } - expect(actual).toEqual(expected); - } else { - expect(actual).not.toBeNull(); - } - } else { - expect(typeof actual).toBe("object"); - } -} - -export function assertThrows(fn: () => void, message?: string): void { - if (message) { - it(message, () => assertThrows(fn)); - } else { - try { - fn(); - } catch (error) { - expect(error).toBeDefined(); - return; - } - throw new Error("Expected an error to be thrown"); - } -} - -export async function assertRejects(fn: () => Promise<unknown>, message?: string): Promise<void> { - if (message) { - it(message, () => assertRejects(fn)); - } else { - try { - await fn(); - } catch (error) { - expect(error).toBeDefined(); - return; - } - throw new Error("Expected an error to be thrown"); - } -} - -export function equal(a: unknown, b: unknown): boolean { - return Bun.deepEquals(a, b); -} - -export function fail(message: string): never { - throw new Error(message); -} - -export function unimplemented(message: string): never { - throw new Error(`Unimplemented: ${message}`); -} - -export function unreachable(): never { - throw new Error("Unreachable"); -} - -export function concat(...buffers: Uint8Array[]): Uint8Array { - return new Uint8Array(concatArrayBuffers(buffers)); -} - -export function inspect(...args: unknown[]): string { - return Bun.inspect(...args); -} - -// @ts-expect-error -globalThis["Deno"] = { - test, - inspect, -}; +export * from "./harness/global.js"; +export * from "./harness/util.js"; +export * from "./harness/assert.js"; +export * from "./harness/fixture.js"; diff --git a/test/js/deno/harness/assert.ts b/test/js/deno/harness/assert.ts new file mode 100644 index 000000000..ba3570115 --- /dev/null +++ b/test/js/deno/harness/assert.ts @@ -0,0 +1,207 @@ +// Deno's test assertions implemented using expect(). +// https://github.com/denoland/deno/blob/main/cli/tests/unit/test_util.ts + +import { test, expect } from "bun:test"; + +export function assert(condition: unknown, message?: string): asserts condition is true { + if (message) { + test(message, () => assert(condition)); + } else { + expect(condition).toBeTruthy(); + } +} + +export function assertFalse(condition: unknown, message?: string): asserts condition is false { + if (message) { + test(message, () => assertFalse(condition)); + } else { + expect(condition).toBeFalsy(); + } +} + +export function assertEquals(actual: unknown, expected: unknown, message?: string): void { + if (message) { + test(message, () => assertEquals(actual, expected)); + } else { + expect(actual).toEqual(expected); + } +} + +export function assertExists(value: unknown, message?: string): void { + if (message) { + test(message, () => assertExists(value)); + } else { + expect(value).toBeDefined(); + } +} + +export function assertNotEquals(actual: unknown, expected: unknown, message?: string): void { + if (message) { + test(message, () => assertNotEquals(actual, expected)); + } else { + expect(actual).not.toEqual(expected); + } +} + +export function assertStrictEquals(actual: unknown, expected: unknown, message?: string): void { + if (message) { + test(message, () => assertStrictEquals(actual, expected)); + } else { + expect(actual).toStrictEqual(expected); + } +} + +export function assertNotStrictEquals(actual: unknown, expected: unknown, message?: string): void { + if (message) { + test(message, () => assertNotStrictEquals(actual, expected)); + } else { + expect(actual).not.toStrictEqual(expected); + } +} + +export function assertAlmostEquals(actual: unknown, expected: number, epsilon: number = 1e-7, message?: string): void { + if (message) { + test(message, () => assertAlmostEquals(actual, expected)); + } else if (typeof actual === "number") { + // TODO: toBeCloseTo() + expect(Math.abs(actual - expected)).toBeLessThanOrEqual(epsilon); + } else { + expect(typeof actual).toBe("number"); + } +} + +export function assertInstanceOf(actual: unknown, expected: unknown, message?: string): void { + if (message) { + test(message, () => assertInstanceOf(actual, expected)); + } else if (typeof actual === "object") { + if (actual !== null) { + expect(actual).toHaveProperty("constructor", expected); + } else { + expect(actual).not.toBeNull(); + } + } else { + expect(typeof actual).toBe("object"); + } +} + +export function assertNotInstanceOf(actual: unknown, expected: unknown, message?: string): void { + if (message) { + test(message, () => assertNotInstanceOf(actual, expected)); + } else if (typeof actual === "object") { + if (actual !== null) { + expect(actual).not.toHaveProperty("constructor", expected); + } else { + expect(actual).not.toBeNull(); + } + } else { + expect(typeof actual).toBe("object"); + } +} + +export function assertStringIncludes(actual: unknown, expected: string, message?: string): void { + if (message) { + test(message, () => assertStringIncludes(actual, expected)); + } else if (typeof actual === "string") { + expect(actual).toContain(expected); + } else { + expect(typeof actual).toBe("string"); + } +} + +export function assertArrayIncludes(actual: unknown, expected: unknown[], message?: string): void { + if (message) { + test(message, () => assertArrayIncludes(actual, expected)); + } else if (Array.isArray(actual)) { + for (const value of expected) { + expect(actual).toContain(value); + } + } else { + expect(Array.isArray(actual)).toBe(true); + } +} + +export function assertMatch(actual: unknown, expected: RegExp, message?: string): void { + if (message) { + test(message, () => assertMatch(actual, expected)); + } else if (typeof actual === "string") { + expect(expected.test(actual)).toBe(true); + } else { + expect(typeof actual).toBe("string"); + } +} + +export function assertNotMatch(actual: unknown, expected: RegExp, message?: string): void { + if (message) { + test(message, () => assertNotMatch(actual, expected)); + } else if (typeof actual === "string") { + expect(expected.test(actual)).toBe(false); + } else { + expect(typeof actual).toBe("string"); + } +} + +export function assertObjectMatch(actual: unknown, expected: Record<PropertyKey, unknown>, message?: string): void { + if (message) { + test(message, () => assertObjectMatch(actual, expected)); + } else if (typeof actual === "object") { + // TODO: toMatchObject() + if (actual !== null) { + const expectedKeys = Object.keys(expected); + for (const key of Object.keys(actual)) { + if (!expectedKeys.includes(key)) { + // @ts-ignore + delete actual[key]; + } + } + expect(actual).toEqual(expected); + } else { + expect(actual).not.toBeNull(); + } + } else { + expect(typeof actual).toBe("object"); + } +} + +export function assertThrows(fn: () => void, message?: string): void { + if (message) { + test(message, () => assertThrows(fn)); + } else { + try { + fn(); + } catch (error) { + expect(error).toBeDefined(); + return; + } + throw new Error("Expected an error to be thrown"); + } +} + +export async function assertRejects(fn: () => Promise<unknown>, message?: string): Promise<void> { + if (message) { + test(message, () => assertRejects(fn)); + } else { + try { + await fn(); + } catch (error) { + expect(error).toBeDefined(); + return; + } + throw new Error("Expected an error to be thrown"); + } +} + +export function equal(a: unknown, b: unknown): boolean { + return Bun.deepEquals(a, b); +} + +export function fail(message: string): never { + throw new Error(message); +} + +export function unimplemented(message: string): never { + throw new Error(`Unimplemented: ${message}`); +} + +export function unreachable(): never { + throw new Error("Unreachable"); +} diff --git a/test/js/deno/harness/fixture.ts b/test/js/deno/harness/fixture.ts new file mode 100644 index 000000000..13a531e52 --- /dev/null +++ b/test/js/deno/harness/fixture.ts @@ -0,0 +1,26 @@ +import type { Server } from "bun"; +import { serve } from "bun"; +import { afterAll, beforeAll } from "bun:test"; + +let server: Server; + +beforeAll(() => { + server = serve({ + port: 4545, + fetch(request: Request): Response { + const { url } = request; + const { pathname, search } = new URL(url); + const redirect = new URL( + `${pathname}?${search}`, + "https://raw.githubusercontent.com/denoland/deno/main/cli/tests/testdata/", + ); + return Response.redirect(redirect.toString()); + }, + }); +}); + +afterAll(() => { + if (server) { + server.stop(true); + } +}); diff --git a/test/js/deno/harness/global.ts b/test/js/deno/harness/global.ts new file mode 100644 index 000000000..4992f026f --- /dev/null +++ b/test/js/deno/harness/global.ts @@ -0,0 +1,45 @@ +import { test as bunTest } from "bun:test"; + +type Fn = () => void | Promise<unknown>; +type Options = { + permissions?: { + net?: boolean; + }; + ignore?: boolean; +}; + +function test(arg0: Fn | Options, arg1?: Fn): void { + if (typeof arg0 === "function") { + bunTest(arg0.name, arg0); + } else if (typeof arg1 === "function") { + if (arg0?.ignore === true || arg0?.permissions?.net === false) { + bunTest.skip(arg1.name, arg1); + } else { + bunTest(arg1.name, arg1); + } + } else { + throw new Error("Unimplemented"); + } +} + +test.ignore = (arg0: Fn | Options, arg1?: Fn) => { + if (typeof arg0 === "function") { + bunTest.skip(arg0.name, arg0); + } else if (typeof arg1 === "function") { + bunTest.skip(arg1.name, arg1); + } else { + throw new Error("Unimplemented"); + } +}; + +export function inspect(...args: unknown[]): string { + return Bun.inspect(...args); +} + +export const Deno = { + test, + inspect, +}; + +// @ts-expect-error +globalThis["Deno"] = Deno; diff --git a/test/js/deno/harness/util.ts b/test/js/deno/harness/util.ts new file mode 100644 index 000000000..a7fbf7fce --- /dev/null +++ b/test/js/deno/harness/util.ts @@ -0,0 +1,5 @@ +import { concatArrayBuffers } from "bun"; + +export function concat(...buffers: Uint8Array[]): Uint8Array { + return new Uint8Array(concatArrayBuffers(buffers)); +} diff --git a/test/js/deno/html/blob.test.ts b/test/js/deno/html/blob.test.ts index af1e7f6e8..306d9ca59 100644 --- a/test/js/deno/html/blob.test.ts +++ b/test/js/deno/html/blob.test.ts @@ -1,114 +1,119 @@ -// Updated: Wed, 08 Mar 2023 00:55:15 GMT -// URL: https://raw.githubusercontent.com/denoland/deno/main/cli/tests/unit/blob_test.ts -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2018+ the Deno authors. All rights reserved. MIT license. +// https://raw.githubusercontent.com/denoland/deno/main/cli/tests/unit/blob_test.ts + import { assert, assertEquals, assertStringIncludes } from "deno:harness"; import { concat } from "deno:harness"; - Deno.test(function blobString() { - const b1 = new Blob(["Hello World"]); - const str = "Test"; - const b2 = new Blob([b1, str]); - assertEquals(b2.size, b1.size + str.length); + const b1 = new Blob([ + "Hello World" + ]); + const str = "Test"; + const b2 = new Blob([ + b1, + str + ]); + assertEquals(b2.size, b1.size + str.length); }); - Deno.test(function blobBuffer() { - const buffer = new ArrayBuffer(12); - const u8 = new Uint8Array(buffer); - const f1 = new Float32Array(buffer); - const b1 = new Blob([buffer, u8]); - assertEquals(b1.size, 2 * u8.length); - const b2 = new Blob([b1, f1]); - assertEquals(b2.size, 3 * u8.length); + const buffer = new ArrayBuffer(12); + const u8 = new Uint8Array(buffer); + const f1 = new Float32Array(buffer); + const b1 = new Blob([ + buffer, + u8 + ]); + assertEquals(b1.size, 2 * u8.length); + const b2 = new Blob([ + b1, + f1 + ]); + assertEquals(b2.size, 3 * u8.length); }); - Deno.test(function blobSlice() { - const blob = new Blob(["Deno", "Foo"]); - const b1 = blob.slice(0, 3, "Text/HTML"); - assert(b1 instanceof Blob); - assertEquals(b1.size, 3); - assertEquals(b1.type, "text/html"); - const b2 = blob.slice(-1, 3); - assertEquals(b2.size, 0); - const b3 = blob.slice(100, 3); - assertEquals(b3.size, 0); - const b4 = blob.slice(0, 10); - assertEquals(b4.size, blob.size); + const blob = new Blob([ + "Deno", + "Foo" + ]); + const b1 = blob.slice(0, 3, "Text/HTML"); + assert(b1 instanceof Blob); + assertEquals(b1.size, 3); + assertEquals(b1.type, "text/html"); + const b2 = blob.slice(-1, 3); + assertEquals(b2.size, 0); + const b3 = blob.slice(100, 3); + assertEquals(b3.size, 0); + const b4 = blob.slice(0, 10); + assertEquals(b4.size, blob.size); }); - Deno.test(function blobInvalidType() { - const blob = new Blob(["foo"], { - type: "\u0521", - }); - - assertEquals(blob.type, ""); + const blob = new Blob([ + "foo" + ], { + type: "\u0521" + }); + assertEquals(blob.type, ""); }); - Deno.test(function blobShouldNotThrowError() { - let hasThrown = false; - - try { - // deno-lint-ignore no-explicit-any - const options1: any = { - ending: "utf8", - hasOwnProperty: "hasOwnProperty", - }; - const options2 = Object.create(null); - new Blob(["Hello World"], options1); - new Blob(["Hello World"], options2); - } catch { - hasThrown = true; - } - - assertEquals(hasThrown, false); -}); - -/* TODO https://github.com/denoland/deno/issues/7540 -Deno.test(function nativeEndLine() { - const options = { - ending: "native", - } as const; - const blob = new Blob(["Hello\nWorld"], options); - - assertEquals(blob.size, Deno.build.os === "windows" ? 12 : 11); + let hasThrown = false; + try { + const options1: any = { + ending: "utf8", + hasOwnProperty: "hasOwnProperty" + }; + const options2 = Object.create(null); + new Blob([ + "Hello World" + ], options1); + new Blob([ + "Hello World" + ], options2); + } catch { + hasThrown = true; + } + assertEquals(hasThrown, false); }); -*/ - Deno.test(async function blobText() { - const blob = new Blob(["Hello World"]); - assertEquals(await blob.text(), "Hello World"); + const blob = new Blob([ + "Hello World" + ]); + assertEquals(await blob.text(), "Hello World"); }); - Deno.test(async function blobStream() { - const blob = new Blob(["Hello World"]); - const stream = blob.stream(); - assert(stream instanceof ReadableStream); - const reader = stream.getReader(); - let bytes = new Uint8Array(); - const read = async (): Promise<void> => { - const { done, value } = await reader.read(); - if (!done && value) { - bytes = concat(bytes, value); - return read(); - } - }; - await read(); - const decoder = new TextDecoder(); - assertEquals(decoder.decode(bytes), "Hello World"); + const blob = new Blob([ + "Hello World" + ]); + const stream = blob.stream(); + assert(stream instanceof ReadableStream); + const reader = stream.getReader(); + let bytes = new Uint8Array(); + const read = async (): Promise<void> =>{ + const { done , value } = await reader.read(); + if (!done && value) { + bytes = concat(bytes, value); + return read(); + } + }; + await read(); + const decoder = new TextDecoder(); + assertEquals(decoder.decode(bytes), "Hello World"); }); - Deno.test(async function blobArrayBuffer() { - const uint = new Uint8Array([102, 111, 111]); - const blob = new Blob([uint]); - assertEquals(await blob.arrayBuffer(), uint.buffer); + const uint = new Uint8Array([ + 102, + 111, + 111 + ]); + const blob = new Blob([ + uint + ]); + assertEquals(await blob.arrayBuffer(), uint.buffer); }); - Deno.test(function blobConstructorNameIsBlob() { - const blob = new Blob(); - assertEquals(blob.constructor.name, "Blob"); + const blob = new Blob(); + assertEquals(blob.constructor.name, "Blob"); }); - -Deno.test(function blobCustomInspectFunction() { - const blob = new Blob(); - assertEquals(Deno.inspect(blob), `Blob { size: 0, type: "" }`); - assertStringIncludes(Deno.inspect(Blob.prototype), "Blob"); +Deno.test.ignore(function blobCustomInspectFunction() { + const blob = new Blob(); + assertEquals(Deno.inspect(blob), `Blob { size: 0, type: "" }`); + assertStringIncludes(Deno.inspect(Blob.prototype), "Blob"); }); diff --git a/test/js/deno/resources/tests.json b/test/js/deno/resources/tests.json index 067cb7205..7de35dd78 100644 --- a/test/js/deno/resources/tests.json +++ b/test/js/deno/resources/tests.json @@ -5,6 +5,11 @@ }, { "path": "html/blob.test.ts", - "remotePath": "unit/blob_test.ts" + "remotePath": "unit/blob_test.ts", + "skip": ["blobCustomInspectFunction"] + }, + { + "path": "fetch/body.test.ts", + "remotePath": "unit/body_test.ts" } ] diff --git a/test/js/deno/scripts/postinstall.ts b/test/js/deno/scripts/postinstall.ts index bca1e6582..65fd5a04e 100644 --- a/test/js/deno/scripts/postinstall.ts +++ b/test/js/deno/scripts/postinstall.ts @@ -1,26 +1,102 @@ import { mkdirSync } from "node:fs"; import { join, dirname } from "node:path"; +import { parse, print } from "@swc/core"; +import type { ImportDeclaration, ExpressionStatement, CallExpression } from "@swc/core"; import imports from "../resources/imports.json"; import tests from "../resources/tests.json"; +// FIXME: https://github.com/oven-sh/bun/issues/2350 +// import * as harness from "deno:harness"; + for (const test of tests) { const path = join(import.meta.dir, "..", test.path); const url = new URL(test.remotePath, "https://raw.githubusercontent.com/denoland/deno/main/cli/tests/"); const response = await fetch(url); console.log(response.status, url.toString(), "->", test.path); if (!response.ok) { - throw new Error(`Failed to download from GitHub: ${url} [status: ${response.status}]`); - } - let body = await response.text(); - for (const query of imports) { - const pattern = new RegExp(`"(.*${query})"`, "gmi"); - body = body.replace(pattern, '"deno:harness"'); + continue; } - const src = `// Updated: ${response.headers.get("Date")} -// URL: ${url} -${body}`; + const src = await response.text(); + const dst = await visit(src, test); try { mkdirSync(dirname(path)); } catch {} - await Bun.write(path, src); + await Bun.write(path.replace(".test.", ".deno."), src); + await Bun.write(path, dst); +} + +async function visit(src: string, test: any): Promise<string> { + const ast = await parse(src, { + syntax: "typescript", + target: "esnext", + dynamicImport: true, + }); + for (const item of ast.body) { + if (item.type === "ImportDeclaration") { + visitImport(item); + } + if (item.type === "ExpressionStatement") { + visitExpression(item, test); + } + } + const header = `// Copyright 2018+ the Deno authors. All rights reserved. MIT license. +// https://raw.githubusercontent.com/denoland/deno/main/cli/tests/${test.remotePath} +\n`; + const { code } = await print(ast, { + isModule: true, + }); + return header + code; +} + +function visitImport(item: ImportDeclaration): void { + const src = item.source.value; + let match = false; + for (const name of imports) { + if (src.endsWith(name)) { + match = true; + break; + } + } + if (!match) { + console.warn("Unknown import:", src); + return; + } + item.source.raw = '"deno:harness"'; + // FIXME: https://github.com/oven-sh/bun/issues/2350 + /*let missing = []; + for (const specifier of item.specifiers) { + const name = specifier.local.value; + if (!(name in harness)) { + missing.push(name); + } + } + if (missing.length) { + console.warn("Harness does not contain exports:", missing); + }*/ +} + +function visitExpression(item: ExpressionStatement, test: any): void { + if ( + item.expression.type === "CallExpression" && + item.expression.callee.type === "MemberExpression" && + item.expression.callee.object.type === "Identifier" && + item.expression.callee.object.value === "Deno" + ) { + if (item.expression.callee.property.type === "Identifier" && item.expression.callee.property.value === "test") { + visitTest(item.expression); + } + } +} + +function visitTest(item: CallExpression): void { + for (const argument of item.arguments) { + if (argument.expression.type === "FunctionExpression") { + const fn = argument.expression.identifier?.value; + for (const test of tests) { + if (test.skip && test.skip.includes(fn)) { + item.callee.property.value = "test.ignore"; + } + } + } + } } diff --git a/test/package.json b/test/package.json index dfeabcd42..bffbfee57 100644 --- a/test/package.json +++ b/test/package.json @@ -6,6 +6,7 @@ "bun-types": "canary" }, "dependencies": { + "@swc/core": "^1.3.38", "bktree-fast": "^0.0.7", "body-parser": "^1.20.2", "esbuild": "^0.17.11", |