Improve test harness

This commit is contained in:
Ashcon Partovi
2023-03-08 11:38:09 -08:00
parent deb7a2b192
commit ab02ab25b1
14 changed files with 618 additions and 385 deletions

View File

@@ -8,3 +8,4 @@ src/test/fixtures
src/react-refresh.js
test/snapshots
test/snapshots-no-hmr
test/js/deno

Binary file not shown.

1
test/js/deno/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.deno.*

View File

@@ -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!");
});

View File

@@ -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);
});

View File

@@ -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";

View File

@@ -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");
}

View File

@@ -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);
}
});

View File

@@ -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;

View File

@@ -0,0 +1,5 @@
import { concatArrayBuffers } from "bun";
export function concat(...buffers: Uint8Array[]): Uint8Array {
return new Uint8Array(concatArrayBuffers(buffers));
}

View File

@@ -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);
});
*/
Deno.test(async function blobText() {
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();
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;
}
};
await read();
const decoder = new TextDecoder();
assertEquals(decoder.decode(bytes), "Hello World");
assertEquals(hasThrown, false);
});
Deno.test(async function blobText() {
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");
});
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");
});

View File

@@ -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"
}
]

View File

@@ -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}]`);
continue;
}
let body = await response.text();
for (const query of imports) {
const pattern = new RegExp(`"(.*${query})"`, "gmi");
body = body.replace(pattern, '"deno:harness"');
}
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";
}
}
}
}
}

View File

@@ -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",