summaryrefslogtreecommitdiff
path: root/cli/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tests/unit')
-rw-r--r--cli/tests/unit/README.md43
-rw-r--r--cli/tests/unit/abort_controller_test.ts64
-rw-r--r--cli/tests/unit/blob_test.ts115
-rw-r--r--cli/tests/unit/body_test.ts189
-rw-r--r--cli/tests/unit/broadcast_channel_test.ts34
-rw-r--r--cli/tests/unit/buffer_test.ts461
-rw-r--r--cli/tests/unit/build_test.ts10
-rw-r--r--cli/tests/unit/cache_api_test.ts207
-rw-r--r--cli/tests/unit/chmod_test.ts190
-rw-r--r--cli/tests/unit/chown_test.ts190
-rw-r--r--cli/tests/unit/command_test.ts967
-rw-r--r--cli/tests/unit/console_test.ts2411
-rw-r--r--cli/tests/unit/copy_file_test.ts249
-rw-r--r--cli/tests/unit/cron_test.ts460
-rw-r--r--cli/tests/unit/custom_event_test.ts27
-rw-r--r--cli/tests/unit/dir_test.ts63
-rw-r--r--cli/tests/unit/dom_exception_test.ts23
-rw-r--r--cli/tests/unit/error_stack_test.ts54
-rw-r--r--cli/tests/unit/error_test.ts33
-rw-r--r--cli/tests/unit/esnext_test.ts43
-rw-r--r--cli/tests/unit/event_target_test.ts295
-rw-r--r--cli/tests/unit/event_test.ts143
-rw-r--r--cli/tests/unit/fetch_test.ts2071
-rw-r--r--cli/tests/unit/ffi_test.ts137
-rw-r--r--cli/tests/unit/file_test.ts112
-rw-r--r--cli/tests/unit/filereader_test.ts242
-rw-r--r--cli/tests/unit/files_test.ts1095
-rw-r--r--cli/tests/unit/flock_test.ts197
-rw-r--r--cli/tests/unit/fs_events_test.ts139
-rw-r--r--cli/tests/unit/get_random_values_test.ts63
-rw-r--r--cli/tests/unit/globals_test.ts225
-rw-r--r--cli/tests/unit/headers_test.ts416
-rw-r--r--cli/tests/unit/http_test.ts2801
-rw-r--r--cli/tests/unit/image_bitmap_test.ts92
-rw-r--r--cli/tests/unit/image_data_test.ts53
-rw-r--r--cli/tests/unit/internals_test.ts10
-rw-r--r--cli/tests/unit/intl_test.ts7
-rw-r--r--cli/tests/unit/io_test.ts77
-rw-r--r--cli/tests/unit/jupyter_test.ts79
-rw-r--r--cli/tests/unit/kv_queue_test.ts13
-rw-r--r--cli/tests/unit/kv_queue_test_no_db_close.ts20
-rw-r--r--cli/tests/unit/kv_queue_undelivered_test.ts59
-rw-r--r--cli/tests/unit/kv_test.ts2321
-rw-r--r--cli/tests/unit/link_test.ts195
-rw-r--r--cli/tests/unit/make_temp_test.ts157
-rw-r--r--cli/tests/unit/message_channel_test.ts55
-rw-r--r--cli/tests/unit/mkdir_test.ts235
-rw-r--r--cli/tests/unit/navigator_test.ts11
-rw-r--r--cli/tests/unit/net_test.ts1274
-rw-r--r--cli/tests/unit/network_interfaces_test.ts30
-rw-r--r--cli/tests/unit/ops_test.ts17
-rw-r--r--cli/tests/unit/os_test.ts304
-rw-r--r--cli/tests/unit/path_from_url_test.ts41
-rw-r--r--cli/tests/unit/performance_test.ts185
-rw-r--r--cli/tests/unit/permissions_test.ts202
-rw-r--r--cli/tests/unit/process_test.ts689
-rw-r--r--cli/tests/unit/progressevent_test.ts18
-rw-r--r--cli/tests/unit/promise_hooks_test.ts109
-rw-r--r--cli/tests/unit/read_dir_test.ts113
-rw-r--r--cli/tests/unit/read_file_test.ts182
-rw-r--r--cli/tests/unit/read_link_test.ts99
-rw-r--r--cli/tests/unit/read_text_file_test.ts208
-rw-r--r--cli/tests/unit/real_path_test.ts114
-rw-r--r--cli/tests/unit/ref_unref_test.ts12
-rw-r--r--cli/tests/unit/remove_test.ts291
-rw-r--r--cli/tests/unit/rename_test.ts274
-rw-r--r--cli/tests/unit/request_test.ts77
-rw-r--r--cli/tests/unit/resources_test.ts55
-rw-r--r--cli/tests/unit/response_test.ts102
-rw-r--r--cli/tests/unit/serve_test.ts3932
-rw-r--r--cli/tests/unit/signal_test.ts296
-rw-r--r--cli/tests/unit/stat_test.ts342
-rw-r--r--cli/tests/unit/stdio_test.ts32
-rw-r--r--cli/tests/unit/streams_test.ts478
-rw-r--r--cli/tests/unit/structured_clone_test.ts55
-rw-r--r--cli/tests/unit/symbol_test.ts11
-rw-r--r--cli/tests/unit/symlink_test.ts140
-rw-r--r--cli/tests/unit/sync_test.ts69
-rw-r--r--cli/tests/unit/test_util.ts87
-rw-r--r--cli/tests/unit/testing_test.ts154
-rw-r--r--cli/tests/unit/text_encoding_test.ts326
-rw-r--r--cli/tests/unit/timers_test.ts763
-rw-r--r--cli/tests/unit/tls_test.ts1546
-rw-r--r--cli/tests/unit/truncate_test.ts114
-rw-r--r--cli/tests/unit/tty_color_test.ts55
-rw-r--r--cli/tests/unit/tty_test.ts32
-rw-r--r--cli/tests/unit/umask_test.ts15
-rw-r--r--cli/tests/unit/url_search_params_test.ts356
-rw-r--r--cli/tests/unit/url_test.ts529
-rw-r--r--cli/tests/unit/urlpattern_test.ts65
-rw-r--r--cli/tests/unit/utime_test.ts337
-rw-r--r--cli/tests/unit/version_test.ts10
-rw-r--r--cli/tests/unit/wasm_test.ts104
-rw-r--r--cli/tests/unit/webcrypto_test.ts2047
-rw-r--r--cli/tests/unit/webgpu_test.ts267
-rw-r--r--cli/tests/unit/websocket_test.ts738
-rw-r--r--cli/tests/unit/websocketstream_test.ts.disabled359
-rw-r--r--cli/tests/unit/webstorage_test.ts52
-rw-r--r--cli/tests/unit/worker_permissions_test.ts34
-rw-r--r--cli/tests/unit/worker_test.ts843
-rw-r--r--cli/tests/unit/write_file_test.ts427
-rw-r--r--cli/tests/unit/write_text_file_test.ts218
102 files changed, 0 insertions, 36382 deletions
diff --git a/cli/tests/unit/README.md b/cli/tests/unit/README.md
deleted file mode 100644
index af31c08fc..000000000
--- a/cli/tests/unit/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# Deno runtime tests
-
-Files in this directory are unit tests for Deno runtime.
-
-Testing Deno runtime code requires checking API under different runtime
-permissions. To accomplish this all tests exercised are created using
-`Deno.test()` function.
-
-```ts
-import {} from "./test_util.ts";
-
-Deno.test(function simpleTestFn(): void {
- // test code here
-});
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- function complexTestFn(): void {
- // test code here
- },
-);
-```
-
-## Running tests
-
-There are two ways to run `unit_test_runner.ts`:
-
-```sh
-# Run all tests.
-cargo run --bin deno -- test --allow-all --unstable --location=http://js-unit-tests/foo/bar cli/tests/unit/
-
-# Run a specific test module
-cargo run --bin deno -- test --allow-all --unstable --location=http://js-unit-tests/foo/bar cli/tests/unit/files_test.ts
-```
-
-### Http server
-
-`target/debug/test_server` is required to run when one's running unit tests.
-During CI it's spawned automatically, but if you want to run tests manually make
-sure that server is spawned otherwise there'll be cascade of test failures.
diff --git a/cli/tests/unit/abort_controller_test.ts b/cli/tests/unit/abort_controller_test.ts
deleted file mode 100644
index 60ea6aa24..000000000
--- a/cli/tests/unit/abort_controller_test.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assert, assertEquals } from "./test_util.ts";
-
-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);
-});
-
-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);
-});
-
-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);
-});
-
-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);
-});
-
-Deno.test(function controllerHasProperToString() {
- 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!");
-});
diff --git a/cli/tests/unit/blob_test.ts b/cli/tests/unit/blob_test.ts
deleted file mode 100644
index e6623a65c..000000000
--- a/cli/tests/unit/blob_test.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals, assertStringIncludes } from "./test_util.ts";
-import { concat } from "@test_util/std/bytes/concat.ts";
-
-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);
-});
-
-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);
-});
-
-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);
-});
-
-Deno.test(function blobInvalidType() {
- 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();
- }
- };
- 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);
-});
-
-Deno.test(function blobConstructorNameIsBlob() {
- 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");
-});
diff --git a/cli/tests/unit/body_test.ts b/cli/tests/unit/body_test.ts
deleted file mode 100644
index 18cdb22be..000000000
--- a/cli/tests/unit/body_test.ts
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals } from "./test_util.ts";
-
-// just a hack to get a body object
-// deno-lint-ignore no-explicit-any
-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");
- }
-});
-
-//FormData
-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"));
- },
-);
-
-// FormData: non-ASCII names and filenames
-Deno.test(
- { permissions: { net: true } },
- async function bodyMultipartFormDataNonAsciiNames() {
- const boundary = "----01230123";
- const payload = [
- `--${boundary}`,
- `Content-Disposition: form-data; name="文字"`,
- "",
- "文字",
- `--${boundary}`,
- `Content-Disposition: form-data; name="file"; filename="文字"`,
- "Content-Type: application/octet-stream",
- "",
- "",
- `--${boundary}--`,
- ].join("\r\n");
-
- const body = buildBody(
- new TextEncoder().encode(payload),
- new Headers({
- "Content-Type": `multipart/form-data; boundary=${boundary}`,
- }),
- );
-
- const formData = await body.formData();
- assert(formData.has("文字"));
- assertEquals(formData.get("文字"), "文字");
- assert(formData.has("file"));
- assert(formData.get("file") instanceof File);
- assertEquals((formData.get("file") as File).name, "文字");
- },
-);
-
-// FormData: non-ASCII names and filenames roundtrip
-Deno.test(
- { permissions: { net: true } },
- async function bodyMultipartFormDataNonAsciiRoundtrip() {
- const inFormData = new FormData();
- inFormData.append("文字", "文字");
- inFormData.append("file", new File([], "文字"));
-
- const body = buildBody(inFormData);
-
- const formData = await body.formData();
- assert(formData.has("文字"));
- assertEquals(formData.get("文字"), "文字");
- assert(formData.has("file"));
- assert(formData.get("file") instanceof File);
- assertEquals((formData.get("file") as File).name, "文字");
- },
-);
-
-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) {
- // parts.shift() takes forever: https://github.com/denoland/deno/issues/5259
- const chunk = parts[offset++];
- if (!chunk) return controller.close();
- controller.enqueue(chunk);
- },
- });
-
- const body = buildBody(stream);
- assertEquals((await body.arrayBuffer()).byteLength, size);
-});
-
-// https://github.com/denoland/deno/issues/20793
-Deno.test(
- { permissions: { net: true } },
- async function bodyMultipartFormDataMultipleHeaders() {
- const boundary = "----formdata-polyfill-0.970665446687947";
- const payload = [
- "------formdata-polyfill-0.970665446687947",
- 'Content-Disposition: form-data; name="x"; filename="blob"',
- "Content-Length: 1",
- "Content-Type: application/octet-stream",
- "last-modified: Wed, 04 Oct 2023 20:28:45 GMT",
- "",
- "y",
- "------formdata-polyfill-0.970665446687947--",
- ].join("\r\n");
-
- const body = buildBody(
- new TextEncoder().encode(payload),
- new Headers({
- "Content-Type": `multipart/form-data; boundary=${boundary}`,
- }),
- );
-
- const formData = await body.formData();
- const file = formData.get("x");
- assert(file instanceof File);
- const text = await file.text();
- assertEquals(text, "y");
- assertEquals(file.size, 1);
- },
-);
diff --git a/cli/tests/unit/broadcast_channel_test.ts b/cli/tests/unit/broadcast_channel_test.ts
deleted file mode 100644
index c5d7f7e7f..000000000
--- a/cli/tests/unit/broadcast_channel_test.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "@test_util/std/assert/mod.ts";
-
-Deno.test("BroadcastChannel worker", async () => {
- const intercom = new BroadcastChannel("intercom");
- let count = 0;
-
- const url = import.meta.resolve(
- "../testdata/workers/broadcast_channel.ts",
- );
- const worker = new Worker(url, { type: "module", name: "worker" });
- worker.onmessage = () => intercom.postMessage(++count);
-
- const { promise, resolve } = Promise.withResolvers<void>();
-
- intercom.onmessage = function (e) {
- assertEquals(count, e.data);
- if (count < 42) {
- intercom.postMessage(++count);
- } else {
- worker.terminate();
- intercom.close();
- resolve();
- }
- };
-
- await promise;
-});
-
-Deno.test("BroadcastChannel immediate close after post", () => {
- const bc = new BroadcastChannel("internal_notification");
- bc.postMessage("New listening connected!");
- bc.close();
-});
diff --git a/cli/tests/unit/buffer_test.ts b/cli/tests/unit/buffer_test.ts
deleted file mode 100644
index 9d7e51a95..000000000
--- a/cli/tests/unit/buffer_test.ts
+++ /dev/null
@@ -1,461 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-// deno-lint-ignore-file no-deprecated-deno-api
-
-// This code has been ported almost directly from Go's src/bytes/buffer_test.go
-// Copyright 2009 The Go Authors. All rights reserved. BSD license.
-// https://github.com/golang/go/blob/master/LICENSE
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
-} from "./test_util.ts";
-
-const MAX_SIZE = 2 ** 32 - 2;
-// N controls how many iterations of certain checks are performed.
-const N = 100;
-let testBytes: Uint8Array | null;
-let testString: string | null;
-
-const ignoreMaxSizeTests = true;
-
-function init() {
- if (testBytes == null) {
- testBytes = new Uint8Array(N);
- for (let i = 0; i < N; i++) {
- testBytes[i] = "a".charCodeAt(0) + (i % 26);
- }
- const decoder = new TextDecoder();
- testString = decoder.decode(testBytes);
- }
-}
-
-function check(buf: Deno.Buffer, s: string) {
- const bytes = buf.bytes();
- assertEquals(buf.length, bytes.byteLength);
- const decoder = new TextDecoder();
- const bytesStr = decoder.decode(bytes);
- assertEquals(bytesStr, s);
- assertEquals(buf.length, s.length);
-}
-
-// Fill buf through n writes of byte slice fub.
-// The initial contents of buf corresponds to the string s;
-// the result is the final contents of buf returned as a string.
-async function fillBytes(
- buf: Deno.Buffer,
- s: string,
- n: number,
- fub: Uint8Array,
-): Promise<string> {
- check(buf, s);
- for (; n > 0; n--) {
- const m = await buf.write(fub);
- assertEquals(m, fub.byteLength);
- const decoder = new TextDecoder();
- s += decoder.decode(fub);
- check(buf, s);
- }
- return s;
-}
-
-// Empty buf through repeated reads into fub.
-// The initial contents of buf corresponds to the string s.
-async function empty(
- buf: Deno.Buffer,
- s: string,
- fub: Uint8Array,
-) {
- check(buf, s);
- while (true) {
- const r = await buf.read(fub);
- if (r === null) {
- break;
- }
- s = s.slice(r);
- check(buf, s);
- }
- check(buf, "");
-}
-
-function repeat(c: string, bytes: number): Uint8Array {
- assertEquals(c.length, 1);
- const ui8 = new Uint8Array(bytes);
- ui8.fill(c.charCodeAt(0));
- return ui8;
-}
-
-Deno.test(function bufferNewBuffer() {
- init();
- assert(testBytes);
- assert(testString);
- const buf = new Deno.Buffer(testBytes.buffer as ArrayBuffer);
- check(buf, testString);
-});
-
-Deno.test(async function bufferBasicOperations() {
- init();
- assert(testBytes);
- assert(testString);
- const buf = new Deno.Buffer();
- for (let i = 0; i < 5; i++) {
- check(buf, "");
-
- buf.reset();
- check(buf, "");
-
- buf.truncate(0);
- check(buf, "");
-
- let n = await buf.write(testBytes.subarray(0, 1));
- assertEquals(n, 1);
- check(buf, "a");
-
- n = await buf.write(testBytes.subarray(1, 2));
- assertEquals(n, 1);
- check(buf, "ab");
-
- n = await buf.write(testBytes.subarray(2, 26));
- assertEquals(n, 24);
- check(buf, testString.slice(0, 26));
-
- buf.truncate(26);
- check(buf, testString.slice(0, 26));
-
- buf.truncate(20);
- check(buf, testString.slice(0, 20));
-
- await empty(buf, testString.slice(0, 20), new Uint8Array(5));
- await empty(buf, "", new Uint8Array(100));
-
- // TODO(bartlomieju): buf.writeByte()
- // TODO(bartlomieju): buf.readByte()
- }
-});
-
-Deno.test(async function bufferReadEmptyAtEOF() {
- // check that EOF of 'buf' is not reached (even though it's empty) if
- // results are written to buffer that has 0 length (ie. it can't store any data)
- const buf = new Deno.Buffer();
- const zeroLengthTmp = new Uint8Array(0);
- const result = await buf.read(zeroLengthTmp);
- assertEquals(result, 0);
-});
-
-Deno.test(async function bufferLargeByteWrites() {
- init();
- const buf = new Deno.Buffer();
- const limit = 9;
- for (let i = 3; i < limit; i += 3) {
- const s = await fillBytes(buf, "", 5, testBytes!);
- await empty(buf, s, new Uint8Array(Math.floor(testString!.length / i)));
- }
- check(buf, "");
-});
-
-Deno.test(async function bufferTooLargeByteWrites() {
- init();
- const tmp = new Uint8Array(72);
- const growLen = Number.MAX_VALUE;
- const xBytes = repeat("x", 0);
- const buf = new Deno.Buffer(xBytes.buffer as ArrayBuffer);
- await buf.read(tmp);
-
- assertThrows(
- () => {
- buf.grow(growLen);
- },
- Error,
- "grown beyond the maximum size",
- );
-});
-
-Deno.test(
- { ignore: ignoreMaxSizeTests },
- function bufferGrowWriteMaxBuffer() {
- const bufSize = 16 * 1024;
- const capacities = [MAX_SIZE, MAX_SIZE - 1];
- for (const capacity of capacities) {
- let written = 0;
- const buf = new Deno.Buffer();
- const writes = Math.floor(capacity / bufSize);
- for (let i = 0; i < writes; i++) {
- written += buf.writeSync(repeat("x", bufSize));
- }
-
- if (written < capacity) {
- written += buf.writeSync(repeat("x", capacity - written));
- }
-
- assertEquals(written, capacity);
- }
- },
-);
-
-Deno.test(
- { ignore: ignoreMaxSizeTests },
- async function bufferGrowReadCloseMaxBufferPlus1() {
- const reader = new Deno.Buffer(new ArrayBuffer(MAX_SIZE + 1));
- const buf = new Deno.Buffer();
-
- await assertRejects(
- async () => {
- await buf.readFrom(reader);
- },
- Error,
- "grown beyond the maximum size",
- );
- },
-);
-
-Deno.test(
- { ignore: ignoreMaxSizeTests },
- function bufferGrowReadSyncCloseMaxBufferPlus1() {
- const reader = new Deno.Buffer(new ArrayBuffer(MAX_SIZE + 1));
- const buf = new Deno.Buffer();
-
- assertThrows(
- () => {
- buf.readFromSync(reader);
- },
- Error,
- "grown beyond the maximum size",
- );
- },
-);
-
-Deno.test(
- { ignore: ignoreMaxSizeTests },
- function bufferGrowReadSyncCloseToMaxBuffer() {
- const capacities = [MAX_SIZE, MAX_SIZE - 1];
- for (const capacity of capacities) {
- const reader = new Deno.Buffer(new ArrayBuffer(capacity));
- const buf = new Deno.Buffer();
- buf.readFromSync(reader);
-
- assertEquals(buf.length, capacity);
- }
- },
-);
-
-Deno.test(
- { ignore: ignoreMaxSizeTests },
- async function bufferGrowReadCloseToMaxBuffer() {
- const capacities = [MAX_SIZE, MAX_SIZE - 1];
- for (const capacity of capacities) {
- const reader = new Deno.Buffer(new ArrayBuffer(capacity));
- const buf = new Deno.Buffer();
- await buf.readFrom(reader);
- assertEquals(buf.length, capacity);
- }
- },
-);
-
-Deno.test(
- { ignore: ignoreMaxSizeTests },
- async function bufferReadCloseToMaxBufferWithInitialGrow() {
- const capacities = [MAX_SIZE, MAX_SIZE - 1, MAX_SIZE - 512];
- for (const capacity of capacities) {
- const reader = new Deno.Buffer(new ArrayBuffer(capacity));
- const buf = new Deno.Buffer();
- buf.grow(MAX_SIZE);
- await buf.readFrom(reader);
- assertEquals(buf.length, capacity);
- }
- },
-);
-
-Deno.test(async function bufferLargeByteReads() {
- init();
- assert(testBytes);
- assert(testString);
- const buf = new Deno.Buffer();
- for (let i = 3; i < 30; i += 3) {
- const n = Math.floor(testBytes.byteLength / i);
- const s = await fillBytes(buf, "", 5, testBytes.subarray(0, n));
- await empty(buf, s, new Uint8Array(testString.length));
- }
- check(buf, "");
-});
-
-Deno.test(function bufferCapWithPreallocatedSlice() {
- const buf = new Deno.Buffer(new ArrayBuffer(10));
- assertEquals(buf.capacity, 10);
-});
-
-Deno.test(async function bufferReadFrom() {
- init();
- assert(testBytes);
- assert(testString);
- const buf = new Deno.Buffer();
- for (let i = 3; i < 30; i += 3) {
- const s = await fillBytes(
- buf,
- "",
- 5,
- testBytes.subarray(0, Math.floor(testBytes.byteLength / i)),
- );
- const b = new Deno.Buffer();
- await b.readFrom(buf);
- const fub = new Uint8Array(testString.length);
- await empty(b, s, fub);
- }
- await assertRejects(async function () {
- await new Deno.Buffer().readFrom(null!);
- });
-});
-
-Deno.test(async function bufferReadFromSync() {
- init();
- assert(testBytes);
- assert(testString);
- const buf = new Deno.Buffer();
- for (let i = 3; i < 30; i += 3) {
- const s = await fillBytes(
- buf,
- "",
- 5,
- testBytes.subarray(0, Math.floor(testBytes.byteLength / i)),
- );
- const b = new Deno.Buffer();
- b.readFromSync(buf);
- const fub = new Uint8Array(testString.length);
- await empty(b, s, fub);
- }
- assertThrows(function () {
- new Deno.Buffer().readFromSync(null!);
- });
-});
-
-Deno.test(async function bufferTestGrow() {
- const tmp = new Uint8Array(72);
- for (const startLen of [0, 100, 1000, 10000]) {
- const xBytes = repeat("x", startLen);
- for (const growLen of [0, 100, 1000, 10000]) {
- const buf = new Deno.Buffer(xBytes.buffer as ArrayBuffer);
- // If we read, this affects buf.off, which is good to test.
- const nread = (await buf.read(tmp)) ?? 0;
- buf.grow(growLen);
- const yBytes = repeat("y", growLen);
- await buf.write(yBytes);
- // Check that buffer has correct data.
- assertEquals(
- buf.bytes().subarray(0, startLen - nread),
- xBytes.subarray(nread),
- );
- assertEquals(
- buf.bytes().subarray(startLen - nread, startLen - nread + growLen),
- yBytes,
- );
- }
- }
-});
-
-Deno.test(async function testReadAll() {
- init();
- assert(testBytes);
- const reader = new Deno.Buffer(testBytes.buffer as ArrayBuffer);
- const actualBytes = await Deno.readAll(reader);
- assertEquals(testBytes.byteLength, actualBytes.byteLength);
- for (let i = 0; i < testBytes.length; ++i) {
- assertEquals(testBytes[i], actualBytes[i]);
- }
-});
-
-Deno.test(function testReadAllSync() {
- init();
- assert(testBytes);
- const reader = new Deno.Buffer(testBytes.buffer as ArrayBuffer);
- const actualBytes = Deno.readAllSync(reader);
- assertEquals(testBytes.byteLength, actualBytes.byteLength);
- for (let i = 0; i < testBytes.length; ++i) {
- assertEquals(testBytes[i], actualBytes[i]);
- }
-});
-
-Deno.test(async function testWriteAll() {
- init();
- assert(testBytes);
- const writer = new Deno.Buffer();
- await Deno.writeAll(writer, testBytes);
- const actualBytes = writer.bytes();
- assertEquals(testBytes.byteLength, actualBytes.byteLength);
- for (let i = 0; i < testBytes.length; ++i) {
- assertEquals(testBytes[i], actualBytes[i]);
- }
-});
-
-Deno.test(function testWriteAllSync() {
- init();
- assert(testBytes);
- const writer = new Deno.Buffer();
- Deno.writeAllSync(writer, testBytes);
- const actualBytes = writer.bytes();
- assertEquals(testBytes.byteLength, actualBytes.byteLength);
- for (let i = 0; i < testBytes.length; ++i) {
- assertEquals(testBytes[i], actualBytes[i]);
- }
-});
-
-Deno.test(function testBufferBytesArrayBufferLength() {
- // defaults to copy
- const args = [{}, { copy: undefined }, undefined, { copy: true }];
- for (const arg of args) {
- const bufSize = 64 * 1024;
- const bytes = new TextEncoder().encode("a".repeat(bufSize));
- const reader = new Deno.Buffer();
- Deno.writeAllSync(reader, bytes);
-
- const writer = new Deno.Buffer();
- writer.readFromSync(reader);
- const actualBytes = writer.bytes(arg);
-
- assertEquals(actualBytes.byteLength, bufSize);
- assert(actualBytes.buffer !== writer.bytes(arg).buffer);
- assertEquals(actualBytes.byteLength, actualBytes.buffer.byteLength);
- }
-});
-
-Deno.test(function testBufferBytesCopyFalse() {
- const bufSize = 64 * 1024;
- const bytes = new TextEncoder().encode("a".repeat(bufSize));
- const reader = new Deno.Buffer();
- Deno.writeAllSync(reader, bytes);
-
- const writer = new Deno.Buffer();
- writer.readFromSync(reader);
- const actualBytes = writer.bytes({ copy: false });
-
- assertEquals(actualBytes.byteLength, bufSize);
- assertEquals(actualBytes.buffer, writer.bytes({ copy: false }).buffer);
- assert(actualBytes.buffer.byteLength > actualBytes.byteLength);
-});
-
-Deno.test(function testBufferBytesCopyFalseGrowExactBytes() {
- const bufSize = 64 * 1024;
- const bytes = new TextEncoder().encode("a".repeat(bufSize));
- const reader = new Deno.Buffer();
- Deno.writeAllSync(reader, bytes);
-
- const writer = new Deno.Buffer();
- writer.grow(bufSize);
- writer.readFromSync(reader);
- const actualBytes = writer.bytes({ copy: false });
-
- assertEquals(actualBytes.byteLength, bufSize);
- assertEquals(actualBytes.buffer.byteLength, actualBytes.byteLength);
-});
-
-Deno.test(function testThrowsErrorWhenBufferExceedsMaxLength() {
- const kStringMaxLengthPlusOne = 536870888 + 1;
- const bytes = new Uint8Array(kStringMaxLengthPlusOne);
-
- assertThrows(
- () => {
- new TextDecoder().decode(bytes);
- },
- TypeError,
- "buffer exceeds maximum length",
- );
-});
diff --git a/cli/tests/unit/build_test.ts b/cli/tests/unit/build_test.ts
deleted file mode 100644
index f697b64d3..000000000
--- a/cli/tests/unit/build_test.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert } from "./test_util.ts";
-
-Deno.test(function buildInfo() {
- // Deno.build is injected by rollup at compile time. Here
- // we check it has been properly transformed.
- const { arch, os } = Deno.build;
- assert(arch.length > 0);
- assert(os === "darwin" || os === "windows" || os === "linux");
-});
diff --git a/cli/tests/unit/cache_api_test.ts b/cli/tests/unit/cache_api_test.ts
deleted file mode 100644
index 792929870..000000000
--- a/cli/tests/unit/cache_api_test.ts
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertFalse,
- assertRejects,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(async function cacheStorage() {
- const cacheName = "cache-v1";
- const _cache = await caches.open(cacheName);
- assert(await caches.has(cacheName));
- assert(await caches.delete(cacheName));
- assertFalse(await caches.has(cacheName));
-});
-
-Deno.test(async function cacheApi() {
- const cacheName = "cache-v1";
- const cache = await caches.open(cacheName);
- // Test cache.put() with url string as key.
- {
- const req = "https://deno.com";
- await cache.put(req, new Response("deno.com - key is string"));
- const res = await cache.match(req);
- assertEquals(await res?.text(), "deno.com - key is string");
- assert(await cache.delete(req));
- }
- // Test cache.put() with url instance as key.
- {
- const req = new URL("https://deno.com");
- await cache.put(req, new Response("deno.com - key is URL"));
- const res = await cache.match(req);
- assertEquals(await res?.text(), "deno.com - key is URL");
- assert(await cache.delete(req));
- }
- // Test cache.put() with request instance as key.
- {
- const req = new Request("https://deno.com");
- await cache.put(req, new Response("deno.com - key is Request"));
- const res = await cache.match(req);
- assertEquals(await res?.text(), "deno.com - key is Request");
- assert(await cache.delete(req));
- }
-
- // Test cache.put() throws with response Vary header set to *.
- {
- const req = new Request("https://deno.com");
- assertRejects(
- async () => {
- await cache.put(
- req,
- new Response("deno.com - key is Request", {
- headers: { Vary: "*" },
- }),
- );
- },
- TypeError,
- "Vary header must not contain '*'",
- );
- }
-
- // Test cache.match() with same url but different values for Vary header.
- {
- await cache.put(
- new Request("https://example.com/", {
- headers: {
- "Accept": "application/json",
- },
- }),
- Response.json({ msg: "hello world" }, {
- headers: {
- "Content-Type": "application/json",
- "Vary": "Accept",
- },
- }),
- );
- const res = await cache.match("https://example.com/");
- assertEquals(res, undefined);
- const res2 = await cache.match(
- new Request("https://example.com/", {
- headers: { "Accept": "text/html" },
- }),
- );
- assertEquals(res2, undefined);
-
- const res3 = await cache.match(
- new Request("https://example.com/", {
- headers: { "Accept": "application/json" },
- }),
- );
- assertEquals(await res3?.json(), { msg: "hello world" });
- }
-
- assert(await caches.delete(cacheName));
- assertFalse(await caches.has(cacheName));
-});
-
-Deno.test(function cacheIllegalConstructor() {
- assertThrows(() => new Cache(), TypeError, "Illegal constructor");
- // @ts-expect-error illegal constructor
- assertThrows(() => new Cache("foo", "bar"), TypeError, "Illegal constructor");
-});
-
-Deno.test(async function cachePutReaderLock() {
- const cacheName = "cache-v1";
- const cache = await caches.open(cacheName);
-
- const response = new Response("consumed");
-
- const promise = cache.put(
- new Request("https://example.com/"),
- response,
- );
-
- await assertRejects(
- async () => {
- await response.arrayBuffer();
- },
- TypeError,
- "Body already consumed.",
- );
-
- await promise;
-});
-
-Deno.test(async function cachePutResourceLeak() {
- const cacheName = "cache-v1";
- const cache = await caches.open(cacheName);
-
- const stream = new ReadableStream({
- start(controller) {
- controller.error(new Error("leak"));
- },
- });
-
- await assertRejects(
- async () => {
- await cache.put(
- new Request("https://example.com/leak"),
- new Response(stream),
- );
- },
- Error,
- "leak",
- );
-});
-
-Deno.test(async function cachePutFailedBody() {
- const cacheName = "cache-v1";
- const cache = await caches.open(cacheName);
-
- const request = new Request("https://example.com/failed-body");
- const stream = new ReadableStream({
- start(controller) {
- controller.error(new Error("corrupt"));
- },
- });
-
- await assertRejects(
- async () => {
- await cache.put(
- request,
- new Response(stream),
- );
- },
- Error,
- "corrupt",
- );
-
- const response = await cache.match(request);
- // if it fails to read the body, the cache should be empty
- assertEquals(response, undefined);
-});
-
-Deno.test(async function cachePutOverwrite() {
- const cacheName = "cache-v1";
- const cache = await caches.open(cacheName);
-
- const request = new Request("https://example.com/overwrite");
- const res1 = new Response("res1");
- const res2 = new Response("res2");
-
- await cache.put(request, res1);
- const res = await cache.match(request);
- assertEquals(await res?.text(), "res1");
-
- await cache.put(request, res2);
- const res_ = await cache.match(request);
- assertEquals(await res_?.text(), "res2");
-});
-
-// Ensure that we can successfully put a response backed by a resource
-Deno.test(async function cachePutResource() {
- const tempFile = Deno.makeTempFileSync({ prefix: "deno-", suffix: ".txt" });
- Deno.writeTextFileSync(tempFile, "Contents".repeat(1024));
-
- const file = Deno.openSync(tempFile);
-
- const cacheName = "cache-v1";
- const cache = await caches.open(cacheName);
-
- const request = new Request("https://example.com/file");
- await cache.put(request, new Response(file.readable));
- const res = await cache.match(request);
- assertEquals(await res?.text(), "Contents".repeat(1024));
-});
diff --git a/cli/tests/unit/chmod_test.ts b/cli/tests/unit/chmod_test.ts
deleted file mode 100644
index df3771bbc..000000000
--- a/cli/tests/unit/chmod_test.ts
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- function chmodSyncSuccess() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = Deno.makeTempDirSync();
- const filename = tempDir + "/test.txt";
- Deno.writeFileSync(filename, data, { mode: 0o666 });
-
- Deno.chmodSync(filename, 0o777);
-
- const fileInfo = Deno.statSync(filename);
- assert(fileInfo.mode);
- assertEquals(fileInfo.mode & 0o777, 0o777);
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- function chmodSyncUrl() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = Deno.makeTempDirSync();
- const fileUrl = new URL(`file://${tempDir}/test.txt`);
- Deno.writeFileSync(fileUrl, data, { mode: 0o666 });
-
- Deno.chmodSync(fileUrl, 0o777);
-
- const fileInfo = Deno.statSync(fileUrl);
- assert(fileInfo.mode);
- assertEquals(fileInfo.mode & 0o777, 0o777);
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-// Check symlink when not on windows
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- function chmodSyncSymlinkSuccess() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = Deno.makeTempDirSync();
-
- const filename = tempDir + "/test.txt";
- Deno.writeFileSync(filename, data, { mode: 0o666 });
- const symlinkName = tempDir + "/test_symlink.txt";
- Deno.symlinkSync(filename, symlinkName);
-
- let symlinkInfo = Deno.lstatSync(symlinkName);
- assert(symlinkInfo.mode);
- const symlinkMode = symlinkInfo.mode & 0o777; // platform dependent
-
- Deno.chmodSync(symlinkName, 0o777);
-
- // Change actual file mode, not symlink
- const fileInfo = Deno.statSync(filename);
- assert(fileInfo.mode);
- assertEquals(fileInfo.mode & 0o777, 0o777);
- symlinkInfo = Deno.lstatSync(symlinkName);
- assert(symlinkInfo.mode);
- assertEquals(symlinkInfo.mode & 0o777, symlinkMode);
- },
-);
-
-Deno.test({ permissions: { write: true } }, function chmodSyncFailure() {
- const filename = "/badfile.txt";
- assertThrows(
- () => {
- Deno.chmodSync(filename, 0o777);
- },
- Deno.errors.NotFound,
- `chmod '${filename}'`,
- );
-});
-
-Deno.test({ permissions: { write: false } }, function chmodSyncPerm() {
- assertThrows(() => {
- Deno.chmodSync("/somefile.txt", 0o777);
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function chmodSuccess() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = Deno.makeTempDirSync();
- const filename = tempDir + "/test.txt";
- Deno.writeFileSync(filename, data, { mode: 0o666 });
-
- await Deno.chmod(filename, 0o777);
-
- const fileInfo = Deno.statSync(filename);
- assert(fileInfo.mode);
- assertEquals(fileInfo.mode & 0o777, 0o777);
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function chmodUrl() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = Deno.makeTempDirSync();
- const fileUrl = new URL(`file://${tempDir}/test.txt`);
- Deno.writeFileSync(fileUrl, data, { mode: 0o666 });
-
- await Deno.chmod(fileUrl, 0o777);
-
- const fileInfo = Deno.statSync(fileUrl);
- assert(fileInfo.mode);
- assertEquals(fileInfo.mode & 0o777, 0o777);
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-// Check symlink when not on windows
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function chmodSymlinkSuccess() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = Deno.makeTempDirSync();
-
- const filename = tempDir + "/test.txt";
- Deno.writeFileSync(filename, data, { mode: 0o666 });
- const symlinkName = tempDir + "/test_symlink.txt";
- Deno.symlinkSync(filename, symlinkName);
-
- let symlinkInfo = Deno.lstatSync(symlinkName);
- assert(symlinkInfo.mode);
- const symlinkMode = symlinkInfo.mode & 0o777; // platform dependent
-
- await Deno.chmod(symlinkName, 0o777);
-
- // Just change actual file mode, not symlink
- const fileInfo = Deno.statSync(filename);
- assert(fileInfo.mode);
- assertEquals(fileInfo.mode & 0o777, 0o777);
- symlinkInfo = Deno.lstatSync(symlinkName);
- assert(symlinkInfo.mode);
- assertEquals(symlinkInfo.mode & 0o777, symlinkMode);
- },
-);
-
-Deno.test({ permissions: { write: true } }, async function chmodFailure() {
- const filename = "/badfile.txt";
- await assertRejects(
- async () => {
- await Deno.chmod(filename, 0o777);
- },
- Deno.errors.NotFound,
- `chmod '${filename}'`,
- );
-});
-
-Deno.test({ permissions: { write: false } }, async function chmodPerm() {
- await assertRejects(async () => {
- await Deno.chmod("/somefile.txt", 0o777);
- }, Deno.errors.PermissionDenied);
-});
diff --git a/cli/tests/unit/chown_test.ts b/cli/tests/unit/chown_test.ts
deleted file mode 100644
index 033d4592d..000000000
--- a/cli/tests/unit/chown_test.ts
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertRejects, assertThrows } from "./test_util.ts";
-
-// chown on Windows is noop for now, so ignore its testing on Windows
-
-async function getUidAndGid(): Promise<{ uid: number; gid: number }> {
- // get the user ID and group ID of the current process
- const uidProc = await new Deno.Command("id", {
- args: ["-u"],
- }).output();
- const gidProc = await new Deno.Command("id", {
- args: ["-g"],
- }).output();
-
- assertEquals(uidProc.code, 0);
- assertEquals(gidProc.code, 0);
- const uid = parseInt(new TextDecoder("utf-8").decode(uidProc.stdout));
- const gid = parseInt(new TextDecoder("utf-8").decode(gidProc.stdout));
-
- return { uid, gid };
-}
-
-Deno.test(
- { ignore: Deno.build.os == "windows", permissions: { write: false } },
- async function chownNoWritePermission() {
- const filePath = "chown_test_file.txt";
- await assertRejects(async () => {
- await Deno.chown(filePath, 1000, 1000);
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, write: true },
- ignore: Deno.build.os == "windows",
- },
- async function chownSyncFileNotExist() {
- const { uid, gid } = await getUidAndGid();
- const filePath = Deno.makeTempDirSync() + "/chown_test_file.txt";
-
- assertThrows(
- () => {
- Deno.chownSync(filePath, uid, gid);
- },
- Deno.errors.NotFound,
- `chown '${filePath}'`,
- );
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, write: true },
- ignore: Deno.build.os == "windows",
- },
- async function chownFileNotExist() {
- const { uid, gid } = await getUidAndGid();
- const filePath = (await Deno.makeTempDir()) + "/chown_test_file.txt";
-
- await assertRejects(
- async () => {
- await Deno.chown(filePath, uid, gid);
- },
- Deno.errors.NotFound,
- `chown '${filePath}'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { write: true }, ignore: Deno.build.os == "windows" },
- function chownSyncPermissionDenied() {
- const dirPath = Deno.makeTempDirSync();
- const filePath = dirPath + "/chown_test_file.txt";
- Deno.writeTextFileSync(filePath, "Hello");
-
- assertThrows(() => {
- // try changing the file's owner to root
- Deno.chownSync(filePath, 0, 0);
- }, Deno.errors.PermissionDenied);
- Deno.removeSync(dirPath, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { write: true }, ignore: Deno.build.os == "windows" },
- async function chownPermissionDenied() {
- const dirPath = await Deno.makeTempDir();
- const filePath = dirPath + "/chown_test_file.txt";
- await Deno.writeTextFile(filePath, "Hello");
-
- await assertRejects(async () => {
- // try changing the file's owner to root
- await Deno.chown(filePath, 0, 0);
- }, Deno.errors.PermissionDenied);
- await Deno.remove(dirPath, { recursive: true });
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, write: true },
- ignore: Deno.build.os == "windows",
- },
- async function chownSyncSucceed() {
- // TODO(bartlomieju): when a file's owner is actually being changed,
- // chown only succeeds if run under privileged user (root)
- // The test script has no such privilege, so need to find a better way to test this case
- const { uid, gid } = await getUidAndGid();
-
- const dirPath = Deno.makeTempDirSync();
- const filePath = dirPath + "/chown_test_file.txt";
- Deno.writeTextFileSync(filePath, "Hello");
-
- // the test script creates this file with the same uid and gid,
- // here chown is a noop so it succeeds under non-privileged user
- Deno.chownSync(filePath, uid, gid);
-
- Deno.removeSync(dirPath, { recursive: true });
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, write: true },
- ignore: Deno.build.os == "windows",
- },
- async function chownSyncWithUrl() {
- const { uid, gid } = await getUidAndGid();
- const dirPath = Deno.makeTempDirSync();
- const fileUrl = new URL(`file://${dirPath}/chown_test_file.txt`);
- Deno.writeTextFileSync(fileUrl, "Hello");
- Deno.chownSync(fileUrl, uid, gid);
- Deno.removeSync(dirPath, { recursive: true });
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, write: true },
- ignore: Deno.build.os == "windows",
- },
- async function chownSucceed() {
- const { uid, gid } = await getUidAndGid();
- const dirPath = await Deno.makeTempDir();
- const filePath = dirPath + "/chown_test_file.txt";
- await Deno.writeTextFile(filePath, "Hello");
- await Deno.chown(filePath, uid, gid);
- Deno.removeSync(dirPath, { recursive: true });
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, write: true },
- ignore: Deno.build.os == "windows",
- },
- async function chownUidOnly() {
- const { uid } = await getUidAndGid();
- const dirPath = await Deno.makeTempDir();
- const filePath = dirPath + "/chown_test_file.txt";
- await Deno.writeTextFile(filePath, "Foo");
- await Deno.chown(filePath, uid, null);
- Deno.removeSync(dirPath, { recursive: true });
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, write: true },
- ignore: Deno.build.os == "windows",
- },
- async function chownWithUrl() {
- // TODO(bartlomieju): same as chownSyncSucceed
- const { uid, gid } = await getUidAndGid();
-
- const enc = new TextEncoder();
- const dirPath = await Deno.makeTempDir();
- const fileUrl = new URL(`file://${dirPath}/chown_test_file.txt`);
- const fileData = enc.encode("Hello");
- await Deno.writeFile(fileUrl, fileData);
-
- // the test script creates this file with the same uid and gid,
- // here chown is a noop so it succeeds under non-privileged user
- await Deno.chown(fileUrl, uid, gid);
-
- Deno.removeSync(dirPath, { recursive: true });
- },
-);
diff --git a/cli/tests/unit/command_test.ts b/cli/tests/unit/command_test.ts
deleted file mode 100644
index cbb1c4921..000000000
--- a/cli/tests/unit/command_test.ts
+++ /dev/null
@@ -1,967 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import {
- assert,
- assertEquals,
- assertRejects,
- assertStringIncludes,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(
- { permissions: { write: true, run: true, read: true } },
- async function commandWithCwdIsAsync() {
- const enc = new TextEncoder();
- const cwd = await Deno.makeTempDir({ prefix: "deno_command_test" });
-
- const exitCodeFile = "deno_was_here";
- const programFile = "poll_exit.ts";
- const program = `
-async function tryExit() {
- try {
- const code = parseInt(await Deno.readTextFile("${exitCodeFile}"));
- Deno.exit(code);
- } catch {
- // Retry if we got here before deno wrote the file.
- setTimeout(tryExit, 0.01);
- }
-}
-
-tryExit();
-`;
-
- Deno.writeFileSync(`${cwd}/${programFile}`, enc.encode(program));
-
- const command = new Deno.Command(Deno.execPath(), {
- cwd,
- args: ["run", "--allow-read", programFile],
- stdout: "inherit",
- stderr: "inherit",
- });
- const child = command.spawn();
-
- // Write the expected exit code *after* starting deno.
- // This is how we verify that `Child` is actually asynchronous.
- const code = 84;
- Deno.writeFileSync(`${cwd}/${exitCodeFile}`, enc.encode(`${code}`));
-
- const status = await child.status;
- await Deno.remove(cwd, { recursive: true });
- assertEquals(status.success, false);
- assertEquals(status.code, code);
- assertEquals(status.signal, null);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandStdinPiped() {
- const command = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "if (new TextDecoder().decode(await Deno.readAll(Deno.stdin)) !== 'hello') throw new Error('Expected \\'hello\\'')",
- ],
- stdin: "piped",
- stdout: "null",
- stderr: "null",
- });
- const child = command.spawn();
-
- assertThrows(() => child.stdout, TypeError, "stdout is not piped");
- assertThrows(() => child.stderr, TypeError, "stderr is not piped");
-
- const msg = new TextEncoder().encode("hello");
- const writer = child.stdin.getWriter();
- await writer.write(msg);
- writer.releaseLock();
-
- await child.stdin.close();
- const status = await child.status;
- assertEquals(status.success, true);
- assertEquals(status.code, 0);
- assertEquals(status.signal, null);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandStdinPiped() {
- const command = new Deno.Command(Deno.execPath(), {
- args: ["info"],
- stdout: "null",
- stderr: "null",
- });
- const child = command.spawn();
-
- assertThrows(() => child.stdin, TypeError, "stdin is not piped");
- assertThrows(() => child.stdout, TypeError, "stdout is not piped");
- assertThrows(() => child.stderr, TypeError, "stderr is not piped");
-
- await child.status;
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandStdoutPiped() {
- const command = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "await Deno.stdout.write(new TextEncoder().encode('hello'))",
- ],
- stderr: "null",
- stdout: "piped",
- });
- const child = command.spawn();
-
- assertThrows(() => child.stdin, TypeError, "stdin is not piped");
- assertThrows(() => child.stderr, TypeError, "stderr is not piped");
-
- const readable = child.stdout.pipeThrough(new TextDecoderStream());
- const reader = readable.getReader();
- const res = await reader.read();
- assert(!res.done);
- assertEquals(res.value, "hello");
-
- const resEnd = await reader.read();
- assert(resEnd.done);
- assertEquals(resEnd.value, undefined);
- reader.releaseLock();
-
- const status = await child.status;
- assertEquals(status.success, true);
- assertEquals(status.code, 0);
- assertEquals(status.signal, null);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandStderrPiped() {
- const command = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "await Deno.stderr.write(new TextEncoder().encode('hello'))",
- ],
- stdout: "null",
- stderr: "piped",
- });
- const child = command.spawn();
-
- assertThrows(() => child.stdin, TypeError, "stdin is not piped");
- assertThrows(() => child.stdout, TypeError, "stdout is not piped");
-
- const readable = child.stderr.pipeThrough(new TextDecoderStream());
- const reader = readable.getReader();
- const res = await reader.read();
- assert(!res.done);
- assertEquals(res.value, "hello");
-
- const resEnd = await reader.read();
- assert(resEnd.done);
- assertEquals(resEnd.value, undefined);
- reader.releaseLock();
-
- const status = await child.status;
- assertEquals(status.success, true);
- assertEquals(status.code, 0);
- assertEquals(status.signal, null);
- },
-);
-
-Deno.test(
- { permissions: { run: true, write: true, read: true } },
- async function commandRedirectStdoutStderr() {
- const tempDir = await Deno.makeTempDir();
- const fileName = tempDir + "/redirected_stdio.txt";
- const file = await Deno.open(fileName, {
- create: true,
- write: true,
- });
-
- const command = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "Deno.stderr.write(new TextEncoder().encode('error\\n')); Deno.stdout.write(new TextEncoder().encode('output\\n'));",
- ],
- stdout: "piped",
- stderr: "piped",
- });
- const child = command.spawn();
- await child.stdout.pipeTo(file.writable, {
- preventClose: true,
- });
- await child.stderr.pipeTo(file.writable);
- await child.status;
-
- const fileContents = await Deno.readFile(fileName);
- const decoder = new TextDecoder();
- const text = decoder.decode(fileContents);
-
- assertStringIncludes(text, "error");
- assertStringIncludes(text, "output");
- },
-);
-
-Deno.test(
- { permissions: { run: true, write: true, read: true } },
- async function commandRedirectStdin() {
- const tempDir = await Deno.makeTempDir();
- const fileName = tempDir + "/redirected_stdio.txt";
- await Deno.writeTextFile(fileName, "hello");
- const file = await Deno.open(fileName);
-
- const command = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "if (new TextDecoder().decode(await Deno.readAll(Deno.stdin)) !== 'hello') throw new Error('Expected \\'hello\\'')",
- ],
- stdin: "piped",
- stdout: "null",
- stderr: "null",
- });
- const child = command.spawn();
- await file.readable.pipeTo(child.stdin, {
- preventClose: true,
- });
-
- await child.stdin.close();
- const status = await child.status;
- assertEquals(status.code, 0);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandKillSuccess() {
- const command = new Deno.Command(Deno.execPath(), {
- args: ["eval", "setTimeout(() => {}, 10000)"],
- stdout: "null",
- stderr: "null",
- });
- const child = command.spawn();
-
- child.kill("SIGKILL");
- const status = await child.status;
-
- assertEquals(status.success, false);
- if (Deno.build.os === "windows") {
- assertEquals(status.code, 1);
- assertEquals(status.signal, null);
- } else {
- assertEquals(status.code, 137);
- assertEquals(status.signal, "SIGKILL");
- }
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- // deno lint bug, see https://github.com/denoland/deno_lint/issues/1206
- // deno-lint-ignore require-await
- async function childProcessExplicitResourceManagement() {
- let dead = undefined;
- {
- const command = new Deno.Command(Deno.execPath(), {
- args: ["eval", "setTimeout(() => {}, 10000)"],
- stdout: "null",
- stderr: "null",
- });
- await using child = command.spawn();
- child.status.then(({ signal }) => {
- dead = signal;
- });
- }
-
- if (Deno.build.os == "windows") {
- assertEquals(dead, null);
- } else {
- assertEquals(dead, "SIGTERM");
- }
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function childProcessExplicitResourceManagementManualClose() {
- const command = new Deno.Command(Deno.execPath(), {
- args: ["eval", "setTimeout(() => {}, 10000)"],
- stdout: "null",
- stderr: "null",
- });
- await using child = command.spawn();
- child.kill("SIGTERM");
- await child.status;
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandKillFailed() {
- const command = new Deno.Command(Deno.execPath(), {
- args: ["eval", "setTimeout(() => {}, 5000)"],
- stdout: "null",
- stderr: "null",
- });
- const child = command.spawn();
-
- assertThrows(() => {
- // @ts-expect-error testing runtime error of bad signal
- child.kill("foobar");
- }, TypeError);
-
- await child.status;
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandKillOptional() {
- const command = new Deno.Command(Deno.execPath(), {
- args: ["eval", "setTimeout(() => {}, 10000)"],
- stdout: "null",
- stderr: "null",
- });
- const child = command.spawn();
-
- child.kill();
- const status = await child.status;
-
- assertEquals(status.success, false);
- if (Deno.build.os === "windows") {
- assertEquals(status.code, 1);
- assertEquals(status.signal, null);
- } else {
- assertEquals(status.code, 143);
- assertEquals(status.signal, "SIGTERM");
- }
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandAbort() {
- const ac = new AbortController();
- const command = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "setTimeout(console.log, 1e8)",
- ],
- signal: ac.signal,
- stdout: "null",
- stderr: "null",
- });
- const child = command.spawn();
- queueMicrotask(() => ac.abort());
- const status = await child.status;
- assertEquals(status.success, false);
- if (Deno.build.os === "windows") {
- assertEquals(status.code, 1);
- assertEquals(status.signal, null);
- } else {
- assertEquals(status.success, false);
- assertEquals(status.code, 143);
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: false } },
- async function commandPermissions() {
- await assertRejects(async () => {
- await new Deno.Command(Deno.execPath(), {
- args: ["eval", "console.log('hello world')"],
- }).output();
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: false } },
- function commandSyncPermissions() {
- assertThrows(() => {
- new Deno.Command(Deno.execPath(), {
- args: ["eval", "console.log('hello world')"],
- }).outputSync();
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandSuccess() {
- const output = await new Deno.Command(Deno.execPath(), {
- args: ["eval", "console.log('hello world')"],
- }).output();
-
- assertEquals(output.success, true);
- assertEquals(output.code, 0);
- assertEquals(output.signal, null);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- function commandSyncSuccess() {
- const output = new Deno.Command(Deno.execPath(), {
- args: ["eval", "console.log('hello world')"],
- }).outputSync();
-
- assertEquals(output.success, true);
- assertEquals(output.code, 0);
- assertEquals(output.signal, null);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandUrl() {
- const output = await new Deno.Command(
- new URL(`file:///${Deno.execPath()}`),
- {
- args: ["eval", "console.log('hello world')"],
- },
- ).output();
-
- assertEquals(new TextDecoder().decode(output.stdout), "hello world\n");
-
- assertEquals(output.success, true);
- assertEquals(output.code, 0);
- assertEquals(output.signal, null);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- function commandSyncUrl() {
- const output = new Deno.Command(
- new URL(`file:///${Deno.execPath()}`),
- {
- args: ["eval", "console.log('hello world')"],
- },
- ).outputSync();
-
- assertEquals(new TextDecoder().decode(output.stdout), "hello world\n");
-
- assertEquals(output.success, true);
- assertEquals(output.code, 0);
- assertEquals(output.signal, null);
- },
-);
-
-Deno.test({ permissions: { run: true } }, function commandNotFound() {
- assertThrows(
- () => new Deno.Command("this file hopefully doesn't exist").output(),
- Deno.errors.NotFound,
- );
-});
-
-Deno.test({ permissions: { run: true } }, function commandSyncNotFound() {
- assertThrows(
- () => new Deno.Command("this file hopefully doesn't exist").outputSync(),
- Deno.errors.NotFound,
- );
-});
-
-Deno.test({ permissions: { run: true, read: true } }, function cwdNotFound() {
- assertThrows(
- () =>
- new Deno.Command(Deno.execPath(), {
- cwd: Deno.cwd() + "/non-existent-directory",
- }).output(),
- Deno.errors.NotFound,
- "No such cwd",
- );
-});
-
-Deno.test(
- { permissions: { run: true, read: true } },
- function cwdNotDirectory() {
- assertThrows(
- () =>
- new Deno.Command(Deno.execPath(), {
- cwd: Deno.execPath(),
- }).output(),
- Deno.errors.NotFound,
- "cwd is not a directory",
- );
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandFailedWithCode() {
- const output = await new Deno.Command(Deno.execPath(), {
- args: ["eval", "Deno.exit(41 + 1)"],
- }).output();
- assertEquals(output.success, false);
- assertEquals(output.code, 42);
- assertEquals(output.signal, null);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- function commandSyncFailedWithCode() {
- const output = new Deno.Command(Deno.execPath(), {
- args: ["eval", "Deno.exit(41 + 1)"],
- }).outputSync();
- assertEquals(output.success, false);
- assertEquals(output.code, 42);
- assertEquals(output.signal, null);
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true },
- },
- async function commandFailedWithSignal() {
- const output = await new Deno.Command(Deno.execPath(), {
- args: ["eval", "--unstable", "Deno.kill(Deno.pid, 'SIGKILL')"],
- }).output();
- assertEquals(output.success, false);
- if (Deno.build.os === "windows") {
- assertEquals(output.code, 1);
- assertEquals(output.signal, null);
- } else {
- assertEquals(output.code, 128 + 9);
- assertEquals(output.signal, "SIGKILL");
- }
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true },
- },
- function commandSyncFailedWithSignal() {
- const output = new Deno.Command(Deno.execPath(), {
- args: ["eval", "--unstable", "Deno.kill(Deno.pid, 'SIGKILL')"],
- }).outputSync();
- assertEquals(output.success, false);
- if (Deno.build.os === "windows") {
- assertEquals(output.code, 1);
- assertEquals(output.signal, null);
- } else {
- assertEquals(output.code, 128 + 9);
- assertEquals(output.signal, "SIGKILL");
- }
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandOutput() {
- const { stdout } = await new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "await Deno.stdout.write(new TextEncoder().encode('hello'))",
- ],
- }).output();
-
- const s = new TextDecoder().decode(stdout);
- assertEquals(s, "hello");
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- function commandSyncOutput() {
- const { stdout } = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "await Deno.stdout.write(new TextEncoder().encode('hello'))",
- ],
- }).outputSync();
-
- const s = new TextDecoder().decode(stdout);
- assertEquals(s, "hello");
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandStderrOutput() {
- const { stderr } = await new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "await Deno.stderr.write(new TextEncoder().encode('error'))",
- ],
- }).output();
-
- const s = new TextDecoder().decode(stderr);
- assertEquals(s, "error");
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- function commandSyncStderrOutput() {
- const { stderr } = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "await Deno.stderr.write(new TextEncoder().encode('error'))",
- ],
- }).outputSync();
-
- const s = new TextDecoder().decode(stderr);
- assertEquals(s, "error");
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandEnv() {
- const { stdout } = await new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "Deno.stdout.write(new TextEncoder().encode(Deno.env.get('FOO') + Deno.env.get('BAR')))",
- ],
- env: {
- FOO: "0123",
- BAR: "4567",
- },
- }).output();
- const s = new TextDecoder().decode(stdout);
- assertEquals(s, "01234567");
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- function commandSyncEnv() {
- const { stdout } = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "Deno.stdout.write(new TextEncoder().encode(Deno.env.get('FOO') + Deno.env.get('BAR')))",
- ],
- env: {
- FOO: "0123",
- BAR: "4567",
- },
- }).outputSync();
- const s = new TextDecoder().decode(stdout);
- assertEquals(s, "01234567");
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true, env: true } },
- async function commandClearEnv() {
- const { stdout } = await new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "-p",
- "JSON.stringify(Deno.env.toObject())",
- ],
- clearEnv: true,
- env: {
- FOO: "23147",
- },
- }).output();
-
- const obj = JSON.parse(new TextDecoder().decode(stdout));
-
- // can't check for object equality because the OS may set additional env
- // vars for processes, so we check if PATH isn't present as that is a common
- // env var across OS's and isn't set for processes.
- assertEquals(obj.FOO, "23147");
- assert(!("PATH" in obj));
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true, env: true } },
- function commandSyncClearEnv() {
- const { stdout } = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "-p",
- "JSON.stringify(Deno.env.toObject())",
- ],
- clearEnv: true,
- env: {
- FOO: "23147",
- },
- }).outputSync();
-
- const obj = JSON.parse(new TextDecoder().decode(stdout));
-
- // can't check for object equality because the OS may set additional env
- // vars for processes, so we check if PATH isn't present as that is a common
- // env var across OS's and isn't set for processes.
- assertEquals(obj.FOO, "23147");
- assert(!("PATH" in obj));
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true },
- ignore: Deno.build.os === "windows",
- },
- async function commandUid() {
- const { stdout } = await new Deno.Command("id", {
- args: ["-u"],
- }).output();
-
- const currentUid = new TextDecoder().decode(stdout);
-
- if (currentUid !== "0") {
- await assertRejects(async () => {
- await new Deno.Command("echo", {
- args: ["fhqwhgads"],
- uid: 0,
- }).output();
- }, Deno.errors.PermissionDenied);
- }
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true },
- ignore: Deno.build.os === "windows",
- },
- function commandSyncUid() {
- const { stdout } = new Deno.Command("id", {
- args: ["-u"],
- }).outputSync();
-
- const currentUid = new TextDecoder().decode(stdout);
-
- if (currentUid !== "0") {
- assertThrows(() => {
- new Deno.Command("echo", {
- args: ["fhqwhgads"],
- uid: 0,
- }).outputSync();
- }, Deno.errors.PermissionDenied);
- }
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true },
- ignore: Deno.build.os === "windows",
- },
- async function commandGid() {
- const { stdout } = await new Deno.Command("id", {
- args: ["-g"],
- }).output();
-
- const currentGid = new TextDecoder().decode(stdout);
-
- if (currentGid !== "0") {
- await assertRejects(async () => {
- await new Deno.Command("echo", {
- args: ["fhqwhgads"],
- gid: 0,
- }).output();
- }, Deno.errors.PermissionDenied);
- }
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true },
- ignore: Deno.build.os === "windows",
- },
- function commandSyncGid() {
- const { stdout } = new Deno.Command("id", {
- args: ["-g"],
- }).outputSync();
-
- const currentGid = new TextDecoder().decode(stdout);
-
- if (currentGid !== "0") {
- assertThrows(() => {
- new Deno.Command("echo", {
- args: ["fhqwhgads"],
- gid: 0,
- }).outputSync();
- }, Deno.errors.PermissionDenied);
- }
- },
-);
-
-Deno.test(function commandStdinPipedFails() {
- assertThrows(
- () =>
- new Deno.Command("id", {
- stdin: "piped",
- }).output(),
- TypeError,
- "Piped stdin is not supported for this function, use 'Deno.Command.spawn()' instead",
- );
-});
-
-Deno.test(function spawnSyncStdinPipedFails() {
- assertThrows(
- () =>
- new Deno.Command("id", {
- stdin: "piped",
- }).outputSync(),
- TypeError,
- "Piped stdin is not supported for this function, use 'Deno.Command.spawn()' instead",
- );
-});
-
-Deno.test(
- // FIXME(bartlomieju): this test is very flaky on CI, fix it
- {
- ignore: true,
- permissions: { write: true, run: true, read: true },
- },
- async function commandChildUnref() {
- const enc = new TextEncoder();
- const cwd = await Deno.makeTempDir({ prefix: "deno_command_test" });
-
- const programFile = "unref.ts";
- const program = `
-const command = await new Deno.Command(Deno.execPath(), {
- cwd: Deno.args[0],
- stdout: "piped",
- args: ["run", "-A", "--unstable", Deno.args[1]],
-});
-const child = command.spawn();
-const readable = child.stdout.pipeThrough(new TextDecoderStream());
-const reader = readable.getReader();
-// set up an interval that will end after reading a few messages from stdout,
-// to verify that stdio streams are properly unrefed
-let count = 0;
-let interval;
-interval = setInterval(async () => {
- count += 1;
- if (count > 10) {
- clearInterval(interval);
- console.log("cleared interval");
- }
- const res = await reader.read();
- if (res.done) {
- throw new Error("stream shouldn't be done");
- }
- if (res.value.trim() != "hello from interval") {
- throw new Error("invalid message received");
- }
-}, 120);
-console.log("spawned pid", child.pid);
-child.unref();
-`;
-
- const childProgramFile = "unref_child.ts";
- const childProgram = `
-setInterval(() => {
- console.log("hello from interval");
-}, 100);
-`;
- Deno.writeFileSync(`${cwd}/${programFile}`, enc.encode(program));
- Deno.writeFileSync(`${cwd}/${childProgramFile}`, enc.encode(childProgram));
- // In this subprocess we are spawning another subprocess which has
- // an infinite interval set. Following call would never resolve unless
- // child process gets unrefed.
- const { success, stdout, stderr } = await new Deno.Command(
- Deno.execPath(),
- {
- cwd,
- args: ["run", "-A", "--unstable", programFile, cwd, childProgramFile],
- },
- ).output();
-
- assert(success);
- const stdoutText = new TextDecoder().decode(stdout);
- const stderrText = new TextDecoder().decode(stderr);
- assert(stderrText.length == 0);
- const [line1, line2] = stdoutText.split("\n");
- const pidStr = line1.split(" ").at(-1);
- assert(pidStr);
- assertEquals(line2, "cleared interval");
- const pid = Number.parseInt(pidStr, 10);
- await Deno.remove(cwd, { recursive: true });
- // Child process should have been killed when parent process exits.
- assertThrows(() => {
- Deno.kill(pid, "SIGTERM");
- }, Deno.errors.NotFound);
- },
-);
-
-Deno.test(
- { ignore: Deno.build.os !== "windows" },
- async function commandWindowsRawArguments() {
- let { success, stdout } = await new Deno.Command("cmd", {
- args: ["/d", "/s", "/c", '"deno ^"--version^""'],
- windowsRawArguments: true,
- }).output();
- assert(success);
- let stdoutText = new TextDecoder().decode(stdout);
- assertStringIncludes(stdoutText, "deno");
- assertStringIncludes(stdoutText, "v8");
- assertStringIncludes(stdoutText, "typescript");
-
- ({ success, stdout } = new Deno.Command("cmd", {
- args: ["/d", "/s", "/c", '"deno ^"--version^""'],
- windowsRawArguments: true,
- }).outputSync());
- assert(success);
- stdoutText = new TextDecoder().decode(stdout);
- assertStringIncludes(stdoutText, "deno");
- assertStringIncludes(stdoutText, "v8");
- assertStringIncludes(stdoutText, "typescript");
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: true } },
- async function commandWithPrototypePollution() {
- const originalThen = Promise.prototype.then;
- const originalSymbolIterator = Array.prototype[Symbol.iterator];
- try {
- Promise.prototype.then = Array.prototype[Symbol.iterator] = () => {
- throw new Error();
- };
- await new Deno.Command(Deno.execPath(), {
- args: ["eval", "console.log('hello world')"],
- }).output();
- } finally {
- Promise.prototype.then = originalThen;
- Array.prototype[Symbol.iterator] = originalSymbolIterator;
- }
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function commandKillAfterStatus() {
- const command = new Deno.Command(Deno.execPath(), {
- args: ["help"],
- stdout: "null",
- stderr: "null",
- });
- const child = command.spawn();
- await child.status;
- assertThrows(
- () => child.kill(),
- TypeError,
- "Child process has already terminated.",
- );
- },
-);
-
-Deno.test(
- "process that fails to spawn, prints its name in error",
- async () => {
- assertThrows(
- () => new Deno.Command("doesntexist").outputSync(),
- Error,
- "Failed to spawn 'doesntexist'",
- );
- await assertRejects(
- async () => await new Deno.Command("doesntexist").output(),
- Error,
- "Failed to spawn 'doesntexist'",
- );
- },
-);
diff --git a/cli/tests/unit/console_test.ts b/cli/tests/unit/console_test.ts
deleted file mode 100644
index 2f24b2c4e..000000000
--- a/cli/tests/unit/console_test.ts
+++ /dev/null
@@ -1,2411 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-// TODO(ry) The unit test functions in this module are too coarse. They should
-// be broken up into smaller bits.
-
-// TODO(ry) These tests currently strip all the ANSI colors out. We don't have a
-// good way to control whether we produce color output or not since
-// std/fmt/colors auto determines whether to put colors in or not. We need
-// better infrastructure here so we can properly test the colors.
-
-import {
- assert,
- assertEquals,
- assertStringIncludes,
- assertThrows,
-} from "./test_util.ts";
-import { stripColor } from "@test_util/std/fmt/colors.ts";
-
-const customInspect = Symbol.for("Deno.customInspect");
-const {
- Console,
- cssToAnsi: cssToAnsi_,
- inspectArgs,
- parseCss: parseCss_,
- parseCssColor: parseCssColor_,
- // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
-} = Deno[Deno.internal];
-
-function stringify(...args: unknown[]): string {
- return stripColor(inspectArgs(args).replace(/\n$/, ""));
-}
-
-interface Css {
- backgroundColor: [number, number, number] | string | null;
- color: [number, number, number] | string | null;
- fontWeight: string | null;
- fontStyle: string | null;
- textDecorationColor: [number, number, number] | null;
- textDecorationLine: string[];
-}
-
-const DEFAULT_CSS: Css = {
- backgroundColor: null,
- color: null,
- fontWeight: null,
- fontStyle: null,
- textDecorationColor: null,
- textDecorationLine: [],
-};
-
-function parseCss(cssString: string): Css {
- return parseCss_(cssString);
-}
-
-function parseCssColor(colorString: string): [number, number, number] | null {
- return parseCssColor_(colorString);
-}
-
-/** ANSI-fy the CSS, replace "\x1b" with "_". */
-function cssToAnsiEsc(css: Css, prevCss: Css | null = null): string {
- return cssToAnsi_(css, prevCss).replaceAll("\x1b", "_");
-}
-
-// test cases from web-platform-tests
-// via https://github.com/web-platform-tests/wpt/blob/master/console/console-is-a-namespace.any.js
-Deno.test(function consoleShouldBeANamespace() {
- const prototype1 = Object.getPrototypeOf(console);
- const prototype2 = Object.getPrototypeOf(prototype1);
-
- assertEquals(Object.getOwnPropertyNames(prototype1).length, 0);
- assertEquals(prototype2, Object.prototype);
-});
-
-Deno.test(function consoleHasRightInstance() {
- assert(console instanceof Console);
- assertEquals({} instanceof Console, false);
-});
-
-Deno.test(function consoleTestAssertShouldNotThrowError() {
- mockConsole((console) => {
- console.assert(true);
- let hasThrown = undefined;
- try {
- console.assert(false);
- hasThrown = false;
- } catch {
- hasThrown = true;
- }
- assertEquals(hasThrown, false);
- });
-});
-
-Deno.test(function consoleTestStringifyComplexObjects() {
- assertEquals(stringify("foo"), "foo");
- assertEquals(stringify(["foo", "bar"]), `[ "foo", "bar" ]`);
- assertEquals(stringify({ foo: "bar" }), `{ foo: "bar" }`);
-});
-
-Deno.test(
- function consoleTestStringifyComplexObjectsWithEscapedSequences() {
- assertEquals(
- stringify(
- ["foo\b", "foo\f", "foo\n", "foo\r", "foo\t", "foo\v", "foo\0"],
- ),
- `[
- "foo\\b", "foo\\f",
- "foo\\n", "foo\\r",
- "foo\\t", "foo\\v",
- "foo\\x00"
-]`,
- );
- assertEquals(
- stringify(
- [
- Symbol(),
- Symbol(""),
- Symbol("foo\b"),
- Symbol("foo\f"),
- Symbol("foo\n"),
- Symbol("foo\r"),
- Symbol("foo\t"),
- Symbol("foo\v"),
- Symbol("foo\0"),
- ],
- ),
- `[
- Symbol(),
- Symbol(""),
- Symbol("foo\\b"),
- Symbol("foo\\f"),
- Symbol("foo\\n"),
- Symbol("foo\\r"),
- Symbol("foo\\t"),
- Symbol("foo\\v"),
- Symbol("foo\\x00")
-]`,
- );
- assertEquals(
- stringify(
- { "foo\b": "bar\n", "bar\r": "baz\t", "qux\0": "qux\0" },
- ),
- `{ "foo\\b": "bar\\n", "bar\\r": "baz\\t", "qux\\x00": "qux\\x00" }`,
- );
- assertEquals(
- stringify(
- {
- [Symbol("foo\b")]: `Symbol("foo\n")`,
- [Symbol("bar\n")]: `Symbol("bar\n")`,
- [Symbol("bar\r")]: `Symbol("bar\r")`,
- [Symbol("baz\t")]: `Symbol("baz\t")`,
- [Symbol("qux\0")]: `Symbol("qux\0")`,
- },
- ),
- `{
- [Symbol("foo\\b")]: 'Symbol("foo\\n")',
- [Symbol("bar\\n")]: 'Symbol("bar\\n")',
- [Symbol("bar\\r")]: 'Symbol("bar\\r")',
- [Symbol("baz\\t")]: 'Symbol("baz\\t")',
- [Symbol("qux\\x00")]: 'Symbol("qux\\x00")'
-}`,
- );
- assertEquals(
- stringify(new Set(["foo\n", "foo\r", "foo\0"])),
- `Set(3) { "foo\\n", "foo\\r", "foo\\x00" }`,
- );
- },
-);
-
-Deno.test(function consoleTestStringifyQuotes() {
- assertEquals(stringify(["\\"]), `[ "\\\\" ]`);
- assertEquals(stringify(['\\,"']), `[ '\\\\,"' ]`);
- assertEquals(stringify([`\\,",'`]), `[ \`\\\\,",'\` ]`);
- assertEquals(stringify(["\\,\",',`"]), `[ "\\\\,\\",',\`" ]`);
-});
-
-Deno.test(function consoleTestStringifyLongStrings() {
- const veryLongString = "a".repeat(200);
- // If we stringify an object containing the long string, it gets abbreviated.
- let actual = stringify({ veryLongString });
- assert(actual.includes("..."));
- assert(actual.length < 200);
- // However if we stringify the string itself, we get it exactly.
- actual = stringify(veryLongString);
- assertEquals(actual, veryLongString);
-});
-
-Deno.test(function consoleTestStringifyCircular() {
- class Base {
- a = 1;
- m1() {}
- }
-
- class Extended extends Base {
- b = 2;
- m2() {}
- }
-
- // deno-lint-ignore no-explicit-any
- const nestedObj: any = {
- num: 1,
- bool: true,
- str: "a",
- method() {},
- async asyncMethod() {},
- *generatorMethod() {},
- un: undefined,
- nu: null,
- arrowFunc: () => {},
- extendedClass: new Extended(),
- nFunc: new Function(),
- extendedCstr: Extended,
- };
-
- const circularObj = {
- num: 2,
- bool: false,
- str: "b",
- method() {},
- un: undefined,
- nu: null,
- nested: nestedObj,
- emptyObj: {},
- arr: [1, "s", false, null, nestedObj],
- baseClass: new Base(),
- };
-
- nestedObj.o = circularObj;
- const nestedObjExpected = `<ref *1> {
- num: 1,
- bool: true,
- str: "a",
- method: [Function: method],
- asyncMethod: [AsyncFunction: asyncMethod],
- generatorMethod: [GeneratorFunction: generatorMethod],
- un: undefined,
- nu: null,
- arrowFunc: [Function: arrowFunc],
- extendedClass: Extended { a: 1, b: 2 },
- nFunc: [Function: anonymous],
- extendedCstr: [class Extended extends Base],
- o: {
- num: 2,
- bool: false,
- str: "b",
- method: [Function: method],
- un: undefined,
- nu: null,
- nested: [Circular *1],
- emptyObj: {},
- arr: [ 1, "s", false, null, [Circular *1] ],
- baseClass: Base { a: 1 }
- }
-}`;
-
- assertEquals(stringify(1), "1");
- assertEquals(stringify(-0), "-0");
- assertEquals(stringify(1n), "1n");
- assertEquals(stringify("s"), "s");
- assertEquals(stringify(false), "false");
- assertEquals(stringify(new Number(1)), "[Number: 1]");
- assertEquals(stringify(new Number(-0)), "[Number: -0]");
- assertEquals(stringify(Object(1n)), "[BigInt: 1n]");
- assertEquals(stringify(new Boolean(true)), "[Boolean: true]");
- assertEquals(stringify(new String("deno")), `[String: "deno"]`);
- assertEquals(stringify(/[0-9]*/), "/[0-9]*/");
- assertEquals(
- stringify(new Date("2018-12-10T02:26:59.002Z")),
- "2018-12-10T02:26:59.002Z",
- );
- assertEquals(stringify(new Set([1, 2, 3])), "Set(3) { 1, 2, 3 }");
- assertEquals(
- stringify(new Set([1, 2, 3]).values()),
- "[Set Iterator] { 1, 2, 3 }",
- );
- assertEquals(
- stringify(new Set([1, 2, 3]).entries()),
- "[Set Entries] { [ 1, 1 ], [ 2, 2 ], [ 3, 3 ] }",
- );
- assertEquals(
- stringify(
- new Map([
- [1, "one"],
- [2, "two"],
- ]),
- ),
- `Map(2) { 1 => "one", 2 => "two" }`,
- );
- assertEquals(
- stringify(new Map([[1, "one"], [2, "two"]]).values()),
- `[Map Iterator] { "one", "two" }`,
- );
- assertEquals(
- stringify(new Map([[1, "one"], [2, "two"]]).entries()),
- `[Map Entries] { [ 1, "one" ], [ 2, "two" ] }`,
- );
- assertEquals(stringify(new WeakSet()), "WeakSet { <items unknown> }");
- assertEquals(stringify(new WeakMap()), "WeakMap { <items unknown> }");
- assertEquals(stringify(Symbol(1)), `Symbol("1")`);
- assertEquals(stringify(Object(Symbol(1))), `[Symbol: Symbol("1")]`);
- assertEquals(stringify(null), "null");
- assertEquals(stringify(undefined), "undefined");
- assertEquals(stringify(new Extended()), "Extended { a: 1, b: 2 }");
- assertEquals(
- stringify(function f() {}),
- "[Function: f]",
- );
- assertEquals(
- stringify(async function af() {}),
- "[AsyncFunction: af]",
- );
- assertEquals(
- stringify(function* gf() {}),
- "[GeneratorFunction: gf]",
- );
- assertEquals(
- stringify(async function* agf() {}),
- "[AsyncGeneratorFunction: agf]",
- );
- assertEquals(
- stringify(new Uint8Array([1, 2, 3])),
- "Uint8Array(3) [ 1, 2, 3 ]",
- );
- assertEquals(stringify(Uint8Array.prototype), "TypedArray {}");
- assertEquals(
- stringify({ a: { b: { c: { d: new Set([1]) } } } }),
- `{
- a: {
- b: { c: { d: Set(1) { 1 } } }
- }
-}`,
- );
- assertEquals(stringify(nestedObj), nestedObjExpected);
- assertEquals(
- stringify(JSON),
- "Object [JSON] {}",
- );
- assertEquals(
- stringify(new Console(() => {})),
- `Object [console] {
- log: [Function: log],
- debug: [Function: debug],
- info: [Function: info],
- dir: [Function: dir],
- dirxml: [Function: dir],
- warn: [Function: warn],
- error: [Function: error],
- assert: [Function: assert],
- count: [Function: count],
- countReset: [Function: countReset],
- table: [Function: table],
- time: [Function: time],
- timeLog: [Function: timeLog],
- timeEnd: [Function: timeEnd],
- group: [Function: group],
- groupCollapsed: [Function: group],
- groupEnd: [Function: groupEnd],
- clear: [Function: clear],
- trace: [Function: trace],
- profile: [Function: profile],
- profileEnd: [Function: profileEnd],
- timeStamp: [Function: timeStamp],
- indentLevel: 0,
- [Symbol(isConsoleInstance)]: true
-}`,
- );
- assertEquals(
- stringify({ str: 1, [Symbol.for("sym")]: 2, [Symbol.toStringTag]: "TAG" }),
- `Object [TAG] {
- str: 1,
- [Symbol(sym)]: 2,
- [Symbol(Symbol.toStringTag)]: "TAG"
-}`,
- );
- // test inspect is working the same
- assertEquals(stripColor(Deno.inspect(nestedObj)), nestedObjExpected);
-});
-
-Deno.test(function consoleTestStringifyMultipleCircular() {
- const y = { a: { b: {} }, foo: { bar: {} } };
- y.a.b = y.a;
- y.foo.bar = y.foo;
- assertEquals(
- stringify(y),
- "{\n" +
- " a: <ref *1> { b: [Circular *1] },\n" +
- " foo: <ref *2> { bar: [Circular *2] }\n" +
- "}",
- );
-});
-
-Deno.test(function consoleTestStringifyFunctionWithPrototypeRemoved() {
- const f = function f() {};
- Reflect.setPrototypeOf(f, null);
- assertEquals(stringify(f), "[Function (null prototype): f]");
- const af = async function af() {};
- Reflect.setPrototypeOf(af, null);
- assertEquals(stringify(af), "[AsyncFunction (null prototype): af]");
- const gf = function* gf() {};
- Reflect.setPrototypeOf(gf, null);
- assertEquals(stringify(gf), "[GeneratorFunction (null prototype): gf]");
- const agf = async function* agf() {};
- Reflect.setPrototypeOf(agf, null);
- assertEquals(
- stringify(agf),
- "[AsyncGeneratorFunction (null prototype): agf]",
- );
-});
-
-Deno.test(function consoleTestStringifyFunctionWithProperties() {
- const f = () => "test";
- f.x = () => "foo";
- f.y = 3;
- f.z = () => "baz";
- f.b = function bar() {};
- f.a = new Map();
- assertEquals(
- stringify({ f }),
- `{
- f: [Function: f] {
- x: [Function (anonymous)],
- y: 3,
- z: [Function (anonymous)],
- b: [Function: bar],
- a: Map(0) {}
- }
-}`,
- );
-
- const t = () => {};
- t.x = f;
- f.s = f;
- f.t = t;
- assertEquals(
- stringify({ f }),
- `{
- f: <ref *1> [Function: f] {
- x: [Function (anonymous)],
- y: 3,
- z: [Function (anonymous)],
- b: [Function: bar],
- a: Map(0) {},
- s: [Circular *1],
- t: [Function: t] { x: [Circular *1] }
- }
-}`,
- );
-
- assertEquals(
- stringify(Array),
- `[Function: Array]`,
- );
-
- assertEquals(
- stripColor(Deno.inspect(Array, { showHidden: true })),
- `<ref *1> [Function: Array] {
- [length]: 1,
- [name]: "Array",
- [prototype]: Object(0) [
- [length]: 0,
- [constructor]: [Circular *1],
- [at]: [Function: at] { [length]: 1, [name]: "at" },
- [concat]: [Function: concat] { [length]: 1, [name]: "concat" },
- [copyWithin]: [Function: copyWithin] { [length]: 2, [name]: "copyWithin" },
- [fill]: [Function: fill] { [length]: 1, [name]: "fill" },
- [find]: [Function: find] { [length]: 1, [name]: "find" },
- [findIndex]: [Function: findIndex] { [length]: 1, [name]: "findIndex" },
- [findLast]: [Function: findLast] { [length]: 1, [name]: "findLast" },
- [findLastIndex]: [Function: findLastIndex] { [length]: 1, [name]: "findLastIndex" },
- [lastIndexOf]: [Function: lastIndexOf] { [length]: 1, [name]: "lastIndexOf" },
- [pop]: [Function: pop] { [length]: 0, [name]: "pop" },
- [push]: [Function: push] { [length]: 1, [name]: "push" },
- [reverse]: [Function: reverse] { [length]: 0, [name]: "reverse" },
- [shift]: [Function: shift] { [length]: 0, [name]: "shift" },
- [unshift]: [Function: unshift] { [length]: 1, [name]: "unshift" },
- [slice]: [Function: slice] { [length]: 2, [name]: "slice" },
- [sort]: [Function: sort] { [length]: 1, [name]: "sort" },
- [splice]: [Function: splice] { [length]: 2, [name]: "splice" },
- [includes]: [Function: includes] { [length]: 1, [name]: "includes" },
- [indexOf]: [Function: indexOf] { [length]: 1, [name]: "indexOf" },
- [join]: [Function: join] { [length]: 1, [name]: "join" },
- [keys]: [Function: keys] { [length]: 0, [name]: "keys" },
- [entries]: [Function: entries] { [length]: 0, [name]: "entries" },
- [values]: [Function: values] { [length]: 0, [name]: "values" },
- [forEach]: [Function: forEach] { [length]: 1, [name]: "forEach" },
- [filter]: [Function: filter] { [length]: 1, [name]: "filter" },
- [flat]: [Function: flat] { [length]: 0, [name]: "flat" },
- [flatMap]: [Function: flatMap] { [length]: 1, [name]: "flatMap" },
- [map]: [Function: map] { [length]: 1, [name]: "map" },
- [every]: [Function: every] { [length]: 1, [name]: "every" },
- [some]: [Function: some] { [length]: 1, [name]: "some" },
- [reduce]: [Function: reduce] { [length]: 1, [name]: "reduce" },
- [reduceRight]: [Function: reduceRight] { [length]: 1, [name]: "reduceRight" },
- [toReversed]: [Function: toReversed] { [length]: 0, [name]: "toReversed" },
- [toSorted]: [Function: toSorted] { [length]: 1, [name]: "toSorted" },
- [toSpliced]: [Function: toSpliced] { [length]: 2, [name]: "toSpliced" },
- [with]: [Function: with] { [length]: 2, [name]: "with" },
- [toLocaleString]: [Function: toLocaleString] { [length]: 0, [name]: "toLocaleString" },
- [toString]: [Function: toString] { [length]: 0, [name]: "toString" },
- [Symbol(Symbol.iterator)]: [Function: values] { [length]: 0, [name]: "values" },
- [Symbol(Symbol.unscopables)]: [Object: null prototype] {
- at: true,
- copyWithin: true,
- entries: true,
- fill: true,
- find: true,
- findIndex: true,
- findLast: true,
- findLastIndex: true,
- flat: true,
- flatMap: true,
- includes: true,
- keys: true,
- toReversed: true,
- toSorted: true,
- toSpliced: true,
- values: true
- }
- ],
- [isArray]: [Function: isArray] { [length]: 1, [name]: "isArray" },
- [from]: [Function: from] { [length]: 1, [name]: "from" },
- [of]: [Function: of] { [length]: 0, [name]: "of" },
- [fromAsync]: [Function: fromAsync] { [length]: 1, [name]: "fromAsync" },
- [Symbol(Symbol.species)]: [Getter]
-}`,
- );
-});
-
-Deno.test(function consoleTestStringifyWithDepth() {
- // deno-lint-ignore no-explicit-any
- const nestedObj: any = { a: { b: { c: { d: { e: { f: 42 } } } } } };
- assertEquals(
- stripColor(inspectArgs([nestedObj], { depth: 3 })),
- "{\n a: { b: { c: { d: [Object] } } }\n}",
- );
- assertEquals(
- stripColor(inspectArgs([nestedObj], { depth: 4 })),
- "{\n a: {\n b: { c: { d: { e: [Object] } } }\n }\n}",
- );
- assertEquals(
- stripColor(inspectArgs([nestedObj], { depth: 0 })),
- "{ a: [Object] }",
- );
- assertEquals(
- stripColor(inspectArgs([nestedObj])),
- "{\n a: {\n b: { c: { d: { e: [Object] } } }\n }\n}",
- );
- // test inspect is working the same way
- assertEquals(
- stripColor(Deno.inspect(nestedObj, { depth: 4 })),
- "{\n a: {\n b: { c: { d: { e: [Object] } } }\n }\n}",
- );
-});
-
-Deno.test(function consoleTestStringifyLargeObject() {
- const obj = {
- a: 2,
- o: {
- a: "1",
- b: "2",
- c: "3",
- d: "4",
- e: "5",
- f: "6",
- g: 10,
- asd: 2,
- asda: 3,
- x: { a: "asd", x: 3 },
- },
- };
- assertEquals(
- stringify(obj),
- `{
- a: 2,
- o: {
- a: "1",
- b: "2",
- c: "3",
- d: "4",
- e: "5",
- f: "6",
- g: 10,
- asd: 2,
- asda: 3,
- x: { a: "asd", x: 3 }
- }
-}`,
- );
-});
-
-Deno.test(function consoleTestStringifyIterable() {
- const shortArray = [1, 2, 3, 4, 5];
- assertEquals(stringify(shortArray), "[ 1, 2, 3, 4, 5 ]");
-
- const longArray = new Array(200).fill(0);
- assertEquals(
- stringify(longArray),
- `[
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- ... 100 more items
-]`,
- );
-
- const obj = { a: "a", longArray };
- assertEquals(
- stringify(obj),
- `{
- a: "a",
- longArray: [
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- ... 100 more items
- ]
-}`,
- );
-
- const shortMap = new Map([
- ["a", 0],
- ["b", 1],
- ]);
- assertEquals(stringify(shortMap), `Map(2) { "a" => 0, "b" => 1 }`);
-
- const longMap = new Map();
- for (const key of Array(200).keys()) {
- longMap.set(`${key}`, key);
- }
- assertEquals(
- stringify(longMap),
- `Map(200) {
- "0" => 0,
- "1" => 1,
- "2" => 2,
- "3" => 3,
- "4" => 4,
- "5" => 5,
- "6" => 6,
- "7" => 7,
- "8" => 8,
- "9" => 9,
- "10" => 10,
- "11" => 11,
- "12" => 12,
- "13" => 13,
- "14" => 14,
- "15" => 15,
- "16" => 16,
- "17" => 17,
- "18" => 18,
- "19" => 19,
- "20" => 20,
- "21" => 21,
- "22" => 22,
- "23" => 23,
- "24" => 24,
- "25" => 25,
- "26" => 26,
- "27" => 27,
- "28" => 28,
- "29" => 29,
- "30" => 30,
- "31" => 31,
- "32" => 32,
- "33" => 33,
- "34" => 34,
- "35" => 35,
- "36" => 36,
- "37" => 37,
- "38" => 38,
- "39" => 39,
- "40" => 40,
- "41" => 41,
- "42" => 42,
- "43" => 43,
- "44" => 44,
- "45" => 45,
- "46" => 46,
- "47" => 47,
- "48" => 48,
- "49" => 49,
- "50" => 50,
- "51" => 51,
- "52" => 52,
- "53" => 53,
- "54" => 54,
- "55" => 55,
- "56" => 56,
- "57" => 57,
- "58" => 58,
- "59" => 59,
- "60" => 60,
- "61" => 61,
- "62" => 62,
- "63" => 63,
- "64" => 64,
- "65" => 65,
- "66" => 66,
- "67" => 67,
- "68" => 68,
- "69" => 69,
- "70" => 70,
- "71" => 71,
- "72" => 72,
- "73" => 73,
- "74" => 74,
- "75" => 75,
- "76" => 76,
- "77" => 77,
- "78" => 78,
- "79" => 79,
- "80" => 80,
- "81" => 81,
- "82" => 82,
- "83" => 83,
- "84" => 84,
- "85" => 85,
- "86" => 86,
- "87" => 87,
- "88" => 88,
- "89" => 89,
- "90" => 90,
- "91" => 91,
- "92" => 92,
- "93" => 93,
- "94" => 94,
- "95" => 95,
- "96" => 96,
- "97" => 97,
- "98" => 98,
- "99" => 99,
- ... 100 more items
-}`,
- );
-
- const shortSet = new Set([1, 2, 3]);
- assertEquals(stringify(shortSet), `Set(3) { 1, 2, 3 }`);
- const longSet = new Set();
- for (const key of Array(200).keys()) {
- longSet.add(key);
- }
- assertEquals(
- stringify(longSet),
- `Set(200) {
- 0,
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- 13,
- 14,
- 15,
- 16,
- 17,
- 18,
- 19,
- 20,
- 21,
- 22,
- 23,
- 24,
- 25,
- 26,
- 27,
- 28,
- 29,
- 30,
- 31,
- 32,
- 33,
- 34,
- 35,
- 36,
- 37,
- 38,
- 39,
- 40,
- 41,
- 42,
- 43,
- 44,
- 45,
- 46,
- 47,
- 48,
- 49,
- 50,
- 51,
- 52,
- 53,
- 54,
- 55,
- 56,
- 57,
- 58,
- 59,
- 60,
- 61,
- 62,
- 63,
- 64,
- 65,
- 66,
- 67,
- 68,
- 69,
- 70,
- 71,
- 72,
- 73,
- 74,
- 75,
- 76,
- 77,
- 78,
- 79,
- 80,
- 81,
- 82,
- 83,
- 84,
- 85,
- 86,
- 87,
- 88,
- 89,
- 90,
- 91,
- 92,
- 93,
- 94,
- 95,
- 96,
- 97,
- 98,
- 99,
- ... 100 more items
-}`,
- );
-
- const withEmptyEl = Array(10);
- withEmptyEl.fill(0, 4, 6);
- assertEquals(
- stringify(withEmptyEl),
- `[ <4 empty items>, 0, 0, <4 empty items> ]`,
- );
-
- const emptyArray = Array(5000);
- assertEquals(
- stringify(emptyArray),
- `[ <5000 empty items> ]`,
- );
-
- assertEquals(
- stringify(Array(1)),
- `[ <1 empty item> ]`,
- );
-
- assertEquals(
- stringify([, , 1]),
- `[ <2 empty items>, 1 ]`,
- );
-
- assertEquals(
- stringify([1, , , 1]),
- `[ 1, <2 empty items>, 1 ]`,
- );
-
- const withEmptyElAndMoreItems = Array(500);
- withEmptyElAndMoreItems.fill(0, 50, 80);
- withEmptyElAndMoreItems.fill(2, 100, 120);
- withEmptyElAndMoreItems.fill(3, 140, 160);
- withEmptyElAndMoreItems.fill(4, 180);
- assertEquals(
- stringify(withEmptyElAndMoreItems),
- `[
- <50 empty items>, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, <20 empty items>,
- 2, 2, 2, 2,
- 2, 2, 2, 2,
- 2, 2, 2, 2,
- 2, 2, 2, 2,
- 2, 2, 2, 2,
- <20 empty items>, 3, 3, 3,
- 3, 3, 3, 3,
- 3, 3, 3, 3,
- 3, 3, 3, 3,
- 3, 3, 3, 3,
- 3, <20 empty items>, 4, 4,
- 4, 4, 4, 4,
- 4, 4, 4, 4,
- 4, 4, 4, 4,
- 4, 4, 4, 4,
- 4, 4, 4, 4,
- 4, 4, 4, 4,
- ... 294 more items
-]`,
- );
-
- const lWithEmptyEl = Array(200);
- lWithEmptyEl.fill(0, 50, 80);
- assertEquals(
- stringify(lWithEmptyEl),
- `[
- <50 empty items>, 0, 0,
- 0, 0, 0,
- 0, 0, 0,
- 0, 0, 0,
- 0, 0, 0,
- 0, 0, 0,
- 0, 0, 0,
- 0, 0, 0,
- 0, 0, 0,
- 0, 0, 0,
- 0, <120 empty items>
-]`,
- );
-});
-
-Deno.test(function consoleTestStringifyIterableWhenGrouped() {
- const withOddNumberOfEls = new Float64Array(
- [
- 2.1,
- 2.01,
- 2.001,
- 2.0001,
- 2.00001,
- 2.000001,
- 2.0000001,
- 2.00000001,
- 2.000000001,
- 2.0000000001,
- 2,
- ],
- );
- assertEquals(
- stringify(withOddNumberOfEls),
- `Float64Array(11) [
- 2.1, 2.01,
- 2.001, 2.0001,
- 2.00001, 2.000001,
- 2.0000001, 2.00000001,
- 2.000000001, 2.0000000001,
- 2
-]`,
- );
- const withEvenNumberOfEls = new Float64Array(
- [
- 2.1,
- 2.01,
- 2.001,
- 2.0001,
- 2.00001,
- 2.000001,
- 2.0000001,
- 2.00000001,
- 2.000000001,
- 2.0000000001,
- 2,
- 2,
- ],
- );
- assertEquals(
- stringify(withEvenNumberOfEls),
- `Float64Array(12) [
- 2.1, 2.01,
- 2.001, 2.0001,
- 2.00001, 2.000001,
- 2.0000001, 2.00000001,
- 2.000000001, 2.0000000001,
- 2, 2
-]`,
- );
- const withThreeColumns = [
- 2,
- 2.1,
- 2.11,
- 2,
- 2.111,
- 2.1111,
- 2,
- 2.1,
- 2.11,
- 2,
- 2.1,
- ];
- assertEquals(
- stringify(withThreeColumns),
- `[
- 2, 2.1, 2.11,
- 2, 2.111, 2.1111,
- 2, 2.1, 2.11,
- 2, 2.1
-]`,
- );
-});
-
-Deno.test(function consoleTestIteratorValueAreNotConsumed() {
- const setIterator = new Set([1, 2, 3]).values();
- assertEquals(
- stringify(setIterator),
- "[Set Iterator] { 1, 2, 3 }",
- );
- assertEquals([...setIterator], [1, 2, 3]);
-});
-
-Deno.test(function consoleTestWeakSetAndWeakMapWithShowHidden() {
- assertEquals(
- stripColor(Deno.inspect(new WeakSet([{}]), { showHidden: true })),
- "WeakSet { {} }",
- );
- assertEquals(
- stripColor(Deno.inspect(new WeakMap([[{}, "foo"]]), { showHidden: true })),
- 'WeakMap { {} => "foo" }',
- );
-});
-
-Deno.test(async function consoleTestStringifyPromises() {
- const pendingPromise = new Promise((_res, _rej) => {});
- assertEquals(stringify(pendingPromise), "Promise { <pending> }");
-
- const resolvedPromise = new Promise((res, _rej) => {
- res("Resolved!");
- });
- assertEquals(stringify(resolvedPromise), `Promise { "Resolved!" }`);
-
- let rejectedPromise;
- try {
- rejectedPromise = new Promise((_, rej) => {
- rej(Error("Whoops"));
- });
- await rejectedPromise;
- } catch (_err) {
- // pass
- }
- const strLines = stringify(rejectedPromise).split("\n");
- assertEquals(strLines[0], "Promise {");
- assertEquals(strLines[1], " <rejected> Error: Whoops");
-});
-
-Deno.test(function consoleTestWithCustomInspector() {
- class A {
- [customInspect](
- inspect: unknown,
- options: Deno.InspectOptions,
- ): string {
- assertEquals(typeof inspect, "function");
- assertEquals(typeof options, "object");
- return "b";
- }
- }
-
- assertEquals(stringify(new A()), "b");
-});
-
-Deno.test(function consoleTestWithCustomInspectorUsingInspectFunc() {
- class A {
- [customInspect](
- inspect: (v: unknown, opts?: Deno.InspectOptions) => string,
- ): string {
- return "b " + inspect({ c: 1 });
- }
- }
-
- assertEquals(stringify(new A()), "b { c: 1 }");
-});
-
-Deno.test(function consoleTestWithConstructorError() {
- const obj = new Proxy({}, {
- getOwnPropertyDescriptor(_target, name) {
- if (name == "constructor") {
- throw "yikes";
- }
- return undefined;
- },
- });
- assertEquals(Deno.inspect(obj), "{}");
-});
-
-Deno.test(function consoleTestWithCustomInspectorError() {
- class A {
- [customInspect](): never {
- throw new Error("BOOM");
- }
- }
-
- const a = new A();
- assertThrows(
- () => stringify(a),
- Error,
- "BOOM",
- "Custom inspect won't attempt to parse if user defined function throws",
- );
- assertThrows(
- () => stringify(a),
- Error,
- "BOOM",
- "Inspect should fail and maintain a clear CTX_STACK",
- );
-});
-
-Deno.test(function consoleTestWithCustomInspectFunction() {
- function a() {}
- Object.assign(a, {
- [customInspect]() {
- return "b";
- },
- });
-
- assertEquals(stringify(a), "b");
-});
-
-Deno.test(function consoleTestWithIntegerFormatSpecifier() {
- assertEquals(stringify("%i"), "%i");
- assertEquals(stringify("%i", 42.0), "42");
- assertEquals(stringify("%i", 42), "42");
- assertEquals(stringify("%i", "42"), "NaN");
- assertEquals(stringify("%i", 1.5), "1");
- assertEquals(stringify("%i", -0.5), "0");
- assertEquals(stringify("%i", ""), "NaN");
- assertEquals(stringify("%i", Symbol()), "NaN");
- assertEquals(stringify("%i %d", 42, 43), "42 43");
- assertEquals(stringify("%d %i", 42), "42 %i");
- assertEquals(stringify("%d", 12345678901234567890123), "1");
- assertEquals(
- stringify("%i", 12345678901234567890123n),
- "12345678901234567890123n",
- );
-});
-
-Deno.test(function consoleTestWithFloatFormatSpecifier() {
- assertEquals(stringify("%f"), "%f");
- assertEquals(stringify("%f", 42.0), "42");
- assertEquals(stringify("%f", 42), "42");
- assertEquals(stringify("%f", "42"), "NaN");
- assertEquals(stringify("%f", 1.5), "1.5");
- assertEquals(stringify("%f", -0.5), "-0.5");
- assertEquals(stringify("%f", Math.PI), "3.141592653589793");
- assertEquals(stringify("%f", ""), "NaN");
- assertEquals(stringify("%f", Symbol("foo")), "NaN");
- assertEquals(stringify("%f", 5n), "NaN");
- assertEquals(stringify("%f %f", 42, 43), "42 43");
- assertEquals(stringify("%f %f", 42), "42 %f");
-});
-
-Deno.test(function consoleTestWithStringFormatSpecifier() {
- assertEquals(stringify("%s"), "%s");
- assertEquals(stringify("%s", undefined), "undefined");
- assertEquals(stringify("%s", "foo"), "foo");
- assertEquals(stringify("%s", 42), "42");
- assertEquals(stringify("%s", "42"), "42");
- assertEquals(stringify("%s %s", 42, 43), "42 43");
- assertEquals(stringify("%s %s", 42), "42 %s");
- assertEquals(stringify("%s", Symbol("foo")), "Symbol(foo)");
-});
-
-Deno.test(function consoleTestWithObjectFormatSpecifier() {
- assertEquals(stringify("%o"), "%o");
- assertEquals(stringify("%o", 42), "42");
- assertEquals(stringify("%o", "foo"), `"foo"`);
- assertEquals(stringify("o: %o, a: %O", {}, []), "o: {}, a: []");
- assertEquals(stringify("%o", { a: 42 }), "{ a: 42 }");
- assertEquals(
- stringify("%o", { a: { b: { c: { d: new Set([1]) } } } }),
- "{\n a: {\n b: { c: { d: Set(1) { 1 } } }\n }\n}",
- );
-});
-
-Deno.test(function consoleTestWithStyleSpecifier() {
- assertEquals(stringify("%cfoo%cbar"), "%cfoo%cbar");
- assertEquals(stringify("%cfoo%cbar", ""), "foo%cbar");
- assertEquals(stripColor(stringify("%cfoo%cbar", "", "color: red")), "foobar");
-});
-
-Deno.test(function consoleParseCssColor() {
- assertEquals(parseCssColor("inherit"), null);
- assertEquals(parseCssColor("black"), [0, 0, 0]);
- assertEquals(parseCssColor("darkmagenta"), [139, 0, 139]);
- assertEquals(parseCssColor("slateblue"), [106, 90, 205]);
- assertEquals(parseCssColor("#ffaa00"), [255, 170, 0]);
- assertEquals(parseCssColor("#ffAA00"), [255, 170, 0]);
- assertEquals(parseCssColor("#fa0"), [255, 170, 0]);
- assertEquals(parseCssColor("#FA0"), [255, 170, 0]);
- assertEquals(parseCssColor("#18d"), [17, 136, 221]);
- assertEquals(parseCssColor("#18D"), [17, 136, 221]);
- assertEquals(parseCssColor("#1188DD"), [17, 136, 221]);
- assertEquals(parseCssColor("rgb(100, 200, 50)"), [100, 200, 50]);
- assertEquals(parseCssColor("rgb(+100.3, -200, .5)"), [100, 0, 1]);
- assertEquals(parseCssColor("hsl(75, 60%, 40%)"), [133, 163, 41]);
-
- assertEquals(parseCssColor("rgb(100,200,50)"), [100, 200, 50]);
- assertEquals(
- parseCssColor("rgb( \t\n100 \t\n, \t\n200 \t\n, \t\n50 \t\n)"),
- [100, 200, 50],
- );
-});
-
-Deno.test(function consoleParseCss() {
- assertEquals(
- parseCss("background-color: inherit"),
- { ...DEFAULT_CSS, backgroundColor: "inherit" },
- );
- assertEquals(
- parseCss("color: inherit"),
- { ...DEFAULT_CSS, color: "inherit" },
- );
- assertEquals(
- parseCss("background-color: red"),
- { ...DEFAULT_CSS, backgroundColor: "red" },
- );
- assertEquals(parseCss("color: blue"), { ...DEFAULT_CSS, color: "blue" });
- assertEquals(
- parseCss("font-weight: bold"),
- { ...DEFAULT_CSS, fontWeight: "bold" },
- );
- assertEquals(
- parseCss("font-style: italic"),
- { ...DEFAULT_CSS, fontStyle: "italic" },
- );
- assertEquals(
- parseCss("font-style: oblique"),
- { ...DEFAULT_CSS, fontStyle: "italic" },
- );
- assertEquals(
- parseCss("text-decoration-color: green"),
- { ...DEFAULT_CSS, textDecorationColor: [0, 128, 0] },
- );
- assertEquals(
- parseCss("text-decoration-line: underline overline line-through"),
- {
- ...DEFAULT_CSS,
- textDecorationLine: ["underline", "overline", "line-through"],
- },
- );
- assertEquals(
- parseCss("text-decoration: yellow underline"),
- {
- ...DEFAULT_CSS,
- textDecorationColor: [255, 255, 0],
- textDecorationLine: ["underline"],
- },
- );
-
- assertEquals(
- parseCss("color:red;font-weight:bold;"),
- { ...DEFAULT_CSS, color: "red", fontWeight: "bold" },
- );
- assertEquals(
- parseCss(
- " \t\ncolor \t\n: \t\nred \t\n; \t\nfont-weight \t\n: \t\nbold \t\n; \t\n",
- ),
- { ...DEFAULT_CSS, color: "red", fontWeight: "bold" },
- );
- assertEquals(
- parseCss("color: red; font-weight: bold, font-style: italic"),
- { ...DEFAULT_CSS, color: "red" },
- );
-});
-
-Deno.test(function consoleCssToAnsi() {
- assertEquals(
- cssToAnsiEsc({ ...DEFAULT_CSS, backgroundColor: "inherit" }),
- "_[49m",
- );
- assertEquals(
- cssToAnsiEsc({ ...DEFAULT_CSS, backgroundColor: "foo" }),
- "_[49m",
- );
- assertEquals(
- cssToAnsiEsc({ ...DEFAULT_CSS, backgroundColor: "black" }),
- "_[40m",
- );
- assertEquals(
- cssToAnsiEsc({ ...DEFAULT_CSS, color: "inherit" }),
- "_[39m",
- );
- assertEquals(
- cssToAnsiEsc({ ...DEFAULT_CSS, color: "blue" }),
- "_[34m",
- );
- assertEquals(
- cssToAnsiEsc({ ...DEFAULT_CSS, backgroundColor: [200, 201, 202] }),
- "_[48;2;200;201;202m",
- );
- assertEquals(
- cssToAnsiEsc({ ...DEFAULT_CSS, color: [203, 204, 205] }),
- "_[38;2;203;204;205m",
- );
- assertEquals(cssToAnsiEsc({ ...DEFAULT_CSS, fontWeight: "bold" }), "_[1m");
- assertEquals(cssToAnsiEsc({ ...DEFAULT_CSS, fontStyle: "italic" }), "_[3m");
- assertEquals(
- cssToAnsiEsc({ ...DEFAULT_CSS, textDecorationColor: [206, 207, 208] }),
- "_[58;2;206;207;208m",
- );
- assertEquals(
- cssToAnsiEsc({ ...DEFAULT_CSS, textDecorationLine: ["underline"] }),
- "_[4m",
- );
- assertEquals(
- cssToAnsiEsc(
- { ...DEFAULT_CSS, textDecorationLine: ["overline", "line-through"] },
- ),
- "_[9m_[53m",
- );
- assertEquals(
- cssToAnsiEsc(
- { ...DEFAULT_CSS, color: [203, 204, 205], fontWeight: "bold" },
- ),
- "_[38;2;203;204;205m_[1m",
- );
- assertEquals(
- cssToAnsiEsc(
- { ...DEFAULT_CSS, color: [0, 0, 0], fontWeight: "bold" },
- { ...DEFAULT_CSS, color: [203, 204, 205], fontStyle: "italic" },
- ),
- "_[38;2;0;0;0m_[1m_[23m",
- );
-});
-
-Deno.test(function consoleTestWithVariousOrInvalidFormatSpecifier() {
- assertEquals(stringify("%s:%s"), "%s:%s");
- assertEquals(stringify("%i:%i"), "%i:%i");
- assertEquals(stringify("%d:%d"), "%d:%d");
- assertEquals(stringify("%%s%s", "foo"), "%sfoo");
- assertEquals(stringify("%s:%s", undefined), "undefined:%s");
- assertEquals(stringify("%s:%s", "foo", "bar"), "foo:bar");
- assertEquals(stringify("%s:%s", "foo", "bar", "baz"), "foo:bar baz");
- assertEquals(stringify("%%%s%%", "hi"), "%hi%");
- assertEquals(stringify("%d:%d", 12), "12:%d");
- assertEquals(stringify("%i:%i", 12), "12:%i");
- assertEquals(stringify("%f:%f", 12), "12:%f");
- assertEquals(stringify("o: %o, a: %o", {}), "o: {}, a: %o");
- assertEquals(stringify("abc%", 1), "abc% 1");
-});
-
-Deno.test(function consoleTestCallToStringOnLabel() {
- const methods = ["count", "countReset", "time", "timeLog", "timeEnd"];
- mockConsole((console) => {
- for (const method of methods) {
- let hasCalled = false;
- console[method]({
- toString() {
- hasCalled = true;
- },
- });
- assertEquals(hasCalled, true);
- }
- });
-});
-
-Deno.test(function consoleTestError() {
- class MyError extends Error {
- constructor(errStr: string) {
- super(errStr);
- this.name = "MyError";
- }
- }
- try {
- throw new MyError("This is an error");
- } catch (e) {
- assert(
- stringify(e)
- .split("\n")[0] // error has been caught
- .includes("MyError: This is an error"),
- );
- }
-});
-
-Deno.test(function consoleTestClear() {
- mockConsole((console, out) => {
- console.clear();
- assertEquals(out.toString(), "\x1b[1;1H" + "\x1b[0J");
- });
-});
-
-// Test bound this issue
-Deno.test(function consoleDetachedLog() {
- mockConsole((console) => {
- const log = console.log;
- const dir = console.dir;
- const dirxml = console.dirxml;
- const debug = console.debug;
- const info = console.info;
- const warn = console.warn;
- const error = console.error;
- const consoleAssert = console.assert;
- const consoleCount = console.count;
- const consoleCountReset = console.countReset;
- const consoleTable = console.table;
- const consoleTime = console.time;
- const consoleTimeLog = console.timeLog;
- const consoleTimeEnd = console.timeEnd;
- const consoleGroup = console.group;
- const consoleGroupEnd = console.groupEnd;
- const consoleClear = console.clear;
- log("Hello world");
- dir("Hello world");
- dirxml("Hello world");
- debug("Hello world");
- info("Hello world");
- warn("Hello world");
- error("Hello world");
- consoleAssert(true);
- consoleCount("Hello world");
- consoleCountReset("Hello world");
- consoleTable({ test: "Hello world" });
- consoleTime("Hello world");
- consoleTimeLog("Hello world");
- consoleTimeEnd("Hello world");
- consoleGroup("Hello world");
- consoleGroupEnd();
- consoleClear();
- });
-});
-
-class StringBuffer {
- chunks: string[] = [];
- add(x: string) {
- this.chunks.push(x);
- }
- toString(): string {
- return this.chunks.join("");
- }
-}
-
-type ConsoleExamineFunc = (
- // deno-lint-ignore no-explicit-any
- csl: any,
- out: StringBuffer,
- err?: StringBuffer,
- both?: StringBuffer,
-) => void;
-
-function mockConsole(f: ConsoleExamineFunc) {
- const out = new StringBuffer();
- const err = new StringBuffer();
- const both = new StringBuffer();
- const csl = new Console(
- (x: string, level: number, printsNewLine: boolean) => {
- const content = x + (printsNewLine ? "\n" : "");
- const buf = level > 1 ? err : out;
- buf.add(content);
- both.add(content);
- },
- );
- f(csl, out, err, both);
-}
-
-// console.group test
-Deno.test(function consoleGroup() {
- mockConsole((console, out) => {
- console.group("1");
- console.log("2");
- console.group("3");
- console.log("4");
- console.groupEnd();
- console.groupEnd();
- console.log("5");
- console.log("6");
-
- assertEquals(
- out.toString(),
- `1
- 2
- 3
- 4
-5
-6
-`,
- );
- });
-});
-
-// console.group with console.warn test
-Deno.test(function consoleGroupWarn() {
- mockConsole((console, _out, _err, both) => {
- assert(both);
- console.warn("1");
- console.group();
- console.warn("2");
- console.group();
- console.warn("3");
- console.groupEnd();
- console.warn("4");
- console.groupEnd();
- console.warn("5");
-
- console.warn("6");
- console.warn("7");
- assertEquals(
- both.toString(),
- `1
- 2
- 3
- 4
-5
-6
-7
-`,
- );
- });
-});
-
-// console.table test
-Deno.test(function consoleTable() {
- mockConsole((console, out) => {
- console.table({ a: "test", b: 1 });
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬────────┐
-│ (idx) │ Values │
-├───────┼────────┤
-│ a │ "test" │
-│ b │ 1 │
-└───────┴────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table({ a: { b: 10 }, b: { b: 20, c: 30 } }, ["c"]);
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬────┐
-│ (idx) │ c │
-├───────┼────┤
-│ a │ │
-│ b │ 30 │
-└───────┴────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table([[1, 1], [234, 2.34], [56789, 56.789]]);
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬───────┬────────┐
-│ (idx) │ 0 │ 1 │
-├───────┼───────┼────────┤
-│ 0 │ 1 │ 1 │
-│ 1 │ 234 │ 2.34 │
-│ 2 │ 56789 │ 56.789 │
-└───────┴───────┴────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table([1, 2, [3, [4]], [5, 6], [[7], [8]]]);
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬───────┬───────┬────────┐
-│ (idx) │ 0 │ 1 │ Values │
-├───────┼───────┼───────┼────────┤
-│ 0 │ │ │ 1 │
-│ 1 │ │ │ 2 │
-│ 2 │ 3 │ [ 4 ] │ │
-│ 3 │ 5 │ 6 │ │
-│ 4 │ [ 7 ] │ [ 8 ] │ │
-└───────┴───────┴───────┴────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table(new Set([1, 2, 3, "test"]));
- assertEquals(
- stripColor(out.toString()),
- `\
-┌────────────┬────────┐
-│ (iter idx) │ Values │
-├────────────┼────────┤
-│ 0 │ 1 │
-│ 1 │ 2 │
-│ 2 │ 3 │
-│ 3 │ "test" │
-└────────────┴────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table(
- new Map([
- [1, "one"],
- [2, "two"],
- ]),
- );
- assertEquals(
- stripColor(out.toString()),
- `\
-┌────────────┬─────┬────────┐
-│ (iter idx) │ Key │ Values │
-├────────────┼─────┼────────┤
-│ 0 │ 1 │ "one" │
-│ 1 │ 2 │ "two" │
-└────────────┴─────┴────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table({
- a: true,
- b: { c: { d: 10 }, e: [1, 2, [5, 6]] },
- f: "test",
- g: new Set([1, 2, 3, "test"]),
- h: new Map([[1, "one"]]),
- });
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬───────────┬────────────────────┬────────┐
-│ (idx) │ c │ e │ Values │
-├───────┼───────────┼────────────────────┼────────┤
-│ a │ │ │ true │
-│ b │ { d: 10 } │ [ 1, 2, [ 5, 6 ] ] │ │
-│ f │ │ │ "test" │
-│ g │ │ │ │
-│ h │ │ │ │
-└───────┴───────────┴────────────────────┴────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table([
- 1,
- "test",
- false,
- { a: 10 },
- ["test", { b: 20, c: "test" }],
- ]);
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬────────┬──────────────────────┬────┬────────┐
-│ (idx) │ 0 │ 1 │ a │ Values │
-├───────┼────────┼──────────────────────┼────┼────────┤
-│ 0 │ │ │ │ 1 │
-│ 1 │ │ │ │ "test" │
-│ 2 │ │ │ │ false │
-│ 3 │ │ │ 10 │ │
-│ 4 │ "test" │ { b: 20, c: "test" } │ │ │
-└───────┴────────┴──────────────────────┴────┴────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table([]);
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┐
-│ (idx) │
-├───────┤
-└───────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table({});
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┐
-│ (idx) │
-├───────┤
-└───────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table(new Set());
- assertEquals(
- stripColor(out.toString()),
- `\
-┌────────────┐
-│ (iter idx) │
-├────────────┤
-└────────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table(new Map());
- assertEquals(
- stripColor(out.toString()),
- `\
-┌────────────┐
-│ (iter idx) │
-├────────────┤
-└────────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table("test");
- assertEquals(out.toString(), "test\n");
- });
- mockConsole((console, out) => {
- console.table(["Hello", "你好", "Amapá"]);
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬─────────┐
-│ (idx) │ Values │
-├───────┼─────────┤
-│ 0 │ "Hello" │
-│ 1 │ "你好" │
-│ 2 │ "Amapá" │
-└───────┴─────────┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table([
- [1, 2],
- [3, 4],
- ]);
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬───┬───┐
-│ (idx) │ 0 │ 1 │
-├───────┼───┼───┤
-│ 0 │ 1 │ 2 │
-│ 1 │ 3 │ 4 │
-└───────┴───┴───┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table({ 1: { a: 4, b: 5 }, 2: null, 3: { b: 6, c: 7 } }, ["b"]);
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬───┐
-│ (idx) │ b │
-├───────┼───┤
-│ 1 │ 5 │
-│ 2 │ │
-│ 3 │ 6 │
-└───────┴───┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table([{ a: 0 }, { a: 1, b: 1 }, { a: 2 }, { a: 3, b: 3 }]);
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬───┬───┐
-│ (idx) │ a │ b │
-├───────┼───┼───┤
-│ 0 │ 0 │ │
-│ 1 │ 1 │ 1 │
-│ 2 │ 2 │ │
-│ 3 │ 3 │ 3 │
-└───────┴───┴───┘
-`,
- );
- });
- mockConsole((console, out) => {
- console.table(
- [{ a: 0 }, { a: 1, c: 1 }, { a: 2 }, { a: 3, c: 3 }],
- ["a", "b", "c"],
- );
- assertEquals(
- stripColor(out.toString()),
- `\
-┌───────┬───┬───┬───┐
-│ (idx) │ a │ b │ c │
-├───────┼───┼───┼───┤
-│ 0 │ 0 │ │ │
-│ 1 │ 1 │ │ 1 │
-│ 2 │ 2 │ │ │
-│ 3 │ 3 │ │ 3 │
-└───────┴───┴───┴───┘
-`,
- );
- });
-});
-
-// console.log(Error) test
-Deno.test(function consoleLogShouldNotThrowError() {
- mockConsole((console) => {
- let result = 0;
- try {
- console.log(new Error("foo"));
- result = 1;
- } catch (_e) {
- result = 2;
- }
- assertEquals(result, 1);
- });
-
- // output errors to the console should not include "Uncaught"
- mockConsole((console, out) => {
- console.log(new Error("foo"));
- assertEquals(out.toString().includes("Uncaught"), false);
- });
-});
-
-Deno.test(function consoleLogShouldNotThrowErrorWhenInvalidCssColorsAreGiven() {
- mockConsole((console, out) => {
- console.log("%cfoo", "color: foo; background-color: bar;");
- assertEquals(stripColor(out.toString()), "foo\n");
- });
-});
-
-// console.log(Invalid Date) test
-Deno.test(function consoleLogShouldNotThrowErrorWhenInvalidDateIsPassed() {
- mockConsole((console, out) => {
- const invalidDate = new Date("test");
- console.log(invalidDate);
- assertEquals(stripColor(out.toString()), "Invalid Date\n");
- });
-});
-
-// console.log(new Proxy(new Set(), {}))
-Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedSet() {
- mockConsole((console, out) => {
- const proxiedSet = new Proxy(new Set([1, 2]), {});
- console.log(proxiedSet);
- assertEquals(stripColor(out.toString()), "Set(2) { 1, 2 }\n");
- });
-});
-
-// console.log(new Proxy(new Map(), {}))
-Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedMap() {
- mockConsole((console, out) => {
- const proxiedMap = new Proxy(new Map([[1, 1], [2, 2]]), {});
- console.log(proxiedMap);
- assertEquals(stripColor(out.toString()), "Map(2) { 1 => 1, 2 => 2 }\n");
- });
-});
-
-// console.log(new Proxy(new Uint8Array(), {}))
-Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedTypedArray() {
- mockConsole((console, out) => {
- const proxiedUint8Array = new Proxy(new Uint8Array([1, 2]), {});
- console.log(proxiedUint8Array);
- assertEquals(stripColor(out.toString()), "Uint8Array(2) [ 1, 2 ]\n");
- });
-});
-
-// console.log(new Proxy(new RegExp(), {}))
-Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedRegExp() {
- mockConsole((console, out) => {
- const proxiedRegExp = new Proxy(/aaaa/, {});
- console.log(proxiedRegExp);
- assertEquals(stripColor(out.toString()), "/aaaa/\n");
- });
-});
-
-// console.log(new Proxy(new Date(), {}))
-Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedDate() {
- mockConsole((console, out) => {
- const proxiedDate = new Proxy(new Date("2022-09-24T15:59:39.529Z"), {});
- console.log(proxiedDate);
- assertEquals(stripColor(out.toString()), "2022-09-24T15:59:39.529Z\n");
- });
-});
-
-// console.log(new Proxy(new Error(), {}))
-Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedError() {
- mockConsole((console, out) => {
- const proxiedError = new Proxy(new Error("message"), {});
- console.log(proxiedError);
- assertStringIncludes(stripColor(out.toString()), "Error: message\n");
- });
-});
-
-// console.dir test
-Deno.test(function consoleDir() {
- mockConsole((console, out) => {
- console.dir("DIR");
- assertEquals(out.toString(), "DIR\n");
- });
- mockConsole((console, out) => {
- console.dir("DIR", { indentLevel: 2 });
- assertEquals(out.toString(), " DIR\n");
- });
-});
-
-// console.dir test
-Deno.test(function consoleDirXml() {
- mockConsole((console, out) => {
- console.dirxml("DIRXML");
- assertEquals(out.toString(), "DIRXML\n");
- });
- mockConsole((console, out) => {
- console.dirxml("DIRXML", { indentLevel: 2 });
- assertEquals(out.toString(), " DIRXML\n");
- });
-});
-
-// console.trace test
-Deno.test(function consoleTrace() {
- mockConsole((console, _out, err) => {
- console.trace("%s", "custom message");
- assert(err);
- assert(err.toString().includes("Trace: custom message"));
- });
-});
-
-Deno.test(function inspectString() {
- assertEquals(
- stripColor(Deno.inspect("\0")),
- `"\\x00"`,
- );
- assertEquals(
- stripColor(Deno.inspect("\x1b[2J")),
- `"\\x1b[2J"`,
- );
-});
-
-Deno.test(function inspectGetters() {
- assertEquals(
- stripColor(Deno.inspect({
- get foo() {
- return 0;
- },
- })),
- "{ foo: [Getter] }",
- );
-
- assertEquals(
- stripColor(Deno.inspect({
- get foo() {
- return 0;
- },
- }, { getters: true })),
- "{ foo: [Getter: 0] }",
- );
-
- assertEquals(
- Deno.inspect({
- get foo() {
- throw new Error("bar");
- },
- }, { getters: true }),
- "{ foo: [Getter: <Inspection threw (bar)>] }",
- );
-});
-
-Deno.test(function inspectPrototype() {
- class A {}
- assertEquals(Deno.inspect(A.prototype), "{}");
-});
-
-Deno.test(function inspectSorted() {
- assertEquals(
- stripColor(Deno.inspect({ b: 2, a: 1 }, { sorted: true })),
- "{ a: 1, b: 2 }",
- );
- assertEquals(
- stripColor(Deno.inspect(new Set(["b", "a"]), { sorted: true })),
- `Set(2) { "a", "b" }`,
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Map([
- ["b", 2],
- ["a", 1],
- ]),
- { sorted: true },
- )),
- `Map(2) { "a" => 1, "b" => 2 }`,
- );
-});
-
-Deno.test(function inspectTrailingComma() {
- assertEquals(
- stripColor(Deno.inspect(
- [
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
- ],
- { trailingComma: true },
- )),
- `[
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
-]`,
- );
- assertEquals(
- stripColor(Deno.inspect(
- {
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: 1,
- bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: 2,
- },
- { trailingComma: true },
- )),
- `{
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: 1,
- bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: 2,
-}`,
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Set([
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
- ]),
- { trailingComma: true },
- )),
- `Set(2) {
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
-}`,
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Map([
- ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 1],
- ["bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 2],
- ]),
- { trailingComma: true },
- )),
- `Map(2) {
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" => 1,
- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" => 2,
-}`,
- );
-});
-
-Deno.test(function inspectCompact() {
- assertEquals(
- stripColor(Deno.inspect({ a: 1, b: 2 }, { compact: false })),
- `{
- a: 1,
- b: 2
-}`,
- );
-});
-
-Deno.test(function inspectIterableLimit() {
- assertEquals(
- stripColor(Deno.inspect(["a", "b", "c"], { iterableLimit: 2 })),
- `[ "a", "b", ... 1 more item ]`,
- );
- assertEquals(
- stripColor(Deno.inspect(new Set(["a", "b", "c"]), { iterableLimit: 2 })),
- `Set(3) { "a", "b", ... 1 more item }`,
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Map([
- ["a", 1],
- ["b", 2],
- ["c", 3],
- ]),
- { iterableLimit: 2 },
- )),
- `Map(3) { "a" => 1, "b" => 2, ... 1 more item }`,
- );
-});
-
-Deno.test(function inspectProxy() {
- assertEquals(
- stripColor(Deno.inspect(
- new Proxy([1, 2, 3], {}),
- )),
- "[ 1, 2, 3 ]",
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Proxy({ key: "value" }, {}),
- )),
- `{ key: "value" }`,
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Proxy({}, {
- get(_target, key) {
- if (key === Symbol.toStringTag) {
- return "MyProxy";
- } else {
- return 5;
- }
- },
- getOwnPropertyDescriptor() {
- return {
- enumerable: true,
- configurable: true,
- value: 5,
- };
- },
- ownKeys() {
- return ["prop1", "prop2"];
- },
- }),
- )),
- `Object [MyProxy] { prop1: 5, prop2: 5 }`,
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Proxy([1, 2, 3], { get() {} }),
- { showProxy: true },
- )),
- "Proxy [ [ 1, 2, 3 ], { get: [Function: get] } ]",
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Proxy({ a: 1 }, {
- set(): boolean {
- return false;
- },
- }),
- { showProxy: true },
- )),
- "Proxy [ { a: 1 }, { set: [Function: set] } ]",
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Proxy([1, 2, 3, 4, 5, 6, 7], { get() {} }),
- { showProxy: true },
- )),
- `Proxy [
- [
- 1, 2, 3, 4,
- 5, 6, 7
- ],
- { get: [Function: get] }
-]`,
- );
- assertEquals(
- stripColor(Deno.inspect(
- new Proxy(function fn() {}, { get() {} }),
- { showProxy: true },
- )),
- "Proxy [ [Function: fn], { get: [Function: get] } ]",
- );
-});
-
-Deno.test(function inspectError() {
- const error1 = new Error("This is an error");
- const error2 = new Error("This is an error", {
- cause: new Error("This is a cause error"),
- });
-
- assertStringIncludes(
- stripColor(Deno.inspect(error1)),
- "Error: This is an error",
- );
- assertStringIncludes(
- stripColor(Deno.inspect(error2)),
- "Error: This is an error",
- );
- assertStringIncludes(
- stripColor(Deno.inspect(error2)),
- "Caused by Error: This is a cause error",
- );
-});
-
-Deno.test(function inspectErrorCircular() {
- const error1 = new Error("This is an error");
- const error2 = new Error("This is an error", {
- cause: new Error("This is a cause error"),
- });
- error1.cause = error1;
- assert(error2.cause instanceof Error);
- error2.cause.cause = error2;
-
- assertStringIncludes(
- stripColor(Deno.inspect(error1)),
- "Error: This is an error",
- );
- assertStringIncludes(
- stripColor(Deno.inspect(error2)),
- "<ref *1> Error: This is an error",
- );
- assertStringIncludes(
- stripColor(Deno.inspect(error2)),
- "Caused by Error: This is a cause error",
- );
- assertStringIncludes(
- stripColor(Deno.inspect(error2)),
- "Caused by [Circular *1]",
- );
-});
-
-Deno.test(function inspectColors() {
- assertEquals(Deno.inspect(1), "1");
- assertStringIncludes(Deno.inspect(1, { colors: true }), "\x1b[");
-});
-
-Deno.test(function inspectEmptyArray() {
- const arr: string[] = [];
-
- assertEquals(
- Deno.inspect(arr, {
- compact: false,
- trailingComma: true,
- }),
- "[]",
- );
-});
-
-Deno.test(function inspectDeepEmptyArray() {
- const obj = {
- arr: [],
- };
-
- assertEquals(
- Deno.inspect(obj, {
- compact: false,
- trailingComma: true,
- }),
- `{
- arr: [],
-}`,
- );
-});
-
-Deno.test(function inspectEmptyMap() {
- const map = new Map();
-
- assertEquals(
- Deno.inspect(map, {
- compact: false,
- trailingComma: true,
- }),
- "Map(0) {}",
- );
-});
-
-Deno.test(function inspectEmptySet() {
- const set = new Set();
-
- assertEquals(
- Deno.inspect(set, {
- compact: false,
- trailingComma: true,
- }),
- "Set(0) {}",
- );
-});
-
-Deno.test(function inspectEmptyUint8Array() {
- const typedArray = new Uint8Array(0);
-
- assertEquals(
- Deno.inspect(typedArray, {
- compact: false,
- trailingComma: true,
- }),
- "Uint8Array(0) []",
- );
-});
-
-Deno.test(function inspectLargeArrayBuffer() {
- const arrayBuffer = new ArrayBuffer(2 ** 32 + 1);
- assertEquals(
- Deno.inspect(arrayBuffer),
- `ArrayBuffer {
- [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 4294967197 more bytes>,
- byteLength: 4294967297
-}`,
- );
- structuredClone(arrayBuffer, { transfer: [arrayBuffer] });
- assertEquals(
- Deno.inspect(arrayBuffer),
- "ArrayBuffer { (detached), byteLength: 0 }",
- );
-
- const sharedArrayBuffer = new SharedArrayBuffer(2 ** 32 + 1);
- assertEquals(
- Deno.inspect(sharedArrayBuffer),
- `SharedArrayBuffer {
- [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 4294967197 more bytes>,
- byteLength: 4294967297
-}`,
- );
-});
-
-Deno.test(function inspectStringAbbreviation() {
- const LONG_STRING =
- "This is a really long string which will be abbreviated with ellipsis.";
- const obj = {
- str: LONG_STRING,
- };
- const arr = [LONG_STRING];
-
- assertEquals(
- Deno.inspect(obj, { strAbbreviateSize: 10 }),
- '{ str: "This is a "... 59 more characters }',
- );
-
- assertEquals(
- Deno.inspect(arr, { strAbbreviateSize: 10 }),
- '[ "This is a "... 59 more characters ]',
- );
-});
-
-Deno.test(async function inspectAggregateError() {
- try {
- await Promise.any([]);
- } catch (err) {
- assertEquals(
- Deno.inspect(err).trimEnd(),
- "AggregateError: All promises were rejected",
- );
- }
-});
-
-Deno.test(function inspectWithPrototypePollution() {
- const originalExec = RegExp.prototype.exec;
- try {
- RegExp.prototype.exec = () => {
- throw Error();
- };
- Deno.inspect("foo");
- } finally {
- RegExp.prototype.exec = originalExec;
- }
-});
-
-Deno.test(function inspectPromiseLike() {
- assertEquals(
- Deno.inspect(Object.create(Promise.prototype)),
- "Promise {}",
- );
-});
-
-Deno.test(function inspectorMethods() {
- console.timeStamp("test");
- console.profile("test");
- console.profileEnd("test");
-});
-
-Deno.test(function inspectQuotesOverride() {
- assertEquals(
- // @ts-ignore - 'quotes' is an internal option
- Deno.inspect("foo", { quotes: ["'", '"', "`"] }),
- "'foo'",
- );
- assertEquals(
- // @ts-ignore - 'quotes' is an internal option
- Deno.inspect("'foo'", { quotes: ["'", '"', "`"] }),
- `"'foo'"`,
- );
-});
-
-Deno.test(function inspectAnonymousFunctions() {
- assertEquals(Deno.inspect(() => {}), "[Function (anonymous)]");
- assertEquals(Deno.inspect(function () {}), "[Function (anonymous)]");
- assertEquals(Deno.inspect(async () => {}), "[AsyncFunction (anonymous)]");
- assertEquals(
- Deno.inspect(async function () {}),
- "[AsyncFunction (anonymous)]",
- );
- assertEquals(
- Deno.inspect(function* () {}),
- "[GeneratorFunction (anonymous)]",
- );
- assertEquals(
- Deno.inspect(async function* () {}),
- "[AsyncGeneratorFunction (anonymous)]",
- );
-});
-
-Deno.test(function inspectBreakLengthOption() {
- assertEquals(
- Deno.inspect("123456789\n".repeat(3), { breakLength: 34 }),
- `"123456789\\n123456789\\n123456789\\n"`,
- );
- assertEquals(
- Deno.inspect("123456789\n".repeat(3), { breakLength: 33 }),
- `"123456789\\n" +
- "123456789\\n" +
- "123456789\\n"`,
- );
-});
-
-Deno.test(function inspectEscapeSequencesFalse() {
- assertEquals(
- Deno.inspect("foo\nbar", { escapeSequences: true }),
- '"foo\\nbar"',
- ); // default behavior
- assertEquals(
- Deno.inspect("foo\nbar", { escapeSequences: false }),
- '"foo\nbar"',
- );
-});
diff --git a/cli/tests/unit/copy_file_test.ts b/cli/tests/unit/copy_file_test.ts
deleted file mode 100644
index ad467f510..000000000
--- a/cli/tests/unit/copy_file_test.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertRejects, assertThrows } from "./test_util.ts";
-
-function readFileString(filename: string | URL): string {
- const dataRead = Deno.readFileSync(filename);
- const dec = new TextDecoder("utf-8");
- return dec.decode(dataRead);
-}
-
-function writeFileString(filename: string | URL, s: string) {
- const enc = new TextEncoder();
- const data = enc.encode(s);
- Deno.writeFileSync(filename, data, { mode: 0o666 });
-}
-
-function assertSameContent(
- filename1: string | URL,
- filename2: string | URL,
-) {
- const data1 = Deno.readFileSync(filename1);
- const data2 = Deno.readFileSync(filename2);
- assertEquals(data1, data2);
-}
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function copyFileSyncSuccess() {
- const tempDir = Deno.makeTempDirSync();
- const fromFilename = tempDir + "/from.txt";
- const toFilename = tempDir + "/to.txt";
- writeFileString(fromFilename, "Hello world!");
- Deno.copyFileSync(fromFilename, toFilename);
- // No change to original file
- assertEquals(readFileString(fromFilename), "Hello world!");
- // Original == Dest
- assertSameContent(fromFilename, toFilename);
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function copyFileSyncByUrl() {
- const tempDir = Deno.makeTempDirSync();
- const fromUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/from.txt`,
- );
- const toUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/to.txt`,
- );
- writeFileString(fromUrl, "Hello world!");
- Deno.copyFileSync(fromUrl, toUrl);
- // No change to original file
- assertEquals(readFileString(fromUrl), "Hello world!");
- // Original == Dest
- assertSameContent(fromUrl, toUrl);
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- function copyFileSyncFailure() {
- const tempDir = Deno.makeTempDirSync();
- const fromFilename = tempDir + "/from.txt";
- const toFilename = tempDir + "/to.txt";
- // We skip initial writing here, from.txt does not exist
- assertThrows(
- () => {
- Deno.copyFileSync(fromFilename, toFilename);
- },
- Deno.errors.NotFound,
- `copy '${fromFilename}' -> '${toFilename}'`,
- );
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: false } },
- function copyFileSyncPerm1() {
- assertThrows(() => {
- Deno.copyFileSync("/from.txt", "/to.txt");
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { write: false, read: true } },
- function copyFileSyncPerm2() {
- assertThrows(() => {
- Deno.copyFileSync("/from.txt", "/to.txt");
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function copyFileSyncOverwrite() {
- const tempDir = Deno.makeTempDirSync();
- const fromFilename = tempDir + "/from.txt";
- const toFilename = tempDir + "/to.txt";
- writeFileString(fromFilename, "Hello world!");
- // Make Dest exist and have different content
- writeFileString(toFilename, "Goodbye!");
- Deno.copyFileSync(fromFilename, toFilename);
- // No change to original file
- assertEquals(readFileString(fromFilename), "Hello world!");
- // Original == Dest
- assertSameContent(fromFilename, toFilename);
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function copyFileSuccess() {
- const tempDir = Deno.makeTempDirSync();
- const fromFilename = tempDir + "/from.txt";
- const toFilename = tempDir + "/to.txt";
- writeFileString(fromFilename, "Hello world!");
- await Deno.copyFile(fromFilename, toFilename);
- // No change to original file
- assertEquals(readFileString(fromFilename), "Hello world!");
- // Original == Dest
- assertSameContent(fromFilename, toFilename);
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function copyFileByUrl() {
- const tempDir = Deno.makeTempDirSync();
- const fromUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/from.txt`,
- );
- const toUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/to.txt`,
- );
- writeFileString(fromUrl, "Hello world!");
- await Deno.copyFile(fromUrl, toUrl);
- // No change to original file
- assertEquals(readFileString(fromUrl), "Hello world!");
- // Original == Dest
- assertSameContent(fromUrl, toUrl);
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function copyFileFailure() {
- const tempDir = Deno.makeTempDirSync();
- const fromFilename = tempDir + "/from.txt";
- const toFilename = tempDir + "/to.txt";
- // We skip initial writing here, from.txt does not exist
- await assertRejects(
- async () => {
- await Deno.copyFile(fromFilename, toFilename);
- },
- Deno.errors.NotFound,
- `copy '${fromFilename}' -> '${toFilename}'`,
- );
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function copyFileOverwrite() {
- const tempDir = Deno.makeTempDirSync();
- const fromFilename = tempDir + "/from.txt";
- const toFilename = tempDir + "/to.txt";
- writeFileString(fromFilename, "Hello world!");
- // Make Dest exist and have different content
- writeFileString(toFilename, "Goodbye!");
- await Deno.copyFile(fromFilename, toFilename);
- // No change to original file
- assertEquals(readFileString(fromFilename), "Hello world!");
- // Original == Dest
- assertSameContent(fromFilename, toFilename);
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: false, write: true } },
- async function copyFilePerm1() {
- await assertRejects(async () => {
- await Deno.copyFile("/from.txt", "/to.txt");
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: false } },
- async function copyFilePerm2() {
- await assertRejects(async () => {
- await Deno.copyFile("/from.txt", "/to.txt");
- }, Deno.errors.PermissionDenied);
- },
-);
-
-function copyFileSyncMode(content: string): void {
- const tempDir = Deno.makeTempDirSync();
- const fromFilename = tempDir + "/from.txt";
- const toFilename = tempDir + "/to.txt";
- Deno.writeTextFileSync(fromFilename, content);
- Deno.chmodSync(fromFilename, 0o100755);
-
- Deno.copyFileSync(fromFilename, toFilename);
- const toStat = Deno.statSync(toFilename);
- assertEquals(toStat.mode!, 0o100755);
-}
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- function copyFileSyncChmod() {
- // this Tests different optimization paths on MacOS:
- //
- // < 128 KB clonefile() w/ fallback to copyfile()
- // > 128 KB
- copyFileSyncMode("Hello world!");
- copyFileSyncMode("Hello world!".repeat(128 * 1024));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function copyFileNulPath() {
- const fromFilename = "from.txt\0";
- const toFilename = "to.txt\0";
- await assertRejects(async () => {
- await Deno.copyFile(fromFilename, toFilename);
- }, TypeError);
- },
-);
diff --git a/cli/tests/unit/cron_test.ts b/cli/tests/unit/cron_test.ts
deleted file mode 100644
index 02573a898..000000000
--- a/cli/tests/unit/cron_test.ts
+++ /dev/null
@@ -1,460 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertThrows } from "./test_util.ts";
-
-// @ts-ignore This is not publicly typed namespace, but it's there for sure.
-const {
- formatToCronSchedule,
- parseScheduleToString,
- // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
-} = Deno[Deno.internal];
-
-const sleep = (time: number) => new Promise((r) => setTimeout(r, time));
-
-Deno.test(function noNameTest() {
- assertThrows(
- // @ts-ignore test
- () => Deno.cron(),
- TypeError,
- "Deno.cron requires a unique name",
- );
-});
-
-Deno.test(function noSchedule() {
- assertThrows(
- // @ts-ignore test
- () => Deno.cron("foo"),
- TypeError,
- "Deno.cron requires a valid schedule",
- );
-});
-
-Deno.test(function noHandler() {
- assertThrows(
- // @ts-ignore test
- () => Deno.cron("foo", "*/1 * * * *"),
- TypeError,
- "Deno.cron requires a handler",
- );
-});
-
-Deno.test(function invalidNameTest() {
- assertThrows(
- () => Deno.cron("abc[]", "*/1 * * * *", () => {}),
- TypeError,
- "Invalid cron name",
- );
- assertThrows(
- () => Deno.cron("a**bc", "*/1 * * * *", () => {}),
- TypeError,
- "Invalid cron name",
- );
- assertThrows(
- () => Deno.cron("abc<>", "*/1 * * * *", () => {}),
- TypeError,
- "Invalid cron name",
- );
- assertThrows(
- () => Deno.cron(";']", "*/1 * * * *", () => {}),
- TypeError,
- "Invalid cron name",
- );
- assertThrows(
- () =>
- Deno.cron(
- "0000000000000000000000000000000000000000000000000000000000000000000000",
- "*/1 * * * *",
- () => {},
- ),
- TypeError,
- "Cron name is too long",
- );
-});
-
-Deno.test(function invalidScheduleTest() {
- assertThrows(
- () => Deno.cron("abc", "bogus", () => {}),
- TypeError,
- "Invalid cron schedule",
- );
- assertThrows(
- () => Deno.cron("abc", "* * * * * *", () => {}),
- TypeError,
- "Invalid cron schedule",
- );
- assertThrows(
- () => Deno.cron("abc", "* * * *", () => {}),
- TypeError,
- "Invalid cron schedule",
- );
- assertThrows(
- () => Deno.cron("abc", "m * * * *", () => {}),
- TypeError,
- "Invalid cron schedule",
- );
-});
-
-Deno.test(function invalidBackoffScheduleTest() {
- assertThrows(
- () =>
- Deno.cron(
- "abc",
- "*/1 * * * *",
- { backoffSchedule: [1, 1, 1, 1, 1, 1] },
- () => {},
- ),
- TypeError,
- "Invalid backoff schedule",
- );
- assertThrows(
- () =>
- Deno.cron("abc", "*/1 * * * *", { backoffSchedule: [3600001] }, () => {}),
- TypeError,
- "Invalid backoff schedule",
- );
-});
-
-Deno.test(async function tooManyCrons() {
- const crons: Promise<void>[] = [];
- const ac = new AbortController();
- for (let i = 0; i <= 100; i++) {
- const c = Deno.cron(
- `abc_${i}`,
- "*/1 * * * *",
- { signal: ac.signal },
- () => {},
- );
- crons.push(c);
- }
-
- try {
- assertThrows(
- () => {
- Deno.cron("next-cron", "*/1 * * * *", { signal: ac.signal }, () => {});
- },
- TypeError,
- "Too many crons",
- );
- } finally {
- ac.abort();
- for (const c of crons) {
- await c;
- }
- }
-});
-
-Deno.test(async function duplicateCrons() {
- const ac = new AbortController();
- const c = Deno.cron("abc", "*/20 * * * *", { signal: ac.signal }, () => {});
- try {
- assertThrows(
- () => Deno.cron("abc", "*/20 * * * *", () => {}),
- TypeError,
- "Cron with this name already exists",
- );
- } finally {
- ac.abort();
- await c;
- }
-});
-
-Deno.test(async function basicTest() {
- Deno.env.set("DENO_CRON_TEST_SCHEDULE_OFFSET", "100");
-
- let count = 0;
- const { promise, resolve } = Promise.withResolvers<void>();
- const ac = new AbortController();
- const c = Deno.cron("abc", "*/20 * * * *", { signal: ac.signal }, () => {
- count++;
- if (count > 5) {
- resolve();
- }
- });
- try {
- await promise;
- } finally {
- ac.abort();
- await c;
- }
-});
-
-Deno.test(async function basicTestWithJsonFormatScheduleExpression() {
- Deno.env.set("DENO_CRON_TEST_SCHEDULE_OFFSET", "100");
-
- let count = 0;
- const { promise, resolve } = Promise.withResolvers<void>();
- const ac = new AbortController();
- const c = Deno.cron(
- "abc",
- { minute: { every: 20 } },
- { signal: ac.signal },
- () => {
- count++;
- if (count > 5) {
- resolve();
- }
- },
- );
- try {
- await promise;
- } finally {
- ac.abort();
- await c;
- }
-});
-
-Deno.test(async function multipleCrons() {
- Deno.env.set("DENO_CRON_TEST_SCHEDULE_OFFSET", "100");
-
- let count0 = 0;
- let count1 = 0;
- const { promise: promise0, resolve: resolve0 } = Promise.withResolvers<
- void
- >();
- const { promise: promise1, resolve: resolve1 } = Promise.withResolvers<
- void
- >();
- const ac = new AbortController();
- const c0 = Deno.cron("abc", "*/20 * * * *", { signal: ac.signal }, () => {
- count0++;
- if (count0 > 5) {
- resolve0();
- }
- });
- const c1 = Deno.cron("xyz", "*/20 * * * *", { signal: ac.signal }, () => {
- count1++;
- if (count1 > 5) {
- resolve1();
- }
- });
- try {
- await promise0;
- await promise1;
- } finally {
- ac.abort();
- await c0;
- await c1;
- }
-});
-
-Deno.test(async function overlappingExecutions() {
- Deno.env.set("DENO_CRON_TEST_SCHEDULE_OFFSET", "100");
-
- let count = 0;
- const { promise: promise0, resolve: resolve0 } = Promise.withResolvers<
- void
- >();
- const { promise: promise1, resolve: resolve1 } = Promise.withResolvers<
- void
- >();
- const ac = new AbortController();
- const c = Deno.cron(
- "abc",
- "*/20 * * * *",
- { signal: ac.signal },
- async () => {
- resolve0();
- count++;
- await promise1;
- },
- );
- try {
- await promise0;
- } finally {
- await sleep(2000);
- resolve1();
- ac.abort();
- await c;
- }
- assertEquals(count, 1);
-});
-
-Deno.test(async function retriesWithBackoffSchedule() {
- Deno.env.set("DENO_CRON_TEST_SCHEDULE_OFFSET", "5000");
-
- let count = 0;
- const ac = new AbortController();
- const c = Deno.cron("abc", "*/20 * * * *", {
- signal: ac.signal,
- backoffSchedule: [10, 20],
- }, async () => {
- count += 1;
- await sleep(10);
- throw new TypeError("cron error");
- });
- try {
- await sleep(6000);
- } finally {
- ac.abort();
- await c;
- }
-
- // The cron should have executed 3 times (1st attempt and 2 retries).
- assertEquals(count, 3);
-});
-
-Deno.test(async function retriesWithBackoffScheduleOldApi() {
- Deno.env.set("DENO_CRON_TEST_SCHEDULE_OFFSET", "5000");
-
- let count = 0;
- const ac = new AbortController();
- const c = Deno.cron("abc2", "*/20 * * * *", {
- signal: ac.signal,
- backoffSchedule: [10, 20],
- }, async () => {
- count += 1;
- await sleep(10);
- throw new TypeError("cron error");
- });
-
- try {
- await sleep(6000);
- } finally {
- ac.abort();
- await c;
- }
-
- // The cron should have executed 3 times (1st attempt and 2 retries).
- assertEquals(count, 3);
-});
-
-Deno.test("formatToCronSchedule - undefined value", () => {
- const result = formatToCronSchedule();
- assertEquals(result, "*");
-});
-
-Deno.test("formatToCronSchedule - number value", () => {
- const result = formatToCronSchedule(5);
- assertEquals(result, "5");
-});
-
-Deno.test("formatToCronSchedule - exact array value", () => {
- const result = formatToCronSchedule({ exact: [1, 2, 3] });
- assertEquals(result, "1,2,3");
-});
-
-Deno.test("formatToCronSchedule - exact number value", () => {
- const result = formatToCronSchedule({ exact: 5 });
- assertEquals(result, "5");
-});
-
-Deno.test("formatToCronSchedule - start, end, every values", () => {
- const result = formatToCronSchedule({ start: 1, end: 10, every: 2 });
- assertEquals(result, "1-10/2");
-});
-
-Deno.test("formatToCronSchedule - start, end values", () => {
- const result = formatToCronSchedule({ start: 1, end: 10 });
- assertEquals(result, "1-10");
-});
-
-Deno.test("formatToCronSchedule - start, every values", () => {
- const result = formatToCronSchedule({ start: 1, every: 2 });
- assertEquals(result, "1/2");
-});
-
-Deno.test("formatToCronSchedule - start value", () => {
- const result = formatToCronSchedule({ start: 1 });
- assertEquals(result, "1/1");
-});
-
-Deno.test("formatToCronSchedule - end, every values", () => {
- assertThrows(
- () => formatToCronSchedule({ end: 10, every: 2 }),
- TypeError,
- "Invalid cron schedule",
- );
-});
-
-Deno.test("Parse CronSchedule to string", () => {
- const result = parseScheduleToString({
- minute: { exact: [1, 2, 3] },
- hour: { start: 1, end: 10, every: 2 },
- dayOfMonth: { exact: 5 },
- month: { start: 1, end: 10 },
- dayOfWeek: { start: 1, every: 2 },
- });
- assertEquals(result, "1,2,3 1-10/2 5 1-10 1/2");
-});
-
-Deno.test("Parse schedule to string - string", () => {
- const result = parseScheduleToString("* * * * *");
- assertEquals(result, "* * * * *");
-});
-
-Deno.test("error on two handlers", () => {
- assertThrows(
- () => {
- // @ts-ignore test
- Deno.cron("abc", "* * * * *", () => {}, () => {});
- },
- TypeError,
- "Deno.cron requires a single handler",
- );
-});
-
-Deno.test("Parse test", () => {
- assertEquals(
- parseScheduleToString({
- minute: 3,
- }),
- "3 * * * *",
- );
- assertEquals(
- parseScheduleToString({
- hour: { every: 2 },
- }),
- "0 */2 * * *",
- );
- assertEquals(
- parseScheduleToString({
- dayOfMonth: { every: 10 },
- }),
- "0 0 */10 * *",
- );
- assertEquals(
- parseScheduleToString({
- month: { every: 3 },
- }),
- "0 0 1 */3 *",
- );
- assertEquals(
- parseScheduleToString({
- dayOfWeek: { every: 2 },
- }),
- "0 0 * * */2",
- );
- assertEquals(
- parseScheduleToString({
- minute: 3,
- hour: { every: 2 },
- }),
- "3 */2 * * *",
- );
- assertEquals(
- parseScheduleToString({
- dayOfMonth: { start: 1, end: 10 },
- }),
- "0 0 1-10 * *",
- );
- assertEquals(
- parseScheduleToString({
- minute: { every: 10 },
- dayOfMonth: { every: 5 },
- }),
- "*/10 * */5 * *",
- );
- assertEquals(
- parseScheduleToString({
- hour: { every: 3 },
- month: { every: 2 },
- }),
- "0 */3 * */2 *",
- );
- assertEquals(
- parseScheduleToString({
- minute: { every: 5 },
- month: { every: 2 },
- }),
- "*/5 * * */2 *",
- );
-});
diff --git a/cli/tests/unit/custom_event_test.ts b/cli/tests/unit/custom_event_test.ts
deleted file mode 100644
index b72084eb2..000000000
--- a/cli/tests/unit/custom_event_test.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-Deno.test(function customEventInitializedWithDetail() {
- const type = "touchstart";
- const detail = { message: "hello" };
- const customEventInit = {
- bubbles: true,
- cancelable: true,
- detail,
- } as CustomEventInit;
- const event = new CustomEvent(type, customEventInit);
-
- assertEquals(event.bubbles, true);
- assertEquals(event.cancelable, true);
- assertEquals(event.currentTarget, null);
- assertEquals(event.detail, detail);
- assertEquals(event.isTrusted, false);
- assertEquals(event.target, null);
- assertEquals(event.type, type);
-});
-
-Deno.test(function toStringShouldBeWebCompatibility() {
- const type = "touchstart";
- const event = new CustomEvent(type, {});
- assertEquals(event.toString(), "[object CustomEvent]");
-});
diff --git a/cli/tests/unit/dir_test.ts b/cli/tests/unit/dir_test.ts
deleted file mode 100644
index 4aaadfb12..000000000
--- a/cli/tests/unit/dir_test.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals, assertThrows } from "./test_util.ts";
-
-Deno.test({ permissions: { read: true } }, function dirCwdNotNull() {
- assert(Deno.cwd() != null);
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function dirCwdChdirSuccess() {
- const initialdir = Deno.cwd();
- const path = Deno.makeTempDirSync();
- Deno.chdir(path);
- const current = Deno.cwd();
- if (Deno.build.os === "darwin") {
- assertEquals(current, "/private" + path);
- } else {
- assertEquals(current, path);
- }
- Deno.chdir(initialdir);
- },
-);
-
-Deno.test({ permissions: { read: true, write: true } }, function dirCwdError() {
- // excluding windows since it throws resource busy, while removeSync
- if (["linux", "darwin"].includes(Deno.build.os)) {
- const initialdir = Deno.cwd();
- const path = Deno.makeTempDirSync();
- Deno.chdir(path);
- Deno.removeSync(path);
- try {
- assertThrows(() => {
- Deno.cwd();
- }, Deno.errors.NotFound);
- } finally {
- Deno.chdir(initialdir);
- }
- }
-});
-
-Deno.test({ permissions: { read: false } }, function dirCwdPermError() {
- assertThrows(
- () => {
- Deno.cwd();
- },
- Deno.errors.PermissionDenied,
- "Requires read access to <CWD>, run again with the --allow-read flag",
- );
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function dirChdirError() {
- const path = Deno.makeTempDirSync() + "test";
- assertThrows(
- () => {
- Deno.chdir(path);
- },
- Deno.errors.NotFound,
- `chdir '${path}'`,
- );
- },
-);
diff --git a/cli/tests/unit/dom_exception_test.ts b/cli/tests/unit/dom_exception_test.ts
deleted file mode 100644
index de335e105..000000000
--- a/cli/tests/unit/dom_exception_test.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import {
- assertEquals,
- assertNotEquals,
- assertStringIncludes,
-} from "./test_util.ts";
-
-Deno.test(function customInspectFunction() {
- const exception = new DOMException("test");
- assertEquals(Deno.inspect(exception), exception.stack);
- assertStringIncludes(Deno.inspect(DOMException.prototype), "DOMException");
-});
-
-Deno.test(function nameToCodeMappingPrototypeAccess() {
- const newCode = 100;
- const objectPrototype = Object.prototype as unknown as {
- pollution: number;
- };
- objectPrototype.pollution = newCode;
- assertNotEquals(newCode, new DOMException("test", "pollution").code);
- Reflect.deleteProperty(objectPrototype, "pollution");
-});
diff --git a/cli/tests/unit/error_stack_test.ts b/cli/tests/unit/error_stack_test.ts
deleted file mode 100644
index 7188b9f53..000000000
--- a/cli/tests/unit/error_stack_test.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertMatch } from "./test_util.ts";
-
-Deno.test(function errorStackMessageLine() {
- const e1 = new Error();
- e1.name = "Foo";
- e1.message = "bar";
- assertMatch(e1.stack!, /^Foo: bar\n/);
-
- const e2 = new Error();
- e2.name = "";
- e2.message = "bar";
- assertMatch(e2.stack!, /^bar\n/);
-
- const e3 = new Error();
- e3.name = "Foo";
- e3.message = "";
- assertMatch(e3.stack!, /^Foo\n/);
-
- const e4 = new Error();
- e4.name = "";
- e4.message = "";
- assertMatch(e4.stack!, /^\n/);
-
- const e5 = new Error();
- // deno-lint-ignore ban-ts-comment
- // @ts-expect-error
- e5.name = undefined;
- // deno-lint-ignore ban-ts-comment
- // @ts-expect-error
- e5.message = undefined;
- assertMatch(e5.stack!, /^Error\n/);
-
- const e6 = new Error();
- // deno-lint-ignore ban-ts-comment
- // @ts-expect-error
- e6.name = null;
- // deno-lint-ignore ban-ts-comment
- // @ts-expect-error
- e6.message = null;
- assertMatch(e6.stack!, /^null: null\n/);
-});
-
-Deno.test(function captureStackTrace() {
- function foo() {
- const error = new Error();
- const stack1 = error.stack!;
- Error.captureStackTrace(error, foo);
- const stack2 = error.stack!;
- // stack2 should be stack1 without the first frame.
- assertEquals(stack2, stack1.replace(/(?<=^[^\n]*\n)[^\n]*\n/, ""));
- }
- foo();
-});
diff --git a/cli/tests/unit/error_test.ts b/cli/tests/unit/error_test.ts
deleted file mode 100644
index 9ba09ce0d..000000000
--- a/cli/tests/unit/error_test.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertThrows, fail } from "./test_util.ts";
-
-Deno.test("Errors work", () => {
- assert(new Deno.errors.NotFound("msg") instanceof Error);
- assert(new Deno.errors.PermissionDenied("msg") instanceof Error);
- assert(new Deno.errors.ConnectionRefused("msg") instanceof Error);
- assert(new Deno.errors.ConnectionReset("msg") instanceof Error);
- assert(new Deno.errors.ConnectionAborted("msg") instanceof Error);
- assert(new Deno.errors.NotConnected("msg") instanceof Error);
- assert(new Deno.errors.AddrInUse("msg") instanceof Error);
- assert(new Deno.errors.AddrNotAvailable("msg") instanceof Error);
- assert(new Deno.errors.BrokenPipe("msg") instanceof Error);
- assert(new Deno.errors.AlreadyExists("msg") instanceof Error);
- assert(new Deno.errors.InvalidData("msg") instanceof Error);
- assert(new Deno.errors.TimedOut("msg") instanceof Error);
- assert(new Deno.errors.Interrupted("msg") instanceof Error);
- assert(new Deno.errors.WouldBlock("msg") instanceof Error);
- assert(new Deno.errors.WriteZero("msg") instanceof Error);
- assert(new Deno.errors.UnexpectedEof("msg") instanceof Error);
- assert(new Deno.errors.BadResource("msg") instanceof Error);
- assert(new Deno.errors.Http("msg") instanceof Error);
- assert(new Deno.errors.Busy("msg") instanceof Error);
- assert(new Deno.errors.NotSupported("msg") instanceof Error);
-});
-
-Deno.test("Errors have some tamper resistance", () => {
- // deno-lint-ignore no-explicit-any
- (Object.prototype as any).get = () => {};
- assertThrows(() => fail("test error"), Error, "test error");
- // deno-lint-ignore no-explicit-any
- delete (Object.prototype as any).get;
-});
diff --git a/cli/tests/unit/esnext_test.ts b/cli/tests/unit/esnext_test.ts
deleted file mode 100644
index 6b2334f42..000000000
--- a/cli/tests/unit/esnext_test.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-// TODO(@kitsonk) remove when we are no longer patching TypeScript to have
-// these types available.
-
-Deno.test(function typeCheckingEsNextArrayString() {
- const b = ["a", "b", "c", "d", "e", "f"];
- assertEquals(b.findLast((val) => typeof val === "string"), "f");
- assertEquals(b.findLastIndex((val) => typeof val === "string"), 5);
-});
-
-Deno.test(function intlListFormat() {
- const formatter = new Intl.ListFormat("en", {
- style: "long",
- type: "conjunction",
- });
- assertEquals(
- formatter.format(["red", "green", "blue"]),
- "red, green, and blue",
- );
-
- const formatter2 = new Intl.ListFormat("en", {
- style: "short",
- type: "disjunction",
- });
- assertEquals(formatter2.formatToParts(["Rust", "golang"]), [
- { type: "element", value: "Rust" },
- { type: "literal", value: " or " },
- { type: "element", value: "golang" },
- ]);
-
- // Works with iterables as well
- assertEquals(
- formatter.format(new Set(["red", "green", "blue"])),
- "red, green, and blue",
- );
- assertEquals(formatter2.formatToParts(new Set(["Rust", "golang"])), [
- { type: "element", value: "Rust" },
- { type: "literal", value: " or " },
- { type: "element", value: "golang" },
- ]);
-});
diff --git a/cli/tests/unit/event_target_test.ts b/cli/tests/unit/event_target_test.ts
deleted file mode 100644
index b084eaf90..000000000
--- a/cli/tests/unit/event_target_test.ts
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-// deno-lint-ignore-file no-window-prefix
-import { assertEquals, assertThrows } from "./test_util.ts";
-
-Deno.test(function addEventListenerTest() {
- const document = new EventTarget();
-
- assertEquals(document.addEventListener("x", null, false), undefined);
- assertEquals(document.addEventListener("x", null, true), undefined);
- assertEquals(document.addEventListener("x", null), undefined);
-});
-
-Deno.test(function constructedEventTargetCanBeUsedAsExpected() {
- const target = new EventTarget();
- const event = new Event("foo", { bubbles: true, cancelable: false });
- let callCount = 0;
-
- const listener = (e: Event) => {
- assertEquals(e, event);
- ++callCount;
- };
-
- target.addEventListener("foo", listener);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 1);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
-
- target.removeEventListener("foo", listener);
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
-});
-
-Deno.test(function anEventTargetCanBeSubclassed() {
- class NicerEventTarget extends EventTarget {
- on(
- type: string,
- callback: ((e: Event) => void) | null,
- options?: AddEventListenerOptions,
- ) {
- this.addEventListener(type, callback, options);
- }
-
- off(
- type: string,
- callback: ((e: Event) => void) | null,
- options?: EventListenerOptions,
- ) {
- this.removeEventListener(type, callback, options);
- }
- }
-
- const target = new NicerEventTarget();
- new Event("foo", { bubbles: true, cancelable: false });
- let callCount = 0;
-
- const listener = () => {
- ++callCount;
- };
-
- target.on("foo", listener);
- assertEquals(callCount, 0);
-
- target.off("foo", listener);
- assertEquals(callCount, 0);
-});
-
-Deno.test(function removingNullEventListenerShouldSucceed() {
- const document = new EventTarget();
- assertEquals(document.removeEventListener("x", null, false), undefined);
- assertEquals(document.removeEventListener("x", null, true), undefined);
- assertEquals(document.removeEventListener("x", null), undefined);
-});
-
-Deno.test(function constructedEventTargetUseObjectPrototype() {
- const target = new EventTarget();
- const event = new Event("toString", { bubbles: true, cancelable: false });
- let callCount = 0;
-
- const listener = (e: Event) => {
- assertEquals(e, event);
- ++callCount;
- };
-
- target.addEventListener("toString", listener);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 1);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
-
- target.removeEventListener("toString", listener);
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
-});
-
-Deno.test(function toStringShouldBeWebCompatible() {
- const target = new EventTarget();
- assertEquals(target.toString(), "[object EventTarget]");
-});
-
-Deno.test(function dispatchEventShouldNotThrowError() {
- let hasThrown = false;
-
- try {
- const target = new EventTarget();
- const event = new Event("hasOwnProperty", {
- bubbles: true,
- cancelable: false,
- });
- const listener = () => {};
- target.addEventListener("hasOwnProperty", listener);
- target.dispatchEvent(event);
- } catch {
- hasThrown = true;
- }
-
- assertEquals(hasThrown, false);
-});
-
-Deno.test(function eventTargetThisShouldDefaultToWindow() {
- const {
- addEventListener,
- dispatchEvent,
- removeEventListener,
- } = EventTarget.prototype;
- let n = 1;
- const event = new Event("hello");
- const listener = () => {
- n = 2;
- };
-
- addEventListener("hello", listener);
- window.dispatchEvent(event);
- assertEquals(n, 2);
- n = 1;
- removeEventListener("hello", listener);
- window.dispatchEvent(event);
- assertEquals(n, 1);
-
- window.addEventListener("hello", listener);
- dispatchEvent(event);
- assertEquals(n, 2);
- n = 1;
- window.removeEventListener("hello", listener);
- dispatchEvent(event);
- assertEquals(n, 1);
-});
-
-Deno.test(function eventTargetShouldAcceptEventListenerObject() {
- const target = new EventTarget();
- const event = new Event("foo", { bubbles: true, cancelable: false });
- let callCount = 0;
-
- const listener = {
- handleEvent(e: Event) {
- assertEquals(e, event);
- ++callCount;
- },
- };
-
- target.addEventListener("foo", listener);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 1);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
-
- target.removeEventListener("foo", listener);
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
-});
-
-Deno.test(function eventTargetShouldAcceptAsyncFunction() {
- const target = new EventTarget();
- const event = new Event("foo", { bubbles: true, cancelable: false });
- let callCount = 0;
-
- const listener = (e: Event) => {
- assertEquals(e, event);
- ++callCount;
- };
-
- target.addEventListener("foo", listener);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 1);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
-
- target.removeEventListener("foo", listener);
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
-});
-
-Deno.test(
- function eventTargetShouldAcceptAsyncFunctionForEventListenerObject() {
- const target = new EventTarget();
- const event = new Event("foo", { bubbles: true, cancelable: false });
- let callCount = 0;
-
- const listener = {
- handleEvent(e: Event) {
- assertEquals(e, event);
- ++callCount;
- },
- };
-
- target.addEventListener("foo", listener);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 1);
-
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
-
- target.removeEventListener("foo", listener);
- target.dispatchEvent(event);
- assertEquals(callCount, 2);
- },
-);
-Deno.test(function eventTargetDispatchShouldSetTargetNoListener() {
- const target = new EventTarget();
- const event = new Event("foo");
- assertEquals(event.target, null);
- target.dispatchEvent(event);
- assertEquals(event.target, target);
-});
-
-Deno.test(function eventTargetDispatchShouldSetTargetInListener() {
- const target = new EventTarget();
- const event = new Event("foo");
- assertEquals(event.target, null);
- let called = false;
- target.addEventListener("foo", (e) => {
- assertEquals(e.target, target);
- called = true;
- });
- target.dispatchEvent(event);
- assertEquals(called, true);
-});
-
-Deno.test(function eventTargetDispatchShouldFireCurrentListenersOnly() {
- const target = new EventTarget();
- const event = new Event("foo");
- let callCount = 0;
- target.addEventListener("foo", () => {
- ++callCount;
- target.addEventListener("foo", () => {
- ++callCount;
- });
- });
- target.dispatchEvent(event);
- assertEquals(callCount, 1);
-});
-
-Deno.test(function eventTargetAddEventListenerGlobalAbort() {
- return new Promise((resolve) => {
- const c = new AbortController();
-
- c.signal.addEventListener("abort", () => resolve());
- addEventListener("test", () => {}, { signal: c.signal });
- c.abort();
- });
-});
-
-Deno.test(function eventTargetBrandChecking() {
- const self = {};
-
- assertThrows(
- () => {
- EventTarget.prototype.addEventListener.call(self, "test", null);
- },
- TypeError,
- );
-
- assertThrows(
- () => {
- EventTarget.prototype.removeEventListener.call(self, "test", null);
- },
- TypeError,
- );
-
- assertThrows(
- () => {
- EventTarget.prototype.dispatchEvent.call(self, new Event("test"));
- },
- TypeError,
- );
-});
diff --git a/cli/tests/unit/event_test.ts b/cli/tests/unit/event_test.ts
deleted file mode 100644
index c82873cf6..000000000
--- a/cli/tests/unit/event_test.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertStringIncludes } from "./test_util.ts";
-
-Deno.test(function eventInitializedWithType() {
- const type = "click";
- const event = new Event(type);
-
- assertEquals(event.isTrusted, false);
- assertEquals(event.target, null);
- assertEquals(event.currentTarget, null);
- assertEquals(event.type, "click");
- assertEquals(event.bubbles, false);
- assertEquals(event.cancelable, false);
-});
-
-Deno.test(function eventInitializedWithTypeAndDict() {
- const init = "submit";
- const eventInit = { bubbles: true, cancelable: true } as EventInit;
- const event = new Event(init, eventInit);
-
- assertEquals(event.isTrusted, false);
- assertEquals(event.target, null);
- assertEquals(event.currentTarget, null);
- assertEquals(event.type, "submit");
- assertEquals(event.bubbles, true);
- assertEquals(event.cancelable, true);
-});
-
-Deno.test(function eventComposedPathSuccess() {
- const type = "click";
- const event = new Event(type);
- const composedPath = event.composedPath();
-
- assertEquals(composedPath, []);
-});
-
-Deno.test(function eventStopPropagationSuccess() {
- const type = "click";
- const event = new Event(type);
-
- assertEquals(event.cancelBubble, false);
- event.stopPropagation();
- assertEquals(event.cancelBubble, true);
-});
-
-Deno.test(function eventStopImmediatePropagationSuccess() {
- const type = "click";
- const event = new Event(type);
-
- assertEquals(event.cancelBubble, false);
- event.stopImmediatePropagation();
- assertEquals(event.cancelBubble, true);
-});
-
-Deno.test(function eventPreventDefaultSuccess() {
- const type = "click";
- const event = new Event(type);
-
- assertEquals(event.defaultPrevented, false);
- event.preventDefault();
- assertEquals(event.defaultPrevented, false);
-
- const eventInit = { bubbles: true, cancelable: true } as EventInit;
- const cancelableEvent = new Event(type, eventInit);
- assertEquals(cancelableEvent.defaultPrevented, false);
- cancelableEvent.preventDefault();
- assertEquals(cancelableEvent.defaultPrevented, true);
-});
-
-Deno.test(function eventInitializedWithNonStringType() {
- // deno-lint-ignore no-explicit-any
- const type: any = undefined;
- const event = new Event(type);
-
- assertEquals(event.isTrusted, false);
- assertEquals(event.target, null);
- assertEquals(event.currentTarget, null);
- assertEquals(event.type, "undefined");
- assertEquals(event.bubbles, false);
- assertEquals(event.cancelable, false);
-});
-
-Deno.test(function eventInspectOutput() {
- // deno-lint-ignore no-explicit-any
- const cases: Array<[any, (event: any) => string]> = [
- [
- new Event("test"),
- (event: Event) =>
- `Event {\n bubbles: false,\n cancelable: false,\n composed: false,\n currentTarget: null,\n defaultPrevented: false,\n eventPhase: 0,\n srcElement: null,\n target: null,\n returnValue: true,\n timeStamp: ${event.timeStamp},\n type: "test"\n}`,
- ],
- [
- new ErrorEvent("error"),
- (event: Event) =>
- `ErrorEvent {\n bubbles: false,\n cancelable: false,\n composed: false,\n currentTarget: null,\n defaultPrevented: false,\n eventPhase: 0,\n srcElement: null,\n target: null,\n returnValue: true,\n timeStamp: ${event.timeStamp},\n type: "error",\n message: "",\n filename: "",\n lineno: 0,\n colno: 0,\n error: undefined\n}`,
- ],
- [
- new CloseEvent("close"),
- (event: Event) =>
- `CloseEvent {\n bubbles: false,\n cancelable: false,\n composed: false,\n currentTarget: null,\n defaultPrevented: false,\n eventPhase: 0,\n srcElement: null,\n target: null,\n returnValue: true,\n timeStamp: ${event.timeStamp},\n type: "close",\n wasClean: false,\n code: 0,\n reason: ""\n}`,
- ],
- [
- new CustomEvent("custom"),
- (event: Event) =>
- `CustomEvent {\n bubbles: false,\n cancelable: false,\n composed: false,\n currentTarget: null,\n defaultPrevented: false,\n eventPhase: 0,\n srcElement: null,\n target: null,\n returnValue: true,\n timeStamp: ${event.timeStamp},\n type: "custom",\n detail: undefined\n}`,
- ],
- [
- new ProgressEvent("progress"),
- (event: Event) =>
- `ProgressEvent {\n bubbles: false,\n cancelable: false,\n composed: false,\n currentTarget: null,\n defaultPrevented: false,\n eventPhase: 0,\n srcElement: null,\n target: null,\n returnValue: true,\n timeStamp: ${event.timeStamp},\n type: "progress",\n lengthComputable: false,\n loaded: 0,\n total: 0\n}`,
- ],
- ];
-
- for (const [event, outputProvider] of cases) {
- assertEquals(Deno.inspect(event), outputProvider(event));
- }
-});
-
-Deno.test(function inspectEvent() {
- // has a customInspect implementation that previously would throw on a getter
- assertEquals(
- Deno.inspect(Event.prototype),
- `Event {
- bubbles: [Getter],
- cancelable: [Getter],
- composed: [Getter],
- currentTarget: [Getter],
- defaultPrevented: [Getter],
- eventPhase: [Getter],
- srcElement: [Getter/Setter],
- target: [Getter],
- returnValue: [Getter/Setter],
- timeStamp: [Getter],
- type: [Getter]
-}`,
- );
-
- // ensure this still works
- assertStringIncludes(
- Deno.inspect(new Event("test")),
- // check a substring because one property is a timestamp
- `Event {\n bubbles: false,\n cancelable: false,`,
- );
-});
diff --git a/cli/tests/unit/fetch_test.ts b/cli/tests/unit/fetch_test.ts
deleted file mode 100644
index 84e94de0d..000000000
--- a/cli/tests/unit/fetch_test.ts
+++ /dev/null
@@ -1,2071 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
- delay,
- fail,
- unimplemented,
-} from "./test_util.ts";
-import { Buffer } from "@test_util/std/io/buffer.ts";
-
-const listenPort = 4506;
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchRequiresOneArgument() {
- await assertRejects(
- fetch as unknown as () => Promise<void>,
- TypeError,
- );
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchProtocolError() {
- await assertRejects(
- async () => {
- await fetch("ftp://localhost:21/a/file");
- },
- TypeError,
- "not supported",
- );
-});
-
-function findClosedPortInRange(
- minPort: number,
- maxPort: number,
-): number | never {
- let port = minPort;
-
- // If we hit the return statement of this loop
- // that means that we did not throw an
- // AddrInUse error when we executed Deno.listen.
- while (port < maxPort) {
- try {
- const listener = Deno.listen({ port });
- listener.close();
- return port;
- } catch (_e) {
- port++;
- }
- }
-
- unimplemented(
- `No available ports between ${minPort} and ${maxPort} to test fetch`,
- );
-}
-
-Deno.test(
- // TODO(bartlomieju): reenable this test
- // https://github.com/denoland/deno/issues/18350
- { ignore: Deno.build.os === "windows", permissions: { net: true } },
- async function fetchConnectionError() {
- const port = findClosedPortInRange(4000, 9999);
- await assertRejects(
- async () => {
- await fetch(`http://localhost:${port}`);
- },
- TypeError,
- "error trying to connect",
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchDnsError() {
- await assertRejects(
- async () => {
- await fetch("http://nil/");
- },
- TypeError,
- "error trying to connect",
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInvalidUriError() {
- await assertRejects(
- async () => {
- await fetch("http://<invalid>/");
- },
- TypeError,
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchMalformedUriError() {
- await assertRejects(
- async () => {
- const url = new URL("http://{{google/");
- await fetch(url);
- },
- TypeError,
- );
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchJsonSuccess() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const json = await response.json();
- assertEquals(json.name, "deno");
-});
-
-Deno.test({ permissions: { net: false } }, async function fetchPerm() {
- await assertRejects(async () => {
- await fetch("http://localhost:4545/assets/fixture.json");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchUrl() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- assertEquals(response.url, "http://localhost:4545/assets/fixture.json");
- const _json = await response.json();
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchURL() {
- const response = await fetch(
- new URL("http://localhost:4545/assets/fixture.json"),
- );
- assertEquals(response.url, "http://localhost:4545/assets/fixture.json");
- const _json = await response.json();
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchHeaders() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const headers = response.headers;
- assertEquals(headers.get("Content-Type"), "application/json");
- const _json = await response.json();
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchBlob() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const headers = response.headers;
- const blob = await response.blob();
- assertEquals(blob.type, headers.get("Content-Type"));
- assertEquals(blob.size, Number(headers.get("Content-Length")));
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyUsedReader() {
- const response = await fetch(
- "http://localhost:4545/assets/fixture.json",
- );
- assert(response.body !== null);
-
- const reader = response.body.getReader();
- // Getting a reader should lock the stream but does not consume the body
- // so bodyUsed should not be true
- assertEquals(response.bodyUsed, false);
- reader.releaseLock();
- await response.json();
- assertEquals(response.bodyUsed, true);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyUsedCancelStream() {
- const response = await fetch(
- "http://localhost:4545/assets/fixture.json",
- );
- assert(response.body !== null);
-
- assertEquals(response.bodyUsed, false);
- const promise = response.body.cancel();
- assertEquals(response.bodyUsed, true);
- await promise;
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchAsyncIterator() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const headers = response.headers;
-
- assert(response.body !== null);
- let total = 0;
- for await (const chunk of response.body) {
- assert(chunk instanceof Uint8Array);
- total += chunk.length;
- }
-
- assertEquals(total, Number(headers.get("Content-Length")));
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchBodyReader() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const headers = response.headers;
- assert(response.body !== null);
- const reader = response.body.getReader();
- let total = 0;
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- assert(value instanceof Uint8Array);
- total += value.length;
- }
-
- assertEquals(total, Number(headers.get("Content-Length")));
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyReaderBigBody() {
- const data = "a".repeat(10 << 10); // 10mb
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- assert(response.body !== null);
- const reader = await response.body.getReader();
- let total = 0;
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- total += value.length;
- }
-
- assertEquals(total, data.length);
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function responseClone() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
- const response1 = response.clone();
- assert(response !== response1);
- assertEquals(response.status, response1.status);
- assertEquals(response.statusText, response1.statusText);
- const u8a = new Uint8Array(await response.arrayBuffer());
- const u8a1 = new Uint8Array(await response1.arrayBuffer());
- for (let i = 0; i < u8a.byteLength; i++) {
- assertEquals(u8a[i], u8a1[i]);
- }
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchMultipartFormDataSuccess() {
- const response = await fetch(
- "http://localhost:4545/multipart_form_data.txt",
- );
- const formData = await response.formData();
- assert(formData.has("field_1"));
- assertEquals(formData.get("field_1")!.toString(), "value_1 \r\n");
- assert(formData.has("field_2"));
- const file = formData.get("field_2") as File;
- assertEquals(file.name, "file.js");
-
- assertEquals(await file.text(), `console.log("Hi")`);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchMultipartFormBadContentType() {
- const response = await fetch(
- "http://localhost:4545/multipart_form_bad_content_type",
- );
- assert(response.body !== null);
-
- await assertRejects(
- async () => {
- await response.formData();
- },
- TypeError,
- "Body can not be decoded as form data",
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchURLEncodedFormDataSuccess() {
- const response = await fetch(
- "http://localhost:4545/subdir/form_urlencoded.txt",
- );
- const formData = await response.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: { net: true } },
- async function fetchInitFormDataBinaryFileBody() {
- // Some random bytes
- // deno-fmt-ignore
- const binaryFile = new Uint8Array([108,2,0,0,145,22,162,61,157,227,166,77,138,75,180,56,119,188,177,183]);
- const response = await fetch("http://localhost:4545/echo_multipart_file", {
- method: "POST",
- body: binaryFile,
- });
- const resultForm = await response.formData();
- const resultFile = resultForm.get("file") as File;
-
- assertEquals(resultFile.type, "application/octet-stream");
- assertEquals(resultFile.name, "file.bin");
- assertEquals(new Uint8Array(await resultFile.arrayBuffer()), binaryFile);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataMultipleFilesBody() {
- const files = [
- {
- // deno-fmt-ignore
- content: new Uint8Array([137,80,78,71,13,10,26,10, 137, 1, 25]),
- type: "image/png",
- name: "image",
- fileName: "some-image.png",
- },
- {
- // deno-fmt-ignore
- content: new Uint8Array([108,2,0,0,145,22,162,61,157,227,166,77,138,75,180,56,119,188,177,183]),
- name: "file",
- fileName: "file.bin",
- expectedType: "application/octet-stream",
- },
- {
- content: new TextEncoder().encode("deno land"),
- type: "text/plain",
- name: "text",
- fileName: "deno.txt",
- },
- ];
- const form = new FormData();
- form.append("field", "value");
- for (const file of files) {
- form.append(
- file.name,
- new Blob([file.content], { type: file.type }),
- file.fileName,
- );
- }
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
- for (const file of files) {
- const inputFile = form.get(file.name) as File;
- const resultFile = resultForm.get(file.name) as File;
- assertEquals(inputFile.size, resultFile.size);
- assertEquals(inputFile.name, resultFile.name);
- assertEquals(file.expectedType || file.type, resultFile.type);
- assertEquals(
- new Uint8Array(await resultFile.arrayBuffer()),
- file.content,
- );
- }
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithRedirection() {
- const response = await fetch("http://localhost:4546/assets/hello.txt");
- assertEquals(response.status, 200);
- assertEquals(response.statusText, "OK");
- assertEquals(response.url, "http://localhost:4545/assets/hello.txt");
- const body = await response.text();
- assert(body.includes("Hello world!"));
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithRelativeRedirection() {
- const response = await fetch(
- "http://localhost:4545/run/001_hello.js",
- );
- assertEquals(response.status, 200);
- assertEquals(response.statusText, "OK");
- const body = await response.text();
- assert(body.includes("Hello"));
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithRelativeRedirectionUrl() {
- const cases = [
- ["end", "http://localhost:4550/a/b/end"],
- ["/end", "http://localhost:4550/end"],
- ];
- for (const [loc, redUrl] of cases) {
- const response = await fetch("http://localhost:4550/a/b/c", {
- headers: new Headers([["x-location", loc]]),
- });
- assertEquals(response.url, redUrl);
- assertEquals(response.redirected, true);
- assertEquals(response.status, 404);
- assertEquals(await response.text(), "");
- }
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithInfRedirection() {
- await assertRejects(
- () => fetch("http://localhost:4549"),
- TypeError,
- "redirect",
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitStringBody() {
- const data = "Hello World";
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- const text = await response.text();
- assertEquals(text, data);
- assert(response.headers.get("content-type")!.startsWith("text/plain"));
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchRequestInitStringBody() {
- const data = "Hello World";
- const req = new Request("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- const response = await fetch(req);
- const text = await response.text();
- assertEquals(text, data);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchSeparateInit() {
- // related to: https://github.com/denoland/deno/issues/10396
- const req = new Request("http://localhost:4545/run/001_hello.js");
- const init = {
- method: "GET",
- };
- req.headers.set("foo", "bar");
- const res = await fetch(req, init);
- assertEquals(res.status, 200);
- await res.text();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitTypedArrayBody() {
- const data = "Hello World";
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: new TextEncoder().encode(data),
- });
- const text = await response.text();
- assertEquals(text, data);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitArrayBufferBody() {
- const data = "Hello World";
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: new TextEncoder().encode(data).buffer,
- });
- const text = await response.text();
- assertEquals(text, data);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitURLSearchParamsBody() {
- const data = "param1=value1&param2=value2";
- const params = new URLSearchParams(data);
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: params,
- });
- const text = await response.text();
- assertEquals(text, data);
- assert(
- response.headers
- .get("content-type")!
- .startsWith("application/x-www-form-urlencoded"),
- );
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchInitBlobBody() {
- const data = "const a = 1 🦕";
- const blob = new Blob([data], {
- type: "text/javascript",
- });
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: blob,
- });
- const text = await response.text();
- assertEquals(text, data);
- assert(response.headers.get("content-type")!.startsWith("text/javascript"));
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataBody() {
- const form = new FormData();
- form.append("field", "value");
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataBlobFilenameBody() {
- const form = new FormData();
- form.append("field", "value");
- form.append(
- "file",
- new Blob([new TextEncoder().encode("deno")]),
- "file name",
- );
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
- const file = resultForm.get("file");
- assert(file instanceof File);
- assertEquals(file.name, "file name");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataFileFilenameBody() {
- const form = new FormData();
- form.append("field", "value");
- form.append(
- "file",
- new File([new Blob([new TextEncoder().encode("deno")])], "file name"),
- );
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
- const file = resultForm.get("file");
- assert(file instanceof File);
- assertEquals(file.name, "file name");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchInitFormDataTextFileBody() {
- const fileContent = "deno land";
- const form = new FormData();
- form.append("field", "value");
- form.append(
- "file",
- new Blob([new TextEncoder().encode(fileContent)], {
- type: "text/plain",
- }),
- "deno.txt",
- );
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: form,
- });
- const resultForm = await response.formData();
- assertEquals(form.get("field"), resultForm.get("field"));
-
- const file = form.get("file") as File;
- const resultFile = resultForm.get("file") as File;
-
- assertEquals(file.size, resultFile.size);
- assertEquals(file.name, resultFile.name);
- assertEquals(file.type, resultFile.type);
- assertEquals(await file.text(), await resultFile.text());
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function fetchUserAgent() {
- const data = "Hello World";
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: new TextEncoder().encode(data),
- });
- assertEquals(response.headers.get("user-agent"), `Deno/${Deno.version.deno}`);
- await response.text();
-});
-
-function bufferServer(addr: string): Promise<Buffer> {
- const [hostname, port] = addr.split(":");
- const listener = Deno.listen({
- hostname,
- port: Number(port),
- }) as Deno.Listener;
- return listener.accept().then(async (conn: Deno.Conn) => {
- const buf = new Buffer();
- const p1 = buf.readFrom(conn);
- const p2 = conn.write(
- new TextEncoder().encode(
- "HTTP/1.0 404 Not Found\r\nContent-Length: 2\r\n\r\nNF",
- ),
- );
- // Wait for both an EOF on the read side of the socket and for the write to
- // complete before closing it. Due to keep-alive, the EOF won't be sent
- // until the Connection close (HTTP/1.0) response, so readFrom() can't
- // proceed write. Conversely, if readFrom() is async, waiting for the
- // write() to complete is not a guarantee that we've read the incoming
- // request.
- await Promise.all([p1, p2]);
- conn.close();
- listener.close();
- return buf;
- });
-}
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchRequest() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Hello", "World"],
- ["Foo", "Bar"],
- ],
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "content-length: 0\r\n",
- "hello: World\r\n",
- "foo: Bar\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n\r\n`,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchRequestAcceptHeaders() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Accept", "text/html"],
- ["Accept-Language", "en-US"],
- ],
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "content-length: 0\r\n",
- "accept: text/html\r\n",
- "accept-language: en-US\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n\r\n`,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchPostBodyString() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const body = "hello world";
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Hello", "World"],
- ["Foo", "Bar"],
- ],
- body,
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "hello: World\r\n",
- "foo: Bar\r\n",
- "content-type: text/plain;charset=UTF-8\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n`,
- `content-length: ${body.length}\r\n\r\n`,
- body,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchPostBodyTypedArray() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const bodyStr = "hello world";
- const body = new TextEncoder().encode(bodyStr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Hello", "World"],
- ["Foo", "Bar"],
- ],
- body,
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "hello: World\r\n",
- "foo: Bar\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n`,
- `content-length: ${body.byteLength}\r\n\r\n`,
- bodyStr,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchUserSetContentLength() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Content-Length", "10"],
- ],
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "content-length: 0\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n\r\n`,
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchUserSetTransferEncoding() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Transfer-Encoding", "chunked"],
- ],
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "content-length: 0\r\n",
- `host: ${addr}\r\n`,
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n\r\n",
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithNonAsciiRedirection() {
- const response = await fetch("http://localhost:4545/non_ascii_redirect", {
- redirect: "manual",
- });
- assertEquals(response.status, 301);
- assertEquals(response.headers.get("location"), "/redirect®");
- await response.text();
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithManualRedirection() {
- const response = await fetch("http://localhost:4546/", {
- redirect: "manual",
- }); // will redirect to http://localhost:4545/
- assertEquals(response.status, 301);
- assertEquals(response.url, "http://localhost:4546/");
- assertEquals(response.type, "basic");
- assertEquals(response.headers.get("Location"), "http://localhost:4545/");
- await response.body!.cancel();
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchWithErrorRedirection() {
- await assertRejects(
- () =>
- fetch("http://localhost:4546/", {
- redirect: "error",
- }),
- TypeError,
- "redirect",
- );
- },
-);
-
-Deno.test(function responseRedirect() {
- const redir = Response.redirect("http://example.com/newLocation", 301);
- assertEquals(redir.status, 301);
- assertEquals(redir.statusText, "");
- assertEquals(redir.url, "");
- assertEquals(
- redir.headers.get("Location"),
- "http://example.com/newLocation",
- );
- assertEquals(redir.type, "default");
-});
-
-Deno.test(function responseRedirectTakeURLObjectAsParameter() {
- const redir = Response.redirect(new URL("https://example.com/"));
- assertEquals(
- redir.headers.get("Location"),
- "https://example.com/",
- );
-});
-
-Deno.test(async function responseWithoutBody() {
- const response = new Response();
- assertEquals(await response.arrayBuffer(), new ArrayBuffer(0));
- const blob = await response.blob();
- assertEquals(blob.size, 0);
- assertEquals(await blob.arrayBuffer(), new ArrayBuffer(0));
- assertEquals(await response.text(), "");
- await assertRejects(async () => {
- await response.json();
- });
-});
-
-Deno.test({ permissions: { net: true } }, async function fetchBodyReadTwice() {
- const response = await fetch("http://localhost:4545/assets/fixture.json");
-
- // Read body
- const _json = await response.json();
- assert(_json);
-
- // All calls after the body was consumed, should fail
- const methods = ["json", "text", "formData", "arrayBuffer"] as const;
- for (const method of methods) {
- try {
- await response[method]();
- fail(
- "Reading body multiple times should failed, the stream should've been locked.",
- );
- } catch {
- // pass
- }
- }
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyReaderAfterRead() {
- const response = await fetch(
- "http://localhost:4545/assets/fixture.json",
- );
- assert(response.body !== null);
- const reader = await response.body.getReader();
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- }
-
- try {
- response.body.getReader();
- fail("The stream should've been locked.");
- } catch {
- // pass
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyReaderWithCancelAndNewReader() {
- const data = "a".repeat(1 << 10);
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- assert(response.body !== null);
- const firstReader = await response.body.getReader();
-
- // Acquire reader without reading & release
- await firstReader.releaseLock();
-
- const reader = await response.body.getReader();
-
- let total = 0;
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- total += value.length;
- }
-
- assertEquals(total, data.length);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBodyReaderWithReadCancelAndNewReader() {
- const data = "a".repeat(1 << 10);
-
- const response = await fetch("http://localhost:4545/echo_server", {
- method: "POST",
- body: data,
- });
- assert(response.body !== null);
- const firstReader = await response.body.getReader();
-
- // Do one single read with first reader
- const { value: firstValue } = await firstReader.read();
- assert(firstValue);
- await firstReader.releaseLock();
-
- // Continue read with second reader
- const reader = await response.body.getReader();
- let total = firstValue.length || 0;
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- total += value.length;
- }
- assertEquals(total, data.length);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchResourceCloseAfterStreamCancel() {
- const res = await fetch("http://localhost:4545/assets/fixture.json");
- assert(res.body !== null);
-
- // After ReadableStream.cancel is called, resource handle must be closed
- // The test should not fail with: Test case is leaking resources
- await res.body.cancel();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchNullBodyStatus() {
- const nullBodyStatus = [101, 204, 205, 304];
-
- for (const status of nullBodyStatus) {
- const headers = new Headers([["x-status", String(status)]]);
- const res = await fetch("http://localhost:4545/echo_server", {
- body: "deno",
- method: "POST",
- headers,
- });
- assertEquals(res.body, null);
- assertEquals(res.status, status);
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchResponseContentLength() {
- const body = new Uint8Array(2 ** 16);
- const headers = new Headers([["content-type", "application/octet-stream"]]);
- const res = await fetch("http://localhost:4545/echo_server", {
- body: body,
- method: "POST",
- headers,
- });
- assertEquals(Number(res.headers.get("content-length")), body.byteLength);
-
- const blob = await res.blob();
- // Make sure Body content-type is correctly set
- assertEquals(blob.type, "application/octet-stream");
- assertEquals(blob.size, body.byteLength);
- },
-);
-
-Deno.test(function fetchResponseConstructorNullBody() {
- const nullBodyStatus = [204, 205, 304];
-
- for (const status of nullBodyStatus) {
- try {
- new Response("deno", { status });
- fail("Response with null body status cannot have body");
- } catch (e) {
- assert(e instanceof TypeError);
- assertEquals(
- e.message,
- "Response with null body status cannot have body",
- );
- }
- }
-});
-
-Deno.test(function fetchResponseConstructorInvalidStatus() {
- const invalidStatus = [100, 600, 199, null, "", NaN];
-
- for (const status of invalidStatus) {
- try {
- // deno-lint-ignore ban-ts-comment
- // @ts-ignore
- new Response("deno", { status });
- fail(`Invalid status: ${status}`);
- } catch (e) {
- assert(e instanceof RangeError);
- assert(
- e.message.endsWith(
- "is not equal to 101 and outside the range [200, 599].",
- ),
- );
- }
- }
-});
-
-Deno.test(function fetchResponseEmptyConstructor() {
- const response = new Response();
- assertEquals(response.status, 200);
- assertEquals(response.body, null);
- assertEquals(response.type, "default");
- assertEquals(response.url, "");
- assertEquals(response.redirected, false);
- assertEquals(response.ok, true);
- assertEquals(response.bodyUsed, false);
- assertEquals([...response.headers], []);
-});
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchCustomHttpClientParamCertificateSuccess(): Promise<
- void
- > {
- const caCert = Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const response = await fetch("https://localhost:5545/assets/fixture.json", {
- client,
- });
- const json = await response.json();
- assertEquals(json.name, "deno");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- function createHttpClientAcceptPoolIdleTimeout() {
- const client = Deno.createHttpClient({
- poolIdleTimeout: 1000,
- });
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchCustomClientUserAgent(): Promise<
- void
- > {
- const data = "Hello World";
- const client = Deno.createHttpClient({});
- const response = await fetch("http://localhost:4545/echo_server", {
- client,
- method: "POST",
- body: new TextEncoder().encode(data),
- });
- assertEquals(
- response.headers.get("user-agent"),
- `Deno/${Deno.version.deno}`,
- );
- await response.text();
- client.close();
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function fetchPostBodyReadableStream() {
- const addr = `127.0.0.1:${listenPort}`;
- const bufPromise = bufferServer(addr);
- const stream = new TransformStream();
- const writer = stream.writable.getWriter();
- // transformer writes don't resolve until they are read, so awaiting these
- // will cause the transformer to hang, as the suspend the transformer, it
- // is also illogical to await for the reads, as that is the whole point of
- // streams is to have a "queue" which gets drained...
- writer.write(new TextEncoder().encode("hello "));
- writer.write(new TextEncoder().encode("world"));
- writer.close();
- const response = await fetch(`http://${addr}/blah`, {
- method: "POST",
- headers: [
- ["Hello", "World"],
- ["Foo", "Bar"],
- ],
- body: stream.readable,
- });
- await response.arrayBuffer();
- assertEquals(response.status, 404);
- assertEquals(response.headers.get("Content-Length"), "2");
-
- const actual = new TextDecoder().decode((await bufPromise).bytes());
- const expected = [
- "POST /blah HTTP/1.1\r\n",
- "hello: World\r\n",
- "foo: Bar\r\n",
- "accept: */*\r\n",
- "accept-language: *\r\n",
- `user-agent: Deno/${Deno.version.deno}\r\n`,
- "accept-encoding: gzip, br\r\n",
- `host: ${addr}\r\n`,
- `transfer-encoding: chunked\r\n\r\n`,
- "B\r\n",
- "hello world\r\n",
- "0\r\n\r\n",
- ].join("");
- assertEquals(actual, expected);
- },
-);
-
-Deno.test({}, function fetchWritableRespProps() {
- const original = new Response("https://deno.land", {
- status: 404,
- headers: { "x-deno": "foo" },
- });
- const new_ = new Response("https://deno.land", original);
- assertEquals(original.status, new_.status);
- assertEquals(new_.headers.get("x-deno"), "foo");
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchFilterOutCustomHostHeader(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const [hostname, port] = addr.split(":");
- const listener = Deno.listen({
- hostname,
- port: Number(port),
- }) as Deno.Listener;
-
- let httpConn: Deno.HttpConn;
- listener.accept().then(async (conn: Deno.Conn) => {
- httpConn = Deno.serveHttp(conn);
-
- await httpConn.nextRequest()
- .then(async (requestEvent: Deno.RequestEvent | null) => {
- const hostHeader = requestEvent?.request.headers.get("Host");
- const headersToReturn = hostHeader
- ? { "Host": hostHeader }
- : undefined;
-
- await requestEvent?.respondWith(
- new Response("", {
- status: 200,
- headers: headersToReturn,
- }),
- );
- });
- });
-
- const response = await fetch(`http://${addr}/`, {
- headers: { "Host": "example.com" },
- });
- await response.text();
- listener.close();
- httpConn!.close();
-
- assertEquals(response.headers.get("Host"), addr);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchNoServerReadableStreamBody() {
- const completed = Promise.withResolvers<void>();
- const failed = Promise.withResolvers<void>();
- const body = new ReadableStream({
- start(controller) {
- controller.enqueue(new Uint8Array([1]));
- setTimeout(async () => {
- // This is technically a race. If the fetch has failed by this point, the enqueue will
- // throw. If not, it will succeed. Windows appears to take a while to time out the fetch,
- // so we will just wait for that here before we attempt to enqueue so it's consistent
- // across platforms.
- await failed.promise;
- assertThrows(() => controller.enqueue(new Uint8Array([2])));
- completed.resolve();
- }, 1000);
- },
- });
- const nonExistentHostname = "http://localhost:47582";
- await assertRejects(async () => {
- await fetch(nonExistentHostname, { body, method: "POST" });
- }, TypeError);
- failed.resolve();
- await completed.promise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchHeadRespBody() {
- const res = await fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- });
- assertEquals(res.body, null);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function fetchClientCertWrongPrivateKey(): Promise<void> {
- await assertRejects(async () => {
- const client = Deno.createHttpClient({
- certChain: "bad data",
- privateKey: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.key",
- ),
- });
- await fetch("https://localhost:5552/assets/fixture.json", {
- client,
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function fetchClientCertBadPrivateKey(): Promise<void> {
- await assertRejects(async () => {
- const client = Deno.createHttpClient({
- certChain: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.crt",
- ),
- privateKey: "bad data",
- });
- await fetch("https://localhost:5552/assets/fixture.json", {
- client,
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function fetchClientCertNotPrivateKey(): Promise<void> {
- await assertRejects(async () => {
- const client = Deno.createHttpClient({
- certChain: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.crt",
- ),
- privateKey: "",
- });
- await fetch("https://localhost:5552/assets/fixture.json", {
- client,
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function fetchCustomClientPrivateKey(): Promise<
- void
- > {
- const data = "Hello World";
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.crt");
- const client = Deno.createHttpClient({
- certChain: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.crt",
- ),
- privateKey: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.key",
- ),
- caCerts: [caCert],
- });
- const response = await fetch("https://localhost:5552/echo_server", {
- client,
- method: "POST",
- body: new TextEncoder().encode(data),
- });
- assertEquals(
- response.headers.get("user-agent"),
- `Deno/${Deno.version.deno}`,
- );
- await response.text();
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchAbortWhileUploadStreaming(): Promise<void> {
- const abortController = new AbortController();
- try {
- await fetch(
- "http://localhost:5552/echo_server",
- {
- method: "POST",
- body: new ReadableStream({
- pull(controller) {
- abortController.abort();
- controller.enqueue(new Uint8Array([1, 2, 3, 4]));
- },
- }),
- signal: abortController.signal,
- },
- );
- fail("Fetch didn't reject.");
- } catch (error) {
- assert(error instanceof DOMException);
- assertEquals(error.name, "AbortError");
- assertEquals(error.message, "The signal has been aborted");
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchAbortWhileUploadStreamingWithReason(): Promise<void> {
- const abortController = new AbortController();
- const abortReason = new Error();
- try {
- await fetch(
- "http://localhost:5552/echo_server",
- {
- method: "POST",
- body: new ReadableStream({
- pull(controller) {
- abortController.abort(abortReason);
- controller.enqueue(new Uint8Array([1, 2, 3, 4]));
- },
- }),
- signal: abortController.signal,
- },
- );
- fail("Fetch didn't reject.");
- } catch (error) {
- assertEquals(error, abortReason);
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchAbortWhileUploadStreamingWithPrimitiveReason(): Promise<
- void
- > {
- const abortController = new AbortController();
- try {
- await fetch(
- "http://localhost:5552/echo_server",
- {
- method: "POST",
- body: new ReadableStream({
- pull(controller) {
- abortController.abort("Abort reason");
- controller.enqueue(new Uint8Array([1, 2, 3, 4]));
- },
- }),
- signal: abortController.signal,
- },
- );
- fail("Fetch didn't reject.");
- } catch (error) {
- assertEquals(error, "Abort reason");
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchHeaderValueShouldNotPanic() {
- for (let i = 0; i < 0x21; i++) {
- if (i === 0x09 || i === 0x0A || i === 0x0D || i === 0x20) {
- continue; // these header value will be normalized, will not cause an error.
- }
- // ensure there will be an error instead of panic.
- await assertRejects(() =>
- fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- headers: { "val": String.fromCharCode(i) },
- }), TypeError);
- }
- await assertRejects(() =>
- fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- headers: { "val": String.fromCharCode(127) },
- }), TypeError);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchHeaderNameShouldNotPanic() {
- const validTokens =
- "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUWVXYZ^_`abcdefghijklmnopqrstuvwxyz|~"
- .split("");
- for (let i = 0; i <= 255; i++) {
- const token = String.fromCharCode(i);
- if (validTokens.includes(token)) {
- continue;
- }
- // ensure there will be an error instead of panic.
- await assertRejects(() =>
- fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- headers: { [token]: "value" },
- }), TypeError);
- }
- await assertRejects(() =>
- fetch("http://localhost:4545/echo_server", {
- method: "HEAD",
- headers: { "": "value" },
- }), TypeError);
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchSupportsHttpsOverIpAddress() {
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const res = await fetch("https://localhost:5546/http_version", { client });
- assert(res.ok);
- assertEquals(await res.text(), "HTTP/1.1");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchSupportsHttp1Only() {
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const res = await fetch("https://localhost:5546/http_version", { client });
- assert(res.ok);
- assertEquals(await res.text(), "HTTP/1.1");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchSupportsHttp2() {
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const res = await fetch("https://localhost:5547/http_version", { client });
- assert(res.ok);
- assertEquals(await res.text(), "HTTP/2.0");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchForceHttp1OnHttp2Server() {
- const client = Deno.createHttpClient({ http2: false, http1: true });
- await assertRejects(
- () => fetch("http://localhost:5549/http_version", { client }),
- TypeError,
- );
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchForceHttp2OnHttp1Server() {
- const client = Deno.createHttpClient({ http2: true, http1: false });
- await assertRejects(
- () => fetch("http://localhost:5548/http_version", { client }),
- TypeError,
- );
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function fetchPrefersHttp2() {
- const caCert = await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const res = await fetch("https://localhost:5545/http_version", { client });
- assert(res.ok);
- assertEquals(await res.text(), "HTTP/2.0");
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- async function createHttpClientAllowHost() {
- const client = Deno.createHttpClient({
- allowHost: true,
- });
- const res = await fetch("http://localhost:4545/echo_server", {
- headers: {
- "host": "example.com",
- },
- client,
- });
- assert(res.ok);
- assertEquals(res.headers.get("host"), "example.com");
- await res.body?.cancel();
- client.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function createHttpClientExplicitResourceManagement() {
- using client = Deno.createHttpClient({});
- const response = await fetch("http://localhost:4545/assets/fixture.json", {
- client,
- });
- const json = await response.json();
- assertEquals(json.name, "deno");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function createHttpClientExplicitResourceManagementDoubleClose() {
- using client = Deno.createHttpClient({});
- const response = await fetch("http://localhost:4545/assets/fixture.json", {
- client,
- });
- const json = await response.json();
- assertEquals(json.name, "deno");
- // Close the client even though we declared it with `using` to confirm that
- // the cleanup done as per `Symbol.dispose` will not throw any errors.
- client.close();
- },
-);
-
-Deno.test({ permissions: { read: false } }, async function fetchFilePerm() {
- await assertRejects(async () => {
- await fetch(import.meta.resolve("../testdata/subdir/json_1.json"));
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { read: false } },
- async function fetchFilePermDoesNotExist() {
- await assertRejects(async () => {
- await fetch(import.meta.resolve("./bad.json"));
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function fetchFileBadMethod() {
- await assertRejects(
- async () => {
- await fetch(
- import.meta.resolve("../testdata/subdir/json_1.json"),
- {
- method: "POST",
- },
- );
- },
- TypeError,
- "Fetching files only supports the GET method. Received POST.",
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function fetchFileDoesNotExist() {
- await assertRejects(
- async () => {
- await fetch(import.meta.resolve("./bad.json"));
- },
- TypeError,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function fetchFile() {
- const res = await fetch(
- import.meta.resolve("../testdata/subdir/json_1.json"),
- );
- assert(res.ok);
- const fixture = await Deno.readTextFile(
- "cli/tests/testdata/subdir/json_1.json",
- );
- assertEquals(await res.text(), fixture);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPost() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "POST",
- });
- const length = await response.text();
- assertEquals(length, 'Some("0")');
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPut() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "PUT",
- });
- const length = await response.text();
- assertEquals(length, 'Some("0")');
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPatch() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "PATCH",
- });
- const length = await response.text();
- assertEquals(length, "None");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPostWithStringBody() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "POST",
- body: "Hey!",
- });
- const length = await response.text();
- assertEquals(length, 'Some("4")');
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchContentLengthPostWithBufferBody() {
- const response = await fetch("http://localhost:4545/content_length", {
- method: "POST",
- body: new TextEncoder().encode("Hey!"),
- });
- const length = await response.text();
- assertEquals(length, 'Some("4")');
- },
-);
-
-Deno.test(async function staticResponseJson() {
- const data = { hello: "world" };
- const resp = Response.json(data);
- assertEquals(resp.status, 200);
- assertEquals(resp.headers.get("content-type"), "application/json");
- const res = await resp.json();
- assertEquals(res, data);
-});
-
-function invalidServer(addr: string, body: Uint8Array): Deno.Listener {
- const [hostname, port] = addr.split(":");
- const listener = Deno.listen({
- hostname,
- port: Number(port),
- }) as Deno.Listener;
-
- (async () => {
- for await (const conn of listener) {
- const p1 = conn.read(new Uint8Array(2 ** 14));
- const p2 = conn.write(body);
-
- await Promise.all([p1, p2]);
- conn.close();
- }
- })();
-
- return listener;
-}
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchWithInvalidContentLengthAndTransferEncoding(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const data = "a".repeat(10 << 10);
-
- const body = new TextEncoder().encode(
- `HTTP/1.1 200 OK\r\nContent-Length: ${
- Math.round(data.length * 2)
- }\r\nTransfer-Encoding: chunked\r\n\r\n${
- data.length.toString(16)
- }\r\n${data}\r\n0\r\n\r\n`,
- );
-
- // if transfer-encoding is sent, content-length is ignored
- // even if it has an invalid value (content-length > totalLength)
- const listener = invalidServer(addr, body);
- const response = await fetch(`http://${addr}/`);
-
- const res = await response.arrayBuffer();
- const buf = new TextEncoder().encode(data);
- assertEquals(res.byteLength, buf.byteLength);
- assertEquals(new Uint8Array(res), buf);
-
- listener.close();
- },
-);
-
-Deno.test(
- // TODO(bartlomieju): reenable this test
- // https://github.com/denoland/deno/issues/18350
- { ignore: Deno.build.os === "windows", permissions: { net: true } },
- async function fetchWithInvalidContentLength(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const data = "a".repeat(10 << 10);
-
- const body = new TextEncoder().encode(
- `HTTP/1.1 200 OK\r\nContent-Length: ${
- Math.round(data.length / 2)
- }\r\nContent-Length: ${data.length}\r\n\r\n${data}`,
- );
-
- // It should fail if multiple content-length headers with different values are sent
- const listener = invalidServer(addr, body);
- await assertRejects(
- async () => {
- await fetch(`http://${addr}/`);
- },
- TypeError,
- "invalid content-length parsed",
- );
-
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchWithInvalidContentLength2(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const data = "a".repeat(10 << 10);
-
- const contentLength = data.length / 2;
- const body = new TextEncoder().encode(
- `HTTP/1.1 200 OK\r\nContent-Length: ${contentLength}\r\n\r\n${data}`,
- );
-
- const listener = invalidServer(addr, body);
- const response = await fetch(`http://${addr}/`);
-
- // If content-length < totalLength, a maximum of content-length bytes
- // should be returned.
- const res = await response.arrayBuffer();
- const buf = new TextEncoder().encode(data);
- assertEquals(res.byteLength, contentLength);
- assertEquals(new Uint8Array(res), buf.subarray(contentLength));
-
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchWithInvalidContentLength3(): Promise<
- void
- > {
- const addr = `127.0.0.1:${listenPort}`;
- const data = "a".repeat(10 << 10);
-
- const contentLength = data.length * 2;
- const body = new TextEncoder().encode(
- `HTTP/1.1 200 OK\r\nContent-Length: ${contentLength}\r\n\r\n${data}`,
- );
-
- const listener = invalidServer(addr, body);
- const response = await fetch(`http://${addr}/`);
- // If content-length > totalLength, a maximum of content-length bytes
- // should be returned.
- await assertRejects(
- async () => {
- await response.arrayBuffer();
- },
- Error,
- "end of file before message length reached",
- );
-
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchBlobUrl(): Promise<void> {
- const blob = new Blob(["ok"], { type: "text/plain" });
- const url = URL.createObjectURL(blob);
- assert(url.startsWith("blob:"), `URL was ${url}`);
- const res = await fetch(url);
- assertEquals(res.url, url);
- assertEquals(res.status, 200);
- assertEquals(res.headers.get("content-length"), "2");
- assertEquals(res.headers.get("content-type"), "text/plain");
- assertEquals(await res.text(), "ok");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchResponseStreamIsLockedWhileReading() {
- const response = await fetch("http://localhost:4545/echo_server", {
- body: new Uint8Array(5000),
- method: "POST",
- });
-
- assertEquals(response.body!.locked, false);
- const promise = response.arrayBuffer();
- assertEquals(response.body!.locked, true);
-
- await promise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchConstructorClones() {
- const req = new Request("https://example.com", {
- method: "POST",
- body: "foo",
- });
- assertEquals(await req.text(), "foo");
- await assertRejects(() => req.text());
-
- const req2 = new Request(req, { method: "PUT", body: "bar" }); // should not have any impact on req
- await assertRejects(() => req.text());
- assertEquals(await req2.text(), "bar");
-
- assertEquals(req.method, "POST");
- assertEquals(req2.method, "PUT");
-
- assertEquals(req.headers.get("x-foo"), null);
- assertEquals(req2.headers.get("x-foo"), null);
- req2.headers.set("x-foo", "bar"); // should not have any impact on req
- assertEquals(req.headers.get("x-foo"), null);
- assertEquals(req2.headers.get("x-foo"), "bar");
- },
-);
-
-Deno.test(
- // TODO(bartlomieju): reenable this test
- // https://github.com/denoland/deno/issues/18350
- { ignore: Deno.build.os === "windows", permissions: { net: true } },
- async function fetchRequestBodyErrorCatchable() {
- const listener = Deno.listen({ hostname: "127.0.0.1", port: listenPort });
- const server = (async () => {
- const conn = await listener.accept();
- listener.close();
- const buf = new Uint8Array(256);
- const n = await conn.read(buf);
- const data = new TextDecoder().decode(buf.subarray(0, n!)); // this is the request headers + first body chunk
- assert(data.startsWith("POST / HTTP/1.1\r\n"));
- assert(data.endsWith("1\r\na\r\n"));
- const n2 = await conn.read(buf);
- assertEquals(n2, 6); // this is the second body chunk
- const n3 = await conn.read(buf);
- assertEquals(n3, null); // the connection now abruptly closes because the client has errored
- conn.close();
- })();
-
- const stream = new ReadableStream({
- async start(controller) {
- controller.enqueue(new TextEncoder().encode("a"));
- await delay(1000);
- controller.enqueue(new TextEncoder().encode("b"));
- await delay(1000);
- controller.error(new Error("foo"));
- },
- });
-
- const err = await assertRejects(() =>
- fetch(`http://localhost:${listenPort}/`, {
- body: stream,
- method: "POST",
- })
- );
-
- assert(err instanceof TypeError, `err was not a TypeError ${err}`);
- assert(err.cause, `err.cause was null ${err}`);
- assert(
- err.cause instanceof Error,
- `err.cause was not an Error ${err.cause}`,
- );
- assertEquals(err.cause.message, "foo");
-
- await server;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function fetchRequestBodyEmptyStream() {
- const body = new ReadableStream({
- start(controller) {
- controller.enqueue(new Uint8Array([]));
- controller.close();
- },
- });
-
- await assertRejects(
- async () => {
- const controller = new AbortController();
- const promise = fetch("http://localhost:4545/echo_server", {
- body,
- method: "POST",
- signal: controller.signal,
- });
- try {
- controller.abort();
- } catch (e) {
- console.log(e);
- fail("abort should not throw");
- }
- await promise;
- },
- DOMException,
- "The signal has been aborted",
- );
- },
-);
-
-Deno.test("Request with subarray TypedArray body", async () => {
- const body = new Uint8Array([1, 2, 3, 4, 5]).subarray(1);
- const req = new Request("https://example.com", { method: "POST", body });
- const actual = new Uint8Array(await req.arrayBuffer());
- const expected = new Uint8Array([2, 3, 4, 5]);
- assertEquals(actual, expected);
-});
-
-Deno.test("Response with subarray TypedArray body", async () => {
- const body = new Uint8Array([1, 2, 3, 4, 5]).subarray(1);
- const req = new Response(body);
- const actual = new Uint8Array(await req.arrayBuffer());
- const expected = new Uint8Array([2, 3, 4, 5]);
- assertEquals(actual, expected);
-});
diff --git a/cli/tests/unit/ffi_test.ts b/cli/tests/unit/ffi_test.ts
deleted file mode 100644
index 2b56a8db1..000000000
--- a/cli/tests/unit/ffi_test.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assertEquals, assertRejects, assertThrows } from "./test_util.ts";
-
-Deno.test({ permissions: { ffi: true } }, function dlopenInvalidArguments() {
- const filename = "/usr/lib/libc.so.6";
- assertThrows(() => {
- // @ts-expect-error: ForeignFunction cannot be null
- Deno.dlopen(filename, { malloc: null });
- }, TypeError);
- assertThrows(() => {
- Deno.dlopen(filename, {
- // @ts-expect-error: invalid NativeType
- malloc: { parameters: ["a"], result: "b" },
- });
- }, TypeError);
- assertThrows(() => {
- // @ts-expect-error: DynamicLibrary symbols cannot be null
- Deno.dlopen(filename, null);
- }, TypeError);
- assertThrows(() => {
- // @ts-expect-error: require 2 arguments
- Deno.dlopen(filename);
- }, TypeError);
-});
-
-Deno.test({ permissions: { ffi: false } }, function ffiPermissionDenied() {
- assertThrows(() => {
- Deno.dlopen("/usr/lib/libc.so.6", {});
- }, Deno.errors.PermissionDenied);
- const fnptr = new Deno.UnsafeFnPointer(
- // @ts-expect-error: Not NonNullable but null check is after permissions check.
- null,
- {
- parameters: ["u32", "pointer"],
- result: "void",
- } as const,
- );
- assertThrows(() => {
- fnptr.call(123, null);
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- Deno.UnsafePointer.of(new Uint8Array(0));
- }, Deno.errors.PermissionDenied);
- const ptrView = new Deno.UnsafePointerView(
- // @ts-expect-error: Not NonNullable but null check is after permissions check.
- null,
- );
- assertThrows(() => {
- ptrView.copyInto(new Uint8Array(0));
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- ptrView.getCString();
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- ptrView.getUint8();
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- ptrView.getInt8();
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- ptrView.getUint16();
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- ptrView.getInt16();
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- ptrView.getUint32();
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- ptrView.getInt32();
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- ptrView.getFloat32();
- }, Deno.errors.PermissionDenied);
- assertThrows(() => {
- ptrView.getFloat64();
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { ffi: true } }, function pointerOf() {
- const buffer = new ArrayBuffer(1024);
- const baseAddress = Deno.UnsafePointer.value(Deno.UnsafePointer.of(buffer));
- const uint8Address = Deno.UnsafePointer.value(
- Deno.UnsafePointer.of(new Uint8Array(buffer)),
- );
- assertEquals(baseAddress, uint8Address);
- const float64Address = Deno.UnsafePointer.value(
- Deno.UnsafePointer.of(new Float64Array(buffer)),
- );
- assertEquals(baseAddress, float64Address);
- const uint8AddressOffset = Deno.UnsafePointer.value(
- Deno.UnsafePointer.of(new Uint8Array(buffer, 100)),
- );
- assertEquals(Number(baseAddress) + 100, uint8AddressOffset);
- const float64AddressOffset = Deno.UnsafePointer.value(
- Deno.UnsafePointer.of(new Float64Array(buffer, 80)),
- );
- assertEquals(Number(baseAddress) + 80, float64AddressOffset);
-});
-
-Deno.test({ permissions: { ffi: true } }, function callWithError() {
- const throwCb = () => {
- throw new Error("Error");
- };
- const cb = new Deno.UnsafeCallback({
- parameters: [],
- result: "void",
- }, throwCb);
- const fnPointer = new Deno.UnsafeFnPointer(cb.pointer, {
- parameters: [],
- result: "void",
- });
- assertThrows(() => fnPointer.call());
- cb.close();
-});
-
-Deno.test(
- { permissions: { ffi: true }, ignore: true },
- async function callNonBlockingWithError() {
- const throwCb = () => {
- throw new Error("Error");
- };
- const cb = new Deno.UnsafeCallback({
- parameters: [],
- result: "void",
- }, throwCb);
- const fnPointer = new Deno.UnsafeFnPointer(cb.pointer, {
- parameters: [],
- result: "void",
- nonblocking: true,
- });
- // TODO(mmastrac): currently ignored as we do not thread callback exceptions through nonblocking pointers
- await assertRejects(async () => await fnPointer.call());
- cb.close();
- },
-);
diff --git a/cli/tests/unit/file_test.ts b/cli/tests/unit/file_test.ts
deleted file mode 100644
index 1af3a3f84..000000000
--- a/cli/tests/unit/file_test.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals } from "./test_util.ts";
-
-// deno-lint-ignore no-explicit-any
-function testFirstArgument(arg1: any[], expectedSize: number) {
- const file = new File(arg1, "name");
- assert(file instanceof File);
- assertEquals(file.name, "name");
- assertEquals(file.size, expectedSize);
- assertEquals(file.type, "");
-}
-
-Deno.test(function fileEmptyFileBits() {
- testFirstArgument([], 0);
-});
-
-Deno.test(function fileStringFileBits() {
- testFirstArgument(["bits"], 4);
-});
-
-Deno.test(function fileUnicodeStringFileBits() {
- testFirstArgument(["𝓽𝓮𝔁𝓽"], 16);
-});
-
-Deno.test(function fileStringObjectFileBits() {
- testFirstArgument([new String("string object")], 13);
-});
-
-Deno.test(function fileEmptyBlobFileBits() {
- testFirstArgument([new Blob()], 0);
-});
-
-Deno.test(function fileBlobFileBits() {
- testFirstArgument([new Blob(["bits"])], 4);
-});
-
-Deno.test(function fileEmptyFileFileBits() {
- testFirstArgument([new File([], "world.txt")], 0);
-});
-
-Deno.test(function fileFileFileBits() {
- testFirstArgument([new File(["bits"], "world.txt")], 4);
-});
-
-Deno.test(function fileArrayBufferFileBits() {
- testFirstArgument([new ArrayBuffer(8)], 8);
-});
-
-Deno.test(function fileTypedArrayFileBits() {
- testFirstArgument([new Uint8Array([0x50, 0x41, 0x53, 0x53])], 4);
-});
-
-Deno.test(function fileVariousFileBits() {
- testFirstArgument(
- [
- "bits",
- new Blob(["bits"]),
- new Blob(),
- new Uint8Array([0x50, 0x41]),
- new Uint16Array([0x5353]),
- new Uint32Array([0x53534150]),
- ],
- 16,
- );
-});
-
-Deno.test(function fileNumberInFileBits() {
- testFirstArgument([12], 2);
-});
-
-Deno.test(function fileArrayInFileBits() {
- testFirstArgument([[1, 2, 3]], 5);
-});
-
-Deno.test(function fileObjectInFileBits() {
- // "[object Object]"
- testFirstArgument([{}], 15);
-});
-
-// deno-lint-ignore no-explicit-any
-function testSecondArgument(arg2: any, expectedFileName: string) {
- const file = new File(["bits"], arg2);
- assert(file instanceof File);
- assertEquals(file.name, expectedFileName);
-}
-
-Deno.test(function fileUsingFileName() {
- testSecondArgument("dummy", "dummy");
-});
-
-Deno.test(function fileUsingNullFileName() {
- testSecondArgument(null, "null");
-});
-
-Deno.test(function fileUsingNumberFileName() {
- testSecondArgument(1, "1");
-});
-
-Deno.test(function fileUsingEmptyStringFileName() {
- testSecondArgument("", "");
-});
-
-Deno.test(function inspectFile() {
- assertEquals(
- Deno.inspect(new File([], "file-name.txt")),
- `File { name: "file-name.txt", size: 0, type: "" }`,
- );
- assertEquals(
- Deno.inspect(new File([], "file-name.txt", { type: "text/plain" })),
- `File { name: "file-name.txt", size: 0, type: "text/plain" }`,
- );
-});
diff --git a/cli/tests/unit/filereader_test.ts b/cli/tests/unit/filereader_test.ts
deleted file mode 100644
index 158cf5383..000000000
--- a/cli/tests/unit/filereader_test.ts
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-Deno.test(function fileReaderConstruct() {
- const fr = new FileReader();
- assertEquals(fr.readyState, FileReader.EMPTY);
-
- assertEquals(FileReader.EMPTY, 0);
- assertEquals(FileReader.LOADING, 1);
- assertEquals(FileReader.DONE, 2);
-});
-
-Deno.test(async function fileReaderLoadBlob() {
- await new Promise<void>((resolve) => {
- const fr = new FileReader();
- const b1 = new Blob(["Hello World"]);
-
- assertEquals(fr.readyState, FileReader.EMPTY);
-
- const hasOnEvents = {
- load: false,
- loadend: false,
- loadstart: false,
- progress: 0,
- };
- const hasDispatchedEvents = {
- load: false,
- loadend: false,
- loadstart: false,
- progress: 0,
- };
- let result: string | null = null;
-
- fr.addEventListener("load", () => {
- hasDispatchedEvents.load = true;
- });
- fr.addEventListener("loadend", () => {
- hasDispatchedEvents.loadend = true;
- });
- fr.addEventListener("loadstart", () => {
- hasDispatchedEvents.loadstart = true;
- });
- fr.addEventListener("progress", () => {
- hasDispatchedEvents.progress += 1;
- });
-
- fr.onloadstart = () => {
- hasOnEvents.loadstart = true;
- };
- fr.onprogress = () => {
- assertEquals(fr.readyState, FileReader.LOADING);
-
- hasOnEvents.progress += 1;
- };
- fr.onload = () => {
- hasOnEvents.load = true;
- };
- fr.onloadend = (ev) => {
- hasOnEvents.loadend = true;
- result = fr.result as string;
-
- assertEquals(hasOnEvents.loadstart, true);
- assertEquals(hasDispatchedEvents.loadstart, true);
- assertEquals(hasOnEvents.load, true);
- assertEquals(hasDispatchedEvents.load, true);
- assertEquals(hasOnEvents.loadend, true);
- assertEquals(hasDispatchedEvents.loadend, true);
-
- assertEquals(fr.readyState, FileReader.DONE);
-
- assertEquals(result, "Hello World");
- assertEquals(ev.lengthComputable, true);
- resolve();
- };
-
- fr.readAsText(b1);
- });
-});
-
-Deno.test(async function fileReaderLoadBlobDouble() {
- // impl note from https://w3c.github.io/FileAPI/
- // Event handler for the load or error events could have started another load,
- // if that happens the loadend event for the first load is not fired
-
- const fr = new FileReader();
- const b1 = new Blob(["First load"]);
- const b2 = new Blob(["Second load"]);
-
- await new Promise<void>((resolve) => {
- let result: string | null = null;
-
- fr.onload = () => {
- result = fr.result as string;
- assertEquals(result === "First load" || result === "Second load", true);
-
- if (result === "First load") {
- fr.readAsText(b2);
- }
- };
- fr.onloadend = () => {
- assertEquals(result, "Second load");
-
- resolve();
- };
-
- fr.readAsText(b1);
- });
-});
-
-Deno.test(async function fileReaderLoadBlobArrayBuffer() {
- await new Promise<void>((resolve) => {
- const fr = new FileReader();
- const b1 = new Blob(["Hello World"]);
- let result: ArrayBuffer | null = null;
-
- fr.onloadend = (ev) => {
- assertEquals(fr.result instanceof ArrayBuffer, true);
- result = fr.result as ArrayBuffer;
-
- const decoder = new TextDecoder();
- const text = decoder.decode(result);
-
- assertEquals(text, "Hello World");
- assertEquals(ev.lengthComputable, true);
- resolve();
- };
-
- fr.readAsArrayBuffer(b1);
- });
-});
-
-Deno.test(async function fileReaderLoadBlobDataUrl() {
- await new Promise<void>((resolve) => {
- const fr = new FileReader();
- const b1 = new Blob(["Hello World"]);
- let result: string | null = null;
-
- fr.onloadend = (ev) => {
- result = fr.result as string;
- assertEquals(
- result,
- "data:application/octet-stream;base64,SGVsbG8gV29ybGQ=",
- );
- assertEquals(ev.lengthComputable, true);
- resolve();
- };
-
- fr.readAsDataURL(b1);
- });
-});
-
-Deno.test(async function fileReaderLoadBlobAbort() {
- await new Promise<void>((resolve) => {
- const fr = new FileReader();
- const b1 = new Blob(["Hello World"]);
-
- const hasOnEvents = {
- load: false,
- loadend: false,
- abort: false,
- };
-
- fr.onload = () => {
- hasOnEvents.load = true;
- };
- fr.onloadend = (ev) => {
- hasOnEvents.loadend = true;
-
- assertEquals(hasOnEvents.load, false);
- assertEquals(hasOnEvents.loadend, true);
- assertEquals(hasOnEvents.abort, true);
-
- assertEquals(fr.readyState, FileReader.DONE);
- assertEquals(fr.result, null);
- assertEquals(ev.lengthComputable, false);
- resolve();
- };
- fr.onabort = () => {
- hasOnEvents.abort = true;
- };
-
- fr.readAsDataURL(b1);
- fr.abort();
- });
-});
-
-Deno.test(async function fileReaderLoadBlobAbort() {
- await new Promise<void>((resolve) => {
- const fr = new FileReader();
- const b1 = new Blob(["Hello World"]);
-
- const hasOnEvents = {
- load: false,
- loadend: false,
- abort: false,
- };
-
- fr.onload = () => {
- hasOnEvents.load = true;
- };
- fr.onloadend = (ev) => {
- hasOnEvents.loadend = true;
-
- assertEquals(hasOnEvents.load, false);
- assertEquals(hasOnEvents.loadend, true);
- assertEquals(hasOnEvents.abort, true);
-
- assertEquals(fr.readyState, FileReader.DONE);
- assertEquals(fr.result, null);
- assertEquals(ev.lengthComputable, false);
- resolve();
- };
- fr.onabort = () => {
- hasOnEvents.abort = true;
- };
-
- fr.readAsDataURL(b1);
- fr.abort();
- });
-});
-
-Deno.test(
- async function fileReaderDispatchesEventsInCorrectOrder() {
- await new Promise<void>((resolve) => {
- const fr = new FileReader();
- const b1 = new Blob(["Hello World"]);
- let out = "";
- fr.addEventListener("loadend", () => {
- out += "1";
- });
- fr.onloadend = (_ev) => {
- out += "2";
- };
- fr.addEventListener("loadend", () => {
- assertEquals(out, "12");
- resolve();
- });
-
- fr.readAsDataURL(b1);
- });
- },
-);
diff --git a/cli/tests/unit/files_test.ts b/cli/tests/unit/files_test.ts
deleted file mode 100644
index 2501ea643..000000000
--- a/cli/tests/unit/files_test.ts
+++ /dev/null
@@ -1,1095 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-// deno-lint-ignore-file no-deprecated-deno-api
-
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
-} from "./test_util.ts";
-import { copy } from "@test_util/std/streams/copy.ts";
-
-Deno.test(function filesStdioFileDescriptors() {
- assertEquals(Deno.stdin.rid, 0);
- assertEquals(Deno.stdout.rid, 1);
- assertEquals(Deno.stderr.rid, 2);
-});
-
-Deno.test({ permissions: { read: true } }, async function filesCopyToStdout() {
- const filename = "cli/tests/testdata/assets/fixture.json";
- using file = await Deno.open(filename);
- assert(file instanceof Deno.File);
- assert(file instanceof Deno.FsFile);
- assert(file.rid > 2);
- const bytesWritten = await copy(file, Deno.stdout);
- const fileSize = Deno.statSync(filename).size;
- assertEquals(bytesWritten, fileSize);
-});
-
-Deno.test({ permissions: { read: true } }, async function filesIter() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = await Deno.open(filename);
-
- let totalSize = 0;
- for await (const buf of Deno.iter(file)) {
- totalSize += buf.byteLength;
- }
-
- assertEquals(totalSize, 12);
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function filesIterCustomBufSize() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = await Deno.open(filename);
-
- let totalSize = 0;
- let iterations = 0;
- for await (const buf of Deno.iter(file, { bufSize: 6 })) {
- totalSize += buf.byteLength;
- iterations += 1;
- }
-
- assertEquals(totalSize, 12);
- assertEquals(iterations, 2);
- },
-);
-
-Deno.test({ permissions: { read: true } }, function filesIterSync() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = Deno.openSync(filename);
-
- let totalSize = 0;
- for (const buf of Deno.iterSync(file)) {
- totalSize += buf.byteLength;
- }
-
- assertEquals(totalSize, 12);
-});
-
-Deno.test(
- { permissions: { read: true } },
- function filesIterSyncCustomBufSize() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = Deno.openSync(filename);
-
- let totalSize = 0;
- let iterations = 0;
- for (const buf of Deno.iterSync(file, { bufSize: 6 })) {
- totalSize += buf.byteLength;
- iterations += 1;
- }
-
- assertEquals(totalSize, 12);
- assertEquals(iterations, 2);
- },
-);
-
-Deno.test(async function readerIter() {
- // ref: https://github.com/denoland/deno/issues/2330
- const encoder = new TextEncoder();
-
- class TestReader implements Deno.Reader {
- #offset = 0;
- #buf: Uint8Array;
-
- constructor(s: string) {
- this.#buf = new Uint8Array(encoder.encode(s));
- }
-
- read(p: Uint8Array): Promise<number | null> {
- const n = Math.min(p.byteLength, this.#buf.byteLength - this.#offset);
- p.set(this.#buf.slice(this.#offset, this.#offset + n));
- this.#offset += n;
-
- if (n === 0) {
- return Promise.resolve(null);
- }
-
- return Promise.resolve(n);
- }
- }
-
- const reader = new TestReader("hello world!");
-
- let totalSize = 0;
- for await (const buf of Deno.iter(reader)) {
- totalSize += buf.byteLength;
- }
-
- assertEquals(totalSize, 12);
-});
-
-Deno.test(async function readerIterSync() {
- // ref: https://github.com/denoland/deno/issues/2330
- const encoder = new TextEncoder();
-
- class TestReader implements Deno.ReaderSync {
- #offset = 0;
- #buf: Uint8Array;
-
- constructor(s: string) {
- this.#buf = new Uint8Array(encoder.encode(s));
- }
-
- readSync(p: Uint8Array): number | null {
- const n = Math.min(p.byteLength, this.#buf.byteLength - this.#offset);
- p.set(this.#buf.slice(this.#offset, this.#offset + n));
- this.#offset += n;
-
- if (n === 0) {
- return null;
- }
-
- return n;
- }
- }
-
- const reader = new TestReader("hello world!");
-
- let totalSize = 0;
- for await (const buf of Deno.iterSync(reader)) {
- totalSize += buf.byteLength;
- }
-
- assertEquals(totalSize, 12);
-});
-
-Deno.test(
- {
- permissions: { read: true, write: true },
- },
- function openSyncMode() {
- const path = Deno.makeTempDirSync() + "/test_openSync.txt";
- using _file = Deno.openSync(path, {
- write: true,
- createNew: true,
- mode: 0o626,
- });
- const pathInfo = Deno.statSync(path);
- if (Deno.build.os !== "windows") {
- assertEquals(pathInfo.mode! & 0o777, 0o626 & ~Deno.umask());
- }
- },
-);
-
-Deno.test(
- {
- permissions: { read: true, write: true },
- },
- async function openMode() {
- const path = (await Deno.makeTempDir()) + "/test_open.txt";
- using _file = await Deno.open(path, {
- write: true,
- createNew: true,
- mode: 0o626,
- });
- const pathInfo = Deno.statSync(path);
- if (Deno.build.os !== "windows") {
- assertEquals(pathInfo.mode! & 0o777, 0o626 & ~Deno.umask());
- }
- },
-);
-
-Deno.test(
- {
- permissions: { read: true, write: true },
- },
- function openSyncUrl() {
- const tempDir = Deno.makeTempDirSync();
- const fileUrl = new URL(
- `file://${
- Deno.build.os === "windows" ? "/" : ""
- }${tempDir}/test_open.txt`,
- );
- using _file = Deno.openSync(fileUrl, {
- write: true,
- createNew: true,
- mode: 0o626,
- });
- const pathInfo = Deno.statSync(fileUrl);
- if (Deno.build.os !== "windows") {
- assertEquals(pathInfo.mode! & 0o777, 0o626 & ~Deno.umask());
- }
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- {
- permissions: { read: true, write: true },
- },
- async function openUrl() {
- const tempDir = await Deno.makeTempDir();
- const fileUrl = new URL(
- `file://${
- Deno.build.os === "windows" ? "/" : ""
- }${tempDir}/test_open.txt`,
- );
- using _file = await Deno.open(fileUrl, {
- write: true,
- createNew: true,
- mode: 0o626,
- });
- const pathInfo = Deno.statSync(fileUrl);
- if (Deno.build.os !== "windows") {
- assertEquals(pathInfo.mode! & 0o777, 0o626 & ~Deno.umask());
- }
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { write: false } },
- async function writePermFailure() {
- const filename = "tests/hello.txt";
- const openOptions: Deno.OpenOptions[] = [{ write: true }, { append: true }];
- for (const options of openOptions) {
- await assertRejects(async () => {
- await Deno.open(filename, options);
- }, Deno.errors.PermissionDenied);
- }
- },
-);
-
-Deno.test(async function openOptions() {
- const filename = "cli/tests/testdata/assets/fixture.json";
- await assertRejects(
- async () => {
- await Deno.open(filename, { write: false });
- },
- Error,
- "OpenOptions requires at least one option to be true",
- );
-
- await assertRejects(
- async () => {
- await Deno.open(filename, { truncate: true, write: false });
- },
- Error,
- "'truncate' option requires 'write' option",
- );
-
- await assertRejects(
- async () => {
- await Deno.open(filename, { create: true, write: false });
- },
- Error,
- "'create' or 'createNew' options require 'write' or 'append' option",
- );
-
- await assertRejects(
- async () => {
- await Deno.open(filename, { createNew: true, append: false });
- },
- Error,
- "'create' or 'createNew' options require 'write' or 'append' option",
- );
-});
-
-Deno.test({ permissions: { read: false } }, async function readPermFailure() {
- await assertRejects(async () => {
- await Deno.open("package.json", { read: true });
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { write: true } },
- async function writeNullBufferFailure() {
- const tempDir = Deno.makeTempDirSync();
- const filename = tempDir + "hello.txt";
- const w = {
- write: true,
- truncate: true,
- create: true,
- };
- using file = await Deno.open(filename, w);
-
- // writing null should throw an error
- await assertRejects(
- async () => {
- // deno-lint-ignore no-explicit-any
- await file.write(null as any);
- },
- ); // TODO(bartlomieju): Check error kind when dispatch_minimal pipes errors properly
- await Deno.remove(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function readNullBufferFailure() {
- const tempDir = Deno.makeTempDirSync();
- const filename = tempDir + "hello.txt";
- using file = await Deno.open(filename, {
- read: true,
- write: true,
- truncate: true,
- create: true,
- });
-
- // reading into an empty buffer should return 0 immediately
- const bytesRead = await file.read(new Uint8Array(0));
- assert(bytesRead === 0);
-
- // reading file into null buffer should throw an error
- await assertRejects(async () => {
- // deno-lint-ignore no-explicit-any
- await file.read(null as any);
- }, TypeError);
- // TODO(bartlomieju): Check error kind when dispatch_minimal pipes errors properly
-
- await Deno.remove(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { write: false, read: false } },
- async function readWritePermFailure() {
- const filename = "tests/hello.txt";
- await assertRejects(async () => {
- await Deno.open(filename, { read: true });
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function openNotFound() {
- await assertRejects(
- async () => {
- await Deno.open("bad_file_name");
- },
- Deno.errors.NotFound,
- `open 'bad_file_name'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- function openSyncNotFound() {
- assertThrows(
- () => {
- Deno.openSync("bad_file_name");
- },
- Deno.errors.NotFound,
- `open 'bad_file_name'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function createFile() {
- const tempDir = await Deno.makeTempDir();
- const filename = tempDir + "/test.txt";
- const f = await Deno.create(filename);
- let fileInfo = Deno.statSync(filename);
- assert(fileInfo.isFile);
- assert(fileInfo.size === 0);
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- await f.write(data);
- fileInfo = Deno.statSync(filename);
- assert(fileInfo.size === 5);
- f.close();
-
- // TODO(bartlomieju): test different modes
- await Deno.remove(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function createFileWithUrl() {
- const tempDir = await Deno.makeTempDir();
- const fileUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/test.txt`,
- );
- const f = await Deno.create(fileUrl);
- let fileInfo = Deno.statSync(fileUrl);
- assert(fileInfo.isFile);
- assert(fileInfo.size === 0);
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- await f.write(data);
- fileInfo = Deno.statSync(fileUrl);
- assert(fileInfo.size === 5);
- f.close();
-
- await Deno.remove(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function createSyncFile() {
- const tempDir = await Deno.makeTempDir();
- const filename = tempDir + "/test.txt";
- const f = Deno.createSync(filename);
- let fileInfo = Deno.statSync(filename);
- assert(fileInfo.isFile);
- assert(fileInfo.size === 0);
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- await f.write(data);
- fileInfo = Deno.statSync(filename);
- assert(fileInfo.size === 5);
- f.close();
-
- // TODO(bartlomieju): test different modes
- await Deno.remove(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function createSyncFileWithUrl() {
- const tempDir = await Deno.makeTempDir();
- const fileUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/test.txt`,
- );
- const f = Deno.createSync(fileUrl);
- let fileInfo = Deno.statSync(fileUrl);
- assert(fileInfo.isFile);
- assert(fileInfo.size === 0);
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- await f.write(data);
- fileInfo = Deno.statSync(fileUrl);
- assert(fileInfo.size === 5);
- f.close();
-
- await Deno.remove(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function openModeWrite() {
- const tempDir = Deno.makeTempDirSync();
- const encoder = new TextEncoder();
- const filename = tempDir + "hello.txt";
- const data = encoder.encode("Hello world!\n");
- let file = await Deno.open(filename, {
- create: true,
- write: true,
- truncate: true,
- });
- // assert file was created
- let fileInfo = Deno.statSync(filename);
- assert(fileInfo.isFile);
- assertEquals(fileInfo.size, 0);
- // write some data
- await file.write(data);
- fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.size, 13);
- // assert we can't read from file
- let thrown = false;
- try {
- const buf = new Uint8Array(20);
- await file.read(buf);
- } catch (_e) {
- thrown = true;
- } finally {
- assert(thrown, "'w' mode shouldn't allow to read file");
- }
- file.close();
- // assert that existing file is truncated on open
- file = await Deno.open(filename, {
- write: true,
- truncate: true,
- });
- file.close();
- const fileSize = Deno.statSync(filename).size;
- assertEquals(fileSize, 0);
- await Deno.remove(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function openModeWriteRead() {
- const tempDir = Deno.makeTempDirSync();
- const encoder = new TextEncoder();
- const filename = tempDir + "hello.txt";
- const data = encoder.encode("Hello world!\n");
-
- using file = await Deno.open(filename, {
- write: true,
- truncate: true,
- create: true,
- read: true,
- });
- const seekPosition = 0;
- // assert file was created
- let fileInfo = Deno.statSync(filename);
- assert(fileInfo.isFile);
- assertEquals(fileInfo.size, 0);
- // write some data
- await file.write(data);
- fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.size, 13);
-
- const buf = new Uint8Array(20);
- // seeking from beginning of a file
- const cursorPosition = await file.seek(seekPosition, Deno.SeekMode.Start);
- assertEquals(seekPosition, cursorPosition);
- const result = await file.read(buf);
- assertEquals(result, 13);
-
- await Deno.remove(tempDir, { recursive: true });
- },
-);
-
-Deno.test({ permissions: { read: true } }, async function seekStart() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = await Deno.open(filename);
- const seekPosition = 6;
- // Deliberately move 1 step forward
- await file.read(new Uint8Array(1)); // "H"
- // Skipping "Hello "
- // seeking from beginning of a file plus seekPosition
- const cursorPosition = await file.seek(seekPosition, Deno.SeekMode.Start);
- assertEquals(seekPosition, cursorPosition);
- const buf = new Uint8Array(6);
- await file.read(buf);
- const decoded = new TextDecoder().decode(buf);
- assertEquals(decoded, "world!");
-});
-
-Deno.test({ permissions: { read: true } }, async function seekStartBigInt() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = await Deno.open(filename);
- const seekPosition = 6n;
- // Deliberately move 1 step forward
- await file.read(new Uint8Array(1)); // "H"
- // Skipping "Hello "
- // seeking from beginning of a file plus seekPosition
- const cursorPosition = await file.seek(seekPosition, Deno.SeekMode.Start);
- assertEquals(seekPosition, BigInt(cursorPosition));
- const buf = new Uint8Array(6);
- await file.read(buf);
- const decoded = new TextDecoder().decode(buf);
- assertEquals(decoded, "world!");
-});
-
-Deno.test({ permissions: { read: true } }, function seekSyncStart() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = Deno.openSync(filename);
- const seekPosition = 6;
- // Deliberately move 1 step forward
- file.readSync(new Uint8Array(1)); // "H"
- // Skipping "Hello "
- // seeking from beginning of a file plus seekPosition
- const cursorPosition = file.seekSync(seekPosition, Deno.SeekMode.Start);
- assertEquals(seekPosition, cursorPosition);
- const buf = new Uint8Array(6);
- file.readSync(buf);
- const decoded = new TextDecoder().decode(buf);
- assertEquals(decoded, "world!");
-});
-
-Deno.test({ permissions: { read: true } }, async function seekCurrent() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = await Deno.open(filename);
- // Deliberately move 1 step forward
- await file.read(new Uint8Array(1)); // "H"
- // Skipping "ello "
- const seekPosition = 5;
- // seekPosition is relative to current cursor position after read
- const cursorPosition = await file.seek(seekPosition, Deno.SeekMode.Current);
- assertEquals(seekPosition + 1, cursorPosition);
- const buf = new Uint8Array(6);
- await file.read(buf);
- const decoded = new TextDecoder().decode(buf);
- assertEquals(decoded, "world!");
-});
-
-Deno.test({ permissions: { read: true } }, function seekSyncCurrent() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = Deno.openSync(filename);
- // Deliberately move 1 step forward
- file.readSync(new Uint8Array(1)); // "H"
- // Skipping "ello "
- const seekPosition = 5;
- // seekPosition is relative to current cursor position after read
- const cursorPosition = file.seekSync(seekPosition, Deno.SeekMode.Current);
- assertEquals(seekPosition + 1, cursorPosition);
- const buf = new Uint8Array(6);
- file.readSync(buf);
- const decoded = new TextDecoder().decode(buf);
- assertEquals(decoded, "world!");
-});
-
-Deno.test({ permissions: { read: true } }, async function seekEnd() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = await Deno.open(filename);
- const seekPosition = -6;
- // seek from end of file that has 12 chars, 12 - 6 = 6
- const cursorPosition = await file.seek(seekPosition, Deno.SeekMode.End);
- assertEquals(6, cursorPosition);
- const buf = new Uint8Array(6);
- await file.read(buf);
- const decoded = new TextDecoder().decode(buf);
- assertEquals(decoded, "world!");
-});
-
-Deno.test({ permissions: { read: true } }, function seekSyncEnd() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = Deno.openSync(filename);
- const seekPosition = -6;
- // seek from end of file that has 12 chars, 12 - 6 = 6
- const cursorPosition = file.seekSync(seekPosition, Deno.SeekMode.End);
- assertEquals(6, cursorPosition);
- const buf = new Uint8Array(6);
- file.readSync(buf);
- const decoded = new TextDecoder().decode(buf);
- assertEquals(decoded, "world!");
-});
-
-Deno.test({ permissions: { read: true } }, async function seekMode() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- using file = await Deno.open(filename);
- await assertRejects(
- async () => {
- await file.seek(1, -1 as unknown as Deno.SeekMode);
- },
- TypeError,
- "Invalid seek mode",
- );
-
- // We should still be able to read the file
- // since it is still open.
- const buf = new Uint8Array(1);
- await file.read(buf); // "H"
- assertEquals(new TextDecoder().decode(buf), "H");
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function fileTruncateSyncSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_fileTruncateSync.txt";
- using file = Deno.openSync(filename, {
- create: true,
- read: true,
- write: true,
- });
-
- file.truncateSync(20);
- assertEquals(Deno.readFileSync(filename).byteLength, 20);
- file.truncateSync(5);
- assertEquals(Deno.readFileSync(filename).byteLength, 5);
- file.truncateSync(-5);
- assertEquals(Deno.readFileSync(filename).byteLength, 0);
-
- Deno.removeSync(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function fileTruncateSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_fileTruncate.txt";
- using file = await Deno.open(filename, {
- create: true,
- read: true,
- write: true,
- });
-
- await file.truncate(20);
- assertEquals((await Deno.readFile(filename)).byteLength, 20);
- await file.truncate(5);
- assertEquals((await Deno.readFile(filename)).byteLength, 5);
- await file.truncate(-5);
- assertEquals((await Deno.readFile(filename)).byteLength, 0);
-
- await Deno.remove(filename);
- },
-);
-
-Deno.test({ permissions: { read: true } }, function fileStatSyncSuccess() {
- using file = Deno.openSync("README.md");
- const fileInfo = file.statSync();
- assert(fileInfo.isFile);
- assert(!fileInfo.isSymlink);
- assert(!fileInfo.isDirectory);
- assert(fileInfo.size);
- assert(fileInfo.atime);
- assert(fileInfo.mtime);
- // The `birthtime` field is not available on Linux before kernel version 4.11.
- assert(fileInfo.birthtime || Deno.build.os === "linux");
-});
-
-Deno.test(async function fileStatSuccess() {
- using file = await Deno.open("README.md");
- const fileInfo = await file.stat();
- assert(fileInfo.isFile);
- assert(!fileInfo.isSymlink);
- assert(!fileInfo.isDirectory);
- assert(fileInfo.size);
- assert(fileInfo.atime);
- assert(fileInfo.mtime);
- // The `birthtime` field is not available on Linux before kernel version 4.11.
- assert(fileInfo.birthtime || Deno.build.os === "linux");
-});
-
-Deno.test({ permissions: { read: true } }, async function readableStream() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- const file = await Deno.open(filename);
- assert(file.readable instanceof ReadableStream);
- const chunks = [];
- for await (const chunk of file.readable) {
- chunks.push(chunk);
- }
- assertEquals(chunks.length, 1);
- assertEquals(chunks[0].byteLength, 12);
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function readableStreamTextEncoderPipe() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- const file = await Deno.open(filename);
- const readable = file.readable.pipeThrough(new TextDecoderStream());
- const chunks = [];
- for await (const chunk of readable) {
- chunks.push(chunk);
- }
- assertEquals(chunks.length, 1);
- assertEquals(chunks[0].length, 12);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writableStream() {
- const path = await Deno.makeTempFile();
- const file = await Deno.open(path, { write: true });
- assert(file.writable instanceof WritableStream);
- const readable = new ReadableStream({
- start(controller) {
- controller.enqueue(new TextEncoder().encode("hello "));
- controller.enqueue(new TextEncoder().encode("world!"));
- controller.close();
- },
- });
- await readable.pipeTo(file.writable);
- const res = await Deno.readTextFile(path);
- assertEquals(res, "hello world!");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function readTextFileNonUtf8() {
- const path = await Deno.makeTempFile();
- using file = await Deno.open(path, { write: true });
- await file.write(new TextEncoder().encode("hello "));
- await file.write(new Uint8Array([0xC0]));
-
- const res = await Deno.readTextFile(path);
- const resSync = Deno.readTextFileSync(path);
- assertEquals(res, resSync);
- assertEquals(res, "hello \uFFFD");
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function fsFileExplicitResourceManagement() {
- let file2: Deno.FsFile;
-
- {
- using file = await Deno.open("cli/tests/testdata/assets/hello.txt");
- file2 = file;
-
- const stat = file.statSync();
- assert(stat.isFile);
- }
-
- assertThrows(() => file2.statSync(), Deno.errors.BadResource);
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function fsFileExplicitResourceManagementManualClose() {
- using file = await Deno.open("cli/tests/testdata/assets/hello.txt");
- file.close();
- assertThrows(() => file.statSync(), Deno.errors.BadResource); // definitely closed
- // calling [Symbol.dispose] after manual close is a no-op
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function fsFileDatasyncSyncSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_fdatasyncSync.txt";
- const file = Deno.openSync(filename, {
- read: true,
- write: true,
- create: true,
- });
- const data = new Uint8Array(64);
- file.writeSync(data);
- file.syncDataSync();
- assertEquals(Deno.readFileSync(filename), data);
- file.close();
- Deno.removeSync(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function fsFileDatasyncSuccess() {
- const filename = (await Deno.makeTempDir()) + "/test_fdatasync.txt";
- const file = await Deno.open(filename, {
- read: true,
- write: true,
- create: true,
- });
- const data = new Uint8Array(64);
- await file.write(data);
- await file.syncData();
- assertEquals(await Deno.readFile(filename), data);
- file.close();
- await Deno.remove(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function fsFileSyncSyncSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_fsyncSync.txt";
- const file = Deno.openSync(filename, {
- read: true,
- write: true,
- create: true,
- });
- const size = 64;
- file.truncateSync(size);
- file.syncSync();
- assertEquals(file.statSync().size, size);
- file.close();
- Deno.removeSync(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function fsFileSyncSuccess() {
- const filename = (await Deno.makeTempDir()) + "/test_fsync.txt";
- const file = await Deno.open(filename, {
- read: true,
- write: true,
- create: true,
- });
- const size = 64;
- await file.truncate(size);
- await file.sync();
- assertEquals((await file.stat()).size, size);
- file.close();
- await Deno.remove(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: true, hrtime: true } },
- async function fsFileLockFileSync() {
- await runFlockTests({ sync: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: true, hrtime: true } },
- async function fsFileLockFileAsync() {
- await runFlockTests({ sync: false });
- },
-);
-
-async function runFlockTests(opts: { sync: boolean }) {
- assertEquals(
- await checkFirstBlocksSecond({
- firstExclusive: true,
- secondExclusive: false,
- sync: opts.sync,
- }),
- true,
- "exclusive blocks shared",
- );
- assertEquals(
- await checkFirstBlocksSecond({
- firstExclusive: false,
- secondExclusive: true,
- sync: opts.sync,
- }),
- true,
- "shared blocks exclusive",
- );
- assertEquals(
- await checkFirstBlocksSecond({
- firstExclusive: true,
- secondExclusive: true,
- sync: opts.sync,
- }),
- true,
- "exclusive blocks exclusive",
- );
- assertEquals(
- await checkFirstBlocksSecond({
- firstExclusive: false,
- secondExclusive: false,
- sync: opts.sync,
- // need to wait for both to enter the lock to prevent the case where the
- // first process enters and exits the lock before the second even enters
- waitBothEnteredLock: true,
- }),
- false,
- "shared does not block shared",
- );
-}
-
-async function checkFirstBlocksSecond(opts: {
- firstExclusive: boolean;
- secondExclusive: boolean;
- sync: boolean;
- waitBothEnteredLock?: boolean;
-}) {
- const firstProcess = runFlockTestProcess({
- exclusive: opts.firstExclusive,
- sync: opts.sync,
- });
- const secondProcess = runFlockTestProcess({
- exclusive: opts.secondExclusive,
- sync: opts.sync,
- });
- try {
- const sleep = (time: number) => new Promise((r) => setTimeout(r, time));
-
- await Promise.all([
- firstProcess.waitStartup(),
- secondProcess.waitStartup(),
- ]);
-
- await firstProcess.enterLock();
- await firstProcess.waitEnterLock();
-
- await secondProcess.enterLock();
- await sleep(100);
-
- if (!opts.waitBothEnteredLock) {
- await firstProcess.exitLock();
- }
-
- await secondProcess.waitEnterLock();
-
- if (opts.waitBothEnteredLock) {
- await firstProcess.exitLock();
- }
-
- await secondProcess.exitLock();
-
- // collect the final output
- const firstPsTimes = await firstProcess.getTimes();
- const secondPsTimes = await secondProcess.getTimes();
- return firstPsTimes.exitTime < secondPsTimes.enterTime;
- } finally {
- await firstProcess.close();
- await secondProcess.close();
- }
-}
-
-function runFlockTestProcess(opts: { exclusive: boolean; sync: boolean }) {
- const path = "cli/tests/testdata/assets/lock_target.txt";
- const scriptText = `
- const file = Deno.openSync("${path}");
-
- // ready signal
- Deno.stdout.writeSync(new Uint8Array(1));
- // wait for enter lock signal
- Deno.stdin.readSync(new Uint8Array(1));
-
- // entering signal
- Deno.stdout.writeSync(new Uint8Array(1));
- // lock and record the entry time
- ${
- opts.sync
- ? `file.lockSync(${opts.exclusive ? "true" : "false"});`
- : `await file.lock(${opts.exclusive ? "true" : "false"});`
- }
- const enterTime = new Date().getTime();
- // entered signal
- Deno.stdout.writeSync(new Uint8Array(1));
-
- // wait for exit lock signal
- Deno.stdin.readSync(new Uint8Array(1));
-
- // record the exit time and wait a little bit before releasing
- // the lock so that the enter time of the next process doesn't
- // occur at the same time as this exit time
- const exitTime = new Date().getTime();
- await new Promise(resolve => setTimeout(resolve, 100));
-
- // release the lock
- ${opts.sync ? "file.unlockSync();" : "await file.unlock();"}
-
- // exited signal
- Deno.stdout.writeSync(new Uint8Array(1));
-
- // output the enter and exit time
- console.log(JSON.stringify({ enterTime, exitTime }));
-`;
-
- const process = new Deno.Command(Deno.execPath(), {
- args: ["eval", "--unstable", scriptText],
- stdin: "piped",
- stdout: "piped",
- stderr: "null",
- }).spawn();
-
- const waitSignal = async () => {
- const reader = process.stdout.getReader({ mode: "byob" });
- await reader.read(new Uint8Array(1));
- reader.releaseLock();
- };
- const signal = async () => {
- const writer = process.stdin.getWriter();
- await writer.write(new Uint8Array(1));
- writer.releaseLock();
- };
-
- return {
- async waitStartup() {
- await waitSignal();
- },
- async enterLock() {
- await signal();
- await waitSignal(); // entering signal
- },
- async waitEnterLock() {
- await waitSignal();
- },
- async exitLock() {
- await signal();
- await waitSignal();
- },
- getTimes: async () => {
- const { stdout } = await process.output();
- const text = new TextDecoder().decode(stdout);
- return JSON.parse(text) as {
- enterTime: number;
- exitTime: number;
- };
- },
- close: async () => {
- await process.status;
- await process.stdin.close();
- },
- };
-}
diff --git a/cli/tests/unit/flock_test.ts b/cli/tests/unit/flock_test.ts
deleted file mode 100644
index 3189b4a56..000000000
--- a/cli/tests/unit/flock_test.ts
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-Deno.test(
- { permissions: { read: true, run: true, hrtime: true } },
- async function flockFileSync() {
- await runFlockTests({ sync: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: true, hrtime: true } },
- async function flockFileAsync() {
- await runFlockTests({ sync: false });
- },
-);
-
-async function runFlockTests(opts: { sync: boolean }) {
- assertEquals(
- await checkFirstBlocksSecond({
- firstExclusive: true,
- secondExclusive: false,
- sync: opts.sync,
- }),
- true,
- "exclusive blocks shared",
- );
- assertEquals(
- await checkFirstBlocksSecond({
- firstExclusive: false,
- secondExclusive: true,
- sync: opts.sync,
- }),
- true,
- "shared blocks exclusive",
- );
- assertEquals(
- await checkFirstBlocksSecond({
- firstExclusive: true,
- secondExclusive: true,
- sync: opts.sync,
- }),
- true,
- "exclusive blocks exclusive",
- );
- assertEquals(
- await checkFirstBlocksSecond({
- firstExclusive: false,
- secondExclusive: false,
- sync: opts.sync,
- // need to wait for both to enter the lock to prevent the case where the
- // first process enters and exits the lock before the second even enters
- waitBothEnteredLock: true,
- }),
- false,
- "shared does not block shared",
- );
-}
-
-async function checkFirstBlocksSecond(opts: {
- firstExclusive: boolean;
- secondExclusive: boolean;
- sync: boolean;
- waitBothEnteredLock?: boolean;
-}) {
- const firstProcess = runFlockTestProcess({
- exclusive: opts.firstExclusive,
- sync: opts.sync,
- });
- const secondProcess = runFlockTestProcess({
- exclusive: opts.secondExclusive,
- sync: opts.sync,
- });
- try {
- const sleep = (time: number) => new Promise((r) => setTimeout(r, time));
-
- await Promise.all([
- firstProcess.waitStartup(),
- secondProcess.waitStartup(),
- ]);
-
- await firstProcess.enterLock();
- await firstProcess.waitEnterLock();
-
- await secondProcess.enterLock();
- await sleep(100);
-
- if (!opts.waitBothEnteredLock) {
- await firstProcess.exitLock();
- }
-
- await secondProcess.waitEnterLock();
-
- if (opts.waitBothEnteredLock) {
- await firstProcess.exitLock();
- }
-
- await secondProcess.exitLock();
-
- // collect the final output
- const firstPsTimes = await firstProcess.getTimes();
- const secondPsTimes = await secondProcess.getTimes();
- return firstPsTimes.exitTime < secondPsTimes.enterTime;
- } finally {
- await firstProcess.close();
- await secondProcess.close();
- }
-}
-
-function runFlockTestProcess(opts: { exclusive: boolean; sync: boolean }) {
- const path = "cli/tests/testdata/assets/lock_target.txt";
- const scriptText = `
- const { rid } = Deno.openSync("${path}");
-
- // ready signal
- Deno.stdout.writeSync(new Uint8Array(1));
- // wait for enter lock signal
- Deno.stdin.readSync(new Uint8Array(1));
-
- // entering signal
- Deno.stdout.writeSync(new Uint8Array(1));
- // lock and record the entry time
- ${
- opts.sync
- ? `Deno.flockSync(rid, ${opts.exclusive ? "true" : "false"});`
- : `await Deno.flock(rid, ${opts.exclusive ? "true" : "false"});`
- }
- const enterTime = new Date().getTime();
- // entered signal
- Deno.stdout.writeSync(new Uint8Array(1));
-
- // wait for exit lock signal
- Deno.stdin.readSync(new Uint8Array(1));
-
- // record the exit time and wait a little bit before releasing
- // the lock so that the enter time of the next process doesn't
- // occur at the same time as this exit time
- const exitTime = new Date().getTime();
- await new Promise(resolve => setTimeout(resolve, 100));
-
- // release the lock
- ${opts.sync ? "Deno.funlockSync(rid);" : "await Deno.funlock(rid);"}
-
- // exited signal
- Deno.stdout.writeSync(new Uint8Array(1));
-
- // output the enter and exit time
- console.log(JSON.stringify({ enterTime, exitTime }));
-`;
-
- const process = new Deno.Command(Deno.execPath(), {
- args: ["eval", "--unstable", scriptText],
- stdin: "piped",
- stdout: "piped",
- stderr: "null",
- }).spawn();
-
- const waitSignal = async () => {
- const reader = process.stdout.getReader({ mode: "byob" });
- await reader.read(new Uint8Array(1));
- reader.releaseLock();
- };
- const signal = async () => {
- const writer = process.stdin.getWriter();
- await writer.write(new Uint8Array(1));
- writer.releaseLock();
- };
-
- return {
- async waitStartup() {
- await waitSignal();
- },
- async enterLock() {
- await signal();
- await waitSignal(); // entering signal
- },
- async waitEnterLock() {
- await waitSignal();
- },
- async exitLock() {
- await signal();
- await waitSignal();
- },
- getTimes: async () => {
- const { stdout } = await process.output();
- const text = new TextDecoder().decode(stdout);
- return JSON.parse(text) as {
- enterTime: number;
- exitTime: number;
- };
- },
- close: async () => {
- await process.status;
- await process.stdin.close();
- },
- };
-}
diff --git a/cli/tests/unit/fs_events_test.ts b/cli/tests/unit/fs_events_test.ts
deleted file mode 100644
index 4f7cdc4d5..000000000
--- a/cli/tests/unit/fs_events_test.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assert, assertEquals, assertThrows, delay } from "./test_util.ts";
-
-// TODO(ry) Add more tests to specify format.
-
-Deno.test({ permissions: { read: false } }, function watchFsPermissions() {
- assertThrows(() => {
- Deno.watchFs(".");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function watchFsInvalidPath() {
- if (Deno.build.os === "windows") {
- assertThrows(
- () => {
- Deno.watchFs("non-existent.file");
- },
- Error,
- "Input watch path is neither a file nor a directory",
- );
- } else {
- assertThrows(() => {
- Deno.watchFs("non-existent.file");
- }, Deno.errors.NotFound);
- }
-});
-
-async function getTwoEvents(
- iter: Deno.FsWatcher,
-): Promise<Deno.FsEvent[]> {
- const events = [];
- for await (const event of iter) {
- events.push(event);
- if (events.length > 2) break;
- }
- return events;
-}
-
-async function makeTempDir(): Promise<string> {
- const testDir = await Deno.makeTempDir();
- // The watcher sometimes witnesses the creation of it's own root
- // directory. Delay a bit.
- await delay(100);
- return testDir;
-}
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function watchFsBasic() {
- const testDir = await makeTempDir();
- const iter = Deno.watchFs(testDir);
-
- // Asynchronously capture two fs events.
- const eventsPromise = getTwoEvents(iter);
-
- // Make some random file system activity.
- const file1 = testDir + "/file1.txt";
- const file2 = testDir + "/file2.txt";
- Deno.writeFileSync(file1, new Uint8Array([0, 1, 2]));
- Deno.writeFileSync(file2, new Uint8Array([0, 1, 2]));
-
- // We should have gotten two fs events.
- const events = await eventsPromise;
- assert(events.length >= 2);
- assert(events[0].kind == "create");
- assert(events[0].paths[0].includes(testDir));
- assert(events[1].kind == "create" || events[1].kind == "modify");
- assert(events[1].paths[0].includes(testDir));
- },
-);
-
-// TODO(kt3k): This test is for the backward compatibility of `.return` method.
-// This should be removed at 2.0
-Deno.test(
- { permissions: { read: true, write: true } },
- async function watchFsReturn() {
- const testDir = await makeTempDir();
- const iter = Deno.watchFs(testDir);
-
- // Asynchronously loop events.
- const eventsPromise = getTwoEvents(iter);
-
- // Close the watcher.
- await iter.return!();
-
- // Expect zero events.
- const events = await eventsPromise;
- assertEquals(events, []);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function watchFsClose() {
- const testDir = await makeTempDir();
- const iter = Deno.watchFs(testDir);
-
- // Asynchronously loop events.
- const eventsPromise = getTwoEvents(iter);
-
- // Close the watcher.
- iter.close();
-
- // Expect zero events.
- const events = await eventsPromise;
- assertEquals(events, []);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function watchFsExplicitResourceManagement() {
- let res;
- {
- const testDir = await makeTempDir();
- using iter = Deno.watchFs(testDir);
-
- res = iter[Symbol.asyncIterator]().next();
- }
-
- const { done } = await res;
- assert(done);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function watchFsExplicitResourceManagementManualClose() {
- const testDir = await makeTempDir();
- using iter = Deno.watchFs(testDir);
-
- const res = iter[Symbol.asyncIterator]().next();
-
- iter.close();
- const { done } = await res;
- assert(done);
- },
-);
diff --git a/cli/tests/unit/get_random_values_test.ts b/cli/tests/unit/get_random_values_test.ts
deleted file mode 100644
index 75aaf4c1b..000000000
--- a/cli/tests/unit/get_random_values_test.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertNotEquals, assertStrictEquals } from "./test_util.ts";
-
-Deno.test(function getRandomValuesInt8Array() {
- const arr = new Int8Array(32);
- crypto.getRandomValues(arr);
- assertNotEquals(arr, new Int8Array(32));
-});
-
-Deno.test(function getRandomValuesUint8Array() {
- const arr = new Uint8Array(32);
- crypto.getRandomValues(arr);
- assertNotEquals(arr, new Uint8Array(32));
-});
-
-Deno.test(function getRandomValuesUint8ClampedArray() {
- const arr = new Uint8ClampedArray(32);
- crypto.getRandomValues(arr);
- assertNotEquals(arr, new Uint8ClampedArray(32));
-});
-
-Deno.test(function getRandomValuesInt16Array() {
- const arr = new Int16Array(4);
- crypto.getRandomValues(arr);
- assertNotEquals(arr, new Int16Array(4));
-});
-
-Deno.test(function getRandomValuesUint16Array() {
- const arr = new Uint16Array(4);
- crypto.getRandomValues(arr);
- assertNotEquals(arr, new Uint16Array(4));
-});
-
-Deno.test(function getRandomValuesInt32Array() {
- const arr = new Int32Array(8);
- crypto.getRandomValues(arr);
- assertNotEquals(arr, new Int32Array(8));
-});
-
-Deno.test(function getRandomValuesBigInt64Array() {
- const arr = new BigInt64Array(8);
- crypto.getRandomValues(arr);
- assertNotEquals(arr, new BigInt64Array(8));
-});
-
-Deno.test(function getRandomValuesUint32Array() {
- const arr = new Uint32Array(8);
- crypto.getRandomValues(arr);
- assertNotEquals(arr, new Uint32Array(8));
-});
-
-Deno.test(function getRandomValuesBigUint64Array() {
- const arr = new BigUint64Array(8);
- crypto.getRandomValues(arr);
- assertNotEquals(arr, new BigUint64Array(8));
-});
-
-Deno.test(function getRandomValuesReturnValue() {
- const arr = new Uint32Array(8);
- const rtn = crypto.getRandomValues(arr);
- assertNotEquals(arr, new Uint32Array(8));
- assertStrictEquals(rtn, arr);
-});
diff --git a/cli/tests/unit/globals_test.ts b/cli/tests/unit/globals_test.ts
deleted file mode 100644
index 00be3f451..000000000
--- a/cli/tests/unit/globals_test.ts
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-// deno-lint-ignore-file no-window-prefix
-import { assert, assertEquals, assertRejects } from "./test_util.ts";
-
-Deno.test(function globalThisExists() {
- assert(globalThis != null);
-});
-
-Deno.test(function noInternalGlobals() {
- // globalThis.__bootstrap should not be there.
- for (const key of Object.keys(globalThis)) {
- assert(!key.startsWith("_"));
- }
-});
-
-Deno.test(function windowExists() {
- assert(window != null);
-});
-
-Deno.test(function selfExists() {
- assert(self != null);
-});
-
-Deno.test(function windowWindowExists() {
- assert(window.window === window);
-});
-
-Deno.test(function windowSelfExists() {
- assert(window.self === window);
-});
-
-Deno.test(function globalThisEqualsWindow() {
- assert(globalThis === window);
-});
-
-Deno.test(function globalThisEqualsSelf() {
- assert(globalThis === self);
-});
-
-Deno.test(function globalThisInstanceofWindow() {
- assert(globalThis instanceof Window);
-});
-
-Deno.test(function globalThisConstructorLength() {
- assert(globalThis.constructor.length === 0);
-});
-
-Deno.test(function globalThisInstanceofEventTarget() {
- assert(globalThis instanceof EventTarget);
-});
-
-Deno.test(function navigatorInstanceofNavigator() {
- // TODO(nayeemrmn): Add `Navigator` to deno_lint globals.
- // deno-lint-ignore no-undef
- assert(navigator instanceof Navigator);
-});
-
-Deno.test(function DenoNamespaceExists() {
- assert(Deno != null);
-});
-
-Deno.test(function DenoNamespaceEqualsWindowDeno() {
- assert(Deno === window.Deno);
-});
-
-Deno.test(function DenoNamespaceIsNotFrozen() {
- assert(!Object.isFrozen(Deno));
-});
-
-Deno.test(function webAssemblyExists() {
- assert(typeof WebAssembly.compile === "function");
-});
-
-// @ts-ignore This is not publicly typed namespace, but it's there for sure.
-const core = Deno[Deno.internal].core;
-
-Deno.test(function DenoNamespaceConfigurable() {
- const desc = Object.getOwnPropertyDescriptor(globalThis, "Deno");
- assert(desc);
- assert(desc.configurable);
- assert(!desc.writable);
-});
-
-Deno.test(function DenoCoreNamespaceIsImmutable() {
- const { print } = core;
- try {
- core.print = 1;
- } catch {
- // pass
- }
- assert(print === core.print);
- try {
- delete core.print;
- } catch {
- // pass
- }
- assert(print === core.print);
-});
-
-Deno.test(async function windowQueueMicrotask() {
- let resolve1: () => void | undefined;
- let resolve2: () => void | undefined;
- let microtaskDone = false;
- const p1 = new Promise<void>((res) => {
- resolve1 = () => {
- microtaskDone = true;
- res();
- };
- });
- const p2 = new Promise<void>((res) => {
- resolve2 = () => {
- assert(microtaskDone);
- res();
- };
- });
- window.queueMicrotask(resolve1!);
- setTimeout(resolve2!, 0);
- await p1;
- await p2;
-});
-
-Deno.test(function webApiGlobalThis() {
- assert(globalThis.FormData !== null);
- assert(globalThis.TextEncoder !== null);
- assert(globalThis.TextEncoderStream !== null);
- assert(globalThis.TextDecoder !== null);
- assert(globalThis.TextDecoderStream !== null);
- assert(globalThis.CountQueuingStrategy !== null);
- assert(globalThis.ByteLengthQueuingStrategy !== null);
-});
-
-Deno.test(function windowNameIsDefined() {
- assertEquals(typeof globalThis.name, "string");
- assertEquals(name, "");
- assertEquals(window.name, name);
- name = "foobar";
- assertEquals(window.name, "foobar");
- assertEquals(name, "foobar");
- name = "";
- assertEquals(window.name, "");
- assertEquals(name, "");
-});
-
-Deno.test(async function promiseWithResolvers() {
- {
- const { promise, resolve } = Promise.withResolvers();
- resolve(true);
- assert(await promise);
- }
- {
- const { promise, reject } = Promise.withResolvers();
- reject(new Error("boom!"));
- await assertRejects(() => promise, Error, "boom!");
- }
-});
-
-Deno.test(async function arrayFromAsync() {
- // Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync#examples
- // Thank you.
- const asyncIterable = (async function* () {
- for (let i = 0; i < 5; i++) {
- await new Promise((resolve) => setTimeout(resolve, 10 * i));
- yield i;
- }
- })();
-
- const a = await Array.fromAsync(asyncIterable);
- assertEquals(a, [0, 1, 2, 3, 4]);
-
- const b = await Array.fromAsync(new Map([[1, 2], [3, 4]]));
- assertEquals(b, [[1, 2], [3, 4]]);
-});
-
-// Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy#examples
-Deno.test(function objectGroupBy() {
- const inventory = [
- { name: "asparagus", type: "vegetables", quantity: 5 },
- { name: "bananas", type: "fruit", quantity: 0 },
- { name: "goat", type: "meat", quantity: 23 },
- { name: "cherries", type: "fruit", quantity: 5 },
- { name: "fish", type: "meat", quantity: 22 },
- ];
- const result = Object.groupBy(inventory, ({ type }) => type);
- assertEquals(result, {
- vegetables: [
- { name: "asparagus", type: "vegetables", quantity: 5 },
- ],
- fruit: [
- { name: "bananas", type: "fruit", quantity: 0 },
- { name: "cherries", type: "fruit", quantity: 5 },
- ],
- meat: [
- { name: "goat", type: "meat", quantity: 23 },
- { name: "fish", type: "meat", quantity: 22 },
- ],
- });
-});
-
-Deno.test(function objectGroupByEmpty() {
- const empty: string[] = [];
- const result = Object.groupBy(empty, () => "abc");
- assertEquals(result.abc, undefined);
-});
-
-// Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy#examples
-Deno.test(function mapGroupBy() {
- const inventory = [
- { name: "asparagus", type: "vegetables", quantity: 9 },
- { name: "bananas", type: "fruit", quantity: 5 },
- { name: "goat", type: "meat", quantity: 23 },
- { name: "cherries", type: "fruit", quantity: 12 },
- { name: "fish", type: "meat", quantity: 22 },
- ];
- const restock = { restock: true };
- const sufficient = { restock: false };
- const result = Map.groupBy(
- inventory,
- ({ quantity }) => quantity < 6 ? restock : sufficient,
- );
- assertEquals(result.get(restock), [{
- name: "bananas",
- type: "fruit",
- quantity: 5,
- }]);
-});
diff --git a/cli/tests/unit/headers_test.ts b/cli/tests/unit/headers_test.ts
deleted file mode 100644
index ad453b67f..000000000
--- a/cli/tests/unit/headers_test.ts
+++ /dev/null
@@ -1,416 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals, assertThrows } from "./test_util.ts";
-const {
- inspectArgs,
- // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
-} = Deno[Deno.internal];
-
-Deno.test(function headersHasCorrectNameProp() {
- assertEquals(Headers.name, "Headers");
-});
-
-// Logic heavily copied from web-platform-tests, make
-// sure pass mostly header basic test
-// ref: https://github.com/web-platform-tests/wpt/blob/7c50c216081d6ea3c9afe553ee7b64534020a1b2/fetch/api/headers/headers-basic.html
-Deno.test(function newHeaderTest() {
- new Headers();
- new Headers(undefined);
- new Headers({});
- try {
- // deno-lint-ignore no-explicit-any
- new Headers(null as any);
- } catch (e) {
- assert(e instanceof TypeError);
- }
-});
-
-const headerDict: Record<string, string> = {
- name1: "value1",
- name2: "value2",
- name3: "value3",
- // deno-lint-ignore no-explicit-any
- name4: undefined as any,
- "Content-Type": "value4",
-};
-// deno-lint-ignore no-explicit-any
-const headerSeq: any[] = [];
-for (const [name, value] of Object.entries(headerDict)) {
- headerSeq.push([name, value]);
-}
-
-Deno.test(function newHeaderWithSequence() {
- const headers = new Headers(headerSeq);
- for (const [name, value] of Object.entries(headerDict)) {
- assertEquals(headers.get(name), String(value));
- }
- assertEquals(headers.get("length"), null);
-});
-
-Deno.test(function newHeaderWithRecord() {
- const headers = new Headers(headerDict);
- for (const [name, value] of Object.entries(headerDict)) {
- assertEquals(headers.get(name), String(value));
- }
-});
-
-Deno.test(function newHeaderWithHeadersInstance() {
- const headers = new Headers(headerDict);
- const headers2 = new Headers(headers);
- for (const [name, value] of Object.entries(headerDict)) {
- assertEquals(headers2.get(name), String(value));
- }
-});
-
-Deno.test(function headerAppendSuccess() {
- const headers = new Headers();
- for (const [name, value] of Object.entries(headerDict)) {
- headers.append(name, value);
- assertEquals(headers.get(name), String(value));
- }
-});
-
-Deno.test(function headerSetSuccess() {
- const headers = new Headers();
- for (const [name, value] of Object.entries(headerDict)) {
- headers.set(name, value);
- assertEquals(headers.get(name), String(value));
- }
-});
-
-Deno.test(function headerHasSuccess() {
- const headers = new Headers(headerDict);
- for (const name of Object.keys(headerDict)) {
- assert(headers.has(name), "headers has name " + name);
- assert(
- !headers.has("nameNotInHeaders"),
- "headers do not have header: nameNotInHeaders",
- );
- }
-});
-
-Deno.test(function headerDeleteSuccess() {
- const headers = new Headers(headerDict);
- for (const name of Object.keys(headerDict)) {
- assert(headers.has(name), "headers have a header: " + name);
- headers.delete(name);
- assert(!headers.has(name), "headers do not have anymore a header: " + name);
- }
-});
-
-Deno.test(function headerGetSuccess() {
- const headers = new Headers(headerDict);
- for (const [name, value] of Object.entries(headerDict)) {
- assertEquals(headers.get(name), String(value));
- assertEquals(headers.get("nameNotInHeaders"), null);
- }
-});
-
-Deno.test(function headerEntriesSuccess() {
- const headers = new Headers(headerDict);
- const iterators = headers.entries();
- for (const it of iterators) {
- const key = it[0];
- const value = it[1];
- assert(headers.has(key));
- assertEquals(value, headers.get(key));
- }
-});
-
-Deno.test(function headerKeysSuccess() {
- const headers = new Headers(headerDict);
- const iterators = headers.keys();
- for (const it of iterators) {
- assert(headers.has(it));
- }
-});
-
-Deno.test(function headerValuesSuccess() {
- const headers = new Headers(headerDict);
- const iterators = headers.values();
- const entries = headers.entries();
- const values = [];
- for (const pair of entries) {
- values.push(pair[1]);
- }
- for (const it of iterators) {
- assert(values.includes(it));
- }
-});
-
-const headerEntriesDict: Record<string, string> = {
- name1: "value1",
- Name2: "value2",
- name: "value3",
- "content-Type": "value4",
- "Content-Typ": "value5",
- "Content-Types": "value6",
-};
-
-Deno.test(function headerForEachSuccess() {
- const headers = new Headers(headerEntriesDict);
- const keys = Object.keys(headerEntriesDict);
- keys.forEach((key) => {
- const value = headerEntriesDict[key];
- const newkey = key.toLowerCase();
- headerEntriesDict[newkey] = value;
- });
- let callNum = 0;
- headers.forEach((value, key, container) => {
- assertEquals(headers, container);
- assertEquals(value, headerEntriesDict[key]);
- callNum++;
- });
- assertEquals(callNum, keys.length);
-});
-
-Deno.test(function headerSymbolIteratorSuccess() {
- assert(Symbol.iterator in Headers.prototype);
- const headers = new Headers(headerEntriesDict);
- for (const header of headers) {
- const key = header[0];
- const value = header[1];
- assert(headers.has(key));
- assertEquals(value, headers.get(key));
- }
-});
-
-Deno.test(function headerTypesAvailable() {
- function newHeaders(): Headers {
- return new Headers();
- }
- const headers = newHeaders();
- assert(headers instanceof Headers);
-});
-
-// Modified from https://github.com/bitinn/node-fetch/blob/7d3293200a91ad52b5ca7962f9d6fd1c04983edb/test/test.js#L2001-L2014
-// Copyright (c) 2016 David Frank. MIT License.
-Deno.test(function headerIllegalReject() {
- let errorCount = 0;
- try {
- new Headers({ "He y": "ok" });
- } catch (_e) {
- errorCount++;
- }
- try {
- new Headers({ "Hé-y": "ok" });
- } catch (_e) {
- errorCount++;
- }
- try {
- new Headers({ "He-y": "ăk" });
- } catch (_e) {
- errorCount++;
- }
- const headers = new Headers();
- try {
- headers.append("Hé-y", "ok");
- } catch (_e) {
- errorCount++;
- }
- try {
- headers.delete("Hé-y");
- } catch (_e) {
- errorCount++;
- }
- try {
- headers.get("Hé-y");
- } catch (_e) {
- errorCount++;
- }
- try {
- headers.has("Hé-y");
- } catch (_e) {
- errorCount++;
- }
- try {
- headers.set("Hé-y", "ok");
- } catch (_e) {
- errorCount++;
- }
- try {
- headers.set("", "ok");
- } catch (_e) {
- errorCount++;
- }
- assertEquals(errorCount, 9);
- // 'o k' is valid value but invalid name
- new Headers({ "He-y": "o k" });
-});
-
-// If pair does not contain exactly two items,then throw a TypeError.
-Deno.test(function headerParamsShouldThrowTypeError() {
- let hasThrown = 0;
-
- try {
- new Headers(([["1"]] as unknown) as Array<[string, string]>);
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
-
- assertEquals(hasThrown, 2);
-});
-
-Deno.test(function headerParamsArgumentsCheck() {
- const methodRequireOneParam = ["delete", "get", "has", "forEach"] as const;
-
- const methodRequireTwoParams = ["append", "set"] as const;
-
- methodRequireOneParam.forEach((method) => {
- const headers = new Headers();
- let hasThrown = 0;
- try {
- // deno-lint-ignore no-explicit-any
- (headers as any)[method]();
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
- assertEquals(hasThrown, 2);
- });
-
- methodRequireTwoParams.forEach((method) => {
- const headers = new Headers();
- let hasThrown = 0;
-
- try {
- // deno-lint-ignore no-explicit-any
- (headers as any)[method]();
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
- assertEquals(hasThrown, 2);
-
- hasThrown = 0;
- try {
- // deno-lint-ignore no-explicit-any
- (headers as any)[method]("foo");
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
- assertEquals(hasThrown, 2);
- });
-});
-
-Deno.test(function headersInitMultiple() {
- const headers = new Headers([
- ["Set-Cookie", "foo=bar"],
- ["Set-Cookie", "bar=baz"],
- ["X-Deno", "foo"],
- ["X-Deno", "bar"],
- ]);
- const actual = [...headers];
- assertEquals(actual, [
- ["set-cookie", "foo=bar"],
- ["set-cookie", "bar=baz"],
- ["x-deno", "foo, bar"],
- ]);
-});
-
-Deno.test(function headerInitWithPrototypePollution() {
- const originalExec = RegExp.prototype.exec;
- try {
- RegExp.prototype.exec = () => {
- throw Error();
- };
- new Headers([
- ["X-Deno", "foo"],
- ["X-Deno", "bar"],
- ]);
- } finally {
- RegExp.prototype.exec = originalExec;
- }
-});
-
-Deno.test(function headersAppendMultiple() {
- const headers = new Headers([
- ["Set-Cookie", "foo=bar"],
- ["X-Deno", "foo"],
- ]);
- headers.append("set-Cookie", "bar=baz");
- headers.append("x-Deno", "bar");
- const actual = [...headers];
- assertEquals(actual, [
- ["set-cookie", "foo=bar"],
- ["set-cookie", "bar=baz"],
- ["x-deno", "foo, bar"],
- ]);
-});
-
-Deno.test(function headersAppendDuplicateSetCookieKey() {
- const headers = new Headers([["Set-Cookie", "foo=bar"]]);
- headers.append("set-Cookie", "foo=baz");
- headers.append("Set-cookie", "baz=bar");
- const actual = [...headers];
- assertEquals(actual, [
- ["set-cookie", "foo=bar"],
- ["set-cookie", "foo=baz"],
- ["set-cookie", "baz=bar"],
- ]);
-});
-
-Deno.test(function headersGetSetCookie() {
- const headers = new Headers([
- ["Set-Cookie", "foo=bar"],
- ["set-Cookie", "bar=qat"],
- ]);
- assertEquals(headers.get("SET-COOKIE"), "foo=bar, bar=qat");
-});
-
-Deno.test(function toStringShouldBeWebCompatibility() {
- const headers = new Headers();
- assertEquals(headers.toString(), "[object Headers]");
-});
-
-function stringify(...args: unknown[]): string {
- return inspectArgs(args).replace(/\n$/, "");
-}
-
-Deno.test(function customInspectReturnsCorrectHeadersFormat() {
- const blankHeaders = new Headers();
- assertEquals(stringify(blankHeaders), "Headers {}");
- const singleHeader = new Headers([["Content-Type", "application/json"]]);
- assertEquals(
- stringify(singleHeader),
- `Headers { "content-type": "application/json" }`,
- );
- const multiParamHeader = new Headers([
- ["Content-Type", "application/json"],
- ["Content-Length", "1337"],
- ]);
- assertEquals(
- stringify(multiParamHeader),
- `Headers { "content-length": "1337", "content-type": "application/json" }`,
- );
-});
-
-Deno.test(function invalidHeadersFlaky() {
- assertThrows(
- () => new Headers([["x", "\u0000x"]]),
- TypeError,
- "Header value is not valid.",
- );
- assertThrows(
- () => new Headers([["x", "\u0000x"]]),
- TypeError,
- "Header value is not valid.",
- );
-});
diff --git a/cli/tests/unit/http_test.ts b/cli/tests/unit/http_test.ts
deleted file mode 100644
index 66cc53113..000000000
--- a/cli/tests/unit/http_test.ts
+++ /dev/null
@@ -1,2801 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { Buffer, BufReader, BufWriter } from "@test_util/std/io/mod.ts";
-import { TextProtoReader } from "../testdata/run/textproto.ts";
-import {
- assert,
- assertEquals,
- assertRejects,
- assertStrictEquals,
- assertThrows,
- delay,
- fail,
-} from "./test_util.ts";
-import { join } from "@test_util/std/path/mod.ts";
-
-const listenPort = 4507;
-const listenPort2 = 4508;
-
-const {
- buildCaseInsensitiveCommaValueFinder,
- // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
-} = Deno[Deno.internal];
-
-async function writeRequestAndReadResponse(conn: Deno.Conn): Promise<string> {
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- const w = new BufWriter(conn);
- const r = new BufReader(conn);
- const body = `GET / HTTP/1.1\r\nHost: 127.0.0.1:${listenPort}\r\n\r\n`;
- const writeResult = await w.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await w.flush();
- const tpr = new TextProtoReader(r);
- const statusLine = await tpr.readLine();
- assert(statusLine !== null);
- const headers = await tpr.readMimeHeader();
- assert(headers !== null);
-
- const chunkedReader = chunkedBodyReader(headers, r);
- const buf = new Uint8Array(5);
- const dest = new Buffer();
- let result: number | null;
- while ((result = await chunkedReader.read(buf)) !== null) {
- const len = Math.min(buf.byteLength, result);
- await dest.write(buf.subarray(0, len));
- }
- return decoder.decode(dest.bytes());
-}
-
-Deno.test({ permissions: { net: true } }, async function httpServerBasic() {
- let httpConn: Deno.HttpConn;
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const reqEvent = await httpConn.nextRequest();
- assert(reqEvent);
- const { request, respondWith } = reqEvent;
- assertEquals(new URL(request.url).href, `http://127.0.0.1:${listenPort}/`);
- assertEquals(await request.text(), "");
- await respondWith(
- new Response("Hello World", { headers: { "foo": "bar" } }),
- );
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`, {
- headers: { "connection": "close" },
- });
- const clone = resp.clone();
- const text = await resp.text();
- assertEquals(text, "Hello World");
- assertEquals(resp.headers.get("foo"), "bar");
- const cloneText = await clone.text();
- assertEquals(cloneText, "Hello World");
- await promise;
-
- httpConn!.close();
-});
-
-// https://github.com/denoland/deno/issues/15107
-Deno.test(
- { permissions: { net: true } },
- async function httpLazyHeadersIssue15107() {
- let headers: Headers;
- const promise = (async () => {
- const listener = Deno.listen({ port: 2333 });
- const conn = await listener.accept();
- listener.close();
- const httpConn = Deno.serveHttp(conn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request } = e;
- request.text();
- headers = request.headers;
- httpConn!.close();
- })();
-
- const conn = await Deno.connect({ port: 2333 });
- // Send GET request with a body + content-length.
- const encoder = new TextEncoder();
- const body =
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:2333\r\nContent-Length: 5\r\n\r\n12345`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await promise;
- conn.close();
- assertEquals(headers!.get("content-length"), "5");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpReadHeadersAfterClose() {
- const promise = (async () => {
- const listener = Deno.listen({ port: 2334 });
- const conn = await listener.accept();
- listener.close();
- const httpConn = Deno.serveHttp(conn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
-
- await request.text(); // Read body
- await respondWith(new Response("Hello World")); // Closes request
-
- assertThrows(() => request.headers, TypeError, "request closed");
- httpConn!.close();
- })();
-
- const conn = await Deno.connect({ port: 2334 });
- // Send GET request with a body + content-length.
- const encoder = new TextEncoder();
- const body =
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:2333\r\nContent-Length: 5\r\n\r\n12345`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await promise;
- conn.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerGetRequestBody() {
- let httpConn: Deno.HttpConn;
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.body, null);
- await respondWith(new Response("", { headers: {} }));
- })();
-
- const conn = await Deno.connect({ port: listenPort });
- // Send GET request with a body + content-length.
- const encoder = new TextEncoder();
- const body =
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:${listenPort}\r\nContent-Length: 5\r\n\r\n12345`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- const resp = new Uint8Array(200);
- const readResult = await conn.read(resp);
- assertEquals(readResult, 138);
-
- conn.close();
-
- await promise;
- httpConn!.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerStreamResponse() {
- const stream = new TransformStream();
- const writer = stream.writable.getWriter();
- writer.write(new TextEncoder().encode("hello "));
- writer.write(new TextEncoder().encode("world"));
- writer.close();
-
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ port: listenPort });
- const promise = (async () => {
- const conn = await listener.accept();
- httpConn = Deno.serveHttp(conn);
- const evt = await httpConn.nextRequest();
- assert(evt);
- const { request, respondWith } = evt;
- assert(!request.body);
- await respondWith(new Response(stream.readable));
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`);
- const respBody = await resp.text();
- assertEquals("hello world", respBody);
- await promise;
- httpConn!.close();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerStreamRequest() {
- const stream = new TransformStream();
- const writer = stream.writable.getWriter();
- writer.write(new TextEncoder().encode("hello "));
- writer.write(new TextEncoder().encode("world"));
- writer.close();
-
- const listener = Deno.listen({ port: listenPort });
- const promise = (async () => {
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const evt = await httpConn.nextRequest();
- assert(evt);
- const { request, respondWith } = evt;
- const reqBody = await request.text();
- assertEquals("hello world", reqBody);
- await respondWith(new Response(""));
-
- // TODO(ry) If we don't call httpConn.nextRequest() here we get "error sending
- // request for url (https://localhost:${listenPort}/): connection closed before
- // message completed".
- assertEquals(await httpConn.nextRequest(), null);
-
- listener.close();
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`, {
- body: stream.readable,
- method: "POST",
- headers: { "connection": "close" },
- });
-
- await resp.arrayBuffer();
- await promise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerStreamDuplex() {
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ port: listenPort });
- const promise = (async () => {
- const conn = await listener.accept();
- httpConn = Deno.serveHttp(conn);
- const evt = await httpConn.nextRequest();
- assert(evt);
- const { request, respondWith } = evt;
- assert(request.body);
- await respondWith(new Response(request.body));
- })();
-
- const ts = new TransformStream();
- const writable = ts.writable.getWriter();
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`, {
- method: "POST",
- body: ts.readable,
- });
- assert(resp.body);
- const reader = resp.body.getReader();
- await writable.write(new Uint8Array([1]));
- const chunk1 = await reader.read();
- assert(!chunk1.done);
- assertEquals(chunk1.value, new Uint8Array([1]));
- await writable.write(new Uint8Array([2]));
- const chunk2 = await reader.read();
- assert(!chunk2.done);
- assertEquals(chunk2.value, new Uint8Array([2]));
-
- await writable.close();
- const chunk3 = await reader.read();
- assert(chunk3.done);
- await promise;
- httpConn!.close();
- listener.close();
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function httpServerClose() {
- const listener = Deno.listen({ port: listenPort });
- const client = await Deno.connect({ port: listenPort });
- const httpConn = Deno.serveHttp(await listener.accept());
- client.close();
- const evt = await httpConn.nextRequest();
- assertEquals(evt, null);
- // Note httpConn is automatically closed when "done" is reached.
- listener.close();
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerInvalidMethod() {
- const listener = Deno.listen({ port: listenPort });
- const client = await Deno.connect({ port: listenPort });
- const httpConn = Deno.serveHttp(await listener.accept());
- await client.write(new Uint8Array([1, 2, 3]));
- await assertRejects(
- async () => {
- await httpConn.nextRequest();
- },
- Deno.errors.Http,
- "invalid HTTP method parsed",
- );
- // Note httpConn is automatically closed when it errors.
- client.close();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function httpServerWithTls() {
- const hostname = "localhost";
- const port = listenPort;
-
- const promise = (async () => {
- const listener = Deno.listenTls({
- hostname,
- port,
- cert: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.crt"),
- key: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.key"),
- });
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const evt = await httpConn.nextRequest();
- assert(evt);
- const { respondWith } = evt;
- await respondWith(new Response("Hello World"));
-
- // TODO(ry) If we don't call httpConn.nextRequest() here we get "error sending
- // request for url (https://localhost:${listenPort}/): connection closed before
- // message completed".
- assertEquals(await httpConn.nextRequest(), null);
-
- listener.close();
- })();
-
- const caCert = Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const resp = await fetch(`https://${hostname}:${port}/`, {
- headers: { "connection": "close" },
- client,
- });
- client.close();
- const respBody = await resp.text();
- assertEquals("Hello World", respBody);
- await promise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerRegressionHang() {
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ port: listenPort });
- const promise = (async () => {
- const conn = await listener.accept();
- httpConn = Deno.serveHttp(conn);
- const event = await httpConn.nextRequest();
- assert(event);
- const { request, respondWith } = event;
- const reqBody = await request.text();
- assertEquals("request", reqBody);
- await respondWith(new Response("response"));
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`, {
- method: "POST",
- body: "request",
- });
- const respBody = await resp.text();
- assertEquals("response", respBody);
- await promise;
-
- httpConn!.close();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerCancelBodyOnResponseFailure() {
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const event = await httpConn.nextRequest();
- assert(event);
- const { respondWith } = event;
- let cancelReason: string;
- await assertRejects(
- async () => {
- let interval = 0;
- await respondWith(
- new Response(
- new ReadableStream({
- start(controller) {
- interval = setInterval(() => {
- const message = `data: ${Date.now()}\n\n`;
- controller.enqueue(new TextEncoder().encode(message));
- }, 200);
- },
- cancel(reason) {
- cancelReason = reason;
- clearInterval(interval);
- },
- }),
- ),
- );
- },
- Deno.errors.Http,
- cancelReason!,
- );
- assert(cancelReason!);
- httpConn!.close();
- listener.close();
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`);
- await resp.body!.cancel();
- await promise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerNextRequestErrorExposedInResponse() {
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const event = await httpConn.nextRequest();
- assert(event);
- // Start polling for the next request before awaiting response.
- const nextRequestPromise = httpConn.nextRequest();
- const { respondWith } = event;
- await assertRejects(
- async () => {
- let interval = 0;
- await respondWith(
- new Response(
- new ReadableStream({
- start(controller) {
- interval = setInterval(() => {
- const message = `data: ${Date.now()}\n\n`;
- controller.enqueue(new TextEncoder().encode(message));
- }, 200);
- },
- cancel() {
- clearInterval(interval);
- },
- }),
- ),
- );
- },
- Deno.errors.Http,
- "connection closed",
- );
- // The error from `op_http_accept` reroutes to `respondWith()`.
- assertEquals(await nextRequestPromise, null);
- listener.close();
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`);
- await resp.body!.cancel();
- await promise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerEmptyBlobResponse() {
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ port: listenPort });
- const promise = (async () => {
- const conn = await listener.accept();
- httpConn = Deno.serveHttp(conn);
- const event = await httpConn.nextRequest();
- assert(event);
- const { respondWith } = event;
- await respondWith(new Response(new Blob([])));
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`);
- const respBody = await resp.text();
- assertEquals("", respBody);
- await promise;
- httpConn!.close();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerNextRequestResolvesOnClose() {
- const httpConnList: Deno.HttpConn[] = [];
-
- async function serve(l: Deno.Listener) {
- for await (const conn of l) {
- (async () => {
- const c = Deno.serveHttp(conn);
- httpConnList.push(c);
- for await (const { respondWith } of c) {
- respondWith(new Response("hello"));
- }
- })();
- }
- }
-
- const l = Deno.listen({ port: listenPort });
- serve(l);
-
- await delay(300);
- const res = await fetch(`http://localhost:${listenPort}/`);
- const _text = await res.text();
-
- // Close connection and listener.
- httpConnList.forEach((conn) => conn.close());
- l.close();
-
- await delay(300);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- // Issue: https://github.com/denoland/deno/issues/10870
- async function httpServerHang() {
- // Quick and dirty way to make a readable stream from a string. Alternatively,
- // `readableStreamFromReader(file)` could be used.
- function stream(s: string): ReadableStream<Uint8Array> {
- return new Response(s).body!;
- }
-
- const httpConns: Deno.HttpConn[] = [];
- const promise = (async () => {
- let count = 0;
- const listener = Deno.listen({ port: listenPort });
- for await (const conn of listener) {
- (async () => {
- const httpConn = Deno.serveHttp(conn);
- httpConns.push(httpConn);
- for await (const { respondWith } of httpConn) {
- respondWith(new Response(stream("hello")));
-
- count++;
- if (count >= 2) {
- listener.close();
- }
- }
- })();
- }
- })();
-
- const clientConn = await Deno.connect({ port: listenPort });
-
- const r1 = await writeRequestAndReadResponse(clientConn);
- assertEquals(r1, "hello");
-
- const r2 = await writeRequestAndReadResponse(clientConn);
- assertEquals(r2, "hello");
-
- clientConn.close();
- await promise;
- for (const conn of httpConns) {
- conn.close();
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- // Issue: https://github.com/denoland/deno/issues/10930
- async function httpServerStreamingResponse() {
- // This test enqueues a single chunk for readable
- // stream and waits for client to read that chunk and signal
- // it before enqueueing subsequent chunk. Issue linked above
- // presented a situation where enqueued chunks were not
- // written to the HTTP connection until the next chunk was enqueued.
-
- let counter = 0;
-
- const deferreds = [
- Promise.withResolvers<void>(),
- Promise.withResolvers<void>(),
- Promise.withResolvers<void>(),
- ];
-
- async function writeRequest(conn: Deno.Conn) {
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- const w = new BufWriter(conn);
- const r = new BufReader(conn);
- const body = `GET / HTTP/1.1\r\nHost: 127.0.0.1:${listenPort}\r\n\r\n`;
- const writeResult = await w.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await w.flush();
- const tpr = new TextProtoReader(r);
- const statusLine = await tpr.readLine();
- assert(statusLine !== null);
- const headers = await tpr.readMimeHeader();
- assert(headers !== null);
-
- const chunkedReader = chunkedBodyReader(headers, r);
- const buf = new Uint8Array(5);
- const dest = new Buffer();
- let result: number | null;
- while ((result = await chunkedReader.read(buf)) !== null) {
- const len = Math.min(buf.byteLength, result);
- await dest.write(buf.subarray(0, len));
- // Resolve a deferred - this will make response stream to
- // enqueue next chunk.
- deferreds[counter - 1].resolve();
- }
- return decoder.decode(dest.bytes());
- }
-
- function periodicStream() {
- return new ReadableStream({
- start(controller) {
- controller.enqueue(`${counter}\n`);
- counter++;
- },
-
- async pull(controller) {
- if (counter >= 3) {
- return controller.close();
- }
-
- await deferreds[counter - 1].promise;
-
- controller.enqueue(`${counter}\n`);
- counter++;
- },
- }).pipeThrough(new TextEncoderStream());
- }
-
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ port: listenPort });
- const finished = (async () => {
- const conn = await listener.accept();
- httpConn = Deno.serveHttp(conn);
- const requestEvent = await httpConn.nextRequest();
- const { respondWith } = requestEvent!;
- await respondWith(new Response(periodicStream()));
- })();
-
- // start a client
- const clientConn = await Deno.connect({ port: listenPort });
-
- const r1 = await writeRequest(clientConn);
- assertEquals(r1, "0\n1\n2\n");
-
- await finished;
- clientConn.close();
-
- httpConn!.close();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpRequestLatin1Headers() {
- let httpConn: Deno.HttpConn;
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const reqEvent = await httpConn.nextRequest();
- assert(reqEvent);
- const { request, respondWith } = reqEvent;
- assertEquals(request.headers.get("X-Header-Test"), "á");
- await respondWith(
- new Response("", { headers: { "X-Header-Test": "Æ" } }),
- );
- })();
-
- const clientConn = await Deno.connect({ port: listenPort });
- const requestText =
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:${listenPort}\r\nX-Header-Test: á\r\n\r\n`;
- const requestBytes = new Uint8Array(requestText.length);
- for (let i = 0; i < requestText.length; i++) {
- requestBytes[i] = requestText.charCodeAt(i);
- }
- let written = 0;
- while (written < requestBytes.byteLength) {
- written += await clientConn.write(requestBytes.slice(written));
- }
-
- let responseText = "";
- const buf = new Uint8Array(1024);
- let read;
-
- while ((read = await clientConn.read(buf)) !== null) {
- httpConn!.close();
- for (let i = 0; i < read; i++) {
- responseText += String.fromCharCode(buf[i]);
- }
- }
-
- clientConn.close();
-
- assert(/\r\n[Xx]-[Hh]eader-[Tt]est: Æ\r\n/.test(responseText));
-
- await promise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerRequestWithoutPath() {
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ port: listenPort });
- const promise = (async () => {
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const reqEvent = await httpConn.nextRequest();
- assert(reqEvent);
- const { request, respondWith } = reqEvent;
- assertEquals(
- new URL(request.url).href,
- `http://127.0.0.1:${listenPort}/`,
- );
- assertEquals(await request.text(), "");
- await respondWith(new Response());
- })();
-
- const clientConn = await Deno.connect({ port: listenPort });
-
- async function writeRequest(conn: Deno.Conn) {
- const encoder = new TextEncoder();
-
- const w = new BufWriter(conn);
- const r = new BufReader(conn);
- const body =
- `CONNECT 127.0.0.1:${listenPort} HTTP/1.1\r\nHost: 127.0.0.1:${listenPort}\r\n\r\n`;
- const writeResult = await w.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await w.flush();
- const tpr = new TextProtoReader(r);
- const statusLine = await tpr.readLine();
- assert(statusLine !== null);
- const m = statusLine.match(/^(.+?) (.+?) (.+?)$/);
- assert(m !== null, "must be matched");
- const [_, _proto, status, _ok] = m;
- assertEquals(status, "200");
- const headers = await tpr.readMimeHeader();
- assert(headers !== null);
- }
-
- await writeRequest(clientConn);
- clientConn.close();
- await promise;
- httpConn!.close();
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function httpServerWebSocket() {
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- listener.close();
- const httpConn = Deno.serveHttp(conn);
- const reqEvent = await httpConn.nextRequest();
- assert(reqEvent);
- const { request, respondWith } = reqEvent;
- const {
- response,
- socket,
- } = Deno.upgradeWebSocket(request);
- socket.onerror = () => fail();
- socket.onmessage = (m) => {
- socket.send(m.data);
- socket.close(1001);
- };
- const close = new Promise<void>((resolve) => {
- socket.onclose = () => resolve();
- });
- await respondWith(response);
- await close;
- })();
-
- const def = Promise.withResolvers<void>();
- const ws = new WebSocket(`ws://localhost:${listenPort}`);
- ws.onmessage = (m) => assertEquals(m.data, "foo");
- ws.onerror = () => fail();
- ws.onclose = () => def.resolve();
- ws.onopen = () => ws.send("foo");
- await def.promise;
- await promise;
-});
-
-Deno.test(function httpUpgradeWebSocket() {
- const request = new Request("https://deno.land/", {
- headers: {
- connection: "Upgrade",
- upgrade: "websocket",
- "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==",
- },
- });
- const { response } = Deno.upgradeWebSocket(request);
- assertEquals(response.status, 101);
- assertEquals(response.headers.get("connection"), "Upgrade");
- assertEquals(response.headers.get("upgrade"), "websocket");
- assertEquals(
- response.headers.get("sec-websocket-accept"),
- "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
- );
-});
-
-Deno.test(function httpUpgradeWebSocketMultipleConnectionOptions() {
- const request = new Request("https://deno.land/", {
- headers: {
- connection: "keep-alive, upgrade",
- upgrade: "websocket",
- "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==",
- },
- });
- const { response } = Deno.upgradeWebSocket(request);
- assertEquals(response.status, 101);
-});
-
-Deno.test(function httpUpgradeWebSocketMultipleUpgradeOptions() {
- const request = new Request("https://deno.land/", {
- headers: {
- connection: "upgrade",
- upgrade: "websocket, foo",
- "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==",
- },
- });
- const { response } = Deno.upgradeWebSocket(request);
- assertEquals(response.status, 101);
-});
-
-Deno.test(function httpUpgradeWebSocketCaseInsensitiveUpgradeHeader() {
- const request = new Request("https://deno.land/", {
- headers: {
- connection: "upgrade",
- upgrade: "Websocket",
- "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==",
- },
- });
- const { response } = Deno.upgradeWebSocket(request);
- assertEquals(response.status, 101);
-});
-
-Deno.test(function httpUpgradeWebSocketInvalidUpgradeHeader() {
- assertThrows(
- () => {
- const request = new Request("https://deno.land/", {
- headers: {
- connection: "upgrade",
- upgrade: "invalid",
- "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==",
- },
- });
- Deno.upgradeWebSocket(request);
- },
- TypeError,
- "Invalid Header: 'upgrade' header must contain 'websocket'",
- );
-});
-
-Deno.test(function httpUpgradeWebSocketWithoutUpgradeHeader() {
- assertThrows(
- () => {
- const request = new Request("https://deno.land/", {
- headers: {
- connection: "upgrade",
- "sec-websocket-key": "dGhlIHNhbXBsZSBub25jZQ==",
- },
- });
- Deno.upgradeWebSocket(request);
- },
- TypeError,
- "Invalid Header: 'upgrade' header must contain 'websocket'",
- );
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function httpCookieConcatenation() {
- let httpConn: Deno.HttpConn;
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const reqEvent = await httpConn.nextRequest();
- assert(reqEvent);
- const { request, respondWith } = reqEvent;
- assertEquals(
- new URL(request.url).href,
- `http://127.0.0.1:${listenPort}/`,
- );
- assertEquals(await request.text(), "");
- assertEquals(request.headers.get("cookie"), "foo=bar; bar=foo");
- await respondWith(new Response("ok"));
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`, {
- headers: [
- ["connection", "close"],
- ["cookie", "foo=bar"],
- ["cookie", "bar=foo"],
- ],
- });
- const text = await resp.text();
- assertEquals(text, "ok");
- await promise;
- httpConn!.close();
- },
-);
-
-// https://github.com/denoland/deno/issues/11651
-Deno.test({ permissions: { net: true } }, async function httpServerPanic() {
- const listener = Deno.listen({ port: listenPort });
- const client = await Deno.connect({ port: listenPort });
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
-
- // This message is incomplete on purpose, we'll forcefully close client connection
- // after it's flushed to cause connection to error out on the server side.
- const encoder = new TextEncoder();
- await client.write(encoder.encode("GET / HTTP/1.1"));
-
- httpConn.nextRequest();
- await client.write(encoder.encode("\r\n\r\n"));
- httpConn!.close();
-
- client.close();
- listener.close();
-});
-
-Deno.test(
- { permissions: { net: true, write: true, read: true } },
- async function httpServerCorrectSizeResponse() {
- const tmpFile = await Deno.makeTempFile();
- using file = await Deno.open(tmpFile, { write: true, read: true });
- await file.write(new Uint8Array(70 * 1024).fill(1)); // 70kb sent in 64kb + 6kb chunks
-
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ port: listenPort });
- const promise = (async () => {
- const conn = await listener.accept();
- httpConn = Deno.serveHttp(conn);
- const ev = await httpConn.nextRequest();
- const { respondWith } = ev!;
- const f = await Deno.open(tmpFile, { read: true });
- await respondWith(new Response(f.readable, { status: 200 }));
- })();
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`);
- const body = await resp.arrayBuffer();
- assertEquals(body.byteLength, 70 * 1024);
- await promise;
- httpConn!.close();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true, write: true, read: true } },
- async function httpServerClosedStream() {
- const listener = Deno.listen({ port: listenPort });
-
- const client = await Deno.connect({ port: listenPort });
- await client.write(new TextEncoder().encode(
- `GET / HTTP/1.0\r\n\r\n`,
- ));
-
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const ev = await httpConn.nextRequest();
- const { respondWith } = ev!;
-
- const tmpFile = await Deno.makeTempFile();
- const file = await Deno.open(tmpFile, { write: true, read: true });
- await file.write(new TextEncoder().encode("hello"));
-
- const reader = await file.readable.getReader();
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
- assert(value);
- }
-
- let didThrow = false;
- try {
- await respondWith(new Response(file.readable));
- } catch {
- // pass
- didThrow = true;
- }
-
- assert(didThrow);
- httpConn!.close();
- listener.close();
- client.close();
- },
-);
-
-// https://github.com/denoland/deno/issues/11595
-Deno.test(
- { permissions: { net: true } },
- async function httpServerIncompleteMessage() {
- const listener = Deno.listen({ port: listenPort });
-
- const client = await Deno.connect({ port: listenPort });
- await client.write(new TextEncoder().encode(
- `GET / HTTP/1.0\r\n\r\n`,
- ));
-
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const ev = await httpConn.nextRequest();
- const { respondWith } = ev!;
-
- const errors: Error[] = [];
-
- const readable = new ReadableStream({
- async pull(controller) {
- client.close();
- await delay(1000);
- controller.enqueue(new TextEncoder().encode(
- "written to the writable side of a TransformStream",
- ));
- controller.close();
- },
- cancel(error) {
- errors.push(error);
- },
- });
-
- const res = new Response(readable);
-
- await respondWith(res).catch((error: Error) => errors.push(error));
-
- httpConn!.close();
- listener.close();
-
- assert(errors.length >= 1);
- for (const error of errors) {
- assertEquals(error.name, "Http");
- assert(error.message.includes("connection"));
- }
- },
-);
-
-// https://github.com/denoland/deno/issues/11743
-Deno.test(
- { permissions: { net: true } },
- async function httpServerDoesntLeakResources() {
- const listener = Deno.listen({ port: listenPort });
- const [conn, clientConn] = await Promise.all([
- listener.accept(),
- Deno.connect({ port: listenPort }),
- ]);
- const httpConn = Deno.serveHttp(conn);
-
- await Promise.all([
- httpConn.nextRequest(),
- clientConn.write(new TextEncoder().encode(
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:${listenPort}\r\n\r\n`,
- )),
- ]);
-
- httpConn!.close();
- listener.close();
- clientConn.close();
- },
-);
-
-// https://github.com/denoland/deno/issues/11926
-// verify that the only new resource is "httpConnection", to make
-// sure "request" resource is closed even if its body was not read
-// by server handler
-Deno.test(
- { permissions: { net: true } },
- async function httpServerDoesntLeakResources2() {
- let listener: Deno.Listener;
- let httpConn: Deno.HttpConn;
-
- const promise = (async () => {
- listener = Deno.listen({ port: listenPort });
- for await (const conn of listener) {
- httpConn = Deno.serveHttp(conn);
- for await (const { request, respondWith } of httpConn) {
- assertEquals(
- new URL(request.url).href,
- `http://127.0.0.1:${listenPort}/`,
- );
- // not reading request body on purpose
- respondWith(new Response("ok"));
- }
- }
- })();
-
- const response = await fetch(`http://127.0.0.1:${listenPort}`, {
- method: "POST",
- body: "hello world",
- });
- await response.text();
-
- listener!.close();
- httpConn!.close();
- await promise;
- },
-);
-
-// https://github.com/denoland/deno/pull/12216
-Deno.test(
- { permissions: { net: true } },
- async function droppedConnSenderNoPanic() {
- async function server() {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- const http = Deno.serveHttp(conn);
- const evt = await http.nextRequest();
- http.close();
- try {
- await evt!.respondWith(new Response("boom"));
- } catch {
- // Ignore error.
- }
- listener.close();
- }
-
- async function client() {
- try {
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`);
- await resp.body?.cancel();
- } catch {
- // Ignore error
- }
- }
-
- await Promise.all([server(), client()]);
- },
-);
-
-// https://github.com/denoland/deno/issues/12193
-Deno.test(
- { permissions: { net: true } },
- async function httpConnConcurrentNextRequestCalls() {
- const hostname = "localhost";
- const port = listenPort;
-
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ hostname, port });
- async function server() {
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const promises = new Array(10).fill(null).map(async (_, i) => {
- const event = await httpConn.nextRequest();
- assert(event);
- const { pathname } = new URL(event.request.url);
- assertStrictEquals(pathname, `/${i}`);
- const response = new Response(`Response #${i}`);
- await event.respondWith(response);
- });
- await Promise.all(promises);
- }
-
- async function client() {
- for (let i = 0; i < 10; i++) {
- const response = await fetch(`http://${hostname}:${port}/${i}`);
- const body = await response.text();
- assertStrictEquals(body, `Response #${i}`);
- }
- }
-
- await Promise.all([server(), delay(100).then(client)]);
- httpConn!.close();
- listener.close();
- },
-);
-
-// https://github.com/denoland/deno/pull/12704
-// https://github.com/denoland/deno/pull/12732
-Deno.test(
- { permissions: { net: true } },
- async function httpConnAutoCloseDelayedOnUpgrade() {
- const hostname = "localhost";
- const port = listenPort;
-
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- const httpConn = Deno.serveHttp(tcpConn);
-
- const event1 = await httpConn.nextRequest() as Deno.RequestEvent;
- const event2Promise = httpConn.nextRequest();
-
- const { socket, response } = Deno.upgradeWebSocket(event1.request);
- socket.onmessage = (event) => socket.send(event.data);
- const socketClosed = new Promise<void>((resolve) => {
- socket.onclose = () => resolve();
- });
- event1.respondWith(response);
-
- const event2 = await event2Promise;
- assertStrictEquals(event2, null);
-
- listener.close();
- await socketClosed;
- }
-
- async function client() {
- const socket = new WebSocket(`ws://${hostname}:${port}/`);
- socket.onopen = () => socket.send("bla bla");
- const closed = new Promise<void>((resolve) => {
- socket.onclose = () => resolve();
- });
- const { data } = await new Promise<MessageEvent<string>>((res) =>
- socket.onmessage = res
- );
- assertStrictEquals(data, "bla bla");
- socket.close();
- await closed;
- }
-
- await Promise.all([server(), client()]);
- },
-);
-
-// https://github.com/denoland/deno/issues/12741
-// https://github.com/denoland/deno/pull/12746
-// https://github.com/denoland/deno/pull/12798
-Deno.test(
- { permissions: { net: true, run: true } },
- async function httpServerDeleteRequestHasBody() {
- const hostname = "localhost";
- const port = listenPort;
-
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ hostname, port });
- async function server() {
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const event = await httpConn.nextRequest() as Deno.RequestEvent;
- assert(event.request.body);
- const response = new Response();
- await event.respondWith(response);
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = ["-X", "DELETE", url];
- const { success } = await new Deno.Command("curl", {
- args,
- stdout: "null",
- stderr: "null",
- }).output();
- assert(success);
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerRespondNonAsciiUint8Array() {
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ port: listenPort });
- const promise = (async () => {
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.body, null);
- await respondWith(
- new Response(new Uint8Array([128]), {}),
- );
- })();
-
- const resp = await fetch(`http://localhost:${listenPort}/`);
- assertEquals(resp.status, 200);
- const body = await resp.arrayBuffer();
- assertEquals(new Uint8Array(body), new Uint8Array([128]));
-
- await promise;
- httpConn!.close();
- },
-);
-
-function tmpUnixSocketPath(): string {
- const folder = Deno.makeTempDirSync();
- return join(folder, "socket");
-}
-
-// https://github.com/denoland/deno/pull/13628
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function httpServerOnUnixSocket() {
- const filePath = tmpUnixSocketPath();
-
- let httpConn: Deno.HttpConn;
- const promise = (async () => {
- const listener = Deno.listen({ path: filePath, transport: "unix" });
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const reqEvent = await httpConn.nextRequest();
- assert(reqEvent);
- const { request, respondWith } = reqEvent;
- const url = new URL(request.url);
- assertEquals(url.protocol, "http+unix:");
- assertEquals(decodeURIComponent(url.host), filePath);
- assertEquals(url.pathname, "/path/name");
- await respondWith(new Response("", { headers: {} }));
- })();
-
- // fetch() does not supports unix domain sockets yet https://github.com/denoland/deno/issues/8821
- const conn = await Deno.connect({ path: filePath, transport: "unix" });
- const encoder = new TextEncoder();
- // The Host header must be present and empty if it is not a Internet host name (RFC2616, Section 14.23)
- const body = `GET /path/name HTTP/1.1\r\nHost:\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- const resp = new Uint8Array(200);
- const readResult = await conn.read(resp);
- assertEquals(readResult, 138);
-
- conn.close();
-
- await promise;
- httpConn!.close();
- },
-);
-
-/* Automatic Body Compression */
-
-const decoder = new TextDecoder();
-
-Deno.test({
- name: "http server compresses body - check headers",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
- const listener = Deno.listen({ hostname, port });
-
- const data = { hello: "deno", now: "with", compressed: "body" };
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const response = new Response(JSON.stringify(data), {
- headers: { "content-type": "application/json" },
- });
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout);
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(output.includes("content-encoding: gzip\r\n"));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server compresses body - check body",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
- const listener = Deno.listen({ hostname, port });
-
- const data = { hello: "deno", now: "with", compressed: "body" };
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const response = new Response(JSON.stringify(data), {
- headers: { "content-type": "application/json" },
- });
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const proc = new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).spawn();
- const status = await proc.status;
- assert(status.success);
- const stdout = proc.stdout
- .pipeThrough(new DecompressionStream("gzip"))
- .pipeThrough(new TextDecoderStream());
- let body = "";
- for await (const chunk of stdout) {
- body += chunk;
- }
- assertEquals(JSON.parse(body), data);
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server doesn't compress small body",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const response = new Response(
- JSON.stringify({ hello: "deno" }),
- {
- headers: { "content-type": "application/json" },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout).toLocaleLowerCase();
- assert(output.includes("vary: accept-encoding\r\n"));
- assert(!output.includes("content-encoding: "));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server respects accept-encoding weights",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(
- request.headers.get("Accept-Encoding"),
- "gzip;q=0.8, br;q=1.0, *;q=0.1",
- );
- const response = new Response(
- JSON.stringify({ hello: "deno", now: "with", compressed: "body" }),
- {
- headers: { "content-type": "application/json" },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip;q=0.8, br;q=1.0, *;q=0.1",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout);
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(output.includes("content-encoding: br\r\n"));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server augments vary header",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const response = new Response(
- JSON.stringify({ hello: "deno", now: "with", compressed: "body" }),
- {
- headers: { "content-type": "application/json", vary: "Accept" },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout);
- assert(output.includes("vary: Accept-Encoding, Accept\r\n"));
- assert(output.includes("content-encoding: gzip\r\n"));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server weakens etag header",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const response = new Response(
- JSON.stringify({ hello: "deno", now: "with", compressed: "body" }),
- {
- headers: {
- "content-type": "application/json",
- etag: "33a64df551425fcc55e4d42a148795d9f25f89d4",
- },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "curl",
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout);
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(
- output.includes("etag: W/33a64df551425fcc55e4d42a148795d9f25f89d4\r\n"),
- );
- assert(output.includes("content-encoding: gzip\r\n"));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server passes through weak etag header",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const response = new Response(
- JSON.stringify({ hello: "deno", now: "with", compressed: "body" }),
- {
- headers: {
- "content-type": "application/json",
- etag: "W/33a64df551425fcc55e4d42a148795d9f25f89d4",
- },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout);
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(
- output.includes("etag: W/33a64df551425fcc55e4d42a148795d9f25f89d4\r\n"),
- );
- assert(output.includes("content-encoding: gzip\r\n"));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server doesn't compress body when no-transform is set",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const response = new Response(
- JSON.stringify({ hello: "deno", now: "with", compressed: "body" }),
- {
- headers: {
- "content-type": "application/json",
- "cache-control": "no-transform",
- },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout);
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(!output.includes("content-encoding: "));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server doesn't compress body when content-range is set",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const response = new Response(
- JSON.stringify({ hello: "deno", now: "with", compressed: "body" }),
- {
- headers: {
- "content-type": "application/json",
- "content-range": "bytes 200-100/67589",
- },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout);
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(!output.includes("content-encoding: "));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server compresses streamed bodies - check headers",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- const encoder = new TextEncoder();
- const listener = Deno.listen({ hostname, port });
-
- const data = { hello: "deno", now: "with", compressed: "body" };
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const bodyInit = new ReadableStream({
- start(controller) {
- controller.enqueue(encoder.encode(JSON.stringify(data)));
- controller.close();
- },
- });
- const response = new Response(
- bodyInit,
- { headers: { "content-type": "application/json" } },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "curl",
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout);
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(output.includes("content-encoding: gzip\r\n"));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server compresses streamed bodies - check body",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- const encoder = new TextEncoder();
- const listener = Deno.listen({ hostname, port });
-
- const data = { hello: "deno", now: "with", compressed: "body" };
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const bodyInit = new ReadableStream({
- start(controller) {
- controller.enqueue(encoder.encode(JSON.stringify(data)));
- controller.close();
- },
- });
- const response = new Response(
- bodyInit,
- { headers: { "content-type": "application/json" } },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const proc = new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).spawn();
- const status = await proc.status;
- assert(status.success);
- const stdout = proc.stdout
- .pipeThrough(new DecompressionStream("gzip"))
- .pipeThrough(new TextDecoderStream());
- let body = "";
- for await (const chunk of stdout) {
- body += chunk;
- }
- assertEquals(JSON.parse(body), data);
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server updates content-length header if compression is applied",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
- let contentLength: string;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const body = JSON.stringify({
- hello: "deno",
- now: "with",
- compressed: "body",
- });
- contentLength = String(body.length);
- const response = new Response(
- body,
- {
- headers: {
- "content-type": "application/json",
- "content-length": contentLength,
- },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- ];
- const { success, stdout } = await new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).output();
- assert(success);
- const output = decoder.decode(stdout);
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(output.includes("content-encoding: gzip\r\n"));
- // Ensure the content-length header is updated (but don't check the exact length).
- assert(!output.includes(`content-length: ${contentLength}\r\n`));
- assert(output.includes("content-length: "));
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server compresses when accept-encoding is deflate, gzip",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
- let contentLength: string;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "deflate, gzip");
- const body = "x".repeat(10000);
- contentLength = String(body.length);
- const response = new Response(
- body,
- {
- headers: {
- "content-length": contentLength,
- },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const cmd = [
- "curl",
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- // "--compressed", // Windows curl does not support --compressed
- "--header",
- "Accept-Encoding: deflate, gzip",
- ];
- // deno-lint-ignore no-deprecated-deno-api
- const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" });
- const status = await proc.status();
- assert(status.success);
- const output = decoder.decode(await proc.output());
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(output.includes("content-encoding: gzip\r\n"));
- // Ensure the content-length header is updated.
- assert(!output.includes(`content-length: ${contentLength}\r\n`));
- assert(output.includes("content-length: "));
- proc.close();
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test({
- name: "http server custom content-encoding is left untouched",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
- let contentLength: string;
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const listener = Deno.listen({ hostname, port });
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "deflate, gzip");
- const body = new Uint8Array([3, 1, 4, 1]);
- contentLength = String(body.length);
- const response = new Response(
- body,
- {
- headers: {
- "content-length": contentLength,
- "content-encoding": "arbitrary",
- },
- },
- );
- await respondWith(response);
- listener.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const cmd = [
- "curl",
- "-i",
- "--request",
- "GET",
- "--url",
- url,
- // "--compressed", // Windows curl does not support --compressed
- "--header",
- "Accept-Encoding: deflate, gzip",
- ];
- // deno-lint-ignore no-deprecated-deno-api
- const proc = Deno.run({ cmd, stdout: "piped", stderr: "null" });
- const status = await proc.status();
- assert(status.success);
- const output = decoder.decode(await proc.output());
- assert(output.includes("vary: Accept-Encoding\r\n"));
- assert(output.includes("content-encoding: arbitrary\r\n"));
- proc.close();
- }
-
- await Promise.all([server(), client()]);
- httpConn!.close();
- },
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerReadLargeBodyWithContentLength() {
- const TLS_PACKET_SIZE = 16 * 1024 + 256;
- // We want the body to be read in multiple packets
- const body = "aa\n" + "deno.land large body\n".repeat(TLS_PACKET_SIZE) +
- "zz";
-
- let httpConn: Deno.HttpConn;
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const reqEvent = await httpConn.nextRequest();
- assert(reqEvent);
- const { request, respondWith } = reqEvent;
- assertEquals(await request.text(), body);
- await respondWith(new Response(body));
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`, {
- method: "POST",
- headers: { "connection": "close" },
- body,
- });
- const text = await resp.text();
- assertEquals(text, body);
- await promise;
-
- httpConn!.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerReadLargeBodyWithTransferChunked() {
- const TLS_PACKET_SIZE = 16 * 1024 + 256;
-
- // We want the body to be read in multiple packets
- const chunks = [
- "aa\n",
- "deno.land large body\n".repeat(TLS_PACKET_SIZE),
- "zz",
- ];
-
- const body = chunks.join("");
-
- const stream = new TransformStream();
- const writer = stream.writable.getWriter();
- for (const chunk of chunks) {
- writer.write(new TextEncoder().encode(chunk));
- }
- writer.close();
-
- let httpConn: Deno.HttpConn;
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const reqEvent = await httpConn.nextRequest();
- assert(reqEvent);
- const { request, respondWith } = reqEvent;
- assertEquals(await request.text(), body);
- await respondWith(new Response(body));
- })();
-
- const resp = await fetch(`http://127.0.0.1:${listenPort}/`, {
- method: "POST",
- headers: { "connection": "close" },
- body: stream.readable,
- });
- const text = await resp.text();
- assertEquals(text, body);
- await promise;
-
- httpConn!.close();
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function httpServerWithoutExclusiveAccessToTcp() {
- const port = listenPort;
- const listener = Deno.listen({ port });
-
- const [clientConn, serverConn] = await Promise.all([
- Deno.connect({ port }),
- listener.accept(),
- ]);
-
- const buf = new Uint8Array(128);
- const readPromise = serverConn.read(buf);
- assertThrows(() => Deno.serveHttp(serverConn), Deno.errors.BadResource);
-
- clientConn.close();
- listener.close();
- await readPromise;
- },
-);
-
-Deno.test(
- {
- permissions: { net: true, read: true },
- },
- async function httpServerWithoutExclusiveAccessToTls() {
- const hostname = "localhost";
- const port = listenPort;
- const listener = Deno.listenTls({
- hostname,
- port,
- cert: await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"),
- key: await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"),
- });
-
- const caCerts = [
- await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem"),
- ];
- const [clientConn, serverConn] = await Promise.all([
- Deno.connectTls({ hostname, port, caCerts }),
- listener.accept(),
- ]);
- await Promise.all([clientConn.handshake(), serverConn.handshake()]);
-
- const buf = new Uint8Array(128);
- const readPromise = serverConn.read(buf);
- assertThrows(() => Deno.serveHttp(serverConn), Deno.errors.BadResource);
-
- clientConn.close();
- listener.close();
- await readPromise;
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function httpServerWithoutExclusiveAccessToUnixSocket() {
- const filePath = tmpUnixSocketPath();
- const listener = Deno.listen({ path: filePath, transport: "unix" });
-
- const [clientConn, serverConn] = await Promise.all([
- Deno.connect({ path: filePath, transport: "unix" }),
- listener.accept(),
- ]);
-
- const buf = new Uint8Array(128);
- const readPromise = serverConn.read(buf);
- assertThrows(() => Deno.serveHttp(serverConn), Deno.errors.BadResource);
-
- clientConn.close();
- listener.close();
- await readPromise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerRequestResponseClone() {
- const body = "deno".repeat(64 * 1024);
- let httpConn: Deno.HttpConn;
- const listener = Deno.listen({ port: listenPort });
- const promise = (async () => {
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const reqEvent = await httpConn.nextRequest();
- assert(reqEvent);
- const { request, respondWith } = reqEvent;
- const clone = request.clone();
- const reader = clone.body!.getReader();
-
- // get first chunk from branch2
- const clonedChunks = [];
- const { value, done } = await reader.read();
- assert(!done);
- clonedChunks.push(value);
-
- // consume request after first chunk single read
- // readAll should read correctly the rest of the body.
- // firstChunk should be in the stream internal buffer
- const body1 = await request.text();
-
- while (true) {
- const { value, done } = await reader.read();
- if (done) break;
- clonedChunks.push(value);
- }
- let offset = 0;
- const body2 = new Uint8Array(body.length);
- for (const chunk of clonedChunks) {
- body2.set(chunk, offset);
- offset += chunk.byteLength;
- }
-
- assertEquals(body1, body);
- assertEquals(body1, new TextDecoder().decode(body2));
- await respondWith(new Response(body));
- })();
-
- const response = await fetch(`http://localhost:${listenPort}`, {
- body,
- method: "POST",
- });
- const clone = response.clone();
- assertEquals(await response.text(), await clone.text());
-
- await promise;
- httpConn!.close();
- },
-);
-
-Deno.test({
- name: "http server compresses and flushes each chunk of a streamed resource",
- permissions: { net: true, run: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
- const port2 = listenPort2;
-
- const encoder = new TextEncoder();
- const listener = Deno.listen({ hostname, port });
- const listener2 = Deno.listen({ hostname, port: port2 });
-
- let httpConn: Deno.HttpConn;
- async function server() {
- const tcpConn = await listener.accept();
- httpConn = Deno.serveHttp(tcpConn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { request, respondWith } = e;
- assertEquals(request.headers.get("Accept-Encoding"), "gzip, deflate, br");
- const resp = await fetch(`http://${hostname}:${port2}/`);
- await respondWith(resp);
- listener.close();
- }
-
- const ts = new TransformStream();
- const writer = ts.writable.getWriter();
- writer.write(encoder.encode("hello"));
-
- let httpConn2: Deno.HttpConn;
- async function server2() {
- const tcpConn = await listener2.accept();
- httpConn2 = Deno.serveHttp(tcpConn);
- const e = await httpConn2.nextRequest();
- assert(e);
- await e.respondWith(
- new Response(ts.readable, {
- headers: { "Content-Type": "text/plain" },
- }),
- );
- listener2.close();
- }
-
- async function client() {
- const url = `http://${hostname}:${port}/`;
- const args = [
- "--request",
- "GET",
- "--url",
- url,
- "--header",
- "Accept-Encoding: gzip, deflate, br",
- "--no-buffer",
- ];
- const proc = new Deno.Command("curl", {
- args,
- stderr: "null",
- stdout: "piped",
- }).spawn();
- const stdout = proc.stdout
- .pipeThrough(new DecompressionStream("gzip"))
- .pipeThrough(new TextDecoderStream());
- let body = "";
- for await (const chunk of stdout) {
- body += chunk;
- if (body === "hello") {
- writer.write(encoder.encode(" world"));
- writer.close();
- }
- }
- assertEquals(body, "hello world");
- const status = await proc.status;
- assert(status.success);
- }
-
- await Promise.all([server(), server2(), client()]);
- httpConn!.close();
- httpConn2!.close();
- },
-});
-
-Deno.test("case insensitive comma value finder", async (t) => {
- const cases = /** @type {[string, boolean][]} */ ([
- ["websocket", true],
- ["wEbSOcKET", true],
- [",wEbSOcKET", true],
- [",wEbSOcKET,", true],
- [", wEbSOcKET ,", true],
- ["test, wEbSOcKET ,", true],
- ["test ,\twEbSOcKET\t\t ,", true],
- ["test , wEbSOcKET", true],
- ["test, asdf,web,wEbSOcKET", true],
- ["test, asdf,web,wEbSOcKETs", false],
- ["test, asdf,awebsocket,wEbSOcKETs", false],
- ]);
-
- const findValue = buildCaseInsensitiveCommaValueFinder("websocket");
- for (const [input, expected] of cases) {
- await t.step(input.toString(), () => {
- const actual = findValue(input);
- assertEquals(actual, expected);
- });
- }
-});
-
-async function httpServerWithErrorBody(
- listener: Deno.Listener,
- compression: boolean,
-): Promise<Deno.HttpConn> {
- const conn = await listener.accept();
- listener.close();
- const httpConn = Deno.serveHttp(conn);
- const e = await httpConn.nextRequest();
- assert(e);
- const { respondWith } = e;
- const originalErr = new Error("boom");
- const rs = new ReadableStream({
- async start(controller) {
- controller.enqueue(new Uint8Array([65]));
- await delay(1000);
- controller.error(originalErr);
- },
- });
- const init = compression ? { headers: { "content-type": "text/plain" } } : {};
- const response = new Response(rs, init);
- const err = await assertRejects(() => respondWith(response));
- assert(err === originalErr);
- return httpConn;
-}
-
-for (const compression of [true, false]) {
- Deno.test({
- name: `http server errors stream if response body errors (http/1.1${
- compression ? " + compression" : ""
- })`,
- permissions: { net: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- const listener = Deno.listen({ hostname, port });
- const server = httpServerWithErrorBody(listener, compression);
-
- const conn = await Deno.connect({ hostname, port });
- const msg = new TextEncoder().encode(
- `GET / HTTP/1.1\r\nHost: ${hostname}:${port}\r\n\r\n`,
- );
- const nwritten = await conn.write(msg);
- assertEquals(nwritten, msg.byteLength);
-
- const buf = new Uint8Array(1024);
- const nread = await conn.read(buf);
- assert(nread);
- const data = new TextDecoder().decode(buf.subarray(0, nread));
- assert(data.endsWith("1\r\nA\r\n"));
- const nread2 = await conn.read(buf); // connection should be closed now because the stream errored
- assertEquals(nread2, null);
- conn.close();
-
- const httpConn = await server;
- httpConn.close();
- },
- });
-
- Deno.test({
- name: `http server errors stream if response body errors (http/1.1 + fetch${
- compression ? " + compression" : ""
- })`,
- permissions: { net: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- const listener = Deno.listen({ hostname, port });
- const server = httpServerWithErrorBody(listener, compression);
-
- const resp = await fetch(`http://${hostname}:${port}/`);
- assert(resp.body);
- const reader = resp.body.getReader();
- const result = await reader.read();
- assert(!result.done);
- assertEquals(result.value, new Uint8Array([65]));
- const err = await assertRejects(() => reader.read());
- assert(err instanceof TypeError);
- assert(err.message.includes("unexpected EOF"));
-
- const httpConn = await server;
- httpConn.close();
- },
- });
-
- Deno.test({
- name: `http server errors stream if response body errors (http/2 + fetch${
- compression ? " + compression" : ""
- }))`,
- permissions: { net: true, read: true },
- async fn() {
- const hostname = "localhost";
- const port = listenPort;
-
- const listener = Deno.listenTls({
- hostname,
- port,
- cert: await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"),
- key: await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"),
- alpnProtocols: ["h2"],
- });
- const server = httpServerWithErrorBody(listener, compression);
-
- const caCert = Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const resp = await fetch(`https://${hostname}:${port}/`, { client });
- client.close();
- assert(resp.body);
- const reader = resp.body.getReader();
- const result = await reader.read();
- assert(!result.done);
- assertEquals(result.value, new Uint8Array([65]));
- const err = await assertRejects(() => reader.read());
- assert(err instanceof TypeError);
- assert(err.message.includes("unexpected internal error encountered"));
-
- const httpConn = await server;
- httpConn.close();
- },
- });
-}
-
-Deno.test({
- name: "request signal is aborted when response errors",
- permissions: { net: true },
- async fn() {
- let httpConn: Deno.HttpConn;
- const promise = (async () => {
- const listener = Deno.listen({ port: listenPort });
- const conn = await listener.accept();
- listener.close();
- httpConn = Deno.serveHttp(conn);
- const ev = await httpConn.nextRequest();
- const { request, respondWith } = ev!;
-
- await delay(300);
- await assertRejects(() => respondWith(new Response("Hello World")));
- assert(request.signal.aborted);
- })();
-
- const abortController = new AbortController();
-
- fetch(`http://127.0.0.1:${listenPort}/`, {
- signal: abortController.signal,
- }).catch(() => {
- // ignore
- });
-
- await delay(100);
- abortController.abort();
- await promise;
- httpConn!.close();
- },
-});
-
-Deno.test(
- async function httpConnExplicitResourceManagement() {
- let promise;
-
- {
- const listen = Deno.listen({ port: listenPort });
- promise = fetch(`http://localhost:${listenPort}/`).catch(() => null);
- const serverConn = await listen.accept();
- listen.close();
-
- using _httpConn = Deno.serveHttp(serverConn);
- }
-
- const response = await promise;
- assertEquals(response, null);
- },
-);
-
-function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader {
- // Based on https://tools.ietf.org/html/rfc2616#section-19.4.6
- const tp = new TextProtoReader(r);
- let finished = false;
- const chunks: Array<{
- offset: number;
- data: Uint8Array;
- }> = [];
- async function read(buf: Uint8Array): Promise<number | null> {
- if (finished) return null;
- const [chunk] = chunks;
- if (chunk) {
- const chunkRemaining = chunk.data.byteLength - chunk.offset;
- const readLength = Math.min(chunkRemaining, buf.byteLength);
- for (let i = 0; i < readLength; i++) {
- buf[i] = chunk.data[chunk.offset + i];
- }
- chunk.offset += readLength;
- if (chunk.offset === chunk.data.byteLength) {
- chunks.shift();
- // Consume \r\n;
- if ((await tp.readLine()) === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- }
- return readLength;
- }
- const line = await tp.readLine();
- if (line === null) throw new Deno.errors.UnexpectedEof();
- // TODO(bartlomieju): handle chunk extension
- const [chunkSizeString] = line.split(";");
- const chunkSize = parseInt(chunkSizeString, 16);
- if (Number.isNaN(chunkSize) || chunkSize < 0) {
- throw new Deno.errors.InvalidData("Invalid chunk size");
- }
- if (chunkSize > 0) {
- if (chunkSize > buf.byteLength) {
- let eof = await r.readFull(buf);
- if (eof === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- const restChunk = new Uint8Array(chunkSize - buf.byteLength);
- eof = await r.readFull(restChunk);
- if (eof === null) {
- throw new Deno.errors.UnexpectedEof();
- } else {
- chunks.push({
- offset: 0,
- data: restChunk,
- });
- }
- return buf.byteLength;
- } else {
- const bufToFill = buf.subarray(0, chunkSize);
- const eof = await r.readFull(bufToFill);
- if (eof === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- // Consume \r\n
- if ((await tp.readLine()) === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- return chunkSize;
- }
- } else {
- assert(chunkSize === 0);
- // Consume \r\n
- if ((await r.readLine()) === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- await readTrailers(h, r);
- finished = true;
- return null;
- }
- }
- return { read };
-}
-
-async function readTrailers(
- headers: Headers,
- r: BufReader,
-) {
- const trailers = parseTrailer(headers.get("trailer"));
- if (trailers == null) return;
- const trailerNames = [...trailers.keys()];
- const tp = new TextProtoReader(r);
- const result = await tp.readMimeHeader();
- if (result == null) {
- throw new Deno.errors.InvalidData("Missing trailer header.");
- }
- const undeclared = [...result.keys()].filter(
- (k) => !trailerNames.includes(k),
- );
- if (undeclared.length > 0) {
- throw new Deno.errors.InvalidData(
- `Undeclared trailers: ${Deno.inspect(undeclared)}.`,
- );
- }
- for (const [k, v] of result) {
- headers.append(k, v);
- }
- const missingTrailers = trailerNames.filter((k) => !result.has(k));
- if (missingTrailers.length > 0) {
- throw new Deno.errors.InvalidData(
- `Missing trailers: ${Deno.inspect(missingTrailers)}.`,
- );
- }
- headers.delete("trailer");
-}
-
-function parseTrailer(field: string | null): Headers | undefined {
- if (field == null) {
- return undefined;
- }
- const trailerNames = field.split(",").map((v) => v.trim().toLowerCase());
- if (trailerNames.length === 0) {
- throw new Deno.errors.InvalidData("Empty trailer header.");
- }
- const prohibited = trailerNames.filter((k) => isProhibitedForTrailer(k));
- if (prohibited.length > 0) {
- throw new Deno.errors.InvalidData(
- `Prohibited trailer names: ${Deno.inspect(prohibited)}.`,
- );
- }
- return new Headers(trailerNames.map((key) => [key, ""]));
-}
-
-function isProhibitedForTrailer(key: string): boolean {
- const s = new Set(["transfer-encoding", "content-length", "trailer"]);
- return s.has(key.toLowerCase());
-}
diff --git a/cli/tests/unit/image_bitmap_test.ts b/cli/tests/unit/image_bitmap_test.ts
deleted file mode 100644
index 364f2a167..000000000
--- a/cli/tests/unit/image_bitmap_test.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assertEquals } from "./test_util.ts";
-
-function generateNumberedData(n: number): Uint8ClampedArray {
- return new Uint8ClampedArray(
- Array.from({ length: n }, (_, i) => [i + 1, 0, 0, 1]).flat(),
- );
-}
-
-Deno.test(async function imageBitmapDirect() {
- const data = generateNumberedData(3);
- const imageData = new ImageData(data, 3, 1);
- const imageBitmap = await createImageBitmap(imageData);
- assertEquals(
- // @ts-ignore: Deno[Deno.internal].core allowed
- Deno[Deno.internal].getBitmapData(imageBitmap),
- new Uint8Array(data.buffer),
- );
-});
-
-Deno.test(async function imageBitmapCrop() {
- const data = generateNumberedData(3 * 3);
- const imageData = new ImageData(data, 3, 3);
- const imageBitmap = await createImageBitmap(imageData, 1, 1, 1, 1);
- assertEquals(
- // @ts-ignore: Deno[Deno.internal].core allowed
- Deno[Deno.internal].getBitmapData(imageBitmap),
- new Uint8Array([5, 0, 0, 1]),
- );
-});
-
-Deno.test(async function imageBitmapCropPartialNegative() {
- const data = generateNumberedData(3 * 3);
- const imageData = new ImageData(data, 3, 3);
- const imageBitmap = await createImageBitmap(imageData, -1, -1, 2, 2);
- // @ts-ignore: Deno[Deno.internal].core allowed
- // deno-fmt-ignore
- assertEquals(Deno[Deno.internal].getBitmapData(imageBitmap), new Uint8Array([
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 0, 0, 1
- ]));
-});
-
-Deno.test(async function imageBitmapCropGreater() {
- const data = generateNumberedData(3 * 3);
- const imageData = new ImageData(data, 3, 3);
- const imageBitmap = await createImageBitmap(imageData, -1, -1, 5, 5);
- // @ts-ignore: Deno[Deno.internal].core allowed
- // deno-fmt-ignore
- assertEquals(Deno[Deno.internal].getBitmapData(imageBitmap), new Uint8Array([
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 0, 0, 1, 2, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 4, 0, 0, 1, 5, 0, 0, 1, 6, 0, 0, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 7, 0, 0, 1, 8, 0, 0, 1, 9, 0, 0, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- ]));
-});
-
-Deno.test(async function imageBitmapScale() {
- const data = generateNumberedData(3);
- const imageData = new ImageData(data, 3, 1);
- const imageBitmap = await createImageBitmap(imageData, {
- resizeHeight: 5,
- resizeWidth: 5,
- resizeQuality: "pixelated",
- });
- // @ts-ignore: Deno[Deno.internal].core allowed
- // deno-fmt-ignore
- assertEquals(Deno[Deno.internal].getBitmapData(imageBitmap), new Uint8Array([
- 1, 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 1,
- 1, 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 1,
- 1, 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 1,
- 1, 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 1,
- 1, 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 1
- ]));
-});
-
-Deno.test(async function imageBitmapFlipY() {
- const data = generateNumberedData(9);
- const imageData = new ImageData(data, 3, 3);
- const imageBitmap = await createImageBitmap(imageData, {
- imageOrientation: "flipY",
- });
- // @ts-ignore: Deno[Deno.internal].core allowed
- // deno-fmt-ignore
- assertEquals(Deno[Deno.internal].getBitmapData(imageBitmap), new Uint8Array([
- 7, 0, 0, 1, 8, 0, 0, 1, 9, 0, 0, 1,
- 4, 0, 0, 1, 5, 0, 0, 1, 6, 0, 0, 1,
- 1, 0, 0, 1, 2, 0, 0, 1, 3, 0, 0, 1,
- ]));
-});
diff --git a/cli/tests/unit/image_data_test.ts b/cli/tests/unit/image_data_test.ts
deleted file mode 100644
index 7156301a0..000000000
--- a/cli/tests/unit/image_data_test.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assertEquals } from "./test_util.ts";
-
-Deno.test(function imageDataInitializedWithSourceWidthAndHeight() {
- const imageData = new ImageData(16, 9);
-
- assertEquals(imageData.width, 16);
- assertEquals(imageData.height, 9);
- assertEquals(imageData.data.length, 16 * 9 * 4); // width * height * 4 (RGBA pixels)
- assertEquals(imageData.colorSpace, "srgb");
-});
-
-Deno.test(function imageDataInitializedWithImageDataAndWidth() {
- const imageData = new ImageData(new Uint8ClampedArray(16 * 9 * 4), 16);
-
- assertEquals(imageData.width, 16);
- assertEquals(imageData.height, 9);
- assertEquals(imageData.data.length, 16 * 9 * 4); // width * height * 4 (RGBA pixels)
- assertEquals(imageData.colorSpace, "srgb");
-});
-
-Deno.test(
- function imageDataInitializedWithImageDataAndWidthAndHeightAndColorSpace() {
- const imageData = new ImageData(new Uint8ClampedArray(16 * 9 * 4), 16, 9, {
- colorSpace: "display-p3",
- });
-
- assertEquals(imageData.width, 16);
- assertEquals(imageData.height, 9);
- assertEquals(imageData.data.length, 16 * 9 * 4); // width * height * 4 (RGBA pixels)
- assertEquals(imageData.colorSpace, "display-p3");
- },
-);
-
-Deno.test(
- async function imageDataUsedInWorker() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const url = import.meta.resolve(
- "../testdata/workers/image_data_worker.ts",
- );
- const expectedData = 16;
-
- const worker = new Worker(url, { type: "module" });
- worker.onmessage = function (e) {
- assertEquals(expectedData, e.data);
- worker.terminate();
- resolve();
- };
-
- await promise;
- },
-);
diff --git a/cli/tests/unit/internals_test.ts b/cli/tests/unit/internals_test.ts
deleted file mode 100644
index bb4c21793..000000000
--- a/cli/tests/unit/internals_test.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert } from "./test_util.ts";
-
-Deno.test(function internalsExists() {
- const {
- inspectArgs,
- // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
- } = Deno[Deno.internal];
- assert(!!inspectArgs);
-});
diff --git a/cli/tests/unit/intl_test.ts b/cli/tests/unit/intl_test.ts
deleted file mode 100644
index 6e4de378c..000000000
--- a/cli/tests/unit/intl_test.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-Deno.test("Intl.v8BreakIterator should be undefined", () => {
- // @ts-expect-error Intl.v8BreakIterator is not a standard API
- assertEquals(Intl.v8BreakIterator, undefined);
-});
diff --git a/cli/tests/unit/io_test.ts b/cli/tests/unit/io_test.ts
deleted file mode 100644
index 04c9dab4b..000000000
--- a/cli/tests/unit/io_test.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-import { Buffer } from "@test_util/std/io/buffer.ts";
-
-const DEFAULT_BUF_SIZE = 32 * 1024;
-
-type Spy = { calls: number };
-
-function repeat(c: string, bytes: number): Uint8Array {
- assertEquals(c.length, 1);
- const ui8 = new Uint8Array(bytes);
- ui8.fill(c.charCodeAt(0));
- return ui8;
-}
-
-function spyRead(obj: Buffer): Spy {
- const spy: Spy = {
- calls: 0,
- };
-
- const orig = obj.read.bind(obj);
-
- obj.read = (p: Uint8Array): Promise<number | null> => {
- spy.calls++;
- return orig(p);
- };
-
- return spy;
-}
-
-Deno.test(async function copyWithDefaultBufferSize() {
- const xBytes = repeat("b", DEFAULT_BUF_SIZE);
- const reader = new Buffer(xBytes.buffer as ArrayBuffer);
- const write = new Buffer();
-
- const readSpy = spyRead(reader);
-
- // deno-lint-ignore no-deprecated-deno-api
- const n = await Deno.copy(reader, write);
-
- assertEquals(n, xBytes.length);
- assertEquals(write.length, xBytes.length);
- assertEquals(readSpy.calls, 2); // read with DEFAULT_BUF_SIZE bytes + read with 0 bytes
-});
-
-Deno.test(async function copyWithCustomBufferSize() {
- const bufSize = 1024;
- const xBytes = repeat("b", DEFAULT_BUF_SIZE);
- const reader = new Buffer(xBytes.buffer as ArrayBuffer);
- const write = new Buffer();
-
- const readSpy = spyRead(reader);
-
- // deno-lint-ignore no-deprecated-deno-api
- const n = await Deno.copy(reader, write, { bufSize });
-
- assertEquals(n, xBytes.length);
- assertEquals(write.length, xBytes.length);
- assertEquals(readSpy.calls, DEFAULT_BUF_SIZE / bufSize + 1);
-});
-
-Deno.test({ permissions: { write: true } }, async function copyBufferToFile() {
- const filePath = "test-file.txt";
- // bigger than max File possible buffer 16kb
- const bufSize = 32 * 1024;
- const xBytes = repeat("b", bufSize);
- const reader = new Buffer(xBytes.buffer as ArrayBuffer);
- const write = await Deno.open(filePath, { write: true, create: true });
-
- // deno-lint-ignore no-deprecated-deno-api
- const n = await Deno.copy(reader, write, { bufSize });
-
- assertEquals(n, xBytes.length);
-
- write.close();
- await Deno.remove(filePath);
-});
diff --git a/cli/tests/unit/jupyter_test.ts b/cli/tests/unit/jupyter_test.ts
deleted file mode 100644
index 07defe230..000000000
--- a/cli/tests/unit/jupyter_test.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assertEquals, assertThrows } from "./test_util.ts";
-
-// @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
-const format = Deno[Deno.internal].jupyter.formatInner;
-
-Deno.test("Deno.jupyter is not available", () => {
- assertThrows(
- () => Deno.jupyter,
- "Deno.jupyter is only available in `deno jupyter` subcommand.",
- );
-});
-
-export async function assertFormattedAs(obj: unknown, result: object) {
- const formatted = await format(obj);
- assertEquals(formatted, result);
-}
-
-Deno.test("display(canvas) creates a PNG", async () => {
- // Let's make a fake Canvas with a fake Data URL
- class FakeCanvas {
- toDataURL() {
- return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAAVSURBVAiZY/zPwPCfAQ0woQtQQRAAzqkCCB/D3o0AAAAASUVORK5CYII=";
- }
- }
- const canvas = new FakeCanvas();
-
- await assertFormattedAs(canvas, {
- "image/png":
- "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAAVSURBVAiZY/zPwPCfAQ0woQtQQRAAzqkCCB/D3o0AAAAASUVORK5CYII=",
- });
-});
-
-Deno.test(
- "class with a Symbol.for('Jupyter.display') function gets displayed",
- async () => {
- class Example {
- x: number;
-
- constructor(x: number) {
- this.x = x;
- }
-
- [Symbol.for("Jupyter.display")]() {
- return { "application/json": { x: this.x } };
- }
- }
-
- const example = new Example(5);
-
- // Now to check on the broadcast call being made
- await assertFormattedAs(example, { "application/json": { x: 5 } });
- },
-);
-
-Deno.test(
- "class with an async Symbol.for('Jupyter.display') function gets displayed",
- async () => {
- class Example {
- x: number;
-
- constructor(x: number) {
- this.x = x;
- }
-
- async [Symbol.for("Jupyter.display")]() {
- await new Promise((resolve) => setTimeout(resolve, 0));
-
- return { "application/json": { x: this.x } };
- }
- }
-
- const example = new Example(3);
-
- // Now to check on the broadcast call being made
- await assertFormattedAs(example, { "application/json": { x: 3 } });
- },
-);
diff --git a/cli/tests/unit/kv_queue_test.ts b/cli/tests/unit/kv_queue_test.ts
deleted file mode 100644
index e052dcbf7..000000000
--- a/cli/tests/unit/kv_queue_test.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertFalse } from "./test_util.ts";
-
-Deno.test({}, async function queueTestDbClose() {
- const db: Deno.Kv = await Deno.openKv(":memory:");
- db.close();
- try {
- await db.listenQueue(() => {});
- assertFalse(false);
- } catch (e) {
- assertEquals(e.message, "already closed");
- }
-});
diff --git a/cli/tests/unit/kv_queue_test_no_db_close.ts b/cli/tests/unit/kv_queue_test_no_db_close.ts
deleted file mode 100644
index 947e1c5e6..000000000
--- a/cli/tests/unit/kv_queue_test_no_db_close.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals, assertNotEquals } from "./test_util.ts";
-
-Deno.test({
- sanitizeOps: false,
- sanitizeResources: false,
-}, async function queueTestNoDbClose() {
- const db: Deno.Kv = await Deno.openKv(":memory:");
- const { promise, resolve } = Promise.withResolvers<void>();
- let dequeuedMessage: unknown = null;
- db.listenQueue((msg) => {
- dequeuedMessage = msg;
- resolve();
- });
- const res = await db.enqueue("test");
- assert(res.ok);
- assertNotEquals(res.versionstamp, null);
- await promise;
- assertEquals(dequeuedMessage, "test");
-});
diff --git a/cli/tests/unit/kv_queue_undelivered_test.ts b/cli/tests/unit/kv_queue_undelivered_test.ts
deleted file mode 100644
index 1fcefe7e2..000000000
--- a/cli/tests/unit/kv_queue_undelivered_test.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-const sleep = (time: number) => new Promise((r) => setTimeout(r, time));
-
-// TODO(igorzi): https://github.com/denoland/deno/issues/21437
-// let isCI: boolean;
-// try {
-// isCI = Deno.env.get("CI") !== undefined;
-// } catch {
-// isCI = true;
-// }
-
-function queueTest(name: string, fn: (db: Deno.Kv) => Promise<void>) {
- // TODO(igorzi): https://github.com/denoland/deno/issues/21437
- Deno.test.ignore({
- name,
- // https://github.com/denoland/deno/issues/18363
- // ignore: Deno.build.os === "darwin" && isCI,
- async fn() {
- const db: Deno.Kv = await Deno.openKv(
- ":memory:",
- );
- await fn(db);
- },
- });
-}
-
-async function collect<T>(
- iter: Deno.KvListIterator<T>,
-): Promise<Deno.KvEntry<T>[]> {
- const entries: Deno.KvEntry<T>[] = [];
- for await (const entry of iter) {
- entries.push(entry);
- }
- return entries;
-}
-
-queueTest("queue with undelivered", async (db) => {
- const listener = db.listenQueue((_msg) => {
- throw new TypeError("dequeue error");
- });
- try {
- await db.enqueue("test", {
- keysIfUndelivered: [["queue_failed", "a"], ["queue_failed", "b"]],
- backoffSchedule: [10, 20],
- });
- await sleep(3000);
- const undelivered = await collect(db.list({ prefix: ["queue_failed"] }));
- assertEquals(undelivered.length, 2);
- assertEquals(undelivered[0].key, ["queue_failed", "a"]);
- assertEquals(undelivered[0].value, "test");
- assertEquals(undelivered[1].key, ["queue_failed", "b"]);
- assertEquals(undelivered[1].value, "test");
- } finally {
- db.close();
- await listener;
- }
-});
diff --git a/cli/tests/unit/kv_test.ts b/cli/tests/unit/kv_test.ts
deleted file mode 100644
index 5780d9900..000000000
--- a/cli/tests/unit/kv_test.ts
+++ /dev/null
@@ -1,2321 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- AssertionError,
- assertNotEquals,
- assertRejects,
- assertThrows,
-} from "./test_util.ts";
-import { assertType, IsExact } from "@test_util/std/testing/types.ts";
-
-const sleep = (time: number) => new Promise((r) => setTimeout(r, time));
-
-let isCI: boolean;
-try {
- isCI = Deno.env.get("CI") !== undefined;
-} catch {
- isCI = true;
-}
-
-// Defined in test_util/src/lib.rs
-Deno.env.set("DENO_KV_ACCESS_TOKEN", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
-
-Deno.test({
- name: "openKv :memory: no permissions",
- permissions: {},
- async fn() {
- const db = await Deno.openKv(":memory:");
- await db.close();
- },
-});
-
-Deno.test({
- name: "openKv invalid filenames",
- permissions: {},
- async fn() {
- await assertRejects(
- async () => await Deno.openKv(""),
- TypeError,
- "Filename cannot be empty",
- );
- await assertRejects(
- async () => await Deno.openKv(":foo"),
- TypeError,
- "Filename cannot start with ':' unless prefixed with './'",
- );
- },
-});
-
-function dbTest(name: string, fn: (db: Deno.Kv) => Promise<void> | void) {
- Deno.test({
- name,
- // https://github.com/denoland/deno/issues/18363
- ignore: Deno.build.os === "darwin" && isCI,
- async fn() {
- const db: Deno.Kv = await Deno.openKv(":memory:");
- try {
- await fn(db);
- } finally {
- db.close();
- }
- },
- });
-}
-
-function queueTest(name: string, fn: (db: Deno.Kv) => Promise<void>) {
- Deno.test({
- name,
- // https://github.com/denoland/deno/issues/18363
- ignore: Deno.build.os === "darwin" && isCI,
- async fn() {
- const db: Deno.Kv = await Deno.openKv(":memory:");
- await fn(db);
- },
- });
-}
-
-const ZERO_VERSIONSTAMP = "00000000000000000000";
-
-dbTest("basic read-write-delete and versionstamps", async (db) => {
- const result1 = await db.get(["a"]);
- assertEquals(result1.key, ["a"]);
- assertEquals(result1.value, null);
- assertEquals(result1.versionstamp, null);
-
- const setRes = await db.set(["a"], "b");
- assert(setRes.ok);
- assert(setRes.versionstamp > ZERO_VERSIONSTAMP);
- const result2 = await db.get(["a"]);
- assertEquals(result2.key, ["a"]);
- assertEquals(result2.value, "b");
- assertEquals(result2.versionstamp, setRes.versionstamp);
-
- const setRes2 = await db.set(["a"], "c");
- assert(setRes2.ok);
- assert(setRes2.versionstamp > setRes.versionstamp);
- const result3 = await db.get(["a"]);
- assertEquals(result3.key, ["a"]);
- assertEquals(result3.value, "c");
- assertEquals(result3.versionstamp, setRes2.versionstamp);
-
- await db.delete(["a"]);
- const result4 = await db.get(["a"]);
- assertEquals(result4.key, ["a"]);
- assertEquals(result4.value, null);
- assertEquals(result4.versionstamp, null);
-});
-
-const VALUE_CASES = [
- { name: "string", value: "hello" },
- { name: "number", value: 42 },
- { name: "bigint", value: 42n },
- { name: "boolean", value: true },
- { name: "null", value: null },
- { name: "undefined", value: undefined },
- { name: "Date", value: new Date(0) },
- { name: "Uint8Array", value: new Uint8Array([1, 2, 3]) },
- { name: "ArrayBuffer", value: new ArrayBuffer(3) },
- { name: "array", value: [1, 2, 3] },
- { name: "object", value: { a: 1, b: 2 } },
- { name: "nested array", value: [[1, 2], [3, 4]] },
- { name: "nested object", value: { a: { b: 1 } } },
-];
-
-for (const { name, value } of VALUE_CASES) {
- dbTest(`set and get ${name} value`, async (db) => {
- await db.set(["a"], value);
- const result = await db.get(["a"]);
- assertEquals(result.key, ["a"]);
- assertEquals(result.value, value);
- });
-}
-
-dbTest("set and get recursive object", async (db) => {
- // deno-lint-ignore no-explicit-any
- const value: any = { a: undefined };
- value.a = value;
- await db.set(["a"], value);
- const result = await db.get(["a"]);
- assertEquals(result.key, ["a"]);
- // deno-lint-ignore no-explicit-any
- const resultValue: any = result.value;
- assert(resultValue.a === resultValue);
-});
-
-// invalid values (as per structured clone algorithm with _for storage_, NOT JSON)
-const INVALID_VALUE_CASES = [
- { name: "function", value: () => {} },
- { name: "symbol", value: Symbol() },
- { name: "WeakMap", value: new WeakMap() },
- { name: "WeakSet", value: new WeakSet() },
- {
- name: "WebAssembly.Module",
- value: new WebAssembly.Module(
- new Uint8Array([0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00]),
- ),
- },
- {
- name: "SharedArrayBuffer",
- value: new SharedArrayBuffer(3),
- },
-];
-
-for (const { name, value } of INVALID_VALUE_CASES) {
- dbTest(`set and get ${name} value (invalid)`, async (db) => {
- await assertRejects(
- async () => await db.set(["a"], value),
- Error,
- );
- const res = await db.get(["a"]);
- assertEquals(res.key, ["a"]);
- assertEquals(res.value, null);
- });
-}
-
-const keys = [
- ["a"],
- ["a", "b"],
- ["a", "b", "c"],
- [1],
- ["a", 1],
- ["a", 1, "b"],
- [1n],
- ["a", 1n],
- ["a", 1n, "b"],
- [true],
- ["a", true],
- ["a", true, "b"],
- [new Uint8Array([1, 2, 3])],
- ["a", new Uint8Array([1, 2, 3])],
- ["a", new Uint8Array([1, 2, 3]), "b"],
- [1, 1n, true, new Uint8Array([1, 2, 3]), "a"],
-];
-
-for (const key of keys) {
- dbTest(`set and get ${Deno.inspect(key)} key`, async (db) => {
- await db.set(key, "b");
- const result = await db.get(key);
- assertEquals(result.key, key);
- assertEquals(result.value, "b");
- });
-}
-
-const INVALID_KEYS = [
- [null],
- [undefined],
- [],
- [{}],
- [new Date()],
- [new ArrayBuffer(3)],
- [new Uint8Array([1, 2, 3]).buffer],
- [["a", "b"]],
-];
-
-for (const key of INVALID_KEYS) {
- dbTest(`set and get invalid key ${Deno.inspect(key)}`, async (db) => {
- await assertRejects(
- async () => {
- // @ts-ignore - we are testing invalid keys
- await db.set(key, "b");
- },
- Error,
- );
- });
-}
-
-dbTest("compare and mutate", async (db) => {
- await db.set(["t"], "1");
-
- const currentValue = await db.get(["t"]);
- assert(currentValue.versionstamp);
- assert(currentValue.versionstamp > ZERO_VERSIONSTAMP);
-
- let res = await db.atomic()
- .check({ key: ["t"], versionstamp: currentValue.versionstamp })
- .set(currentValue.key, "2")
- .commit();
- assert(res.ok);
- assert(res.versionstamp > currentValue.versionstamp);
-
- const newValue = await db.get(["t"]);
- assertEquals(newValue.versionstamp, res.versionstamp);
- assertEquals(newValue.value, "2");
-
- res = await db.atomic()
- .check({ key: ["t"], versionstamp: currentValue.versionstamp })
- .set(currentValue.key, "3")
- .commit();
- assert(!res.ok);
-
- const newValue2 = await db.get(["t"]);
- assertEquals(newValue2.versionstamp, newValue.versionstamp);
- assertEquals(newValue2.value, "2");
-});
-
-dbTest("compare and mutate not exists", async (db) => {
- let res = await db.atomic()
- .check({ key: ["t"], versionstamp: null })
- .set(["t"], "1")
- .commit();
- assert(res.ok);
- assert(res.versionstamp > ZERO_VERSIONSTAMP);
-
- const newValue = await db.get(["t"]);
- assertEquals(newValue.versionstamp, res.versionstamp);
- assertEquals(newValue.value, "1");
-
- res = await db.atomic()
- .check({ key: ["t"], versionstamp: null })
- .set(["t"], "2")
- .commit();
- assert(!res.ok);
-});
-
-dbTest("atomic mutation helper (sum)", async (db) => {
- await db.set(["t"], new Deno.KvU64(42n));
- assertEquals((await db.get(["t"])).value, new Deno.KvU64(42n));
-
- await db.atomic().sum(["t"], 1n).commit();
- assertEquals((await db.get(["t"])).value, new Deno.KvU64(43n));
-});
-
-dbTest("atomic mutation helper (min)", async (db) => {
- await db.set(["t"], new Deno.KvU64(42n));
- assertEquals((await db.get(["t"])).value, new Deno.KvU64(42n));
-
- await db.atomic().min(["t"], 1n).commit();
- assertEquals((await db.get(["t"])).value, new Deno.KvU64(1n));
-
- await db.atomic().min(["t"], 2n).commit();
- assertEquals((await db.get(["t"])).value, new Deno.KvU64(1n));
-});
-
-dbTest("atomic mutation helper (max)", async (db) => {
- await db.set(["t"], new Deno.KvU64(42n));
- assertEquals((await db.get(["t"])).value, new Deno.KvU64(42n));
-
- await db.atomic().max(["t"], 41n).commit();
- assertEquals((await db.get(["t"])).value, new Deno.KvU64(42n));
-
- await db.atomic().max(["t"], 43n).commit();
- assertEquals((await db.get(["t"])).value, new Deno.KvU64(43n));
-});
-
-dbTest("compare multiple and mutate", async (db) => {
- const setRes1 = await db.set(["t1"], "1");
- const setRes2 = await db.set(["t2"], "2");
- assert(setRes1.ok);
- assert(setRes1.versionstamp > ZERO_VERSIONSTAMP);
- assert(setRes2.ok);
- assert(setRes2.versionstamp > ZERO_VERSIONSTAMP);
-
- const currentValue1 = await db.get(["t1"]);
- assertEquals(currentValue1.versionstamp, setRes1.versionstamp);
- const currentValue2 = await db.get(["t2"]);
- assertEquals(currentValue2.versionstamp, setRes2.versionstamp);
-
- const res = await db.atomic()
- .check({ key: ["t1"], versionstamp: currentValue1.versionstamp })
- .check({ key: ["t2"], versionstamp: currentValue2.versionstamp })
- .set(currentValue1.key, "3")
- .set(currentValue2.key, "4")
- .commit();
- assert(res.ok);
- assert(res.versionstamp > setRes2.versionstamp);
-
- const newValue1 = await db.get(["t1"]);
- assertEquals(newValue1.versionstamp, res.versionstamp);
- assertEquals(newValue1.value, "3");
- const newValue2 = await db.get(["t2"]);
- assertEquals(newValue2.versionstamp, res.versionstamp);
- assertEquals(newValue2.value, "4");
-
- // just one of the two checks failed
- const res2 = await db.atomic()
- .check({ key: ["t1"], versionstamp: newValue1.versionstamp })
- .check({ key: ["t2"], versionstamp: null })
- .set(newValue1.key, "5")
- .set(newValue2.key, "6")
- .commit();
- assert(!res2.ok);
-
- const newValue3 = await db.get(["t1"]);
- assertEquals(newValue3.versionstamp, res.versionstamp);
- assertEquals(newValue3.value, "3");
- const newValue4 = await db.get(["t2"]);
- assertEquals(newValue4.versionstamp, res.versionstamp);
- assertEquals(newValue4.value, "4");
-});
-
-dbTest("atomic mutation ordering (set before delete)", async (db) => {
- await db.set(["a"], "1");
- const res = await db.atomic()
- .set(["a"], "2")
- .delete(["a"])
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, null);
-});
-
-dbTest("atomic mutation ordering (delete before set)", async (db) => {
- await db.set(["a"], "1");
- const res = await db.atomic()
- .delete(["a"])
- .set(["a"], "2")
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, "2");
-});
-
-dbTest("atomic mutation type=set", async (db) => {
- const res = await db.atomic()
- .mutate({ key: ["a"], value: "1", type: "set" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, "1");
-});
-
-dbTest("atomic mutation type=set overwrite", async (db) => {
- await db.set(["a"], "1");
- const res = await db.atomic()
- .mutate({ key: ["a"], value: "2", type: "set" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, "2");
-});
-
-dbTest("atomic mutation type=delete", async (db) => {
- await db.set(["a"], "1");
- const res = await db.atomic()
- .mutate({ key: ["a"], type: "delete" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, null);
-});
-
-dbTest("atomic mutation type=delete no exists", async (db) => {
- const res = await db.atomic()
- .mutate({ key: ["a"], type: "delete" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, null);
-});
-
-dbTest("atomic mutation type=sum", async (db) => {
- await db.set(["a"], new Deno.KvU64(10n));
- const res = await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(1n), type: "sum" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, new Deno.KvU64(11n));
-});
-
-dbTest("atomic mutation type=sum no exists", async (db) => {
- const res = await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(1n), type: "sum" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assert(result.value);
- assertEquals(result.value, new Deno.KvU64(1n));
-});
-
-dbTest("atomic mutation type=sum wrap around", async (db) => {
- await db.set(["a"], new Deno.KvU64(0xffffffffffffffffn));
- const res = await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(10n), type: "sum" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, new Deno.KvU64(9n));
-
- const res2 = await db.atomic()
- .mutate({
- key: ["a"],
- value: new Deno.KvU64(0xffffffffffffffffn),
- type: "sum",
- })
- .commit();
- assert(res2);
- const result2 = await db.get(["a"]);
- assertEquals(result2.value, new Deno.KvU64(8n));
-});
-
-dbTest("atomic mutation type=sum wrong type in db", async (db) => {
- await db.set(["a"], 1);
- await assertRejects(
- async () => {
- await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(1n), type: "sum" })
- .commit();
- },
- TypeError,
- "Failed to perform 'sum' mutation on a non-U64 value in the database",
- );
-});
-
-dbTest("atomic mutation type=sum wrong type in mutation", async (db) => {
- await db.set(["a"], new Deno.KvU64(1n));
- await assertRejects(
- async () => {
- await db.atomic()
- // @ts-expect-error wrong type is intentional
- .mutate({ key: ["a"], value: 1, type: "sum" })
- .commit();
- },
- TypeError,
- "Failed to perform 'sum' mutation on a non-U64 operand",
- );
-});
-
-dbTest("atomic mutation type=min", async (db) => {
- await db.set(["a"], new Deno.KvU64(10n));
- const res = await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(5n), type: "min" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, new Deno.KvU64(5n));
-
- const res2 = await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(15n), type: "min" })
- .commit();
- assert(res2);
- const result2 = await db.get(["a"]);
- assertEquals(result2.value, new Deno.KvU64(5n));
-});
-
-dbTest("atomic mutation type=min no exists", async (db) => {
- const res = await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(1n), type: "min" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assert(result.value);
- assertEquals(result.value, new Deno.KvU64(1n));
-});
-
-dbTest("atomic mutation type=min wrong type in db", async (db) => {
- await db.set(["a"], 1);
- await assertRejects(
- async () => {
- await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(1n), type: "min" })
- .commit();
- },
- TypeError,
- "Failed to perform 'min' mutation on a non-U64 value in the database",
- );
-});
-
-dbTest("atomic mutation type=min wrong type in mutation", async (db) => {
- await db.set(["a"], new Deno.KvU64(1n));
- await assertRejects(
- async () => {
- await db.atomic()
- // @ts-expect-error wrong type is intentional
- .mutate({ key: ["a"], value: 1, type: "min" })
- .commit();
- },
- TypeError,
- "Failed to perform 'min' mutation on a non-U64 operand",
- );
-});
-
-dbTest("atomic mutation type=max", async (db) => {
- await db.set(["a"], new Deno.KvU64(10n));
- const res = await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(5n), type: "max" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assertEquals(result.value, new Deno.KvU64(10n));
-
- const res2 = await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(15n), type: "max" })
- .commit();
- assert(res2);
- const result2 = await db.get(["a"]);
- assertEquals(result2.value, new Deno.KvU64(15n));
-});
-
-dbTest("atomic mutation type=max no exists", async (db) => {
- const res = await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(1n), type: "max" })
- .commit();
- assert(res.ok);
- const result = await db.get(["a"]);
- assert(result.value);
- assertEquals(result.value, new Deno.KvU64(1n));
-});
-
-dbTest("atomic mutation type=max wrong type in db", async (db) => {
- await db.set(["a"], 1);
- await assertRejects(
- async () => {
- await db.atomic()
- .mutate({ key: ["a"], value: new Deno.KvU64(1n), type: "max" })
- .commit();
- },
- TypeError,
- "Failed to perform 'max' mutation on a non-U64 value in the database",
- );
-});
-
-dbTest("atomic mutation type=max wrong type in mutation", async (db) => {
- await db.set(["a"], new Deno.KvU64(1n));
- await assertRejects(
- async () => {
- await db.atomic()
- // @ts-expect-error wrong type is intentional
- .mutate({ key: ["a"], value: 1, type: "max" })
- .commit();
- },
- TypeError,
- "Failed to perform 'max' mutation on a non-U64 operand",
- );
-});
-
-Deno.test("KvU64 comparison", () => {
- const a = new Deno.KvU64(1n);
- const b = new Deno.KvU64(1n);
- assertEquals(a, b);
- assertThrows(() => {
- assertEquals(a, new Deno.KvU64(2n));
- }, AssertionError);
-});
-
-Deno.test("KvU64 overflow", () => {
- assertThrows(() => {
- new Deno.KvU64(2n ** 64n);
- }, RangeError);
-});
-
-Deno.test("KvU64 underflow", () => {
- assertThrows(() => {
- new Deno.KvU64(-1n);
- }, RangeError);
-});
-
-Deno.test("KvU64 unbox", () => {
- const a = new Deno.KvU64(1n);
- assertEquals(a.value, 1n);
-});
-
-Deno.test("KvU64 unbox with valueOf", () => {
- const a = new Deno.KvU64(1n);
- assertEquals(a.valueOf(), 1n);
-});
-
-Deno.test("KvU64 auto-unbox", () => {
- const a = new Deno.KvU64(1n);
- assertEquals(a as unknown as bigint + 1n, 2n);
-});
-
-Deno.test("KvU64 toString", () => {
- const a = new Deno.KvU64(1n);
- assertEquals(a.toString(), "1");
-});
-
-Deno.test("KvU64 inspect", () => {
- const a = new Deno.KvU64(1n);
- assertEquals(Deno.inspect(a), "[Deno.KvU64: 1n]");
-});
-
-async function collect<T>(
- iter: Deno.KvListIterator<T>,
-): Promise<Deno.KvEntry<T>[]> {
- const entries: Deno.KvEntry<T>[] = [];
- for await (const entry of iter) {
- entries.push(entry);
- }
- return entries;
-}
-
-async function setupData(db: Deno.Kv): Promise<string> {
- const res = await db.atomic()
- .set(["a"], -1)
- .set(["a", "a"], 0)
- .set(["a", "b"], 1)
- .set(["a", "c"], 2)
- .set(["a", "d"], 3)
- .set(["a", "e"], 4)
- .set(["b"], 99)
- .set(["b", "a"], 100)
- .commit();
- assert(res.ok);
- return res.versionstamp;
-}
-
-dbTest("get many", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await db.getMany([["b", "a"], ["a"], ["c"]]);
- assertEquals(entries, [
- { key: ["b", "a"], value: 100, versionstamp },
- { key: ["a"], value: -1, versionstamp },
- { key: ["c"], value: null, versionstamp: null },
- ]);
-});
-
-dbTest("list prefix", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(db.list({ prefix: ["a"] }));
- assertEquals(entries, [
- { key: ["a", "a"], value: 0, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "e"], value: 4, versionstamp },
- ]);
-});
-
-dbTest("list prefix empty", async (db) => {
- await setupData(db);
- const entries = await collect(db.list({ prefix: ["c"] }));
- assertEquals(entries.length, 0);
-
- const entries2 = await collect(db.list({ prefix: ["a", "f"] }));
- assertEquals(entries2.length, 0);
-});
-
-dbTest("list prefix with start", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(db.list({ prefix: ["a"], start: ["a", "c"] }));
- assertEquals(entries, [
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "e"], value: 4, versionstamp },
- ]);
-});
-
-dbTest("list prefix with start empty", async (db) => {
- await setupData(db);
- const entries = await collect(db.list({ prefix: ["a"], start: ["a", "f"] }));
- assertEquals(entries.length, 0);
-});
-
-dbTest("list prefix with start equal to prefix", async (db) => {
- await setupData(db);
- await assertRejects(
- async () => await collect(db.list({ prefix: ["a"], start: ["a"] })),
- TypeError,
- "start key is not in the keyspace defined by prefix",
- );
-});
-
-dbTest("list prefix with start out of bounds", async (db) => {
- await setupData(db);
- await assertRejects(
- async () => await collect(db.list({ prefix: ["b"], start: ["a"] })),
- TypeError,
- "start key is not in the keyspace defined by prefix",
- );
-});
-
-dbTest("list prefix with end", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(db.list({ prefix: ["a"], end: ["a", "c"] }));
- assertEquals(entries, [
- { key: ["a", "a"], value: 0, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- ]);
-});
-
-dbTest("list prefix with end empty", async (db) => {
- await setupData(db);
- const entries = await collect(db.list({ prefix: ["a"], end: ["a", "a"] }));
- assertEquals(entries.length, 0);
-});
-
-dbTest("list prefix with end equal to prefix", async (db) => {
- await setupData(db);
- await assertRejects(
- async () => await collect(db.list({ prefix: ["a"], end: ["a"] })),
- TypeError,
- "end key is not in the keyspace defined by prefix",
- );
-});
-
-dbTest("list prefix with end out of bounds", async (db) => {
- await setupData(db);
- await assertRejects(
- async () => await collect(db.list({ prefix: ["a"], end: ["b"] })),
- TypeError,
- "end key is not in the keyspace defined by prefix",
- );
-});
-
-dbTest("list prefix with empty prefix", async (db) => {
- const res = await db.set(["a"], 1);
- const entries = await collect(db.list({ prefix: [] }));
- assertEquals(entries, [
- { key: ["a"], value: 1, versionstamp: res.versionstamp },
- ]);
-});
-
-dbTest("list prefix reverse", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(db.list({ prefix: ["a"] }, { reverse: true }));
- assertEquals(entries, [
- { key: ["a", "e"], value: 4, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "a"], value: 0, versionstamp },
- ]);
-});
-
-dbTest("list prefix reverse with start", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(
- db.list({ prefix: ["a"], start: ["a", "c"] }, { reverse: true }),
- );
- assertEquals(entries, [
- { key: ["a", "e"], value: 4, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- ]);
-});
-
-dbTest("list prefix reverse with start empty", async (db) => {
- await setupData(db);
- const entries = await collect(
- db.list({ prefix: ["a"], start: ["a", "f"] }, { reverse: true }),
- );
- assertEquals(entries.length, 0);
-});
-
-dbTest("list prefix reverse with end", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(
- db.list({ prefix: ["a"], end: ["a", "c"] }, { reverse: true }),
- );
- assertEquals(entries, [
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "a"], value: 0, versionstamp },
- ]);
-});
-
-dbTest("list prefix reverse with end empty", async (db) => {
- await setupData(db);
- const entries = await collect(
- db.list({ prefix: ["a"], end: ["a", "a"] }, { reverse: true }),
- );
- assertEquals(entries.length, 0);
-});
-
-dbTest("list prefix limit", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(db.list({ prefix: ["a"] }, { limit: 2 }));
- assertEquals(entries, [
- { key: ["a", "a"], value: 0, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- ]);
-});
-
-dbTest("list prefix limit reverse", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(
- db.list({ prefix: ["a"] }, { limit: 2, reverse: true }),
- );
- assertEquals(entries, [
- { key: ["a", "e"], value: 4, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- ]);
-});
-
-dbTest("list prefix with small batch size", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(db.list({ prefix: ["a"] }, { batchSize: 2 }));
- assertEquals(entries, [
- { key: ["a", "a"], value: 0, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "e"], value: 4, versionstamp },
- ]);
-});
-
-dbTest("list prefix with small batch size reverse", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(
- db.list({ prefix: ["a"] }, { batchSize: 2, reverse: true }),
- );
- assertEquals(entries, [
- { key: ["a", "e"], value: 4, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "a"], value: 0, versionstamp },
- ]);
-});
-
-dbTest("list prefix with small batch size and limit", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(
- db.list({ prefix: ["a"] }, { batchSize: 2, limit: 3 }),
- );
- assertEquals(entries, [
- { key: ["a", "a"], value: 0, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- ]);
-});
-
-dbTest("list prefix with small batch size and limit reverse", async (db) => {
- const versionstamp = await setupData(db);
- const entries = await collect(
- db.list({ prefix: ["a"] }, { batchSize: 2, limit: 3, reverse: true }),
- );
- assertEquals(entries, [
- { key: ["a", "e"], value: 4, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- ]);
-});
-
-dbTest("list prefix with manual cursor", async (db) => {
- const versionstamp = await setupData(db);
- const iterator = db.list({ prefix: ["a"] }, { limit: 2 });
- const values = await collect(iterator);
- assertEquals(values, [
- { key: ["a", "a"], value: 0, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- ]);
-
- const cursor = iterator.cursor;
- assertEquals(cursor, "AmIA");
-
- const iterator2 = db.list({ prefix: ["a"] }, { cursor });
- const values2 = await collect(iterator2);
- assertEquals(values2, [
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "e"], value: 4, versionstamp },
- ]);
-});
-
-dbTest("list prefix with manual cursor reverse", async (db) => {
- const versionstamp = await setupData(db);
-
- const iterator = db.list({ prefix: ["a"] }, { limit: 2, reverse: true });
- const values = await collect(iterator);
- assertEquals(values, [
- { key: ["a", "e"], value: 4, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- ]);
-
- const cursor = iterator.cursor;
- assertEquals(cursor, "AmQA");
-
- const iterator2 = db.list({ prefix: ["a"] }, { cursor, reverse: true });
- const values2 = await collect(iterator2);
- assertEquals(values2, [
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "a"], value: 0, versionstamp },
- ]);
-});
-
-dbTest("list range", async (db) => {
- const versionstamp = await setupData(db);
-
- const entries = await collect(
- db.list({ start: ["a", "a"], end: ["a", "z"] }),
- );
- assertEquals(entries, [
- { key: ["a", "a"], value: 0, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "e"], value: 4, versionstamp },
- ]);
-});
-
-dbTest("list range reverse", async (db) => {
- const versionstamp = await setupData(db);
-
- const entries = await collect(
- db.list({ start: ["a", "a"], end: ["a", "z"] }, { reverse: true }),
- );
- assertEquals(entries, [
- { key: ["a", "e"], value: 4, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "a"], value: 0, versionstamp },
- ]);
-});
-
-dbTest("list range with limit", async (db) => {
- const versionstamp = await setupData(db);
-
- const entries = await collect(
- db.list({ start: ["a", "a"], end: ["a", "z"] }, { limit: 3 }),
- );
- assertEquals(entries, [
- { key: ["a", "a"], value: 0, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- ]);
-});
-
-dbTest("list range with limit reverse", async (db) => {
- const versionstamp = await setupData(db);
-
- const entries = await collect(
- db.list({ start: ["a", "a"], end: ["a", "z"] }, {
- limit: 3,
- reverse: true,
- }),
- );
- assertEquals(entries, [
- { key: ["a", "e"], value: 4, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- ]);
-});
-
-dbTest("list range nesting", async (db) => {
- const versionstamp = await setupData(db);
-
- const entries = await collect(db.list({ start: ["a"], end: ["a", "d"] }));
- assertEquals(entries, [
- { key: ["a"], value: -1, versionstamp },
- { key: ["a", "a"], value: 0, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- ]);
-});
-
-dbTest("list range short", async (db) => {
- const versionstamp = await setupData(db);
-
- const entries = await collect(
- db.list({ start: ["a", "b"], end: ["a", "d"] }),
- );
- assertEquals(entries, [
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- ]);
-});
-
-dbTest("list range with manual cursor", async (db) => {
- const versionstamp = await setupData(db);
-
- const iterator = db.list({ start: ["a", "b"], end: ["a", "z"] }, {
- limit: 2,
- });
- const entries = await collect(iterator);
- assertEquals(entries, [
- { key: ["a", "b"], value: 1, versionstamp },
- { key: ["a", "c"], value: 2, versionstamp },
- ]);
-
- const cursor = iterator.cursor;
- const iterator2 = db.list({ start: ["a", "b"], end: ["a", "z"] }, {
- cursor,
- });
- const entries2 = await collect(iterator2);
- assertEquals(entries2, [
- { key: ["a", "d"], value: 3, versionstamp },
- { key: ["a", "e"], value: 4, versionstamp },
- ]);
-});
-
-dbTest("list range with manual cursor reverse", async (db) => {
- const versionstamp = await setupData(db);
-
- const iterator = db.list({ start: ["a", "b"], end: ["a", "z"] }, {
- limit: 2,
- reverse: true,
- });
- const entries = await collect(iterator);
- assertEquals(entries, [
- { key: ["a", "e"], value: 4, versionstamp },
- { key: ["a", "d"], value: 3, versionstamp },
- ]);
-
- const cursor = iterator.cursor;
- const iterator2 = db.list({ start: ["a", "b"], end: ["a", "z"] }, {
- cursor,
- reverse: true,
- });
- const entries2 = await collect(iterator2);
- assertEquals(entries2, [
- { key: ["a", "c"], value: 2, versionstamp },
- { key: ["a", "b"], value: 1, versionstamp },
- ]);
-});
-
-dbTest("list range with start greater than end", async (db) => {
- await setupData(db);
- await assertRejects(
- async () => await collect(db.list({ start: ["b"], end: ["a"] })),
- TypeError,
- "start key is greater than end key",
- );
-});
-
-dbTest("list range with start equal to end", async (db) => {
- await setupData(db);
- const entries = await collect(db.list({ start: ["a"], end: ["a"] }));
- assertEquals(entries.length, 0);
-});
-
-dbTest("list invalid selector", async (db) => {
- await setupData(db);
-
- await assertRejects(async () => {
- await collect(
- db.list({ prefix: ["a"], start: ["a", "b"], end: ["a", "c"] }),
- );
- }, TypeError);
-
- await assertRejects(async () => {
- await collect(
- // @ts-expect-error missing end
- db.list({ start: ["a", "b"] }),
- );
- }, TypeError);
-
- await assertRejects(async () => {
- await collect(
- // @ts-expect-error missing start
- db.list({ end: ["a", "b"] }),
- );
- }, TypeError);
-});
-
-dbTest("invalid versionstamp in atomic check rejects", async (db) => {
- await assertRejects(async () => {
- await db.atomic().check({ key: ["a"], versionstamp: "" }).commit();
- }, TypeError);
-
- await assertRejects(async () => {
- await db.atomic().check({ key: ["a"], versionstamp: "xx".repeat(10) })
- .commit();
- }, TypeError);
-
- await assertRejects(async () => {
- await db.atomic().check({ key: ["a"], versionstamp: "aa".repeat(11) })
- .commit();
- }, TypeError);
-});
-
-dbTest("invalid mutation type rejects", async (db) => {
- await assertRejects(async () => {
- await db.atomic()
- // @ts-expect-error invalid type + value combo
- .mutate({ key: ["a"], type: "set" })
- .commit();
- }, TypeError);
-
- await assertRejects(async () => {
- await db.atomic()
- // @ts-expect-error invalid type + value combo
- .mutate({ key: ["a"], type: "delete", value: "123" })
- .commit();
- }, TypeError);
-
- await assertRejects(async () => {
- await db.atomic()
- // @ts-expect-error invalid type
- .mutate({ key: ["a"], type: "foobar" })
- .commit();
- }, TypeError);
-
- await assertRejects(async () => {
- await db.atomic()
- // @ts-expect-error invalid type
- .mutate({ key: ["a"], type: "foobar", value: "123" })
- .commit();
- }, TypeError);
-});
-
-dbTest("key ordering", async (db) => {
- await db.atomic()
- .set([new Uint8Array(0x1)], 0)
- .set(["a"], 0)
- .set([1n], 0)
- .set([3.14], 0)
- .set([false], 0)
- .set([true], 0)
- .commit();
-
- assertEquals((await collect(db.list({ prefix: [] }))).map((x) => x.key), [
- [new Uint8Array(0x1)],
- ["a"],
- [1n],
- [3.14],
- [false],
- [true],
- ]);
-});
-
-dbTest("key size limit", async (db) => {
- // 1 byte prefix + 1 byte suffix + 2045 bytes key
- const lastValidKey = new Uint8Array(2046).fill(1);
- const firstInvalidKey = new Uint8Array(2047).fill(1);
-
- const res = await db.set([lastValidKey], 1);
-
- assertEquals(await db.get([lastValidKey]), {
- key: [lastValidKey],
- value: 1,
- versionstamp: res.versionstamp,
- });
-
- await assertRejects(
- async () => await db.set([firstInvalidKey], 1),
- TypeError,
- "key too large for write (max 2048 bytes)",
- );
-
- await assertRejects(
- async () => await db.get([firstInvalidKey]),
- TypeError,
- "key too large for read (max 2049 bytes)",
- );
-});
-
-dbTest("value size limit", async (db) => {
- const lastValidValue = new Uint8Array(65536);
- const firstInvalidValue = new Uint8Array(65537);
-
- const res = await db.set(["a"], lastValidValue);
- assertEquals(await db.get(["a"]), {
- key: ["a"],
- value: lastValidValue,
- versionstamp: res.versionstamp,
- });
-
- await assertRejects(
- async () => await db.set(["b"], firstInvalidValue),
- TypeError,
- "value too large (max 65536 bytes)",
- );
-});
-
-dbTest("operation size limit", async (db) => {
- const lastValidKeys: Deno.KvKey[] = new Array(10).fill(0).map((
- _,
- i,
- ) => ["a", i]);
- const firstInvalidKeys: Deno.KvKey[] = new Array(11).fill(0).map((
- _,
- i,
- ) => ["a", i]);
- const invalidCheckKeys: Deno.KvKey[] = new Array(101).fill(0).map((
- _,
- i,
- ) => ["a", i]);
-
- const res = await db.getMany(lastValidKeys);
- assertEquals(res.length, 10);
-
- await assertRejects(
- async () => await db.getMany(firstInvalidKeys),
- TypeError,
- "too many ranges (max 10)",
- );
-
- const res2 = await collect(db.list({ prefix: ["a"] }, { batchSize: 1000 }));
- assertEquals(res2.length, 0);
-
- await assertRejects(
- async () => await collect(db.list({ prefix: ["a"] }, { batchSize: 1001 })),
- TypeError,
- "too many entries (max 1000)",
- );
-
- // when batchSize is not specified, limit is used but is clamped to 500
- assertEquals(
- (await collect(db.list({ prefix: ["a"] }, { limit: 1001 }))).length,
- 0,
- );
-
- const res3 = await db.atomic()
- .check(...lastValidKeys.map((key) => ({
- key,
- versionstamp: null,
- })))
- .mutate(...lastValidKeys.map((key) => ({
- key,
- type: "set",
- value: 1,
- } satisfies Deno.KvMutation)))
- .commit();
- assert(res3);
-
- await assertRejects(
- async () => {
- await db.atomic()
- .check(...invalidCheckKeys.map((key) => ({
- key,
- versionstamp: null,
- })))
- .mutate(...lastValidKeys.map((key) => ({
- key,
- type: "set",
- value: 1,
- } satisfies Deno.KvMutation)))
- .commit();
- },
- TypeError,
- "too many checks (max 100)",
- );
-
- const validMutateKeys: Deno.KvKey[] = new Array(1000).fill(0).map((
- _,
- i,
- ) => ["a", i]);
- const invalidMutateKeys: Deno.KvKey[] = new Array(1001).fill(0).map((
- _,
- i,
- ) => ["a", i]);
-
- const res4 = await db.atomic()
- .check(...lastValidKeys.map((key) => ({
- key,
- versionstamp: null,
- })))
- .mutate(...validMutateKeys.map((key) => ({
- key,
- type: "set",
- value: 1,
- } satisfies Deno.KvMutation)))
- .commit();
- assert(res4);
-
- await assertRejects(
- async () => {
- await db.atomic()
- .check(...lastValidKeys.map((key) => ({
- key,
- versionstamp: null,
- })))
- .mutate(...invalidMutateKeys.map((key) => ({
- key,
- type: "set",
- value: 1,
- } satisfies Deno.KvMutation)))
- .commit();
- },
- TypeError,
- "too many mutations (max 1000)",
- );
-});
-
-dbTest("total mutation size limit", async (db) => {
- const keys: Deno.KvKey[] = new Array(1000).fill(0).map((
- _,
- i,
- ) => ["a", i]);
-
- const atomic = db.atomic();
- for (const key of keys) {
- atomic.set(key, "foo");
- }
- const res = await atomic.commit();
- assert(res);
-
- // Use bigger values to trigger "total mutation size too large" error
- await assertRejects(
- async () => {
- const value = new Array(3000).fill("a").join("");
- const atomic = db.atomic();
- for (const key of keys) {
- atomic.set(key, value);
- }
- await atomic.commit();
- },
- TypeError,
- "total mutation size too large (max 819200 bytes)",
- );
-});
-
-dbTest("total key size limit", async (db) => {
- const longString = new Array(1100).fill("a").join("");
- const keys: Deno.KvKey[] = new Array(80).fill(0).map(() => [longString]);
-
- const atomic = db.atomic();
- for (const key of keys) {
- atomic.set(key, "foo");
- }
- await assertRejects(
- () => atomic.commit(),
- TypeError,
- "total key size too large (max 81920 bytes)",
- );
-});
-
-dbTest("keys must be arrays", async (db) => {
- await assertRejects(
- // @ts-expect-error invalid type
- async () => await db.get("a"),
- TypeError,
- );
-
- await assertRejects(
- // @ts-expect-error invalid type
- async () => await db.getMany(["a"]),
- TypeError,
- );
-
- await assertRejects(
- // @ts-expect-error invalid type
- async () => await db.set("a", 1),
- TypeError,
- );
-
- await assertRejects(
- // @ts-expect-error invalid type
- async () => await db.delete("a"),
- TypeError,
- );
-
- await assertRejects(
- async () =>
- await db.atomic()
- // @ts-expect-error invalid type
- .mutate({ key: "a", type: "set", value: 1 } satisfies Deno.KvMutation)
- .commit(),
- TypeError,
- );
-
- await assertRejects(
- async () =>
- await db.atomic()
- // @ts-expect-error invalid type
- .check({ key: "a", versionstamp: null })
- .set(["a"], 1)
- .commit(),
- TypeError,
- );
-});
-
-Deno.test("Deno.Kv constructor throws", () => {
- assertThrows(() => {
- new Deno.Kv();
- });
-});
-
-// This function is never called, it is just used to check that all the types
-// are behaving as expected.
-async function _typeCheckingTests() {
- const kv = new Deno.Kv();
-
- const a = await kv.get(["a"]);
- assertType<IsExact<typeof a, Deno.KvEntryMaybe<unknown>>>(true);
-
- const b = await kv.get<string>(["b"]);
- assertType<IsExact<typeof b, Deno.KvEntryMaybe<string>>>(true);
-
- const c = await kv.getMany([["a"], ["b"]]);
- assertType<
- IsExact<typeof c, [Deno.KvEntryMaybe<unknown>, Deno.KvEntryMaybe<unknown>]>
- >(true);
-
- const d = await kv.getMany([["a"], ["b"]] as const);
- assertType<
- IsExact<typeof d, [Deno.KvEntryMaybe<unknown>, Deno.KvEntryMaybe<unknown>]>
- >(true);
-
- const e = await kv.getMany<[string, number]>([["a"], ["b"]]);
- assertType<
- IsExact<typeof e, [Deno.KvEntryMaybe<string>, Deno.KvEntryMaybe<number>]>
- >(true);
-
- const keys: Deno.KvKey[] = [["a"], ["b"]];
- const f = await kv.getMany(keys);
- assertType<IsExact<typeof f, Deno.KvEntryMaybe<unknown>[]>>(true);
-
- const g = kv.list({ prefix: ["a"] });
- assertType<IsExact<typeof g, Deno.KvListIterator<unknown>>>(true);
- const h = await g.next();
- assert(!h.done);
- assertType<IsExact<typeof h.value, Deno.KvEntry<unknown>>>(true);
-
- const i = kv.list<string>({ prefix: ["a"] });
- assertType<IsExact<typeof i, Deno.KvListIterator<string>>>(true);
- const j = await i.next();
- assert(!j.done);
- assertType<IsExact<typeof j.value, Deno.KvEntry<string>>>(true);
-}
-
-queueTest("basic listenQueue and enqueue", async (db) => {
- const { promise, resolve } = Promise.withResolvers<void>();
- let dequeuedMessage: unknown = null;
- const listener = db.listenQueue((msg) => {
- dequeuedMessage = msg;
- resolve();
- });
- try {
- const res = await db.enqueue("test");
- assert(res.ok);
- assertNotEquals(res.versionstamp, null);
- await promise;
- assertEquals(dequeuedMessage, "test");
- } finally {
- db.close();
- await listener;
- }
-});
-
-for (const { name, value } of VALUE_CASES) {
- queueTest(`listenQueue and enqueue ${name}`, async (db) => {
- const numEnqueues = 10;
- let count = 0;
- const deferreds: ReturnType<typeof Promise.withResolvers<unknown>>[] = [];
- const listeners: Promise<void>[] = [];
- listeners.push(db.listenQueue((msg: unknown) => {
- deferreds[count++].resolve(msg);
- }));
- try {
- for (let i = 0; i < numEnqueues; i++) {
- deferreds.push(Promise.withResolvers<unknown>());
- await db.enqueue(value);
- }
- const dequeuedMessages = await Promise.all(
- deferreds.map(({ promise }) => promise),
- );
- for (let i = 0; i < numEnqueues; i++) {
- assertEquals(dequeuedMessages[i], value);
- }
- } finally {
- db.close();
- for (const listener of listeners) {
- await listener;
- }
- }
- });
-}
-
-queueTest("queue mixed types", async (db) => {
- let deferred: ReturnType<typeof Promise.withResolvers<void>>;
- let dequeuedMessage: unknown = null;
- const listener = db.listenQueue((msg: unknown) => {
- dequeuedMessage = msg;
- deferred.resolve();
- });
- try {
- for (const item of VALUE_CASES) {
- deferred = Promise.withResolvers<void>();
- await db.enqueue(item.value);
- await deferred.promise;
- assertEquals(dequeuedMessage, item.value);
- }
- } finally {
- db.close();
- await listener;
- }
-});
-
-queueTest("queue delay", async (db) => {
- let dequeueTime: number | undefined;
- const { promise, resolve } = Promise.withResolvers<void>();
- let dequeuedMessage: unknown = null;
- const listener = db.listenQueue((msg) => {
- dequeueTime = Date.now();
- dequeuedMessage = msg;
- resolve();
- });
- try {
- const enqueueTime = Date.now();
- await db.enqueue("test", { delay: 1000 });
- await promise;
- assertEquals(dequeuedMessage, "test");
- assert(dequeueTime !== undefined);
- assert(dequeueTime - enqueueTime >= 1000);
- } finally {
- db.close();
- await listener;
- }
-});
-
-queueTest("queue delay with atomic", async (db) => {
- let dequeueTime: number | undefined;
- const { promise, resolve } = Promise.withResolvers<void>();
- let dequeuedMessage: unknown = null;
- const listener = db.listenQueue((msg) => {
- dequeueTime = Date.now();
- dequeuedMessage = msg;
- resolve();
- });
- try {
- const enqueueTime = Date.now();
- const res = await db.atomic()
- .enqueue("test", { delay: 1000 })
- .commit();
- assert(res.ok);
-
- await promise;
- assertEquals(dequeuedMessage, "test");
- assert(dequeueTime !== undefined);
- assert(dequeueTime - enqueueTime >= 1000);
- } finally {
- db.close();
- await listener;
- }
-});
-
-queueTest("queue delay and now", async (db) => {
- let count = 0;
- let dequeueTime: number | undefined;
- const { promise, resolve } = Promise.withResolvers<void>();
- let dequeuedMessage: unknown = null;
- const listener = db.listenQueue((msg) => {
- count += 1;
- if (count == 2) {
- dequeueTime = Date.now();
- dequeuedMessage = msg;
- resolve();
- }
- });
- try {
- const enqueueTime = Date.now();
- await db.enqueue("test-1000", { delay: 1000 });
- await db.enqueue("test");
- await promise;
- assertEquals(dequeuedMessage, "test-1000");
- assert(dequeueTime !== undefined);
- assert(dequeueTime - enqueueTime >= 1000);
- } finally {
- db.close();
- await listener;
- }
-});
-
-dbTest("queue negative delay", async (db) => {
- await assertRejects(async () => {
- await db.enqueue("test", { delay: -100 });
- }, TypeError);
-});
-
-dbTest("queue nan delay", async (db) => {
- await assertRejects(async () => {
- await db.enqueue("test", { delay: Number.NaN });
- }, TypeError);
-});
-
-dbTest("queue large delay", async (db) => {
- await db.enqueue("test", { delay: 30 * 24 * 60 * 60 * 1000 });
- await assertRejects(async () => {
- await db.enqueue("test", { delay: 30 * 24 * 60 * 60 * 1000 + 1 });
- }, TypeError);
-});
-
-queueTest("listenQueue with async callback", async (db) => {
- const { promise, resolve } = Promise.withResolvers<void>();
- let dequeuedMessage: unknown = null;
- const listener = db.listenQueue(async (msg) => {
- dequeuedMessage = msg;
- await sleep(100);
- resolve();
- });
- try {
- await db.enqueue("test");
- await promise;
- assertEquals(dequeuedMessage, "test");
- } finally {
- db.close();
- await listener;
- }
-});
-
-queueTest("queue retries", async (db) => {
- let count = 0;
- const listener = db.listenQueue(async (_msg) => {
- count += 1;
- await sleep(10);
- throw new TypeError("dequeue error");
- });
- try {
- await db.enqueue("test");
- await sleep(10000);
- } finally {
- db.close();
- await listener;
- }
-
- // There should have been 1 attempt + 3 retries in the 10 seconds
- assertEquals(4, count);
-});
-
-queueTest("queue retries with backoffSchedule", async (db) => {
- let count = 0;
- const listener = db.listenQueue((_msg) => {
- count += 1;
- throw new TypeError("dequeue error");
- });
- try {
- await db.enqueue("test", { backoffSchedule: [1] });
- await sleep(2000);
- } finally {
- db.close();
- await listener;
- }
-
- // There should have been 1 attempt + 1 retry
- assertEquals(2, count);
-});
-
-queueTest("multiple listenQueues", async (db) => {
- const numListens = 10;
- let count = 0;
- const deferreds: ReturnType<typeof Promise.withResolvers<void>>[] = [];
- const dequeuedMessages: unknown[] = [];
- const listeners: Promise<void>[] = [];
- for (let i = 0; i < numListens; i++) {
- listeners.push(db.listenQueue((msg) => {
- dequeuedMessages.push(msg);
- deferreds[count++].resolve();
- }));
- }
- try {
- for (let i = 0; i < numListens; i++) {
- deferreds.push(Promise.withResolvers<void>());
- await db.enqueue("msg_" + i);
- await deferreds[i].promise;
- const msg = dequeuedMessages[i];
- assertEquals("msg_" + i, msg);
- }
- } finally {
- db.close();
- for (let i = 0; i < numListens; i++) {
- await listeners[i];
- }
- }
-});
-
-queueTest("enqueue with atomic", async (db) => {
- const { promise, resolve } = Promise.withResolvers<void>();
- let dequeuedMessage: unknown = null;
- const listener = db.listenQueue((msg) => {
- dequeuedMessage = msg;
- resolve();
- });
-
- try {
- await db.set(["t"], "1");
-
- let currentValue = await db.get(["t"]);
- assertEquals("1", currentValue.value);
-
- const res = await db.atomic()
- .check(currentValue)
- .set(currentValue.key, "2")
- .enqueue("test")
- .commit();
- assert(res.ok);
-
- await promise;
- assertEquals("test", dequeuedMessage);
-
- currentValue = await db.get(["t"]);
- assertEquals("2", currentValue.value);
- } finally {
- db.close();
- await listener;
- }
-});
-
-queueTest("enqueue with atomic nonce", async (db) => {
- const { promise, resolve } = Promise.withResolvers<void>();
- let dequeuedMessage: unknown = null;
-
- const nonce = crypto.randomUUID();
-
- const listener = db.listenQueue(async (val) => {
- const message = val as { msg: string; nonce: string };
- const nonce = message.nonce;
- const nonceValue = await db.get(["nonces", nonce]);
- if (nonceValue.versionstamp === null) {
- dequeuedMessage = message.msg;
- resolve();
- return;
- }
-
- assertNotEquals(nonceValue.versionstamp, null);
- const res = await db.atomic()
- .check(nonceValue)
- .delete(["nonces", nonce])
- .set(["a", "b"], message.msg)
- .commit();
- if (res.ok) {
- // Simulate an error so that the message has to be redelivered
- throw new Error("injected error");
- }
- });
-
- try {
- const res = await db.atomic()
- .check({ key: ["nonces", nonce], versionstamp: null })
- .set(["nonces", nonce], true)
- .enqueue({ msg: "test", nonce })
- .commit();
- assert(res.ok);
-
- await promise;
- assertEquals("test", dequeuedMessage);
-
- const currentValue = await db.get(["a", "b"]);
- assertEquals("test", currentValue.value);
-
- const nonceValue = await db.get(["nonces", nonce]);
- assertEquals(nonceValue.versionstamp, null);
- } finally {
- db.close();
- await listener;
- }
-});
-
-Deno.test({
- name: "queue persistence with inflight messages",
- sanitizeOps: false,
- sanitizeResources: false,
- async fn() {
- const filename = await Deno.makeTempFile({ prefix: "queue_db" });
- try {
- let db: Deno.Kv = await Deno.openKv(filename);
-
- let count = 0;
- let deferred = Promise.withResolvers<void>();
-
- // Register long-running handler.
- let listener = db.listenQueue(async (_msg) => {
- count += 1;
- if (count == 3) {
- deferred.resolve();
- }
- await new Promise(() => {});
- });
-
- // Enqueue 3 messages.
- await db.enqueue("msg0");
- await db.enqueue("msg1");
- await db.enqueue("msg2");
- await deferred.promise;
-
- // Close the database and wait for the listener to finish.
- db.close();
- await listener;
-
- // Wait at least MESSAGE_DEADLINE_TIMEOUT before reopening the database.
- // This ensures that inflight messages are requeued immediately after
- // the database is reopened.
- // https://github.com/denoland/denokv/blob/efb98a1357d37291a225ed5cf1fc4ecc7c737fab/sqlite/backend.rs#L120
- await sleep(6000);
-
- // Now reopen the database.
- db = await Deno.openKv(filename);
-
- count = 0;
- deferred = Promise.withResolvers<void>();
-
- // Register a handler that will complete quickly.
- listener = db.listenQueue((_msg) => {
- count += 1;
- if (count == 3) {
- deferred.resolve();
- }
- });
-
- // Wait for the handlers to finish.
- await deferred.promise;
- assertEquals(3, count);
- db.close();
- await listener;
- } finally {
- try {
- await Deno.remove(filename);
- } catch {
- // pass
- }
- }
- },
-});
-
-Deno.test({
- name: "queue persistence with delay messages",
- async fn() {
- const filename = await Deno.makeTempFile({ prefix: "queue_db" });
- try {
- await Deno.remove(filename);
- } catch {
- // pass
- }
- try {
- let db: Deno.Kv = await Deno.openKv(filename);
-
- let count = 0;
- let deferred = Promise.withResolvers<void>();
-
- // Register long-running handler.
- let listener = db.listenQueue((_msg) => {});
-
- // Enqueue 3 messages into the future.
- await db.enqueue("msg0", { delay: 10000 });
- await db.enqueue("msg1", { delay: 10000 });
- await db.enqueue("msg2", { delay: 10000 });
-
- // Close the database and wait for the listener to finish.
- db.close();
- await listener;
-
- // Now reopen the database.
- db = await Deno.openKv(filename);
-
- count = 0;
- deferred = Promise.withResolvers<void>();
-
- // Register a handler that will complete quickly.
- listener = db.listenQueue((_msg) => {
- count += 1;
- if (count == 3) {
- deferred.resolve();
- }
- });
-
- // Wait for the handlers to finish.
- await deferred.promise;
- assertEquals(3, count);
- db.close();
- await listener;
- } finally {
- try {
- await Deno.remove(filename);
- } catch {
- // pass
- }
- }
- },
-});
-
-Deno.test({
- name: "different kv instances for enqueue and queueListen",
- async fn() {
- const filename = await Deno.makeTempFile({ prefix: "queue_db" });
- try {
- const db0 = await Deno.openKv(filename);
- const db1 = await Deno.openKv(filename);
- const { promise, resolve } = Promise.withResolvers<void>();
- let dequeuedMessage: unknown = null;
- const listener = db0.listenQueue((msg) => {
- dequeuedMessage = msg;
- resolve();
- });
- try {
- const res = await db1.enqueue("test");
- assert(res.ok);
- assertNotEquals(res.versionstamp, null);
- await promise;
- assertEquals(dequeuedMessage, "test");
- } finally {
- db0.close();
- await listener;
- db1.close();
- }
- } finally {
- try {
- await Deno.remove(filename);
- } catch {
- // pass
- }
- }
- },
-});
-
-Deno.test({
- name: "queue graceful close",
- async fn() {
- const db: Deno.Kv = await Deno.openKv(":memory:");
- const listener = db.listenQueue((_msg) => {});
- db.close();
- await listener;
- },
-});
-
-dbTest("invalid backoffSchedule", async (db) => {
- await assertRejects(
- async () => {
- await db.enqueue("foo", { backoffSchedule: [1, 1, 1, 1, 1, 1] });
- },
- TypeError,
- "invalid backoffSchedule",
- );
- await assertRejects(
- async () => {
- await db.enqueue("foo", { backoffSchedule: [3600001] });
- },
- TypeError,
- "invalid backoffSchedule",
- );
-});
-
-dbTest("atomic operation is exposed", (db) => {
- assert(Deno.AtomicOperation);
- const ao = db.atomic();
- assert(ao instanceof Deno.AtomicOperation);
-});
-
-Deno.test({
- name: "racy open",
- async fn() {
- for (let i = 0; i < 100; i++) {
- const filename = await Deno.makeTempFile({ prefix: "racy_open_db" });
- try {
- const [db1, db2, db3] = await Promise.all([
- Deno.openKv(filename),
- Deno.openKv(filename),
- Deno.openKv(filename),
- ]);
- db1.close();
- db2.close();
- db3.close();
- } finally {
- await Deno.remove(filename);
- }
- }
- },
-});
-
-Deno.test({
- name: "racy write",
- async fn() {
- const filename = await Deno.makeTempFile({ prefix: "racy_write_db" });
- const concurrency = 20;
- const iterations = 5;
- try {
- const dbs = await Promise.all(
- Array(concurrency).fill(0).map(() => Deno.openKv(filename)),
- );
- try {
- for (let i = 0; i < iterations; i++) {
- await Promise.all(
- dbs.map((db) => db.atomic().sum(["counter"], 1n).commit()),
- );
- }
- assertEquals(
- ((await dbs[0].get(["counter"])).value as Deno.KvU64).value,
- BigInt(concurrency * iterations),
- );
- } finally {
- dbs.forEach((db) => db.close());
- }
- } finally {
- await Deno.remove(filename);
- }
- },
-});
-
-Deno.test({
- name: "kv expiration",
- async fn() {
- const filename = await Deno.makeTempFile({ prefix: "kv_expiration_db" });
- try {
- await Deno.remove(filename);
- } catch {
- // pass
- }
- let db: Deno.Kv | null = null;
-
- try {
- db = await Deno.openKv(filename);
-
- await db.set(["a"], 1, { expireIn: 1000 });
- await db.set(["b"], 2, { expireIn: 1000 });
- assertEquals((await db.get(["a"])).value, 1);
- assertEquals((await db.get(["b"])).value, 2);
-
- // Value overwrite should also reset expiration
- await db.set(["b"], 2, { expireIn: 3600 * 1000 });
-
- // Wait for expiration
- await sleep(1000);
-
- // Re-open to trigger immediate cleanup
- db.close();
- db = null;
- db = await Deno.openKv(filename);
-
- let ok = false;
- for (let i = 0; i < 50; i++) {
- await sleep(100);
- if (
- JSON.stringify(
- (await db.getMany([["a"], ["b"]])).map((x) => x.value),
- ) === "[null,2]"
- ) {
- ok = true;
- break;
- }
- }
-
- if (!ok) {
- throw new Error("Values did not expire");
- }
- } finally {
- if (db) {
- try {
- db.close();
- } catch {
- // pass
- }
- }
- try {
- await Deno.remove(filename);
- } catch {
- // pass
- }
- }
- },
-});
-
-Deno.test({
- name: "kv expiration with atomic",
- async fn() {
- const filename = await Deno.makeTempFile({ prefix: "kv_expiration_db" });
- try {
- await Deno.remove(filename);
- } catch {
- // pass
- }
- let db: Deno.Kv | null = null;
-
- try {
- db = await Deno.openKv(filename);
-
- await db.atomic().set(["a"], 1, { expireIn: 1000 }).set(["b"], 2, {
- expireIn: 1000,
- }).commit();
- assertEquals((await db.getMany([["a"], ["b"]])).map((x) => x.value), [
- 1,
- 2,
- ]);
-
- // Wait for expiration
- await sleep(1000);
-
- // Re-open to trigger immediate cleanup
- db.close();
- db = null;
- db = await Deno.openKv(filename);
-
- let ok = false;
- for (let i = 0; i < 50; i++) {
- await sleep(100);
- if (
- JSON.stringify(
- (await db.getMany([["a"], ["b"]])).map((x) => x.value),
- ) === "[null,null]"
- ) {
- ok = true;
- break;
- }
- }
-
- if (!ok) {
- throw new Error("Values did not expire");
- }
- } finally {
- if (db) {
- try {
- db.close();
- } catch {
- // pass
- }
- }
- try {
- await Deno.remove(filename);
- } catch {
- // pass
- }
- }
- },
-});
-
-Deno.test({
- name: "remote backend",
- async fn() {
- const db = await Deno.openKv("http://localhost:4545/kv_remote_authorize");
- try {
- await db.set(["some-key"], 1);
- const entry = await db.get(["some-key"]);
- assertEquals(entry.value, null);
- assertEquals(entry.versionstamp, null);
- } finally {
- db.close();
- }
- },
-});
-
-Deno.test({
- name: "remote backend invalid format",
- async fn() {
- const db = await Deno.openKv(
- "http://localhost:4545/kv_remote_authorize_invalid_format",
- );
-
- await assertRejects(
- async () => {
- await db.set(["some-key"], 1);
- },
- Error,
- "Failed to parse metadata: ",
- );
-
- db.close();
- },
-});
-
-Deno.test({
- name: "remote backend invalid version",
- async fn() {
- const db = await Deno.openKv(
- "http://localhost:4545/kv_remote_authorize_invalid_version",
- );
-
- await assertRejects(
- async () => {
- await db.set(["some-key"], 1);
- },
- Error,
- "Failed to parse metadata: unsupported metadata version: 1000",
- );
-
- db.close();
- },
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function kvExplicitResourceManagement() {
- let kv2: Deno.Kv;
-
- {
- using kv = await Deno.openKv(":memory:");
- kv2 = kv;
-
- const res = await kv.get(["a"]);
- assertEquals(res.versionstamp, null);
- }
-
- await assertRejects(() => kv2.get(["a"]), Deno.errors.BadResource);
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function kvExplicitResourceManagementManualClose() {
- using kv = await Deno.openKv(":memory:");
- kv.close();
- await assertRejects(() => kv.get(["a"]), Deno.errors.BadResource);
- // calling [Symbol.dispose] after manual close is a no-op
- },
-);
-
-dbTest("key watch", async (db) => {
- const changeHistory: Deno.KvEntryMaybe<number>[] = [];
- const watcher: ReadableStream<Deno.KvEntryMaybe<number>[]> = db.watch<
- number[]
- >([["key"]]);
-
- const reader = watcher.getReader();
- const expectedChanges = 2;
-
- const work = (async () => {
- for (let i = 0; i < expectedChanges; i++) {
- const message = await reader.read();
- if (message.done) {
- throw new Error("Unexpected end of stream");
- }
- changeHistory.push(message.value[0]);
- }
-
- await reader.cancel();
- })();
-
- while (changeHistory.length !== 1) {
- await sleep(100);
- }
- assertEquals(changeHistory[0], {
- key: ["key"],
- value: null,
- versionstamp: null,
- });
-
- const { versionstamp } = await db.set(["key"], 1);
- while (changeHistory.length as number !== 2) {
- await sleep(100);
- }
- assertEquals(changeHistory[1], {
- key: ["key"],
- value: 1,
- versionstamp,
- });
-
- await work;
- await reader.cancel();
-});
-
-dbTest("set with key versionstamp suffix", async (db) => {
- const result1 = await Array.fromAsync(db.list({ prefix: ["a"] }));
- assertEquals(result1, []);
-
- const setRes1 = await db.set(["a", db.commitVersionstamp()], "b");
- assert(setRes1.ok);
- assert(setRes1.versionstamp > ZERO_VERSIONSTAMP);
-
- const result2 = await Array.fromAsync(db.list({ prefix: ["a"] }));
- assertEquals(result2.length, 1);
- assertEquals(result2[0].key[1], setRes1.versionstamp);
- assertEquals(result2[0].value, "b");
- assertEquals(result2[0].versionstamp, setRes1.versionstamp);
-
- const setRes2 = await db.atomic().set(["a", db.commitVersionstamp()], "c")
- .commit();
- assert(setRes2.ok);
- assert(setRes2.versionstamp > setRes1.versionstamp);
-
- const result3 = await Array.fromAsync(db.list({ prefix: ["a"] }));
- assertEquals(result3.length, 2);
- assertEquals(result3[1].key[1], setRes2.versionstamp);
- assertEquals(result3[1].value, "c");
- assertEquals(result3[1].versionstamp, setRes2.versionstamp);
-
- await assertRejects(
- async () => await db.set(["a", db.commitVersionstamp(), "a"], "x"),
- TypeError,
- "expected string, number, bigint, ArrayBufferView, boolean",
- );
-});
-
-Deno.test({
- name: "watch should stop when db closed",
- async fn() {
- const db = await Deno.openKv(":memory:");
-
- const watch = db.watch([["a"]]);
- const completion = (async () => {
- for await (const _item of watch) {
- // pass
- }
- })();
-
- setTimeout(() => {
- db.close();
- }, 100);
-
- await completion;
- },
-});
diff --git a/cli/tests/unit/link_test.ts b/cli/tests/unit/link_test.ts
deleted file mode 100644
index 6048b8add..000000000
--- a/cli/tests/unit/link_test.ts
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function linkSyncSuccess() {
- const testDir = Deno.makeTempDirSync();
- const oldData = "Hardlink";
- const oldName = testDir + "/oldname";
- const newName = testDir + "/newname";
- Deno.writeFileSync(oldName, new TextEncoder().encode(oldData));
- // Create the hard link.
- Deno.linkSync(oldName, newName);
- // We should expect reading the same content.
- const newData = Deno.readTextFileSync(newName);
- assertEquals(oldData, newData);
- // Writing to newname also affects oldname.
- const newData2 = "Modified";
- Deno.writeFileSync(newName, new TextEncoder().encode(newData2));
- assertEquals(
- newData2,
- Deno.readTextFileSync(oldName),
- );
- // Writing to oldname also affects newname.
- const newData3 = "ModifiedAgain";
- Deno.writeFileSync(oldName, new TextEncoder().encode(newData3));
- assertEquals(
- newData3,
- Deno.readTextFileSync(newName),
- );
- // Remove oldname. File still accessible through newname.
- Deno.removeSync(oldName);
- const newNameStat = Deno.statSync(newName);
- assert(newNameStat.isFile);
- assert(!newNameStat.isSymlink); // Not a symlink.
- assertEquals(
- newData3,
- Deno.readTextFileSync(newName),
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function linkSyncExists() {
- const testDir = Deno.makeTempDirSync();
- const oldName = testDir + "/oldname";
- const newName = testDir + "/newname";
- Deno.writeFileSync(oldName, new TextEncoder().encode("oldName"));
- // newname is already created.
- Deno.writeFileSync(newName, new TextEncoder().encode("newName"));
-
- assertThrows(
- () => {
- Deno.linkSync(oldName, newName);
- },
- Deno.errors.AlreadyExists,
- `link '${oldName}' -> '${newName}'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function linkSyncNotFound() {
- const testDir = Deno.makeTempDirSync();
- const oldName = testDir + "/oldname";
- const newName = testDir + "/newname";
-
- assertThrows(
- () => {
- Deno.linkSync(oldName, newName);
- },
- Deno.errors.NotFound,
- `link '${oldName}' -> '${newName}'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: false, write: true } },
- function linkSyncReadPerm() {
- assertThrows(() => {
- Deno.linkSync("oldbaddir", "newbaddir");
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: false } },
- function linkSyncWritePerm() {
- assertThrows(() => {
- Deno.linkSync("oldbaddir", "newbaddir");
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function linkSuccess() {
- const testDir = Deno.makeTempDirSync();
- const oldData = "Hardlink";
- const oldName = testDir + "/oldname";
- const newName = testDir + "/newname";
- Deno.writeFileSync(oldName, new TextEncoder().encode(oldData));
- // Create the hard link.
- await Deno.link(oldName, newName);
- // We should expect reading the same content.
- const newData = Deno.readTextFileSync(newName);
- assertEquals(oldData, newData);
- // Writing to newname also affects oldname.
- const newData2 = "Modified";
- Deno.writeFileSync(newName, new TextEncoder().encode(newData2));
- assertEquals(
- newData2,
- Deno.readTextFileSync(oldName),
- );
- // Writing to oldname also affects newname.
- const newData3 = "ModifiedAgain";
- Deno.writeFileSync(oldName, new TextEncoder().encode(newData3));
- assertEquals(
- newData3,
- Deno.readTextFileSync(newName),
- );
- // Remove oldname. File still accessible through newname.
- Deno.removeSync(oldName);
- const newNameStat = Deno.statSync(newName);
- assert(newNameStat.isFile);
- assert(!newNameStat.isSymlink); // Not a symlink.
- assertEquals(
- newData3,
- Deno.readTextFileSync(newName),
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function linkExists() {
- const testDir = Deno.makeTempDirSync();
- const oldName = testDir + "/oldname";
- const newName = testDir + "/newname";
- Deno.writeFileSync(oldName, new TextEncoder().encode("oldName"));
- // newname is already created.
- Deno.writeFileSync(newName, new TextEncoder().encode("newName"));
-
- await assertRejects(
- async () => {
- await Deno.link(oldName, newName);
- },
- Deno.errors.AlreadyExists,
- `link '${oldName}' -> '${newName}'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function linkNotFound() {
- const testDir = Deno.makeTempDirSync();
- const oldName = testDir + "/oldname";
- const newName = testDir + "/newname";
-
- await assertRejects(
- async () => {
- await Deno.link(oldName, newName);
- },
- Deno.errors.NotFound,
- `link '${oldName}' -> '${newName}'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: false, write: true } },
- async function linkReadPerm() {
- await assertRejects(async () => {
- await Deno.link("oldbaddir", "newbaddir");
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: false } },
- async function linkWritePerm() {
- await assertRejects(async () => {
- await Deno.link("oldbaddir", "newbaddir");
- }, Deno.errors.PermissionDenied);
- },
-);
diff --git a/cli/tests/unit/make_temp_test.ts b/cli/tests/unit/make_temp_test.ts
deleted file mode 100644
index cbbae8dfe..000000000
--- a/cli/tests/unit/make_temp_test.ts
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test({ permissions: { write: true } }, function makeTempDirSyncSuccess() {
- const dir1 = Deno.makeTempDirSync({ prefix: "hello", suffix: "world" });
- const dir2 = Deno.makeTempDirSync({ prefix: "hello", suffix: "world" });
- // Check that both dirs are different.
- assert(dir1 !== dir2);
- for (const dir of [dir1, dir2]) {
- // Check that the prefix and suffix are applied.
- const lastPart = dir.replace(/^.*[\\\/]/, "");
- assert(lastPart.startsWith("hello"));
- assert(lastPart.endsWith("world"));
- }
- // Check that the `dir` option works.
- const dir3 = Deno.makeTempDirSync({ dir: dir1 });
- assert(dir3.startsWith(dir1));
- assert(/^[\\\/]/.test(dir3.slice(dir1.length)));
- // Check that creating a temp dir inside a nonexisting directory fails.
- assertThrows(() => {
- Deno.makeTempDirSync({ dir: "/baddir" });
- }, Deno.errors.NotFound);
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function makeTempDirSyncMode() {
- const path = Deno.makeTempDirSync();
- const pathInfo = Deno.statSync(path);
- if (Deno.build.os !== "windows") {
- assertEquals(pathInfo.mode! & 0o777, 0o700 & ~Deno.umask());
- }
- },
-);
-
-Deno.test({ permissions: { write: false } }, function makeTempDirSyncPerm() {
- // makeTempDirSync should require write permissions (for now).
- assertThrows(() => {
- Deno.makeTempDirSync({ dir: "/baddir" });
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { write: true } },
- async function makeTempDirSuccess() {
- const dir1 = await Deno.makeTempDir({ prefix: "hello", suffix: "world" });
- const dir2 = await Deno.makeTempDir({ prefix: "hello", suffix: "world" });
- // Check that both dirs are different.
- assert(dir1 !== dir2);
- for (const dir of [dir1, dir2]) {
- // Check that the prefix and suffix are applied.
- const lastPart = dir.replace(/^.*[\\\/]/, "");
- assert(lastPart.startsWith("hello"));
- assert(lastPart.endsWith("world"));
- }
- // Check that the `dir` option works.
- const dir3 = await Deno.makeTempDir({ dir: dir1 });
- assert(dir3.startsWith(dir1));
- assert(/^[\\\/]/.test(dir3.slice(dir1.length)));
- // Check that creating a temp dir inside a nonexisting directory fails.
- await assertRejects(async () => {
- await Deno.makeTempDir({ dir: "/baddir" });
- }, Deno.errors.NotFound);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function makeTempDirMode() {
- const path = await Deno.makeTempDir();
- const pathInfo = Deno.statSync(path);
- if (Deno.build.os !== "windows") {
- assertEquals(pathInfo.mode! & 0o777, 0o700 & ~Deno.umask());
- }
- },
-);
-
-Deno.test({ permissions: { write: true } }, function makeTempFileSyncSuccess() {
- const file1 = Deno.makeTempFileSync({ prefix: "hello", suffix: "world" });
- const file2 = Deno.makeTempFileSync({ prefix: "hello", suffix: "world" });
- // Check that both dirs are different.
- assert(file1 !== file2);
- for (const dir of [file1, file2]) {
- // Check that the prefix and suffix are applied.
- const lastPart = dir.replace(/^.*[\\\/]/, "");
- assert(lastPart.startsWith("hello"));
- assert(lastPart.endsWith("world"));
- }
- // Check that the `dir` option works.
- const dir = Deno.makeTempDirSync({ prefix: "tempdir" });
- const file3 = Deno.makeTempFileSync({ dir });
- assert(file3.startsWith(dir));
- assert(/^[\\\/]/.test(file3.slice(dir.length)));
- // Check that creating a temp file inside a nonexisting directory fails.
- assertThrows(() => {
- Deno.makeTempFileSync({ dir: "/baddir" });
- }, Deno.errors.NotFound);
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function makeTempFileSyncMode() {
- const path = Deno.makeTempFileSync();
- const pathInfo = Deno.statSync(path);
- if (Deno.build.os !== "windows") {
- assertEquals(pathInfo.mode! & 0o777, 0o600 & ~Deno.umask());
- }
- },
-);
-
-Deno.test({ permissions: { write: false } }, function makeTempFileSyncPerm() {
- // makeTempFileSync should require write permissions (for now).
- assertThrows(() => {
- Deno.makeTempFileSync({ dir: "/baddir" });
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { write: true } },
- async function makeTempFileSuccess() {
- const file1 = await Deno.makeTempFile({ prefix: "hello", suffix: "world" });
- const file2 = await Deno.makeTempFile({ prefix: "hello", suffix: "world" });
- // Check that both dirs are different.
- assert(file1 !== file2);
- for (const dir of [file1, file2]) {
- // Check that the prefix and suffix are applied.
- const lastPart = dir.replace(/^.*[\\\/]/, "");
- assert(lastPart.startsWith("hello"));
- assert(lastPart.endsWith("world"));
- }
- // Check that the `dir` option works.
- const dir = Deno.makeTempDirSync({ prefix: "tempdir" });
- const file3 = await Deno.makeTempFile({ dir });
- assert(file3.startsWith(dir));
- assert(/^[\\\/]/.test(file3.slice(dir.length)));
- // Check that creating a temp file inside a nonexisting directory fails.
- await assertRejects(async () => {
- await Deno.makeTempFile({ dir: "/baddir" });
- }, Deno.errors.NotFound);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function makeTempFileMode() {
- const path = await Deno.makeTempFile();
- const pathInfo = Deno.statSync(path);
- if (Deno.build.os !== "windows") {
- assertEquals(pathInfo.mode! & 0o777, 0o600 & ~Deno.umask());
- }
- },
-);
diff --git a/cli/tests/unit/message_channel_test.ts b/cli/tests/unit/message_channel_test.ts
deleted file mode 100644
index 88fb1ba11..000000000
--- a/cli/tests/unit/message_channel_test.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-// NOTE: these are just sometests to test the TypeScript types. Real coverage is
-// provided by WPT.
-import { assert, assertEquals } from "@test_util/std/assert/mod.ts";
-
-Deno.test("messagechannel", async () => {
- const mc = new MessageChannel();
- const mc2 = new MessageChannel();
- assert(mc.port1);
- assert(mc.port2);
-
- const { promise, resolve } = Promise.withResolvers<void>();
-
- mc.port2.onmessage = (e) => {
- assertEquals(e.data, "hello");
- assertEquals(e.ports.length, 1);
- assert(e.ports[0] instanceof MessagePort);
- e.ports[0].close();
- resolve();
- };
-
- mc.port1.postMessage("hello", [mc2.port1]);
- mc.port1.close();
-
- await promise;
-
- mc.port2.close();
- mc2.port2.close();
-});
-
-Deno.test("messagechannel clone port", async () => {
- const mc = new MessageChannel();
- const mc2 = new MessageChannel();
- assert(mc.port1);
- assert(mc.port2);
-
- const { promise, resolve } = Promise.withResolvers<void>();
-
- mc.port2.onmessage = (e) => {
- const { port } = e.data;
- assertEquals(e.ports.length, 1);
- assert(e.ports[0] instanceof MessagePort);
- assertEquals(e.ports[0], port);
- e.ports[0].close();
- resolve();
- };
-
- mc.port1.postMessage({ port: mc2.port1 }, [mc2.port1]);
- mc.port1.close();
-
- await promise;
-
- mc.port2.close();
- mc2.port2.close();
-});
diff --git a/cli/tests/unit/mkdir_test.ts b/cli/tests/unit/mkdir_test.ts
deleted file mode 100644
index 0948a1a84..000000000
--- a/cli/tests/unit/mkdir_test.ts
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
- pathToAbsoluteFileUrl,
-} from "./test_util.ts";
-
-function assertDirectory(path: string, mode?: number) {
- const info = Deno.lstatSync(path);
- assert(info.isDirectory);
- if (Deno.build.os !== "windows" && mode !== undefined) {
- assertEquals(info.mode! & 0o777, mode & ~Deno.umask());
- }
-}
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function mkdirSyncSuccess() {
- const path = Deno.makeTempDirSync() + "/dir";
- Deno.mkdirSync(path);
- assertDirectory(path);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function mkdirSyncMode() {
- const path = Deno.makeTempDirSync() + "/dir";
- Deno.mkdirSync(path, { mode: 0o737 });
- assertDirectory(path, 0o737);
- },
-);
-
-Deno.test({ permissions: { write: false } }, function mkdirSyncPerm() {
- assertThrows(() => {
- Deno.mkdirSync("/baddir");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function mkdirSuccess() {
- const path = Deno.makeTempDirSync() + "/dir";
- await Deno.mkdir(path);
- assertDirectory(path);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function mkdirMode() {
- const path = Deno.makeTempDirSync() + "/dir";
- await Deno.mkdir(path, { mode: 0o737 });
- assertDirectory(path, 0o737);
- },
-);
-
-Deno.test({ permissions: { write: true } }, function mkdirErrSyncIfExists() {
- assertThrows(
- () => {
- Deno.mkdirSync(".");
- },
- Deno.errors.AlreadyExists,
- `mkdir '.'`,
- );
-});
-
-Deno.test({ permissions: { write: true } }, async function mkdirErrIfExists() {
- await assertRejects(
- async () => {
- await Deno.mkdir(".");
- },
- Deno.errors.AlreadyExists,
- `mkdir '.'`,
- );
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function mkdirSyncRecursive() {
- const path = Deno.makeTempDirSync() + "/nested/directory";
- Deno.mkdirSync(path, { recursive: true });
- assertDirectory(path);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function mkdirRecursive() {
- const path = Deno.makeTempDirSync() + "/nested/directory";
- await Deno.mkdir(path, { recursive: true });
- assertDirectory(path);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function mkdirSyncRecursiveMode() {
- const nested = Deno.makeTempDirSync() + "/nested";
- const path = nested + "/dir";
- Deno.mkdirSync(path, { mode: 0o737, recursive: true });
- assertDirectory(path, 0o737);
- assertDirectory(nested, 0o737);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function mkdirRecursiveMode() {
- const nested = Deno.makeTempDirSync() + "/nested";
- const path = nested + "/dir";
- await Deno.mkdir(path, { mode: 0o737, recursive: true });
- assertDirectory(path, 0o737);
- assertDirectory(nested, 0o737);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function mkdirSyncRecursiveIfExists() {
- const path = Deno.makeTempDirSync() + "/dir";
- Deno.mkdirSync(path, { mode: 0o737 });
- Deno.mkdirSync(path, { recursive: true });
- Deno.mkdirSync(path, { recursive: true, mode: 0o731 });
- assertDirectory(path, 0o737);
- if (Deno.build.os !== "windows") {
- const pathLink = path + "Link";
- Deno.symlinkSync(path, pathLink);
- Deno.mkdirSync(pathLink, { recursive: true });
- Deno.mkdirSync(pathLink, { recursive: true, mode: 0o731 });
- assertDirectory(path, 0o737);
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function mkdirRecursiveIfExists() {
- const path = Deno.makeTempDirSync() + "/dir";
- await Deno.mkdir(path, { mode: 0o737 });
- await Deno.mkdir(path, { recursive: true });
- await Deno.mkdir(path, { recursive: true, mode: 0o731 });
- assertDirectory(path, 0o737);
- if (Deno.build.os !== "windows") {
- const pathLink = path + "Link";
- Deno.symlinkSync(path, pathLink);
- await Deno.mkdir(pathLink, { recursive: true });
- await Deno.mkdir(pathLink, { recursive: true, mode: 0o731 });
- assertDirectory(path, 0o737);
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function mkdirSyncErrors() {
- const testDir = Deno.makeTempDirSync();
- const emptydir = testDir + "/empty";
- const fulldir = testDir + "/dir";
- const file = fulldir + "/file";
- Deno.mkdirSync(emptydir);
- Deno.mkdirSync(fulldir);
- Deno.createSync(file).close();
-
- assertThrows(() => {
- Deno.mkdirSync(emptydir, { recursive: false });
- }, Deno.errors.AlreadyExists);
- assertThrows(() => {
- Deno.mkdirSync(fulldir, { recursive: false });
- }, Deno.errors.AlreadyExists);
- assertThrows(() => {
- Deno.mkdirSync(file, { recursive: false });
- }, Deno.errors.AlreadyExists);
- assertThrows(() => {
- Deno.mkdirSync(file, { recursive: true });
- }, Deno.errors.AlreadyExists);
-
- if (Deno.build.os !== "windows") {
- const fileLink = testDir + "/fileLink";
- const dirLink = testDir + "/dirLink";
- const danglingLink = testDir + "/danglingLink";
- Deno.symlinkSync(file, fileLink);
- Deno.symlinkSync(emptydir, dirLink);
- Deno.symlinkSync(testDir + "/nonexistent", danglingLink);
-
- assertThrows(() => {
- Deno.mkdirSync(dirLink, { recursive: false });
- }, Deno.errors.AlreadyExists);
- assertThrows(() => {
- Deno.mkdirSync(fileLink, { recursive: false });
- }, Deno.errors.AlreadyExists);
- assertThrows(() => {
- Deno.mkdirSync(fileLink, { recursive: true });
- }, Deno.errors.AlreadyExists);
- assertThrows(() => {
- Deno.mkdirSync(danglingLink, { recursive: false });
- }, Deno.errors.AlreadyExists);
- assertThrows(() => {
- Deno.mkdirSync(danglingLink, { recursive: true });
- }, Deno.errors.AlreadyExists);
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function mkdirSyncRelativeUrlPath() {
- const testDir = Deno.makeTempDirSync();
- const nestedDir = testDir + "/nested";
- // Add trailing slash so base path is treated as a directory. pathToAbsoluteFileUrl removes trailing slashes.
- const path = new URL("../dir", pathToAbsoluteFileUrl(nestedDir) + "/");
-
- Deno.mkdirSync(nestedDir);
- Deno.mkdirSync(path);
-
- assertDirectory(testDir + "/dir");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function mkdirRelativeUrlPath() {
- const testDir = Deno.makeTempDirSync();
- const nestedDir = testDir + "/nested";
- // Add trailing slash so base path is treated as a directory. pathToAbsoluteFileUrl removes trailing slashes.
- const path = new URL("../dir", pathToAbsoluteFileUrl(nestedDir) + "/");
-
- await Deno.mkdir(nestedDir);
- await Deno.mkdir(path);
-
- assertDirectory(testDir + "/dir");
- },
-);
diff --git a/cli/tests/unit/navigator_test.ts b/cli/tests/unit/navigator_test.ts
deleted file mode 100644
index 5dcc423fa..000000000
--- a/cli/tests/unit/navigator_test.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert } from "./test_util.ts";
-
-Deno.test(function navigatorNumCpus() {
- assert(navigator.hardwareConcurrency > 0);
-});
-
-Deno.test(function navigatorUserAgent() {
- const pattern = /Deno\/\d+\.\d+\.\d+/;
- assert(pattern.test(navigator.userAgent));
-});
diff --git a/cli/tests/unit/net_test.ts b/cli/tests/unit/net_test.ts
deleted file mode 100644
index fa9790a76..000000000
--- a/cli/tests/unit/net_test.ts
+++ /dev/null
@@ -1,1274 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertNotEquals,
- assertRejects,
- assertThrows,
- delay,
- execCode,
- execCode2,
- tmpUnixSocketPath,
-} from "./test_util.ts";
-
-// Since these tests may run in parallel, ensure this port is unique to this file
-const listenPort = 4503;
-const listenPort2 = 4504;
-
-let isCI: boolean;
-try {
- isCI = Deno.env.get("CI") !== undefined;
-} catch {
- isCI = true;
-}
-
-Deno.test({ permissions: { net: true } }, function netTcpListenClose() {
- const listener = Deno.listen({ hostname: "127.0.0.1", port: listenPort });
- assert(listener.addr.transport === "tcp");
- assertEquals(listener.addr.hostname, "127.0.0.1");
- assertEquals(listener.addr.port, listenPort);
- assertNotEquals(listener.rid, 0);
- listener.close();
-});
-
-Deno.test(
- {
- permissions: { net: true },
- },
- function netUdpListenClose() {
- const socket = Deno.listenDatagram({
- hostname: "127.0.0.1",
- port: listenPort,
- transport: "udp",
- });
- assert(socket.addr.transport === "udp");
- assertEquals(socket.addr.hostname, "127.0.0.1");
- assertEquals(socket.addr.port, listenPort);
- socket.close();
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- function netUnixListenClose() {
- const filePath = tmpUnixSocketPath();
- const socket = Deno.listen({
- path: filePath,
- transport: "unix",
- });
- assert(socket.addr.transport === "unix");
- assertEquals(socket.addr.path, filePath);
- socket.close();
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- function netUnixPacketListenClose() {
- const filePath = tmpUnixSocketPath();
- const socket = Deno.listenDatagram({
- path: filePath,
- transport: "unixpacket",
- });
- assert(socket.addr.transport === "unixpacket");
- assertEquals(socket.addr.path, filePath);
- socket.close();
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: false },
- },
- function netUnixListenWritePermission() {
- assertThrows(() => {
- const filePath = tmpUnixSocketPath();
- const socket = Deno.listen({
- path: filePath,
- transport: "unix",
- });
- assert(socket.addr.transport === "unix");
- assertEquals(socket.addr.path, filePath);
- socket.close();
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: false },
- },
- function netUnixPacketListenWritePermission() {
- assertThrows(() => {
- const filePath = tmpUnixSocketPath();
- const socket = Deno.listenDatagram({
- path: filePath,
- transport: "unixpacket",
- });
- assert(socket.addr.transport === "unixpacket");
- assertEquals(socket.addr.path, filePath);
- socket.close();
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function netTcpCloseWhileAccept() {
- const listener = Deno.listen({ port: listenPort });
- const p = listener.accept();
- listener.close();
- // TODO(piscisaureus): the error type should be `Interrupted` here, which
- // gets thrown, but then ext/net catches it and rethrows `BadResource`.
- await assertRejects(
- () => p,
- Deno.errors.BadResource,
- "Listener has been closed",
- );
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function netUnixCloseWhileAccept() {
- const filePath = tmpUnixSocketPath();
- const listener = Deno.listen({
- path: filePath,
- transport: "unix",
- });
- const p = listener.accept();
- listener.close();
- await assertRejects(
- () => p,
- Deno.errors.BadResource,
- "Listener has been closed",
- );
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function netTcpConcurrentAccept() {
- const listener = Deno.listen({ port: 4510 });
- let acceptErrCount = 0;
- const checkErr = (e: Error) => {
- if (e.message === "Listener has been closed") {
- assertEquals(acceptErrCount, 1);
- } else if (e.message === "Another accept task is ongoing") {
- acceptErrCount++;
- } else {
- throw new Error("Unexpected error message");
- }
- };
- const p = listener.accept().catch(checkErr);
- const p1 = listener.accept().catch(checkErr);
- await Promise.race([p, p1]);
- listener.close();
- await Promise.all([p, p1]);
- assertEquals(acceptErrCount, 1);
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function netUnixConcurrentAccept() {
- const filePath = tmpUnixSocketPath();
- const listener = Deno.listen({ transport: "unix", path: filePath });
- let acceptErrCount = 0;
- const checkErr = (e: Error) => {
- if (e.message === "Listener has been closed") {
- assertEquals(acceptErrCount, 1);
- } else if (e instanceof Deno.errors.Busy) { // "Listener already in use"
- acceptErrCount++;
- } else {
- throw e;
- }
- };
- const p = listener.accept().catch(checkErr);
- const p1 = listener.accept().catch(checkErr);
- await Promise.race([p, p1]);
- listener.close();
- await Promise.all([p, p1]);
- assertEquals(acceptErrCount, 1);
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function netTcpDialListen() {
- const listener = Deno.listen({ port: listenPort });
- listener.accept().then(
- async (conn) => {
- assert(conn.remoteAddr != null);
- assert(conn.localAddr.transport === "tcp");
- assertEquals(conn.localAddr.hostname, "127.0.0.1");
- assertEquals(conn.localAddr.port, listenPort);
- await conn.write(new Uint8Array([1, 2, 3]));
- conn.close();
- },
- );
-
- const conn = await Deno.connect({ hostname: "127.0.0.1", port: listenPort });
- assert(conn.remoteAddr.transport === "tcp");
- assertEquals(conn.remoteAddr.hostname, "127.0.0.1");
- assertEquals(conn.remoteAddr.port, listenPort);
- assert(conn.localAddr != null);
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assertEquals(3, readResult);
- assertEquals(1, buf[0]);
- assertEquals(2, buf[1]);
- assertEquals(3, buf[2]);
- assert(conn.rid > 0);
-
- assert(readResult !== null);
-
- const readResult2 = await conn.read(buf);
- assertEquals(readResult2, null);
-
- listener.close();
- conn.close();
-});
-
-Deno.test({ permissions: { net: true } }, async function netTcpSetNoDelay() {
- const listener = Deno.listen({ port: listenPort });
- listener.accept().then(
- async (conn) => {
- assert(conn.remoteAddr != null);
- assert(conn.localAddr.transport === "tcp");
- assertEquals(conn.localAddr.hostname, "127.0.0.1");
- assertEquals(conn.localAddr.port, listenPort);
- await conn.write(new Uint8Array([1, 2, 3]));
- conn.close();
- },
- );
-
- const conn = await Deno.connect({ hostname: "127.0.0.1", port: listenPort });
- conn.setNoDelay(true);
- assert(conn.remoteAddr.transport === "tcp");
- assertEquals(conn.remoteAddr.hostname, "127.0.0.1");
- assertEquals(conn.remoteAddr.port, listenPort);
- assert(conn.localAddr != null);
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assertEquals(3, readResult);
- assertEquals(1, buf[0]);
- assertEquals(2, buf[1]);
- assertEquals(3, buf[2]);
- assert(conn.rid > 0);
-
- assert(readResult !== null);
-
- const readResult2 = await conn.read(buf);
- assertEquals(readResult2, null);
-
- listener.close();
- conn.close();
-});
-
-Deno.test({ permissions: { net: true } }, async function netTcpSetKeepAlive() {
- const listener = Deno.listen({ port: listenPort });
- listener.accept().then(
- async (conn) => {
- assert(conn.remoteAddr != null);
- assert(conn.localAddr.transport === "tcp");
- assertEquals(conn.localAddr.hostname, "127.0.0.1");
- assertEquals(conn.localAddr.port, listenPort);
- await conn.write(new Uint8Array([1, 2, 3]));
- conn.close();
- },
- );
-
- const conn = await Deno.connect({ hostname: "127.0.0.1", port: listenPort });
- conn.setKeepAlive(true);
- assert(conn.remoteAddr.transport === "tcp");
- assertEquals(conn.remoteAddr.hostname, "127.0.0.1");
- assertEquals(conn.remoteAddr.port, listenPort);
- assert(conn.localAddr != null);
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assertEquals(3, readResult);
- assertEquals(1, buf[0]);
- assertEquals(2, buf[1]);
- assertEquals(3, buf[2]);
- assert(conn.rid > 0);
-
- assert(readResult !== null);
-
- const readResult2 = await conn.read(buf);
- assertEquals(readResult2, null);
-
- listener.close();
- conn.close();
-});
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function netUnixDialListen() {
- const filePath = tmpUnixSocketPath();
- const listener = Deno.listen({ path: filePath, transport: "unix" });
- listener.accept().then(
- async (conn) => {
- assert(conn.remoteAddr != null);
- assert(conn.localAddr.transport === "unix");
- assertEquals(conn.localAddr.path, filePath);
- await conn.write(new Uint8Array([1, 2, 3]));
- conn.close();
- },
- );
- const conn = await Deno.connect({ path: filePath, transport: "unix" });
- assert(conn.remoteAddr.transport === "unix");
- assertEquals(conn.remoteAddr.path, filePath);
- assert(conn.remoteAddr != null);
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assertEquals(3, readResult);
- assertEquals(1, buf[0]);
- assertEquals(2, buf[1]);
- assertEquals(3, buf[2]);
- assert(conn.rid > 0);
-
- assert(readResult !== null);
-
- const readResult2 = await conn.read(buf);
- assertEquals(readResult2, null);
-
- listener.close();
- conn.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function netUdpSendReceive() {
- const alice = Deno.listenDatagram({ port: listenPort, transport: "udp" });
- assert(alice.addr.transport === "udp");
- assertEquals(alice.addr.port, listenPort);
- assertEquals(alice.addr.hostname, "127.0.0.1");
-
- const bob = Deno.listenDatagram({ port: listenPort2, transport: "udp" });
- assert(bob.addr.transport === "udp");
- assertEquals(bob.addr.port, listenPort2);
- assertEquals(bob.addr.hostname, "127.0.0.1");
-
- const sent = new Uint8Array([1, 2, 3]);
- const byteLength = await alice.send(sent, bob.addr);
-
- assertEquals(byteLength, 3);
-
- const [recvd, remote] = await bob.receive();
- assert(remote.transport === "udp");
- assertEquals(remote.port, listenPort);
- assertEquals(recvd.length, 3);
- assertEquals(1, recvd[0]);
- assertEquals(2, recvd[1]);
- assertEquals(3, recvd[2]);
- alice.close();
- bob.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true }, ignore: true },
- async function netUdpSendReceiveBroadcast() {
- // Must bind sender to an address that can send to the broadcast address on MacOS.
- // Macos will give us error 49 when sending the broadcast packet if we omit hostname here.
- const alice = Deno.listenDatagram({
- port: listenPort,
- transport: "udp",
- hostname: "0.0.0.0",
- });
-
- const bob = Deno.listenDatagram({
- port: listenPort,
- transport: "udp",
- hostname: "0.0.0.0",
- });
- assert(bob.addr.transport === "udp");
- assertEquals(bob.addr.port, listenPort);
- assertEquals(bob.addr.hostname, "0.0.0.0");
-
- const broadcastAddr = { ...bob.addr, hostname: "255.255.255.255" };
-
- const sent = new Uint8Array([1, 2, 3]);
- const byteLength = await alice.send(sent, broadcastAddr);
-
- assertEquals(byteLength, 3);
- const [recvd, remote] = await bob.receive();
- assert(remote.transport === "udp");
- assertEquals(remote.port, listenPort);
- assertEquals(recvd.length, 3);
- assertEquals(1, recvd[0]);
- assertEquals(2, recvd[1]);
- assertEquals(3, recvd[2]);
- alice.close();
- bob.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true }, ignore: true },
- async function netUdpMulticastV4() {
- const listener = Deno.listenDatagram({
- hostname: "0.0.0.0",
- port: 5353,
- transport: "udp",
- reuseAddress: true,
- });
-
- const membership = await listener.joinMulticastV4(
- "224.0.0.251",
- "127.0.0.1",
- );
-
- membership.setLoopback(true);
- membership.setLoopback(false);
- membership.setTTL(50);
- membership.leave();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true }, ignore: true },
- async function netUdpMulticastV6() {
- const listener = Deno.listenDatagram({
- hostname: "::",
- port: 5353,
- transport: "udp",
- reuseAddress: true,
- });
-
- const membership = await listener.joinMulticastV6(
- "ff02::fb",
- 1,
- );
-
- membership.setLoopback(true);
- membership.setLoopback(false);
- membership.leave();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true }, ignore: true },
- async function netUdpSendReceiveMulticastv4() {
- const alice = Deno.listenDatagram({
- hostname: "0.0.0.0",
- port: 5353,
- transport: "udp",
- reuseAddress: true,
- loopback: true,
- });
-
- const bob = Deno.listenDatagram({
- hostname: "0.0.0.0",
- port: 5353,
- transport: "udp",
- reuseAddress: true,
- });
-
- const aliceMembership = await alice.joinMulticastV4(
- "224.0.0.1",
- "0.0.0.0",
- );
-
- const bobMembership = await bob.joinMulticastV4("224.0.0.1", "0.0.0.0");
-
- const sent = new Uint8Array([1, 2, 3]);
-
- await alice.send(sent, {
- hostname: "224.0.0.1",
- port: 5353,
- transport: "udp",
- });
-
- const [recvd, remote] = await bob.receive();
-
- assert(remote.transport === "udp");
- assertEquals(remote.port, 5353);
- assertEquals(recvd.length, 3);
- assertEquals(1, recvd[0]);
- assertEquals(2, recvd[1]);
- assertEquals(3, recvd[2]);
-
- aliceMembership.leave();
- bobMembership.leave();
-
- alice.close();
- bob.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true }, ignore: true },
- async function netUdpMulticastLoopbackOption() {
- // Must bind sender to an address that can send to the broadcast address on MacOS.
- // Macos will give us error 49 when sending the broadcast packet if we omit hostname here.
- const listener = Deno.listenDatagram({
- port: 5353,
- transport: "udp",
- hostname: "0.0.0.0",
- loopback: true,
- reuseAddress: true,
- });
-
- const membership = await listener.joinMulticastV4(
- "224.0.0.1",
- "0.0.0.0",
- );
-
- // await membership.setLoopback(true);
-
- const sent = new Uint8Array([1, 2, 3]);
- const byteLength = await listener.send(sent, {
- hostname: "224.0.0.1",
- port: 5353,
- transport: "udp",
- });
-
- assertEquals(byteLength, 3);
- const [recvd, remote] = await listener.receive();
- assert(remote.transport === "udp");
- assertEquals(remote.port, 5353);
- assertEquals(recvd.length, 3);
- assertEquals(1, recvd[0]);
- assertEquals(2, recvd[1]);
- assertEquals(3, recvd[2]);
- membership.leave();
- listener.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function netUdpConcurrentSendReceive() {
- const socket = Deno.listenDatagram({ port: listenPort, transport: "udp" });
- assert(socket.addr.transport === "udp");
- assertEquals(socket.addr.port, listenPort);
- assertEquals(socket.addr.hostname, "127.0.0.1");
-
- const recvPromise = socket.receive();
-
- const sendBuf = new Uint8Array([1, 2, 3]);
- const sendLen = await socket.send(sendBuf, socket.addr);
- assertEquals(sendLen, 3);
-
- const [recvBuf, _recvAddr] = await recvPromise;
- assertEquals(recvBuf.length, 3);
- assertEquals(1, recvBuf[0]);
- assertEquals(2, recvBuf[1]);
- assertEquals(3, recvBuf[2]);
-
- socket.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function netUdpBorrowMutError() {
- const socket = Deno.listenDatagram({
- port: listenPort,
- transport: "udp",
- });
- // Panic happened on second send: BorrowMutError
- const a = socket.send(new Uint8Array(), socket.addr);
- const b = socket.send(new Uint8Array(), socket.addr);
- await Promise.all([a, b]);
- socket.close();
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function netUnixPacketSendReceive() {
- const aliceFilePath = tmpUnixSocketPath();
- const alice = Deno.listenDatagram({
- path: aliceFilePath,
- transport: "unixpacket",
- });
- assert(alice.addr.transport === "unixpacket");
- assertEquals(alice.addr.path, aliceFilePath);
-
- const bobFilePath = tmpUnixSocketPath();
- const bob = Deno.listenDatagram({
- path: bobFilePath,
- transport: "unixpacket",
- });
- assert(bob.addr.transport === "unixpacket");
- assertEquals(bob.addr.path, bobFilePath);
-
- const sent = new Uint8Array([1, 2, 3]);
- const byteLength = await alice.send(sent, bob.addr);
- assertEquals(byteLength, 3);
-
- const [recvd, remote] = await bob.receive();
- assert(remote.transport === "unixpacket");
- assertEquals(remote.path, aliceFilePath);
- assertEquals(recvd.length, 3);
- assertEquals(1, recvd[0]);
- assertEquals(2, recvd[1]);
- assertEquals(3, recvd[2]);
- alice.close();
- bob.close();
- },
-);
-
-// TODO(lucacasonato): support concurrent reads and writes on unixpacket sockets
-Deno.test(
- { ignore: true, permissions: { read: true, write: true } },
- async function netUnixPacketConcurrentSendReceive() {
- const filePath = tmpUnixSocketPath();
- const socket = Deno.listenDatagram({
- path: filePath,
- transport: "unixpacket",
- });
- assert(socket.addr.transport === "unixpacket");
- assertEquals(socket.addr.path, filePath);
-
- const recvPromise = socket.receive();
-
- const sendBuf = new Uint8Array([1, 2, 3]);
- const sendLen = await socket.send(sendBuf, socket.addr);
- assertEquals(sendLen, 3);
-
- const [recvBuf, _recvAddr] = await recvPromise;
- assertEquals(recvBuf.length, 3);
- assertEquals(1, recvBuf[0]);
- assertEquals(2, recvBuf[1]);
- assertEquals(3, recvBuf[2]);
-
- socket.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function netTcpListenIteratorBreakClosesResource() {
- async function iterate(listener: Deno.Listener) {
- let i = 0;
-
- for await (const conn of listener) {
- conn.close();
- i++;
-
- if (i > 1) {
- break;
- }
- }
- }
-
- const addr = { hostname: "127.0.0.1", port: 8888 };
- const listener = Deno.listen(addr);
- const iteratePromise = iterate(listener);
-
- await delay(100);
- const conn1 = await Deno.connect(addr);
- conn1.close();
- const conn2 = await Deno.connect(addr);
- conn2.close();
-
- await iteratePromise;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function netTcpListenCloseWhileIterating() {
- const listener = Deno.listen({ port: 8001 });
- const nextWhileClosing = listener[Symbol.asyncIterator]().next();
- listener.close();
- assertEquals(await nextWhileClosing, { value: undefined, done: true });
-
- const nextAfterClosing = listener[Symbol.asyncIterator]().next();
- assertEquals(await nextAfterClosing, { value: undefined, done: true });
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function netUdpListenCloseWhileIterating() {
- const socket = Deno.listenDatagram({ port: 8000, transport: "udp" });
- const nextWhileClosing = socket[Symbol.asyncIterator]().next();
- socket.close();
- assertEquals(await nextWhileClosing, { value: undefined, done: true });
-
- const nextAfterClosing = socket[Symbol.asyncIterator]().next();
- assertEquals(await nextAfterClosing, { value: undefined, done: true });
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function netUnixListenCloseWhileIterating() {
- const filePath = tmpUnixSocketPath();
- const socket = Deno.listen({ path: filePath, transport: "unix" });
- const nextWhileClosing = socket[Symbol.asyncIterator]().next();
- socket.close();
- assertEquals(await nextWhileClosing, { value: undefined, done: true });
-
- const nextAfterClosing = socket[Symbol.asyncIterator]().next();
- assertEquals(await nextAfterClosing, { value: undefined, done: true });
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- async function netUnixPacketListenCloseWhileIterating() {
- const filePath = tmpUnixSocketPath();
- const socket = Deno.listenDatagram({
- path: filePath,
- transport: "unixpacket",
- });
- const nextWhileClosing = socket[Symbol.asyncIterator]().next();
- socket.close();
- assertEquals(await nextWhileClosing, { value: undefined, done: true });
-
- const nextAfterClosing = socket[Symbol.asyncIterator]().next();
- assertEquals(await nextAfterClosing, { value: undefined, done: true });
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function netListenAsyncIterator() {
- const addr = { hostname: "127.0.0.1", port: listenPort };
- const listener = Deno.listen(addr);
- const runAsyncIterator = async () => {
- for await (const conn of listener) {
- await conn.write(new Uint8Array([1, 2, 3]));
- conn.close();
- }
- };
- runAsyncIterator();
- const conn = await Deno.connect(addr);
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assertEquals(3, readResult);
- assertEquals(1, buf[0]);
- assertEquals(2, buf[1]);
- assertEquals(3, buf[2]);
- assert(conn.rid > 0);
-
- assert(readResult !== null);
-
- const readResult2 = await conn.read(buf);
- assertEquals(readResult2, null);
-
- listener.close();
- conn.close();
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- async function netCloseWriteSuccess() {
- const addr = { hostname: "127.0.0.1", port: listenPort };
- const listener = Deno.listen(addr);
- const { promise: closePromise, resolve } = Promise.withResolvers<void>();
- listener.accept().then(async (conn) => {
- await conn.write(new Uint8Array([1, 2, 3]));
- await closePromise;
- conn.close();
- });
- const conn = await Deno.connect(addr);
- conn.closeWrite(); // closing write
- const buf = new Uint8Array(1024);
- // Check read not impacted
- const readResult = await conn.read(buf);
- assertEquals(3, readResult);
- assertEquals(1, buf[0]);
- assertEquals(2, buf[1]);
- assertEquals(3, buf[2]);
- // Verify that the write end of the socket is closed.
- // TODO(piscisaureus): assert that thrown error is of a specific type.
- await assertRejects(async () => {
- await conn.write(new Uint8Array([1, 2, 3]));
- });
- resolve();
- listener.close();
- conn.close();
- },
-);
-
-Deno.test(
- {
- // https://github.com/denoland/deno/issues/11580
- ignore: Deno.build.os === "darwin" && isCI,
- permissions: { net: true },
- },
- async function netHangsOnClose() {
- let acceptedConn: Deno.Conn;
-
- async function iteratorReq(listener: Deno.Listener) {
- const p = new Uint8Array(10);
- const conn = await listener.accept();
- acceptedConn = conn;
-
- try {
- while (true) {
- const nread = await conn.read(p);
- if (nread === null) {
- break;
- }
- await conn.write(new Uint8Array([1, 2, 3]));
- }
- } catch (err) {
- assert(err);
- assert(err instanceof Deno.errors.Interrupted);
- }
- }
-
- const addr = { hostname: "127.0.0.1", port: listenPort };
- const listener = Deno.listen(addr);
- const listenerPromise = iteratorReq(listener);
- const connectionPromise = (async () => {
- const conn = await Deno.connect(addr);
- await conn.write(new Uint8Array([1, 2, 3, 4]));
- const buf = new Uint8Array(10);
- await conn.read(buf);
- conn!.close();
- acceptedConn!.close();
- listener.close();
- })();
-
- await Promise.all([
- listenerPromise,
- connectionPromise,
- ]);
- },
-);
-
-Deno.test(
- {
- permissions: { net: true },
- },
- function netExplicitUndefinedHostname() {
- const listener = Deno.listen({ hostname: undefined, port: 8080 });
- assertEquals((listener.addr as Deno.NetAddr).hostname, "0.0.0.0");
- listener.close();
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os !== "linux",
- permissions: { read: true, write: true },
- },
- function netUnixAbstractPathShouldNotPanic() {
- const listener = Deno.listen({
- path: "\0aaa",
- transport: "unix",
- });
- assert("not panic");
- listener.close();
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function whatwgStreams() {
- const server = (async () => {
- const listener = Deno.listen({ hostname: "127.0.0.1", port: listenPort });
- const conn = await listener.accept();
- await conn.readable.pipeTo(conn.writable);
- listener.close();
- })();
-
- const conn = await Deno.connect({ hostname: "127.0.0.1", port: listenPort });
- const reader = conn.readable.getReader();
- const writer = conn.writable.getWriter();
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
- const data = encoder.encode("Hello World");
-
- await writer.write(data);
- const { value, done } = await reader.read();
- assert(!done);
- assertEquals(decoder.decode(value), "Hello World");
- await reader.cancel();
- await server;
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function readableStreamTextEncoderPipe() {
- const filename = "cli/tests/testdata/assets/hello.txt";
- const file = await Deno.open(filename);
- const readable = file.readable.pipeThrough(new TextDecoderStream());
- const chunks = [];
- for await (const chunk of readable) {
- chunks.push(chunk);
- }
- assertEquals(chunks.length, 1);
- assertEquals(chunks[0].length, 12);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writableStream() {
- const path = await Deno.makeTempFile();
- const file = await Deno.open(path, { write: true });
- assert(file.writable instanceof WritableStream);
- const readable = new ReadableStream({
- start(controller) {
- controller.enqueue(new TextEncoder().encode("hello "));
- controller.enqueue(new TextEncoder().encode("world!"));
- controller.close();
- },
- });
- await readable.pipeTo(file.writable);
- const res = await Deno.readTextFile(path);
- assertEquals(res, "hello world!");
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: true } },
- async function netListenUnref() {
- const [statusCode, _output] = await execCode(`
- async function main() {
- const listener = Deno.listen({ port: ${listenPort} });
- listener.unref();
- await listener.accept(); // This doesn't block the program from exiting
- }
- main();
- `);
- assertEquals(statusCode, 0);
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: true } },
- async function netListenUnref2() {
- const [statusCode, _output] = await execCode(`
- async function main() {
- const listener = Deno.listen({ port: ${listenPort} });
- await listener.accept();
- listener.unref();
- await listener.accept(); // The program exits here
- throw new Error(); // The program doesn't reach here
- }
- main();
- const conn = await Deno.connect({ port: ${listenPort} });
- conn.close();
- `);
- assertEquals(statusCode, 0);
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: true, net: true } },
- async function netListenUnrefAndRef() {
- const p = execCode2(`
- async function main() {
- const listener = Deno.listen({ port: ${listenPort} });
- listener.unref();
- listener.ref(); // This restores 'ref' state of listener
- console.log("started");
- await listener.accept();
- console.log("accepted")
- }
- main();
- `);
- await p.waitStdoutText("started");
- const conn = await Deno.connect({ port: listenPort });
- conn.close();
- const [statusCode, output] = await p.finished();
- assertEquals(statusCode, 0);
- assertEquals(output.trim(), "started\naccepted");
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function netListenUnrefConcurrentAccept() {
- const timer = setTimeout(() => {}, 1000);
- const listener = Deno.listen({ port: listenPort });
- listener.accept().catch(() => {});
- listener.unref();
- // Unref'd listener still causes Busy error
- // on concurrent accept calls.
- await assertRejects(async () => {
- await listener.accept(); // The program exits here
- }, Deno.errors.Busy);
- listener.close();
- clearTimeout(timer);
- },
-);
-
-Deno.test({
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
-}, function netUnixListenAddrAlreadyInUse() {
- const filePath = tmpUnixSocketPath();
- const listener = Deno.listen({ path: filePath, transport: "unix" });
- assertThrows(
- () => {
- Deno.listen({ path: filePath, transport: "unix" });
- },
- Deno.errors.AddrInUse,
- );
- listener.close();
-});
-
-Deno.test(
- { permissions: { net: true, read: true, run: true } },
- async function netConnUnref() {
- const listener = Deno.listen({ port: listenPort });
- const intervalId = setInterval(() => {}); // This keeps event loop alive.
-
- const program = execCode(`
- async function main() {
- const conn = await Deno.connect({ port: ${listenPort} });
- conn.unref();
- await conn.read(new Uint8Array(10)); // The program exits here
- throw new Error(); // The program doesn't reach here
- }
- main();
- `);
- const conn = await listener.accept();
- const [statusCode, _output] = await program;
- conn.close();
- listener.close();
- clearInterval(intervalId);
- assertEquals(statusCode, 0);
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true, run: true } },
- async function netConnUnrefReadable() {
- const listener = Deno.listen({ port: listenPort });
- const intervalId = setInterval(() => {}); // This keeps event loop alive.
-
- const program = execCode(`
- async function main() {
- const conn = await Deno.connect({ port: ${listenPort} });
- conn.unref();
- const reader = conn.readable.getReader();
- await reader.read(); // The program exits here
- throw new Error(); // The program doesn't reach here
- }
- main();
- `);
- const conn = await listener.accept();
- const [statusCode, _output] = await program;
- conn.close();
- listener.close();
- clearInterval(intervalId);
- assertEquals(statusCode, 0);
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function netTcpReuseAddr() {
- const listener1 = Deno.listen({
- hostname: "127.0.0.1",
- port: listenPort,
- });
- listener1.accept().then(
- (conn) => {
- conn.close();
- },
- );
-
- const conn1 = await Deno.connect({ hostname: "127.0.0.1", port: listenPort });
- const buf1 = new Uint8Array(1024);
- await conn1.read(buf1);
- listener1.close();
- conn1.close();
-
- const listener2 = Deno.listen({
- hostname: "127.0.0.1",
- port: listenPort,
- });
-
- listener2.accept().then(
- (conn) => {
- conn.close();
- },
- );
-
- const conn2 = await Deno.connect({ hostname: "127.0.0.1", port: listenPort });
- const buf2 = new Uint8Array(1024);
- await conn2.read(buf2);
-
- listener2.close();
- conn2.close();
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function netUdpReuseAddr() {
- const sender = Deno.listenDatagram({
- port: 4002,
- transport: "udp",
- });
- const listener1 = Deno.listenDatagram({
- port: 4000,
- transport: "udp",
- reuseAddress: true,
- });
- const listener2 = Deno.listenDatagram({
- port: 4000,
- transport: "udp",
- reuseAddress: true,
- });
-
- const sent = new Uint8Array([1, 2, 3]);
- await sender.send(sent, listener1.addr);
- await Promise.any([listener1.receive(), listener2.receive()]).then(
- ([recvd, remote]) => {
- assert(remote.transport === "udp");
- assertEquals(recvd.length, 3);
- assertEquals(1, recvd[0]);
- assertEquals(2, recvd[1]);
- assertEquals(3, recvd[2]);
- },
- );
- sender.close();
- listener1.close();
- listener2.close();
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- function netUdpNoReuseAddr() {
- let listener1;
- try {
- listener1 = Deno.listenDatagram({
- port: 4001,
- transport: "udp",
- reuseAddress: false,
- });
- } catch (err) {
- assert(err);
- assert(err instanceof Deno.errors.AddrInUse); // AddrInUse from previous test
- }
-
- assertThrows(() => {
- Deno.listenDatagram({
- port: 4001,
- transport: "udp",
- reuseAddress: false,
- });
- }, Deno.errors.AddrInUse);
- if (typeof listener1 !== "undefined") {
- listener1.close();
- }
- },
-);
-
-Deno.test({
- ignore: Deno.build.os !== "linux",
- permissions: { net: true },
-}, async function netTcpListenReusePort() {
- const port = 4003;
- const listener1 = Deno.listen({ port, reusePort: true });
- const listener2 = Deno.listen({ port, reusePort: true });
- let p1;
- let p2;
- let listener1Recv = false;
- let listener2Recv = false;
- while (!listener1Recv || !listener2Recv) {
- if (!p1) {
- p1 = listener1.accept().then((conn) => {
- conn.close();
- listener1Recv = true;
- p1 = undefined;
- }).catch(() => {});
- }
- if (!p2) {
- p2 = listener2.accept().then((conn) => {
- conn.close();
- listener2Recv = true;
- p2 = undefined;
- }).catch(() => {});
- }
- const conn = await Deno.connect({ port });
- conn.close();
- await Promise.race([p1, p2]);
- }
- listener1.close();
- listener2.close();
-});
-
-Deno.test({
- ignore: Deno.build.os === "linux",
- permissions: { net: true },
-}, function netTcpListenReusePortDoesNothing() {
- const listener1 = Deno.listen({ port: 4003, reusePort: true });
- assertThrows(() => {
- Deno.listen({ port: 4003, reusePort: true });
- }, Deno.errors.AddrInUse);
- listener1.close();
-});
-
-Deno.test({
- permissions: { net: true },
-}, function netTcpListenDoesNotThrowOnStringPort() {
- // @ts-ignore String port is not allowed by typing, but it shouldn't throw
- // for backwards compatibility.
- const listener = Deno.listen({ hostname: "localhost", port: "0" });
- listener.close();
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function listenerExplicitResourceManagement() {
- let done: Promise<Deno.errors.BadResource>;
-
- {
- using listener = Deno.listen({ port: listenPort });
-
- done = assertRejects(
- () => listener.accept(),
- Deno.errors.BadResource,
- );
- }
-
- await done;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function listenerExplicitResourceManagementManualClose() {
- using listener = Deno.listen({ port: listenPort });
- listener.close();
- await assertRejects( // definitely closed
- () => listener.accept(),
- Deno.errors.BadResource,
- );
- // calling [Symbol.dispose] after manual close is a no-op
- },
-);
diff --git a/cli/tests/unit/network_interfaces_test.ts b/cli/tests/unit/network_interfaces_test.ts
deleted file mode 100644
index 160efbfe6..000000000
--- a/cli/tests/unit/network_interfaces_test.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assert } from "./test_util.ts";
-
-Deno.test(
- {
- name: "Deno.networkInterfaces",
- permissions: { sys: ["networkInterfaces"] },
- },
- () => {
- const networkInterfaces = Deno.networkInterfaces();
- assert(Array.isArray(networkInterfaces));
- assert(networkInterfaces.length > 0);
- for (
- const { name, family, address, netmask, scopeid, cidr, mac }
- of networkInterfaces
- ) {
- assert(typeof name === "string");
- assert(family === "IPv4" || family === "IPv6");
- assert(typeof address === "string");
- assert(typeof netmask === "string");
- assert(
- (family === "IPv6" && typeof scopeid === "number") ||
- (family === "IPv4" && scopeid === null),
- );
- assert(typeof cidr === "string");
- assert(typeof mac === "string");
- }
- },
-);
diff --git a/cli/tests/unit/ops_test.ts b/cli/tests/unit/ops_test.ts
deleted file mode 100644
index 4a0daa0a5..000000000
--- a/cli/tests/unit/ops_test.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-const EXPECTED_OP_COUNT = 15;
-
-Deno.test(function checkExposedOps() {
- // @ts-ignore TS doesn't allow to index with symbol
- const core = Deno[Deno.internal].core;
- const opNames = Object.keys(core.ops);
-
- if (opNames.length !== EXPECTED_OP_COUNT) {
- throw new Error(
- `Expected ${EXPECTED_OP_COUNT} ops, but got ${opNames.length}:\n${
- opNames.join("\n")
- }`,
- );
- }
-});
diff --git a/cli/tests/unit/os_test.ts b/cli/tests/unit/os_test.ts
deleted file mode 100644
index e24494854..000000000
--- a/cli/tests/unit/os_test.ts
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertNotEquals,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test({ permissions: { env: true } }, function envSuccess() {
- Deno.env.set("TEST_VAR", "A");
- const env = Deno.env.toObject();
- Deno.env.set("TEST_VAR", "B");
- assertEquals(env["TEST_VAR"], "A");
- assertNotEquals(Deno.env.get("TEST_VAR"), env["TEST_VAR"]);
-});
-
-Deno.test({ permissions: { env: true } }, function envNotFound() {
- const r = Deno.env.get("env_var_does_not_exist!");
- assertEquals(r, undefined);
-});
-
-Deno.test({ permissions: { env: true } }, function deleteEnv() {
- Deno.env.set("TEST_VAR", "A");
- assertEquals(Deno.env.get("TEST_VAR"), "A");
- assertEquals(Deno.env.delete("TEST_VAR"), undefined);
- assertEquals(Deno.env.get("TEST_VAR"), undefined);
-});
-
-Deno.test({ permissions: { env: true } }, function hasEnv() {
- Deno.env.set("TEST_VAR", "A");
- assert(Deno.env.has("TEST_VAR"));
- Deno.env.delete("TEST_VAR");
- assert(!Deno.env.has("TEST_VAR"));
-});
-
-Deno.test({ permissions: { env: true } }, function avoidEmptyNamedEnv() {
- assertThrows(() => Deno.env.set("", "v"), TypeError);
- assertThrows(() => Deno.env.set("a=a", "v"), TypeError);
- assertThrows(() => Deno.env.set("a\0a", "v"), TypeError);
- assertThrows(() => Deno.env.set("TEST_VAR", "v\0v"), TypeError);
-
- assertThrows(() => Deno.env.get(""), TypeError);
- assertThrows(() => Deno.env.get("a=a"), TypeError);
- assertThrows(() => Deno.env.get("a\0a"), TypeError);
-
- assertThrows(() => Deno.env.delete(""), TypeError);
- assertThrows(() => Deno.env.delete("a=a"), TypeError);
- assertThrows(() => Deno.env.delete("a\0a"), TypeError);
-});
-
-Deno.test({ permissions: { env: false } }, function envPermissionDenied1() {
- assertThrows(() => {
- Deno.env.toObject();
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { env: false } }, function envPermissionDenied2() {
- assertThrows(() => {
- Deno.env.get("PATH");
- }, Deno.errors.PermissionDenied);
-});
-
-// This test verifies that on Windows, environment variables are
-// case-insensitive. Case normalization needs be done using the collation
-// that Windows uses, rather than naively using String.toLowerCase().
-Deno.test(
- {
- ignore: Deno.build.os !== "windows",
- permissions: { read: true, env: true, run: true },
- },
- async function envCaseInsensitive() {
- // Utility function that runs a Deno subprocess with the environment
- // specified in `inputEnv`. The subprocess reads the environment variables
- // which are in the keys of `expectedEnv` and writes them to stdout as JSON.
- // It is then verified that these match with the values of `expectedEnv`.
- const checkChildEnv = async (
- inputEnv: Record<string, string>,
- expectedEnv: Record<string, string>,
- ) => {
- const src = `
- console.log(
- ${JSON.stringify(Object.keys(expectedEnv))}.map(k => Deno.env.get(k))
- )`;
- const { success, stdout } = await new Deno.Command(Deno.execPath(), {
- args: ["eval", src],
- env: { ...inputEnv, NO_COLOR: "1" },
- }).output();
- assertEquals(success, true);
- const expectedValues = Object.values(expectedEnv);
- const actualValues = JSON.parse(new TextDecoder().decode(stdout));
- assertEquals(actualValues, expectedValues);
- };
-
- assertEquals(Deno.env.get("path"), Deno.env.get("PATH"));
- assertEquals(Deno.env.get("Path"), Deno.env.get("PATH"));
-
- // Check 'foo', 'Foo' and 'Foo' are case folded.
- await checkChildEnv({ foo: "X" }, { foo: "X", Foo: "X", FOO: "X" });
-
- // Check that 'µ' and 'Μ' are not case folded.
- const lc1 = "µ";
- const uc1 = lc1.toUpperCase();
- assertNotEquals(lc1, uc1);
- await checkChildEnv(
- { [lc1]: "mu", [uc1]: "MU" },
- { [lc1]: "mu", [uc1]: "MU" },
- );
-
- // Check that 'dž' and 'DŽ' are folded, but 'Dž' is preserved.
- const c2 = "Dž";
- const lc2 = c2.toLowerCase();
- const uc2 = c2.toUpperCase();
- assertNotEquals(c2, lc2);
- assertNotEquals(c2, uc2);
- await checkChildEnv(
- { [c2]: "Dz", [lc2]: "dz" },
- { [c2]: "Dz", [lc2]: "dz", [uc2]: "dz" },
- );
- await checkChildEnv(
- { [c2]: "Dz", [uc2]: "DZ" },
- { [c2]: "Dz", [uc2]: "DZ", [lc2]: "DZ" },
- );
- },
-);
-
-Deno.test({ permissions: { env: true } }, function envInvalidChars() {
- assertThrows(() => Deno.env.get(""), TypeError, "Key is an empty string");
- assertThrows(
- () => Deno.env.get("\0"),
- TypeError,
- 'Key contains invalid characters: "\\0"',
- );
- assertThrows(
- () => Deno.env.get("="),
- TypeError,
- 'Key contains invalid characters: "="',
- );
- assertThrows(
- () => Deno.env.set("", "foo"),
- TypeError,
- "Key is an empty string",
- );
- assertThrows(
- () => Deno.env.set("\0", "foo"),
- TypeError,
- 'Key contains invalid characters: "\\0"',
- );
- assertThrows(
- () => Deno.env.set("=", "foo"),
- TypeError,
- 'Key contains invalid characters: "="',
- );
- assertThrows(
- () => Deno.env.set("foo", "\0"),
- TypeError,
- 'Value contains invalid characters: "\\0"',
- );
-});
-
-Deno.test(function osPid() {
- assertEquals(typeof Deno.pid, "number");
- assert(Deno.pid > 0);
-});
-
-Deno.test(function osPpid() {
- assertEquals(typeof Deno.ppid, "number");
- assert(Deno.ppid > 0);
-});
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function osPpidIsEqualToPidOfParentProcess() {
- const decoder = new TextDecoder();
- const { stdout } = await new Deno.Command(Deno.execPath(), {
- args: ["eval", "-p", "--unstable", "Deno.ppid"],
- env: { NO_COLOR: "true" },
- }).output();
-
- const expected = Deno.pid;
- const actual = parseInt(decoder.decode(stdout));
- assertEquals(actual, expected);
- },
-);
-
-Deno.test({ permissions: { read: true } }, function execPath() {
- assertNotEquals(Deno.execPath(), "");
-});
-
-Deno.test({ permissions: { read: false } }, function execPathPerm() {
- assertThrows(
- () => {
- Deno.execPath();
- },
- Deno.errors.PermissionDenied,
- "Requires read access to <exec_path>, run again with the --allow-read flag",
- );
-});
-
-Deno.test(
- { permissions: { sys: ["loadavg"] } },
- function loadavgSuccess() {
- const load = Deno.loadavg();
- assertEquals(load.length, 3);
- },
-);
-
-Deno.test({ permissions: { sys: false } }, function loadavgPerm() {
- assertThrows(() => {
- Deno.loadavg();
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { sys: ["hostname"] } },
- function hostnameDir() {
- assertNotEquals(Deno.hostname(), "");
- },
-);
-
-Deno.test(
- { permissions: { run: [Deno.execPath()], read: true } },
- // See https://github.com/denoland/deno/issues/16527
- async function hostnameWithoutOtherNetworkUsages() {
- const { stdout } = await new Deno.Command(Deno.execPath(), {
- args: ["eval", "-p", "Deno.hostname()"],
- }).output();
- const hostname = new TextDecoder().decode(stdout).trim();
- assert(hostname.length > 0);
- },
-);
-
-Deno.test({ permissions: { sys: false } }, function hostnamePerm() {
- assertThrows(() => {
- Deno.hostname();
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { sys: ["osRelease"] } },
- function releaseDir() {
- assertNotEquals(Deno.osRelease(), "");
- },
-);
-
-Deno.test({ permissions: { sys: false } }, function releasePerm() {
- assertThrows(() => {
- Deno.osRelease();
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { sys: ["osUptime"] } }, function osUptime() {
- const uptime = Deno.osUptime();
- assert(typeof uptime === "number");
- assert(uptime > 0);
-});
-
-Deno.test({ permissions: { sys: false } }, function osUptimePerm() {
- assertThrows(() => {
- Deno.osUptime();
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { sys: ["systemMemoryInfo"] } },
- function systemMemoryInfo() {
- const info = Deno.systemMemoryInfo();
- assert(info.total >= 0);
- assert(info.free >= 0);
- assert(info.available >= 0);
- assert(info.buffers >= 0);
- assert(info.cached >= 0);
- assert(info.swapTotal >= 0);
- assert(info.swapFree >= 0);
- },
-);
-
-Deno.test({ permissions: { sys: ["uid"] } }, function getUid() {
- if (Deno.build.os === "windows") {
- assertEquals(Deno.uid(), null);
- } else {
- const uid = Deno.uid();
- assert(typeof uid === "number");
- assert(uid > 0);
- }
-});
-
-Deno.test({ permissions: { sys: ["gid"] } }, function getGid() {
- if (Deno.build.os === "windows") {
- assertEquals(Deno.gid(), null);
- } else {
- const gid = Deno.gid();
- assert(typeof gid === "number");
- assert(gid > 0);
- }
-});
-
-Deno.test(function memoryUsage() {
- const mem = Deno.memoryUsage();
- assert(typeof mem.rss === "number");
- assert(typeof mem.heapTotal === "number");
- assert(typeof mem.heapUsed === "number");
- assert(typeof mem.external === "number");
- assert(mem.rss >= mem.heapTotal);
-});
diff --git a/cli/tests/unit/path_from_url_test.ts b/cli/tests/unit/path_from_url_test.ts
deleted file mode 100644
index b3a6406bc..000000000
--- a/cli/tests/unit/path_from_url_test.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assertEquals, assertThrows } from "./test_util.ts";
-
-// @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
-const { pathFromURL } = Deno[Deno.internal];
-
-Deno.test(
- { ignore: Deno.build.os === "windows" },
- function pathFromURLPosix() {
- assertEquals(
- pathFromURL(new URL("file:///test/directory")),
- "/test/directory",
- );
- assertEquals(pathFromURL(new URL("file:///space_ .txt")), "/space_ .txt");
- assertThrows(() => pathFromURL(new URL("https://deno.land/welcome.ts")));
- },
-);
-
-Deno.test(
- { ignore: Deno.build.os !== "windows" },
- function pathFromURLWin32() {
- assertEquals(
- pathFromURL(new URL("file:///c:/windows/test")),
- "c:\\windows\\test",
- );
- assertEquals(
- pathFromURL(new URL("file:///c:/space_ .txt")),
- "c:\\space_ .txt",
- );
- assertThrows(() => pathFromURL(new URL("https://deno.land/welcome.ts")));
- /* TODO(ry) Add tests for these situations
- * ampersand_&.tx file:///D:/weird_names/ampersand_&.txt
- * at_@.txt file:///D:/weird_names/at_@.txt
- * emoji_🙃.txt file:///D:/weird_names/emoji_%F0%9F%99%83.txt
- * percent_%.txt file:///D:/weird_names/percent_%25.txt
- * pound_#.txt file:///D:/weird_names/pound_%23.txt
- * swapped_surrogate_pair_��.txt file:///D:/weird_names/swapped_surrogate_pair_%EF%BF%BD%EF%BF%BD.txt
- */
- },
-);
diff --git a/cli/tests/unit/performance_test.ts b/cli/tests/unit/performance_test.ts
deleted file mode 100644
index 0c9ed21df..000000000
--- a/cli/tests/unit/performance_test.ts
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertNotStrictEquals,
- assertStringIncludes,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test({ permissions: { hrtime: false } }, async function performanceNow() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const start = performance.now();
- let totalTime = 0;
- setTimeout(() => {
- const end = performance.now();
- totalTime = end - start;
- resolve();
- }, 10);
- await promise;
- assert(totalTime >= 10);
-});
-
-Deno.test(function timeOrigin() {
- const origin = performance.timeOrigin;
-
- assert(origin > 0);
- assert(Date.now() >= origin);
-});
-
-Deno.test(function performanceToJSON() {
- const json = performance.toJSON();
-
- assert("timeOrigin" in json);
- assert(json.timeOrigin === performance.timeOrigin);
- // check there are no other keys
- assertEquals(Object.keys(json).length, 1);
-});
-
-Deno.test(function performanceMark() {
- const mark = performance.mark("test");
- assert(mark instanceof PerformanceMark);
- assertEquals(mark.detail, null);
- assertEquals(mark.name, "test");
- assertEquals(mark.entryType, "mark");
- assert(mark.startTime > 0);
- assertEquals(mark.duration, 0);
- const entries = performance.getEntries();
- assert(entries[entries.length - 1] === mark);
- const markEntries = performance.getEntriesByName("test", "mark");
- assert(markEntries[markEntries.length - 1] === mark);
-});
-
-Deno.test(function performanceMarkDetail() {
- const detail = { foo: "foo" };
- const mark = performance.mark("test", { detail });
- assert(mark instanceof PerformanceMark);
- assertEquals(mark.detail, { foo: "foo" });
- assertNotStrictEquals(mark.detail, detail);
-});
-
-Deno.test(function performanceMarkDetailArrayBuffer() {
- const detail = new ArrayBuffer(10);
- const mark = performance.mark("test", { detail });
- assert(mark instanceof PerformanceMark);
- assertEquals(mark.detail, new ArrayBuffer(10));
- assertNotStrictEquals(mark.detail, detail);
-});
-
-Deno.test(function performanceMarkDetailSubTypedArray() {
- class SubUint8Array extends Uint8Array {}
- const detail = new SubUint8Array([1, 2]);
- const mark = performance.mark("test", { detail });
- assert(mark instanceof PerformanceMark);
- assertEquals(mark.detail, new Uint8Array([1, 2]));
- assertNotStrictEquals(mark.detail, detail);
-});
-
-Deno.test(function performanceMeasure() {
- const markName1 = "mark1";
- const measureName1 = "measure1";
- const measureName2 = "measure2";
- const mark1 = performance.mark(markName1);
- // Measure against the inaccurate-but-known-good wall clock
- const now = new Date().valueOf();
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- try {
- const later = new Date().valueOf();
- const measure1 = performance.measure(measureName1, markName1);
- const measure2 = performance.measure(
- measureName2,
- undefined,
- markName1,
- );
- assert(measure1 instanceof PerformanceMeasure);
- assertEquals(measure1.detail, null);
- assertEquals(measure1.name, measureName1);
- assertEquals(measure1.entryType, "measure");
- assert(measure1.startTime > 0);
- assertEquals(measure2.startTime, 0);
- assertEquals(mark1.startTime, measure1.startTime);
- assertEquals(mark1.startTime, measure2.duration);
- assert(
- measure1.duration >= 100,
- `duration below 100ms: ${measure1.duration}`,
- );
- assert(
- measure1.duration < (later - now) * 1.50,
- `duration exceeds 150% of wallclock time: ${measure1.duration}ms vs ${
- later - now
- }ms`,
- );
- const entries = performance.getEntries();
- assert(entries[entries.length - 1] === measure2);
- const entriesByName = performance.getEntriesByName(
- measureName1,
- "measure",
- );
- assert(entriesByName[entriesByName.length - 1] === measure1);
- const measureEntries = performance.getEntriesByType("measure");
- assert(measureEntries[measureEntries.length - 1] === measure2);
- } catch (e) {
- return reject(e);
- }
- resolve();
- }, 100);
- });
-});
-
-Deno.test(function performanceCustomInspectFunction() {
- assertStringIncludes(Deno.inspect(performance), "Performance");
- assertStringIncludes(
- Deno.inspect(Performance.prototype),
- "Performance",
- );
-});
-
-Deno.test(function performanceMarkCustomInspectFunction() {
- const mark1 = performance.mark("mark1");
- assertStringIncludes(Deno.inspect(mark1), "PerformanceMark");
- assertStringIncludes(
- Deno.inspect(PerformanceMark.prototype),
- "PerformanceMark",
- );
-});
-
-Deno.test(function performanceMeasureCustomInspectFunction() {
- const measure1 = performance.measure("measure1");
- assertStringIncludes(Deno.inspect(measure1), "PerformanceMeasure");
- assertStringIncludes(
- Deno.inspect(PerformanceMeasure.prototype),
- "PerformanceMeasure",
- );
-});
-
-Deno.test(function performanceIllegalConstructor() {
- assertThrows(() => new Performance(), TypeError, "Illegal constructor");
- assertEquals(Performance.length, 0);
-});
-
-Deno.test(function performanceEntryIllegalConstructor() {
- assertThrows(() => new PerformanceEntry(), TypeError, "Illegal constructor");
- assertEquals(PerformanceEntry.length, 0);
-});
-
-Deno.test(function performanceMeasureIllegalConstructor() {
- assertThrows(
- () => new PerformanceMeasure(),
- TypeError,
- "Illegal constructor",
- );
-});
-
-Deno.test(function performanceIsEventTarget() {
- assert(performance instanceof EventTarget);
-
- return new Promise((resolve) => {
- const handler = () => {
- resolve();
- };
-
- performance.addEventListener("test", handler, { once: true });
- performance.dispatchEvent(new Event("test"));
- });
-});
diff --git a/cli/tests/unit/permissions_test.ts b/cli/tests/unit/permissions_test.ts
deleted file mode 100644
index 4dab0696a..000000000
--- a/cli/tests/unit/permissions_test.ts
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(async function permissionInvalidName() {
- await assertRejects(async () => {
- // deno-lint-ignore no-explicit-any
- await Deno.permissions.query({ name: "foo" as any });
- }, TypeError);
-});
-
-Deno.test(function permissionInvalidNameSync() {
- assertThrows(() => {
- // deno-lint-ignore no-explicit-any
- Deno.permissions.querySync({ name: "foo" as any });
- }, TypeError);
-});
-
-Deno.test(async function permissionNetInvalidHost() {
- await assertRejects(async () => {
- await Deno.permissions.query({ name: "net", host: ":" });
- }, URIError);
-});
-
-Deno.test(function permissionNetInvalidHostSync() {
- assertThrows(() => {
- Deno.permissions.querySync({ name: "net", host: ":" });
- }, URIError);
-});
-
-Deno.test(async function permissionSysValidKind() {
- await Deno.permissions.query({ name: "sys", kind: "loadavg" });
- await Deno.permissions.query({ name: "sys", kind: "osRelease" });
- await Deno.permissions.query({ name: "sys", kind: "osUptime" });
- await Deno.permissions.query({ name: "sys", kind: "networkInterfaces" });
- await Deno.permissions.query({ name: "sys", kind: "systemMemoryInfo" });
- await Deno.permissions.query({ name: "sys", kind: "hostname" });
- await Deno.permissions.query({ name: "sys", kind: "uid" });
- await Deno.permissions.query({ name: "sys", kind: "gid" });
- await Deno.permissions.query({ name: "sys", kind: "cpus" });
-});
-
-Deno.test(function permissionSysValidKindSync() {
- Deno.permissions.querySync({ name: "sys", kind: "loadavg" });
- Deno.permissions.querySync({ name: "sys", kind: "osRelease" });
- Deno.permissions.querySync({ name: "sys", kind: "networkInterfaces" });
- Deno.permissions.querySync({ name: "sys", kind: "systemMemoryInfo" });
- Deno.permissions.querySync({ name: "sys", kind: "hostname" });
- Deno.permissions.querySync({ name: "sys", kind: "uid" });
- Deno.permissions.querySync({ name: "sys", kind: "gid" });
- Deno.permissions.querySync({ name: "sys", kind: "cpus" });
-});
-
-Deno.test(async function permissionSysInvalidKind() {
- await assertRejects(async () => {
- // deno-lint-ignore no-explicit-any
- await Deno.permissions.query({ name: "sys", kind: "abc" as any });
- }, TypeError);
-});
-
-Deno.test(function permissionSysInvalidKindSync() {
- assertThrows(() => {
- // deno-lint-ignore no-explicit-any
- Deno.permissions.querySync({ name: "sys", kind: "abc" as any });
- }, TypeError);
-});
-
-Deno.test(async function permissionQueryReturnsEventTarget() {
- const status = await Deno.permissions.query({ name: "hrtime" });
- assert(["granted", "denied", "prompt"].includes(status.state));
- let called = false;
- status.addEventListener("change", () => {
- called = true;
- });
- status.dispatchEvent(new Event("change"));
- assert(called);
- assert(status === (await Deno.permissions.query({ name: "hrtime" })));
-});
-
-Deno.test(function permissionQueryReturnsEventTargetSync() {
- const status = Deno.permissions.querySync({ name: "hrtime" });
- assert(["granted", "denied", "prompt"].includes(status.state));
- let called = false;
- status.addEventListener("change", () => {
- called = true;
- });
- status.dispatchEvent(new Event("change"));
- assert(called);
- assert(status === Deno.permissions.querySync({ name: "hrtime" }));
-});
-
-Deno.test(async function permissionQueryForReadReturnsSameStatus() {
- const status1 = await Deno.permissions.query({
- name: "read",
- path: ".",
- });
- const status2 = await Deno.permissions.query({
- name: "read",
- path: ".",
- });
- assert(status1 === status2);
-});
-
-Deno.test(function permissionQueryForReadReturnsSameStatusSync() {
- const status1 = Deno.permissions.querySync({
- name: "read",
- path: ".",
- });
- const status2 = Deno.permissions.querySync({
- name: "read",
- path: ".",
- });
- assert(status1 === status2);
-});
-
-Deno.test(function permissionsIllegalConstructor() {
- assertThrows(() => new Deno.Permissions(), TypeError, "Illegal constructor.");
- assertEquals(Deno.Permissions.length, 0);
-});
-
-Deno.test(function permissionStatusIllegalConstructor() {
- assertThrows(
- () => new Deno.PermissionStatus(),
- TypeError,
- "Illegal constructor.",
- );
- assertEquals(Deno.PermissionStatus.length, 0);
-});
-
-// Regression test for https://github.com/denoland/deno/issues/17020
-Deno.test(async function permissionURL() {
- const path = new URL(".", import.meta.url);
-
- await Deno.permissions.query({ name: "read", path });
- await Deno.permissions.query({ name: "write", path });
- await Deno.permissions.query({ name: "ffi", path });
- await Deno.permissions.query({ name: "run", command: path });
-});
-
-Deno.test(function permissionURLSync() {
- Deno.permissions.querySync({
- name: "read",
- path: new URL(".", import.meta.url),
- });
- Deno.permissions.querySync({
- name: "write",
- path: new URL(".", import.meta.url),
- });
- Deno.permissions.querySync({
- name: "run",
- command: new URL(".", import.meta.url),
- });
-});
-
-Deno.test(async function permissionDescriptorValidation() {
- for (const value of [undefined, null, {}]) {
- for (const method of ["query", "request", "revoke"]) {
- await assertRejects(
- async () => {
- // deno-lint-ignore no-explicit-any
- await (Deno.permissions as any)[method](value as any);
- },
- TypeError,
- '"undefined" is not a valid permission name',
- );
- }
- }
-});
-
-Deno.test(function permissionDescriptorValidationSync() {
- for (const value of [undefined, null, {}]) {
- for (const method of ["querySync", "revokeSync", "requestSync"]) {
- assertThrows(
- () => {
- // deno-lint-ignore no-explicit-any
- (Deno.permissions as any)[method](value as any);
- },
- TypeError,
- '"undefined" is not a valid permission name',
- );
- }
- }
-});
-
-// Regression test for https://github.com/denoland/deno/issues/15894.
-Deno.test(async function permissionStatusObjectsNotEqual() {
- assert(
- await Deno.permissions.query({ name: "env", variable: "A" }) !=
- await Deno.permissions.query({ name: "env", variable: "B" }),
- );
-});
-
-Deno.test(function permissionStatusObjectsNotEqualSync() {
- assert(
- Deno.permissions.querySync({ name: "env", variable: "A" }) !=
- Deno.permissions.querySync({ name: "env", variable: "B" }),
- );
-});
diff --git a/cli/tests/unit/process_test.ts b/cli/tests/unit/process_test.ts
deleted file mode 100644
index 0cc4e99aa..000000000
--- a/cli/tests/unit/process_test.ts
+++ /dev/null
@@ -1,689 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertStrictEquals,
- assertStringIncludes,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(
- { permissions: { read: true, run: false } },
- function runPermissions() {
- assertThrows(() => {
- // deno-lint-ignore no-deprecated-deno-api
- Deno.run({
- cmd: [Deno.execPath(), "eval", "console.log('hello world')"],
- });
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runSuccess() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- // freeze the array to ensure it's not modified
- cmd: Object.freeze([
- Deno.execPath(),
- "eval",
- "console.log('hello world')",
- ]),
- stdout: "piped",
- stderr: "null",
- });
- const status = await p.status();
- assertEquals(status.success, true);
- assertEquals(status.code, 0);
- assertEquals(status.signal, undefined);
- p.stdout.close();
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runUrl() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- new URL(`file:///${Deno.execPath()}`),
- "eval",
- "console.log('hello world')",
- ],
- stdout: "piped",
- stderr: "null",
- });
- const status = await p.status();
- assertEquals(status.success, true);
- assertEquals(status.code, 0);
- assertEquals(status.signal, undefined);
- p.stdout.close();
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runStdinRid0(): Promise<
- void
- > {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [Deno.execPath(), "eval", "console.log('hello world')"],
- stdin: 0,
- stdout: "piped",
- stderr: "null",
- });
- const status = await p.status();
- assertEquals(status.success, true);
- assertEquals(status.code, 0);
- assertEquals(status.signal, undefined);
- p.stdout.close();
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- function runInvalidStdio() {
- assertThrows(() =>
- // deno-lint-ignore no-deprecated-deno-api
- Deno.run({
- cmd: [Deno.execPath(), "eval", "console.log('hello world')"],
- // @ts-expect-error because Deno.run should throw on invalid stdin.
- stdin: "a",
- })
- );
- assertThrows(() =>
- // deno-lint-ignore no-deprecated-deno-api
- Deno.run({
- cmd: [Deno.execPath(), "eval", "console.log('hello world')"],
- // @ts-expect-error because Deno.run should throw on invalid stdout.
- stdout: "b",
- })
- );
- assertThrows(() =>
- // deno-lint-ignore no-deprecated-deno-api
- Deno.run({
- cmd: [Deno.execPath(), "eval", "console.log('hello world')"],
- // @ts-expect-error because Deno.run should throw on invalid stderr.
- stderr: "c",
- })
- );
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runCommandFailedWithCode() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [Deno.execPath(), "eval", "Deno.exit(41 + 1)"],
- });
- const status = await p.status();
- assertEquals(status.success, false);
- assertEquals(status.code, 42);
- assertEquals(status.signal, undefined);
- p.close();
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true },
- },
- async function runCommandFailedWithSignal() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "Deno.kill(Deno.pid, 'SIGKILL')",
- ],
- });
- const status = await p.status();
- assertEquals(status.success, false);
- if (Deno.build.os === "windows") {
- assertEquals(status.code, 1);
- assertEquals(status.signal, undefined);
- } else {
- assertEquals(status.code, 128 + 9);
- assertEquals(status.signal, 9);
- }
- p.close();
- },
-);
-
-Deno.test({ permissions: { run: true } }, function runNotFound() {
- let error;
- try {
- // deno-lint-ignore no-deprecated-deno-api
- Deno.run({ cmd: ["this file hopefully doesn't exist"] });
- } catch (e) {
- error = e;
- }
- assert(error !== undefined);
- assert(error instanceof Deno.errors.NotFound);
-});
-
-Deno.test(
- { permissions: { write: true, run: true, read: true } },
- async function runWithCwdIsAsync() {
- const enc = new TextEncoder();
- const cwd = await Deno.makeTempDir({ prefix: "deno_command_test" });
-
- const exitCodeFile = "deno_was_here";
- const programFile = "poll_exit.ts";
- const program = `
-async function tryExit() {
- try {
- const code = parseInt(await Deno.readTextFile("${exitCodeFile}"));
- Deno.exit(code);
- } catch {
- // Retry if we got here before deno wrote the file.
- setTimeout(tryExit, 0.01);
- }
-}
-
-tryExit();
-`;
-
- Deno.writeFileSync(`${cwd}/${programFile}`, enc.encode(program));
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cwd,
- cmd: [Deno.execPath(), "run", "--allow-read", programFile],
- });
-
- // Write the expected exit code *after* starting deno.
- // This is how we verify that `run()` is actually asynchronous.
- const code = 84;
- Deno.writeFileSync(`${cwd}/${exitCodeFile}`, enc.encode(`${code}`));
-
- const status = await p.status();
- assertEquals(status.success, false);
- assertEquals(status.code, code);
- assertEquals(status.signal, undefined);
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runStdinPiped(): Promise<
- void
- > {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "if (new TextDecoder().decode(await Deno.readAll(Deno.stdin)) !== 'hello') throw new Error('Expected \\'hello\\'')",
- ],
- stdin: "piped",
- });
- assert(p.stdin);
- assert(!p.stdout);
- assert(!p.stderr);
-
- const msg = new TextEncoder().encode("hello");
- const n = await p.stdin.write(msg);
- assertEquals(n, msg.byteLength);
-
- p.stdin.close();
-
- const status = await p.status();
- assertEquals(status.success, true);
- assertEquals(status.code, 0);
- assertEquals(status.signal, undefined);
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runStdoutPiped(): Promise<
- void
- > {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "await Deno.stdout.write(new TextEncoder().encode('hello'))",
- ],
- stdout: "piped",
- });
- assert(!p.stdin);
- assert(!p.stderr);
-
- const data = new Uint8Array(10);
- let r = await p.stdout.read(data);
- if (r === null) {
- throw new Error("p.stdout.read(...) should not be null");
- }
- assertEquals(r, 5);
- const s = new TextDecoder().decode(data.subarray(0, r));
- assertEquals(s, "hello");
- r = await p.stdout.read(data);
- assertEquals(r, null);
- p.stdout.close();
-
- const status = await p.status();
- assertEquals(status.success, true);
- assertEquals(status.code, 0);
- assertEquals(status.signal, undefined);
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runStderrPiped(): Promise<
- void
- > {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "await Deno.stderr.write(new TextEncoder().encode('hello'))",
- ],
- stderr: "piped",
- });
- assert(!p.stdin);
- assert(!p.stdout);
-
- const data = new Uint8Array(10);
- let r = await p.stderr.read(data);
- if (r === null) {
- throw new Error("p.stderr.read should not return null here");
- }
- assertEquals(r, 5);
- const s = new TextDecoder().decode(data.subarray(0, r));
- assertEquals(s, "hello");
- r = await p.stderr.read(data);
- assertEquals(r, null);
- p.stderr!.close();
-
- const status = await p.status();
- assertEquals(status.success, true);
- assertEquals(status.code, 0);
- assertEquals(status.signal, undefined);
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runOutput() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "await Deno.stdout.write(new TextEncoder().encode('hello'))",
- ],
- stdout: "piped",
- });
- const output = await p.output();
- const s = new TextDecoder().decode(output);
- assertEquals(s, "hello");
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runStderrOutput(): Promise<
- void
- > {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "await Deno.stderr.write(new TextEncoder().encode('error'))",
- ],
- stderr: "piped",
- });
- const error = await p.stderrOutput();
- const s = new TextDecoder().decode(error);
- assertEquals(s, "error");
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, write: true, read: true } },
- async function runRedirectStdoutStderr() {
- const tempDir = await Deno.makeTempDir();
- const fileName = tempDir + "/redirected_stdio.txt";
- using file = await Deno.open(fileName, {
- create: true,
- write: true,
- });
-
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "Deno.stderr.write(new TextEncoder().encode('error\\n')); Deno.stdout.write(new TextEncoder().encode('output\\n'));",
- ],
- stdout: file.rid,
- stderr: file.rid,
- });
-
- await p.status();
- p.close();
-
- const fileContents = await Deno.readFile(fileName);
- const decoder = new TextDecoder();
- const text = decoder.decode(fileContents);
-
- assertStringIncludes(text, "error");
- assertStringIncludes(text, "output");
- },
-);
-
-Deno.test(
- { permissions: { run: true, write: true, read: true } },
- async function runRedirectStdin() {
- const tempDir = await Deno.makeTempDir();
- const fileName = tempDir + "/redirected_stdio.txt";
- await Deno.writeTextFile(fileName, "hello");
- using file = await Deno.open(fileName);
-
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "if (new TextDecoder().decode(await Deno.readAll(Deno.stdin)) !== 'hello') throw new Error('Expected \\'hello\\'')",
- ],
- stdin: file.rid,
- });
-
- const status = await p.status();
- assertEquals(status.code, 0);
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runEnv() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "Deno.stdout.write(new TextEncoder().encode(Deno.env.get('FOO') + Deno.env.get('BAR')))",
- ],
- env: {
- FOO: "0123",
- BAR: "4567",
- },
- stdout: "piped",
- });
- const output = await p.output();
- const s = new TextDecoder().decode(output);
- assertEquals(s, "01234567");
- p.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runClose() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "setTimeout(() => Deno.stdout.write(new TextEncoder().encode('error')), 10000)",
- ],
- stderr: "piped",
- });
- assert(!p.stdin);
- assert(!p.stdout);
-
- p.close();
-
- const data = new Uint8Array(10);
- const r = await p.stderr.read(data);
- assertEquals(r, null);
- p.stderr.close();
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function runKillAfterStatus() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [Deno.execPath(), "eval", 'console.log("hello")'],
- });
- await p.status();
-
- let error = null;
- try {
- p.kill("SIGTERM");
- } catch (e) {
- error = e;
- }
-
- assert(
- error instanceof Deno.errors.NotFound ||
- // On Windows, the underlying Windows API may return
- // `ERROR_ACCESS_DENIED` when the process has exited, but hasn't been
- // completely cleaned up yet and its `pid` is still valid.
- (Deno.build.os === "windows" &&
- error instanceof Deno.errors.PermissionDenied),
- );
-
- p.close();
- },
-);
-
-Deno.test({ permissions: { run: false } }, function killPermissions() {
- assertThrows(() => {
- // Unlike the other test cases, we don't have permission to spawn a
- // subprocess we can safely kill. Instead we send SIGCONT to the current
- // process - assuming that Deno does not have a special handler set for it
- // and will just continue even if a signal is erroneously sent.
- Deno.kill(Deno.pid, "SIGCONT");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { ignore: Deno.build.os !== "windows", permissions: { run: true } },
- function negativePidInvalidWindows() {
- assertThrows(() => {
- Deno.kill(-1, "SIGTERM");
- }, TypeError);
- },
-);
-
-Deno.test(
- { ignore: Deno.build.os !== "windows", permissions: { run: true } },
- function invalidSignalNameWindows() {
- assertThrows(() => {
- Deno.kill(Deno.pid, "SIGUSR1");
- }, TypeError);
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function killSuccess() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [Deno.execPath(), "eval", "setTimeout(() => {}, 10000)"],
- });
-
- try {
- Deno.kill(p.pid, "SIGKILL");
- const status = await p.status();
-
- assertEquals(status.success, false);
- if (Deno.build.os === "windows") {
- assertEquals(status.code, 1);
- assertEquals(status.signal, undefined);
- } else {
- assertEquals(status.code, 137);
- assertEquals(status.signal, 9);
- }
- } finally {
- p.close();
- }
- },
-);
-
-Deno.test({ permissions: { run: true, read: true } }, function killFailed() {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [Deno.execPath(), "eval", "setTimeout(() => {}, 10000)"],
- });
- assert(!p.stdin);
- assert(!p.stdout);
-
- assertThrows(() => {
- // @ts-expect-error testing runtime error of bad signal
- Deno.kill(p.pid, "foobar");
- }, TypeError);
-
- p.close();
-});
-
-Deno.test(
- { permissions: { run: true, read: true, env: true } },
- async function clearEnv(): Promise<void> {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- "-p",
- "JSON.stringify(Deno.env.toObject())",
- ],
- stdout: "piped",
- clearEnv: true,
- env: {
- FOO: "23147",
- },
- });
-
- const obj = JSON.parse(new TextDecoder().decode(await p.output()));
-
- // can't check for object equality because the OS may set additional env
- // vars for processes, so we check if PATH isn't present as that is a common
- // env var across OS's and isn't set for processes.
- assertEquals(obj.FOO, "23147");
- assert(!("PATH" in obj));
-
- p.close();
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true },
- ignore: Deno.build.os === "windows",
- },
- async function uid(): Promise<void> {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- "id",
- "-u",
- ],
- stdout: "piped",
- });
-
- const currentUid = new TextDecoder().decode(await p.output());
- p.close();
-
- if (currentUid !== "0") {
- assertThrows(() => {
- // deno-lint-ignore no-deprecated-deno-api
- Deno.run({
- cmd: [
- "echo",
- "fhqwhgads",
- ],
- uid: 0,
- });
- }, Deno.errors.PermissionDenied);
- }
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true },
- ignore: Deno.build.os === "windows",
- },
- async function gid(): Promise<void> {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- "id",
- "-g",
- ],
- stdout: "piped",
- });
-
- const currentGid = new TextDecoder().decode(await p.output());
- p.close();
-
- if (currentGid !== "0") {
- assertThrows(() => {
- // deno-lint-ignore no-deprecated-deno-api
- Deno.run({
- cmd: [
- "echo",
- "fhqwhgads",
- ],
- gid: 0,
- });
- }, Deno.errors.PermissionDenied);
- }
- },
-);
-
-Deno.test(
- {
- permissions: { run: true, read: true, write: true },
- ignore: Deno.build.os === "windows",
- },
- async function non_existent_cwd(): Promise<void> {
- // deno-lint-ignore no-deprecated-deno-api
- const p = Deno.run({
- cmd: [
- Deno.execPath(),
- "eval",
- `const dir = Deno.makeTempDirSync();
- Deno.chdir(dir);
- Deno.removeSync(dir);
- const p = Deno.run({cmd:[Deno.execPath(), "eval", "console.log(1);"]});
- const { code } = await p.status();
- p.close();
- Deno.exit(code);
- `,
- ],
- stdout: "piped",
- stderr: "piped",
- });
-
- const { code } = await p.status();
- const stderr = new TextDecoder().decode(await p.stderrOutput());
- p.close();
- p.stdout.close();
- assertStrictEquals(code, 1);
- assertStringIncludes(stderr, "Failed getting cwd.");
- },
-);
diff --git a/cli/tests/unit/progressevent_test.ts b/cli/tests/unit/progressevent_test.ts
deleted file mode 100644
index 809c2ad39..000000000
--- a/cli/tests/unit/progressevent_test.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-Deno.test(function progressEventConstruct() {
- const progressEventDefs = new ProgressEvent("progressEventType", {});
- assertEquals(progressEventDefs.lengthComputable, false);
- assertEquals(progressEventDefs.loaded, 0);
- assertEquals(progressEventDefs.total, 0);
-
- const progressEvent = new ProgressEvent("progressEventType", {
- lengthComputable: true,
- loaded: 123,
- total: 456,
- });
- assertEquals(progressEvent.lengthComputable, true);
- assertEquals(progressEvent.loaded, 123);
- assertEquals(progressEvent.total, 456);
-});
diff --git a/cli/tests/unit/promise_hooks_test.ts b/cli/tests/unit/promise_hooks_test.ts
deleted file mode 100644
index f7c44155d..000000000
--- a/cli/tests/unit/promise_hooks_test.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assertEquals } from "./test_util.ts";
-
-function monitorPromises(outputArray: string[]) {
- const promiseIds = new Map<Promise<unknown>, string>();
-
- function identify(promise: Promise<unknown>) {
- if (!promiseIds.has(promise)) {
- promiseIds.set(promise, "p" + (promiseIds.size + 1));
- }
- return promiseIds.get(promise);
- }
-
- // @ts-ignore: Deno[Deno.internal].core allowed
- Deno[Deno.internal].core.setPromiseHooks(
- (promise: Promise<unknown>, parentPromise?: Promise<unknown>) => {
- outputArray.push(
- `init ${identify(promise)}` +
- (parentPromise ? ` from ${identify(parentPromise)}` : ``),
- );
- },
- (promise: Promise<unknown>) => {
- outputArray.push(`before ${identify(promise)}`);
- },
- (promise: Promise<unknown>) => {
- outputArray.push(`after ${identify(promise)}`);
- },
- (promise: Promise<unknown>) => {
- outputArray.push(`resolve ${identify(promise)}`);
- },
- );
-}
-
-Deno.test(async function promiseHookBasic() {
- // Bogus await here to ensure any pending promise resolution from the
- // test runtime has a chance to run and avoid contaminating our results.
- await Promise.resolve(null);
-
- const hookResults: string[] = [];
- monitorPromises(hookResults);
-
- async function asyncFn() {
- await Promise.resolve(15);
- await Promise.resolve(20);
- Promise.reject(new Error()).catch(() => {});
- }
-
- // The function above is equivalent to:
- // function asyncFn() {
- // return new Promise(resolve => {
- // Promise.resolve(15).then(() => {
- // Promise.resolve(20).then(() => {
- // Promise.reject(new Error()).catch(() => {});
- // resolve();
- // });
- // });
- // });
- // }
-
- await asyncFn();
-
- assertEquals(hookResults, [
- "init p1", // Creates the promise representing the return of `asyncFn()`.
- "init p2", // Creates the promise representing `Promise.resolve(15)`.
- "resolve p2", // The previous promise resolves to `15` immediately.
- "init p3 from p2", // Creates the promise that is resolved after the first `await` of the function. Equivalent to `p2.then(...)`.
- "init p4 from p1", // The resolution above gives time for other pending code to run. Creates the promise that is resolved
- // from the `await` at `await asyncFn()`, the last code to run. Equivalent to `asyncFn().then(...)`.
- "before p3", // Begins executing the code after `await Promise.resolve(15)`.
- "init p5", // Creates the promise representing `Promise.resolve(20)`.
- "resolve p5", // The previous promise resolves to `20` immediately.
- "init p6 from p5", // Creates the promise that is resolved after the second `await` of the function. Equivalent to `p5.then(...)`.
- "resolve p3", // The promise representing the code right after the first await is marked as resolved.
- "after p3", // We are now after the resolution code of the promise above.
- "before p6", // Begins executing the code after `await Promise.resolve(20)`.
- "init p7", // Creates a new promise representing `Promise.reject(new Error())`.
- "resolve p7", // This promise is "resolved" immediately to a rejection with an error instance.
- "init p8 from p7", // Creates a new promise for the `.catch` of the previous promise.
- "resolve p1", // At this point the promise of the function is resolved.
- "resolve p6", // This concludes the resolution of the code after `await Promise.resolve(20)`.
- "after p6", // We are now after the resolution code of the promise above.
- "before p8", // The `.catch` block is pending execution, it begins to execute.
- "resolve p8", // It does nothing and resolves to `undefined`.
- "after p8", // We are after the resolution of the `.catch` block.
- "before p4", // Now we begin the execution of the code that happens after `await asyncFn();`.
- ]);
-});
-
-Deno.test(async function promiseHookMultipleConsumers() {
- const hookResultsFirstConsumer: string[] = [];
- const hookResultsSecondConsumer: string[] = [];
-
- monitorPromises(hookResultsFirstConsumer);
- monitorPromises(hookResultsSecondConsumer);
-
- async function asyncFn() {
- await Promise.resolve(15);
- await Promise.resolve(20);
- Promise.reject(new Error()).catch(() => {});
- }
- await asyncFn();
-
- // Two invocations of `setPromiseHooks` should yield the exact same results, in the same order.
- assertEquals(
- hookResultsFirstConsumer,
- hookResultsSecondConsumer,
- );
-});
diff --git a/cli/tests/unit/read_dir_test.ts b/cli/tests/unit/read_dir_test.ts
deleted file mode 100644
index 50447ef6a..000000000
--- a/cli/tests/unit/read_dir_test.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
- pathToAbsoluteFileUrl,
-} from "./test_util.ts";
-
-function assertSameContent(files: Deno.DirEntry[]) {
- let counter = 0;
-
- for (const entry of files) {
- if (entry.name === "subdir") {
- assert(entry.isDirectory);
- counter++;
- }
- }
-
- assertEquals(counter, 1);
-}
-
-Deno.test({ permissions: { read: true } }, function readDirSyncSuccess() {
- const files = [...Deno.readDirSync("cli/tests/testdata")];
- assertSameContent(files);
-});
-
-Deno.test({ permissions: { read: true } }, function readDirSyncWithUrl() {
- const files = [
- ...Deno.readDirSync(pathToAbsoluteFileUrl("cli/tests/testdata")),
- ];
- assertSameContent(files);
-});
-
-Deno.test({ permissions: { read: false } }, function readDirSyncPerm() {
- assertThrows(() => {
- Deno.readDirSync("tests/");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function readDirSyncNotDir() {
- assertThrows(
- () => {
- Deno.readDirSync("cli/tests/testdata/assets/fixture.json");
- },
- Error,
- `readdir 'cli/tests/testdata/assets/fixture.json'`,
- );
-});
-
-Deno.test({ permissions: { read: true } }, function readDirSyncNotFound() {
- assertThrows(
- () => {
- Deno.readDirSync("bad_dir_name");
- },
- Deno.errors.NotFound,
- `readdir 'bad_dir_name'`,
- );
-});
-
-Deno.test({ permissions: { read: true } }, async function readDirSuccess() {
- const files = [];
- for await (const dirEntry of Deno.readDir("cli/tests/testdata")) {
- files.push(dirEntry);
- }
- assertSameContent(files);
-});
-
-Deno.test({ permissions: { read: true } }, async function readDirWithUrl() {
- const files = [];
- for await (
- const dirEntry of Deno.readDir(pathToAbsoluteFileUrl("cli/tests/testdata"))
- ) {
- files.push(dirEntry);
- }
- assertSameContent(files);
-});
-
-Deno.test({ permissions: { read: false } }, async function readDirPerm() {
- await assertRejects(async () => {
- await Deno.readDir("tests/")[Symbol.asyncIterator]().next();
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { read: true }, ignore: Deno.build.os == "windows" },
- async function readDirDevFd(): Promise<
- void
- > {
- for await (const _ of Deno.readDir("/dev/fd")) {
- // We don't actually care whats in here; just that we don't panic on non regular entries
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true }, ignore: Deno.build.os == "windows" },
- function readDirDevFdSync() {
- for (const _ of Deno.readDirSync("/dev/fd")) {
- // We don't actually care whats in here; just that we don't panic on non regular file entries
- }
- },
-);
-
-Deno.test({ permissions: { read: true } }, async function readDirNotFound() {
- await assertRejects(
- async () => {
- await Deno.readDir("bad_dir_name")[Symbol.asyncIterator]().next();
- },
- Deno.errors.NotFound,
- `readdir 'bad_dir_name'`,
- );
-});
diff --git a/cli/tests/unit/read_file_test.ts b/cli/tests/unit/read_file_test.ts
deleted file mode 100644
index 24ec1aedc..000000000
--- a/cli/tests/unit/read_file_test.ts
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
- pathToAbsoluteFileUrl,
- unreachable,
-} from "./test_util.ts";
-
-Deno.test({ permissions: { read: true } }, function readFileSyncSuccess() {
- const data = Deno.readFileSync("cli/tests/testdata/assets/fixture.json");
- assert(data.byteLength > 0);
- const decoder = new TextDecoder("utf-8");
- const json = decoder.decode(data);
- const pkg = JSON.parse(json);
- assertEquals(pkg.name, "deno");
-});
-
-Deno.test({ permissions: { read: true } }, function readFileSyncUrl() {
- const data = Deno.readFileSync(
- pathToAbsoluteFileUrl("cli/tests/testdata/assets/fixture.json"),
- );
- assert(data.byteLength > 0);
- const decoder = new TextDecoder("utf-8");
- const json = decoder.decode(data);
- const pkg = JSON.parse(json);
- assertEquals(pkg.name, "deno");
-});
-
-Deno.test({ permissions: { read: false } }, function readFileSyncPerm() {
- assertThrows(() => {
- Deno.readFileSync("cli/tests/testdata/assets/fixture.json");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function readFileSyncNotFound() {
- assertThrows(() => {
- Deno.readFileSync("bad_filename");
- }, Deno.errors.NotFound);
-});
-
-Deno.test({ permissions: { read: true } }, async function readFileUrl() {
- const data = await Deno.readFile(
- pathToAbsoluteFileUrl("cli/tests/testdata/assets/fixture.json"),
- );
- assert(data.byteLength > 0);
- const decoder = new TextDecoder("utf-8");
- const json = decoder.decode(data);
- const pkg = JSON.parse(json);
- assertEquals(pkg.name, "deno");
-});
-
-Deno.test({ permissions: { read: true } }, async function readFileSuccess() {
- const data = await Deno.readFile("cli/tests/testdata/assets/fixture.json");
- assert(data.byteLength > 0);
- const decoder = new TextDecoder("utf-8");
- const json = decoder.decode(data);
- const pkg = JSON.parse(json);
- assertEquals(pkg.name, "deno");
-});
-
-Deno.test({ permissions: { read: false } }, async function readFilePerm() {
- await assertRejects(async () => {
- await Deno.readFile("cli/tests/testdata/assets/fixture.json");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function readFileSyncLoop() {
- for (let i = 0; i < 256; i++) {
- Deno.readFileSync("cli/tests/testdata/assets/fixture.json");
- }
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function readFileDoesNotLeakResources() {
- await assertRejects(async () => await Deno.readFile("cli"));
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- function readFileSyncDoesNotLeakResources() {
- assertThrows(() => Deno.readFileSync("cli"));
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function readFileWithAbortSignal() {
- const ac = new AbortController();
- queueMicrotask(() => ac.abort());
- const error = await assertRejects(
- async () => {
- await Deno.readFile("cli/tests/testdata/assets/fixture.json", {
- signal: ac.signal,
- });
- },
- );
- assert(error instanceof DOMException);
- assertEquals(error.name, "AbortError");
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function readFileWithAbortSignalReason() {
- const ac = new AbortController();
- const abortReason = new Error();
- queueMicrotask(() => ac.abort(abortReason));
- const error = await assertRejects(
- async () => {
- await Deno.readFile("cli/tests/testdata/assets/fixture.json", {
- signal: ac.signal,
- });
- },
- );
- assertEquals(error, abortReason);
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function readFileWithAbortSignalPrimitiveReason() {
- const ac = new AbortController();
- queueMicrotask(() => ac.abort("Some string"));
- try {
- await Deno.readFile("cli/tests/testdata/assets/fixture.json", {
- signal: ac.signal,
- });
- unreachable();
- } catch (e) {
- assertEquals(e, "Some string");
- }
- },
-);
-
-// Test that AbortController's cancel handle is cleaned-up correctly, and do not leak resources.
-Deno.test(
- { permissions: { read: true } },
- async function readFileWithAbortSignalNotCalled() {
- const ac = new AbortController();
- await Deno.readFile("cli/tests/testdata/assets/fixture.json", {
- signal: ac.signal,
- });
- },
-);
-
-Deno.test(
- { permissions: { read: true }, ignore: Deno.build.os !== "linux" },
- async function readFileProcFs() {
- const data = await Deno.readFile("/proc/self/stat");
- assert(data.byteLength > 0);
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function readFileNotFoundErrorCode() {
- try {
- await Deno.readFile("definitely-not-found.json");
- } catch (e) {
- assertEquals(e.code, "ENOENT");
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function readFileIsDirectoryErrorCode() {
- try {
- await Deno.readFile("cli/tests/testdata/assets/");
- } catch (e) {
- if (Deno.build.os === "windows") {
- assertEquals(e.code, "ENOENT");
- } else {
- assertEquals(e.code, "EISDIR");
- }
- }
- },
-);
diff --git a/cli/tests/unit/read_link_test.ts b/cli/tests/unit/read_link_test.ts
deleted file mode 100644
index 3ed1817bb..000000000
--- a/cli/tests/unit/read_link_test.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assertEquals,
- assertRejects,
- assertThrows,
- pathToAbsoluteFileUrl,
-} from "./test_util.ts";
-
-Deno.test(
- { permissions: { write: true, read: true } },
- function readLinkSyncSuccess() {
- const testDir = Deno.makeTempDirSync();
- const target = testDir +
- (Deno.build.os == "windows" ? "\\target" : "/target");
- const symlink = testDir +
- (Deno.build.os == "windows" ? "\\symlink" : "/symlink");
- Deno.mkdirSync(target);
- Deno.symlinkSync(target, symlink);
- const targetPath = Deno.readLinkSync(symlink);
- assertEquals(targetPath, target);
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- function readLinkSyncUrlSuccess() {
- const testDir = Deno.makeTempDirSync();
- const target = testDir +
- (Deno.build.os == "windows" ? "\\target" : "/target");
- const symlink = testDir +
- (Deno.build.os == "windows" ? "\\symlink" : "/symlink");
- Deno.mkdirSync(target);
- Deno.symlinkSync(target, symlink);
- const targetPath = Deno.readLinkSync(pathToAbsoluteFileUrl(symlink));
- assertEquals(targetPath, target);
- },
-);
-
-Deno.test({ permissions: { read: false } }, function readLinkSyncPerm() {
- assertThrows(() => {
- Deno.readLinkSync("/symlink");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function readLinkSyncNotFound() {
- assertThrows(
- () => {
- Deno.readLinkSync("bad_filename");
- },
- Deno.errors.NotFound,
- `readlink 'bad_filename'`,
- );
-});
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function readLinkSuccess() {
- const testDir = Deno.makeTempDirSync();
- const target = testDir +
- (Deno.build.os == "windows" ? "\\target" : "/target");
- const symlink = testDir +
- (Deno.build.os == "windows" ? "\\symlink" : "/symlink");
- Deno.mkdirSync(target);
- Deno.symlinkSync(target, symlink);
- const targetPath = await Deno.readLink(symlink);
- assertEquals(targetPath, target);
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function readLinkUrlSuccess() {
- const testDir = Deno.makeTempDirSync();
- const target = testDir +
- (Deno.build.os == "windows" ? "\\target" : "/target");
- const symlink = testDir +
- (Deno.build.os == "windows" ? "\\symlink" : "/symlink");
- Deno.mkdirSync(target);
- Deno.symlinkSync(target, symlink);
- const targetPath = await Deno.readLink(pathToAbsoluteFileUrl(symlink));
- assertEquals(targetPath, target);
- },
-);
-
-Deno.test({ permissions: { read: false } }, async function readLinkPerm() {
- await assertRejects(async () => {
- await Deno.readLink("/symlink");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, async function readLinkNotFound() {
- await assertRejects(
- async () => {
- await Deno.readLink("bad_filename");
- },
- Deno.errors.NotFound,
- `readlink 'bad_filename'`,
- );
-});
diff --git a/cli/tests/unit/read_text_file_test.ts b/cli/tests/unit/read_text_file_test.ts
deleted file mode 100644
index 5a64522af..000000000
--- a/cli/tests/unit/read_text_file_test.ts
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
- pathToAbsoluteFileUrl,
- unreachable,
-} from "./test_util.ts";
-
-Deno.test({ permissions: { read: true } }, function readTextFileSyncSuccess() {
- const data = Deno.readTextFileSync("cli/tests/testdata/assets/fixture.json");
- assert(data.length > 0);
- const pkg = JSON.parse(data);
- assertEquals(pkg.name, "deno");
-});
-
-Deno.test({ permissions: { read: true } }, function readTextFileSyncByUrl() {
- const data = Deno.readTextFileSync(
- pathToAbsoluteFileUrl("cli/tests/testdata/assets/fixture.json"),
- );
- assert(data.length > 0);
- const pkg = JSON.parse(data);
- assertEquals(pkg.name, "deno");
-});
-
-Deno.test({ permissions: { read: false } }, function readTextFileSyncPerm() {
- assertThrows(() => {
- Deno.readTextFileSync("cli/tests/testdata/assets/fixture.json");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function readTextFileSyncNotFound() {
- assertThrows(() => {
- Deno.readTextFileSync("bad_filename");
- }, Deno.errors.NotFound);
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function readTextFileSuccess() {
- const data = await Deno.readTextFile(
- "cli/tests/testdata/assets/fixture.json",
- );
- assert(data.length > 0);
- const pkg = JSON.parse(data);
- assertEquals(pkg.name, "deno");
- },
-);
-
-Deno.test({ permissions: { read: true } }, async function readTextFileByUrl() {
- const data = await Deno.readTextFile(
- pathToAbsoluteFileUrl("cli/tests/testdata/assets/fixture.json"),
- );
- assert(data.length > 0);
- const pkg = JSON.parse(data);
- assertEquals(pkg.name, "deno");
-});
-
-Deno.test({ permissions: { read: false } }, async function readTextFilePerm() {
- await assertRejects(async () => {
- await Deno.readTextFile("cli/tests/testdata/assets/fixture.json");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function readTextFileSyncLoop() {
- for (let i = 0; i < 256; i++) {
- Deno.readTextFileSync("cli/tests/testdata/assets/fixture.json");
- }
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function readTextFileDoesNotLeakResources() {
- await assertRejects(async () => await Deno.readTextFile("cli"));
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- function readTextFileSyncDoesNotLeakResources() {
- assertThrows(() => Deno.readTextFileSync("cli"));
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function readTextFileWithAbortSignal() {
- const ac = new AbortController();
- queueMicrotask(() => ac.abort());
- const error = await assertRejects(
- async () => {
- await Deno.readTextFile("cli/tests/testdata/assets/fixture.json", {
- signal: ac.signal,
- });
- },
- );
- assert(error instanceof DOMException);
- assertEquals(error.name, "AbortError");
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function readTextFileWithAbortSignalReason() {
- const ac = new AbortController();
- const abortReason = new Error();
- queueMicrotask(() => ac.abort(abortReason));
- const error = await assertRejects(
- async () => {
- await Deno.readTextFile("cli/tests/testdata/assets/fixture.json", {
- signal: ac.signal,
- });
- },
- );
- assertEquals(error, abortReason);
- },
-);
-
-Deno.test(
- { permissions: { read: true } },
- async function readTextFileWithAbortSignalPrimitiveReason() {
- const ac = new AbortController();
- queueMicrotask(() => ac.abort("Some string"));
- try {
- await Deno.readTextFile("cli/tests/testdata/assets/fixture.json", {
- signal: ac.signal,
- });
- unreachable();
- } catch (e) {
- assertEquals(e, "Some string");
- }
- },
-);
-
-// Test that AbortController's cancel handle is cleaned-up correctly, and do not leak resources.
-Deno.test(
- { permissions: { read: true } },
- async function readTextFileWithAbortSignalNotCalled() {
- const ac = new AbortController();
- await Deno.readTextFile("cli/tests/testdata/assets/fixture.json", {
- signal: ac.signal,
- });
- },
-);
-
-Deno.test(
- { permissions: { read: true }, ignore: Deno.build.os !== "linux" },
- async function readTextFileProcFs() {
- const data = await Deno.readTextFile("/proc/self/stat");
- assert(data.length > 0);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function readTextFileSyncV8LimitError() {
- const kStringMaxLengthPlusOne = 536870888 + 1;
- const bytes = new Uint8Array(kStringMaxLengthPlusOne);
- const filePath = "cli/tests/testdata/too_big_a_file.txt";
-
- try {
- Deno.writeFileSync(filePath, bytes);
- } catch {
- // NOTE(bartlomieju): writing a 0.5Gb file might be too much for CI,
- // so skip running if writing fails.
- return;
- }
-
- assertThrows(
- () => {
- Deno.readTextFileSync(filePath);
- },
- TypeError,
- "buffer exceeds maximum length",
- );
-
- Deno.removeSync(filePath);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function readTextFileV8LimitError() {
- const kStringMaxLengthPlusOne = 536870888 + 1;
- const bytes = new Uint8Array(kStringMaxLengthPlusOne);
- const filePath = "cli/tests/testdata/too_big_a_file_2.txt";
-
- try {
- await Deno.writeFile(filePath, bytes);
- } catch {
- // NOTE(bartlomieju): writing a 0.5Gb file might be too much for CI,
- // so skip running if writing fails.
- return;
- }
-
- await assertRejects(
- async () => {
- await Deno.readTextFile(filePath);
- },
- TypeError,
- "buffer exceeds maximum length",
- );
-
- await Deno.remove(filePath);
- },
-);
diff --git a/cli/tests/unit/real_path_test.ts b/cli/tests/unit/real_path_test.ts
deleted file mode 100644
index 1b944f5ad..000000000
--- a/cli/tests/unit/real_path_test.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertMatch,
- assertRejects,
- assertThrows,
- pathToAbsoluteFileUrl,
-} from "./test_util.ts";
-
-Deno.test({ permissions: { read: true } }, function realPathSyncSuccess() {
- const relative = "cli/tests/testdata/assets/fixture.json";
- const realPath = Deno.realPathSync(relative);
- if (Deno.build.os !== "windows") {
- assert(realPath.startsWith("/"));
- assert(realPath.endsWith(relative));
- } else {
- assertMatch(realPath, /^[A-Z]:\\/);
- assert(realPath.endsWith(relative.replace(/\//g, "\\")));
- }
-});
-
-Deno.test({ permissions: { read: true } }, function realPathSyncUrl() {
- const relative = "cli/tests/testdata/assets/fixture.json";
- const url = pathToAbsoluteFileUrl(relative);
- assertEquals(Deno.realPathSync(relative), Deno.realPathSync(url));
-});
-
-Deno.test(
- {
- permissions: { read: true, write: true },
- },
- function realPathSyncSymlink() {
- const testDir = Deno.makeTempDirSync();
- const target = testDir + "/target";
- const symlink = testDir + "/symln";
- Deno.mkdirSync(target);
- Deno.symlinkSync(target, symlink);
- const realPath = Deno.realPathSync(symlink);
- if (Deno.build.os !== "windows") {
- assert(realPath.startsWith("/"));
- assert(realPath.endsWith("/target"));
- } else {
- assertMatch(realPath, /^[A-Z]:\\/);
- assert(realPath.endsWith("\\target"));
- }
- },
-);
-
-Deno.test({ permissions: { read: false } }, function realPathSyncPerm() {
- assertThrows(() => {
- Deno.realPathSync("some_file");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function realPathSyncNotFound() {
- assertThrows(() => {
- Deno.realPathSync("bad_filename");
- }, Deno.errors.NotFound);
-});
-
-Deno.test({ permissions: { read: true } }, async function realPathSuccess() {
- const relativePath = "cli/tests/testdata/assets/fixture.json";
- const realPath = await Deno.realPath(relativePath);
- if (Deno.build.os !== "windows") {
- assert(realPath.startsWith("/"));
- assert(realPath.endsWith(relativePath));
- } else {
- assertMatch(realPath, /^[A-Z]:\\/);
- assert(realPath.endsWith(relativePath.replace(/\//g, "\\")));
- }
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function realPathUrl() {
- const relative = "cli/tests/testdata/assets/fixture.json";
- const url = pathToAbsoluteFileUrl(relative);
- assertEquals(await Deno.realPath(relative), await Deno.realPath(url));
- },
-);
-
-Deno.test(
- {
- permissions: { read: true, write: true },
- },
- async function realPathSymlink() {
- const testDir = Deno.makeTempDirSync();
- const target = testDir + "/target";
- const symlink = testDir + "/symln";
- Deno.mkdirSync(target);
- Deno.symlinkSync(target, symlink);
- const realPath = await Deno.realPath(symlink);
- if (Deno.build.os !== "windows") {
- assert(realPath.startsWith("/"));
- assert(realPath.endsWith("/target"));
- } else {
- assertMatch(realPath, /^[A-Z]:\\/);
- assert(realPath.endsWith("\\target"));
- }
- },
-);
-
-Deno.test({ permissions: { read: false } }, async function realPathPerm() {
- await assertRejects(async () => {
- await Deno.realPath("some_file");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, async function realPathNotFound() {
- await assertRejects(async () => {
- await Deno.realPath("bad_filename");
- }, Deno.errors.NotFound);
-});
diff --git a/cli/tests/unit/ref_unref_test.ts b/cli/tests/unit/ref_unref_test.ts
deleted file mode 100644
index 6f5bcf0a7..000000000
--- a/cli/tests/unit/ref_unref_test.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assertNotEquals, execCode } from "./test_util.ts";
-
-Deno.test("[unrefOpPromise] unref'ing invalid ops does not have effects", async () => {
- const [statusCode, _] = await execCode(`
- Deno[Deno.internal].core.unrefOpPromise(new Promise(r => null));
- setTimeout(() => { throw new Error() }, 10)
- `);
- // Invalid unrefOpPromise call doesn't affect exit condition of event loop
- assertNotEquals(statusCode, 0);
-});
diff --git a/cli/tests/unit/remove_test.ts b/cli/tests/unit/remove_test.ts
deleted file mode 100644
index f4e54dc52..000000000
--- a/cli/tests/unit/remove_test.ts
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertRejects, assertThrows } from "./test_util.ts";
-
-const REMOVE_METHODS = ["remove", "removeSync"] as const;
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function removeDirSuccess() {
- for (const method of REMOVE_METHODS) {
- // REMOVE EMPTY DIRECTORY
- const path = Deno.makeTempDirSync() + "/subdir";
- Deno.mkdirSync(path);
- const pathInfo = Deno.statSync(path);
- assert(pathInfo.isDirectory); // check exist first
- await Deno[method](path); // remove
- // We then check again after remove
- assertThrows(() => {
- Deno.statSync(path);
- }, Deno.errors.NotFound);
- }
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function removeFileSuccess() {
- for (const method of REMOVE_METHODS) {
- // REMOVE FILE
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- Deno.writeFileSync(filename, data, { mode: 0o666 });
- const fileInfo = Deno.statSync(filename);
- assert(fileInfo.isFile); // check exist first
- await Deno[method](filename); // remove
- // We then check again after remove
- assertThrows(() => {
- Deno.statSync(filename);
- }, Deno.errors.NotFound);
- }
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function removeFileByUrl() {
- for (const method of REMOVE_METHODS) {
- // REMOVE FILE
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
-
- const tempDir = Deno.makeTempDirSync();
- const fileUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/test.txt`,
- );
-
- Deno.writeFileSync(fileUrl, data, { mode: 0o666 });
- const fileInfo = Deno.statSync(fileUrl);
- assert(fileInfo.isFile); // check exist first
- await Deno[method](fileUrl); // remove
- // We then check again after remove
- assertThrows(() => {
- Deno.statSync(fileUrl);
- }, Deno.errors.NotFound);
- }
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function removeFail() {
- for (const method of REMOVE_METHODS) {
- // NON-EMPTY DIRECTORY
- const path = Deno.makeTempDirSync() + "/dir/subdir";
- const subPath = path + "/subsubdir";
- Deno.mkdirSync(path, { recursive: true });
- Deno.mkdirSync(subPath);
- const pathInfo = Deno.statSync(path);
- assert(pathInfo.isDirectory); // check exist first
- const subPathInfo = Deno.statSync(subPath);
- assert(subPathInfo.isDirectory); // check exist first
-
- await assertRejects(
- async () => {
- await Deno[method](path);
- },
- Error,
- `remove '${path}'`,
- );
- // TODO(ry) Is Other really the error we should get here? What would Go do?
-
- // NON-EXISTENT DIRECTORY/FILE
- await assertRejects(
- async () => {
- await Deno[method]("/baddir");
- },
- Deno.errors.NotFound,
- `remove '/baddir'`,
- );
- }
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function removeDanglingSymlinkSuccess() {
- for (const method of REMOVE_METHODS) {
- const danglingSymlinkPath = Deno.makeTempDirSync() + "/dangling_symlink";
- if (Deno.build.os === "windows") {
- Deno.symlinkSync("unexistent_file", danglingSymlinkPath, {
- type: "file",
- });
- } else {
- Deno.symlinkSync("unexistent_file", danglingSymlinkPath);
- }
- const pathInfo = Deno.lstatSync(danglingSymlinkPath);
- assert(pathInfo.isSymlink);
- await Deno[method](danglingSymlinkPath);
- assertThrows(() => {
- Deno.lstatSync(danglingSymlinkPath);
- }, Deno.errors.NotFound);
- }
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function removeValidSymlinkSuccess() {
- for (const method of REMOVE_METHODS) {
- const encoder = new TextEncoder();
- const data = encoder.encode("Test");
- const tempDir = Deno.makeTempDirSync();
- const filePath = tempDir + "/test.txt";
- const validSymlinkPath = tempDir + "/valid_symlink";
- Deno.writeFileSync(filePath, data, { mode: 0o666 });
- if (Deno.build.os === "windows") {
- Deno.symlinkSync(filePath, validSymlinkPath, { type: "file" });
- } else {
- Deno.symlinkSync(filePath, validSymlinkPath);
- }
- const symlinkPathInfo = Deno.statSync(validSymlinkPath);
- assert(symlinkPathInfo.isFile);
- await Deno[method](validSymlinkPath);
- assertThrows(() => {
- Deno.statSync(validSymlinkPath);
- }, Deno.errors.NotFound);
- await Deno[method](filePath);
- }
- },
-);
-
-Deno.test({ permissions: { write: false } }, async function removePerm() {
- for (const method of REMOVE_METHODS) {
- await assertRejects(async () => {
- await Deno[method]("/baddir");
- }, Deno.errors.PermissionDenied);
- }
-});
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function removeAllDirSuccess() {
- for (const method of REMOVE_METHODS) {
- // REMOVE EMPTY DIRECTORY
- let path = Deno.makeTempDirSync() + "/dir/subdir";
- Deno.mkdirSync(path, { recursive: true });
- let pathInfo = Deno.statSync(path);
- assert(pathInfo.isDirectory); // check exist first
- await Deno[method](path, { recursive: true }); // remove
- // We then check again after remove
- assertThrows(
- () => {
- Deno.statSync(path);
- }, // Directory is gone
- Deno.errors.NotFound,
- );
-
- // REMOVE NON-EMPTY DIRECTORY
- path = Deno.makeTempDirSync() + "/dir/subdir";
- const subPath = path + "/subsubdir";
- Deno.mkdirSync(path, { recursive: true });
- Deno.mkdirSync(subPath);
- pathInfo = Deno.statSync(path);
- assert(pathInfo.isDirectory); // check exist first
- const subPathInfo = Deno.statSync(subPath);
- assert(subPathInfo.isDirectory); // check exist first
- await Deno[method](path, { recursive: true }); // remove
- // We then check parent directory again after remove
- assertThrows(() => {
- Deno.statSync(path);
- }, Deno.errors.NotFound);
- // Directory is gone
- }
- },
-);
-
-Deno.test(
- { permissions: { write: true, read: true } },
- async function removeAllFileSuccess() {
- for (const method of REMOVE_METHODS) {
- // REMOVE FILE
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- Deno.writeFileSync(filename, data, { mode: 0o666 });
- const fileInfo = Deno.statSync(filename);
- assert(fileInfo.isFile); // check exist first
- await Deno[method](filename, { recursive: true }); // remove
- // We then check again after remove
- assertThrows(() => {
- Deno.statSync(filename);
- }, Deno.errors.NotFound);
- // File is gone
- }
- },
-);
-
-Deno.test({ permissions: { write: true } }, async function removeAllFail() {
- for (const method of REMOVE_METHODS) {
- // NON-EXISTENT DIRECTORY/FILE
- await assertRejects(
- async () => {
- // Non-existent
- await Deno[method]("/baddir", { recursive: true });
- },
- Deno.errors.NotFound,
- `remove '/baddir'`,
- );
- }
-});
-
-Deno.test({ permissions: { write: false } }, async function removeAllPerm() {
- for (const method of REMOVE_METHODS) {
- await assertRejects(async () => {
- await Deno[method]("/baddir", { recursive: true });
- }, Deno.errors.PermissionDenied);
- }
-});
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { write: true, read: true },
- },
- async function removeUnixSocketSuccess() {
- for (const method of REMOVE_METHODS) {
- // MAKE TEMPORARY UNIX SOCKET
- const path = Deno.makeTempDirSync() + "/test.sock";
- const listener = Deno.listen({ transport: "unix", path });
- listener.close();
- Deno.statSync(path); // check if unix socket exists
-
- await Deno[method](path);
- assertThrows(() => Deno.statSync(path), Deno.errors.NotFound);
- }
- },
-);
-
-if (Deno.build.os === "windows") {
- Deno.test(
- { permissions: { run: true, write: true, read: true } },
- async function removeFileSymlink() {
- const { success } = await new Deno.Command("cmd", {
- args: ["/c", "mklink", "file_link", "bar"],
- stdout: "null",
- }).output();
-
- assert(success);
- await Deno.remove("file_link");
- await assertRejects(async () => {
- await Deno.lstat("file_link");
- }, Deno.errors.NotFound);
- },
- );
-
- Deno.test(
- { permissions: { run: true, write: true, read: true } },
- async function removeDirSymlink() {
- const { success } = await new Deno.Command("cmd", {
- args: ["/c", "mklink", "/d", "dir_link", "bar"],
- stdout: "null",
- }).output();
-
- assert(success);
- await Deno.remove("dir_link");
- await assertRejects(async () => {
- await Deno.lstat("dir_link");
- }, Deno.errors.NotFound);
- },
- );
-}
diff --git a/cli/tests/unit/rename_test.ts b/cli/tests/unit/rename_test.ts
deleted file mode 100644
index 4f6bb09cf..000000000
--- a/cli/tests/unit/rename_test.ts
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- AssertionError,
- assertIsError,
- assertThrows,
- pathToAbsoluteFileUrl,
-} from "./test_util.ts";
-
-function assertMissing(path: string) {
- let caughtErr = false;
- let info;
- try {
- info = Deno.lstatSync(path);
- } catch (e) {
- caughtErr = true;
- assert(e instanceof Deno.errors.NotFound);
- }
- assert(caughtErr);
- assertEquals(info, undefined);
-}
-
-function assertFile(path: string) {
- const info = Deno.lstatSync(path);
- assert(info.isFile);
-}
-
-function assertDirectory(path: string, mode?: number) {
- const info = Deno.lstatSync(path);
- assert(info.isDirectory);
- if (Deno.build.os !== "windows" && mode !== undefined) {
- assertEquals(info.mode! & 0o777, mode & ~Deno.umask());
- }
-}
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function renameSyncSuccess() {
- const testDir = Deno.makeTempDirSync();
- const oldpath = testDir + "/oldpath";
- const newpath = testDir + "/newpath";
- Deno.mkdirSync(oldpath);
- Deno.renameSync(oldpath, newpath);
- assertDirectory(newpath);
- assertMissing(oldpath);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function renameSyncWithURL() {
- const testDir = Deno.makeTempDirSync();
- const oldpath = testDir + "/oldpath";
- const newpath = testDir + "/newpath";
- Deno.mkdirSync(oldpath);
- Deno.renameSync(
- pathToAbsoluteFileUrl(oldpath),
- pathToAbsoluteFileUrl(newpath),
- );
- assertDirectory(newpath);
- assertMissing(oldpath);
- },
-);
-
-Deno.test(
- { permissions: { read: false, write: true } },
- function renameSyncReadPerm() {
- assertThrows(() => {
- const oldpath = "/oldbaddir";
- const newpath = "/newbaddir";
- Deno.renameSync(oldpath, newpath);
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: false } },
- function renameSyncWritePerm() {
- assertThrows(() => {
- const oldpath = "/oldbaddir";
- const newpath = "/newbaddir";
- Deno.renameSync(oldpath, newpath);
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function renameSuccess() {
- const testDir = Deno.makeTempDirSync();
- const oldpath = testDir + "/oldpath";
- const newpath = testDir + "/newpath";
- Deno.mkdirSync(oldpath);
- await Deno.rename(oldpath, newpath);
- assertDirectory(newpath);
- assertMissing(oldpath);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function renameWithURL() {
- const testDir = Deno.makeTempDirSync();
- const oldpath = testDir + "/oldpath";
- const newpath = testDir + "/newpath";
- Deno.mkdirSync(oldpath);
- await Deno.rename(
- pathToAbsoluteFileUrl(oldpath),
- pathToAbsoluteFileUrl(newpath),
- );
- assertDirectory(newpath);
- assertMissing(oldpath);
- },
-);
-
-function readFileString(filename: string): string {
- const dataRead = Deno.readFileSync(filename);
- const dec = new TextDecoder("utf-8");
- return dec.decode(dataRead);
-}
-
-function writeFileString(filename: string, s: string) {
- const enc = new TextEncoder();
- const data = enc.encode(s);
- Deno.writeFileSync(filename, data, { mode: 0o666 });
-}
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- function renameSyncErrorsUnix() {
- const testDir = Deno.makeTempDirSync();
- const oldfile = testDir + "/oldfile";
- const olddir = testDir + "/olddir";
- const emptydir = testDir + "/empty";
- const fulldir = testDir + "/dir";
- const file = fulldir + "/file";
- writeFileString(oldfile, "Hello");
- Deno.mkdirSync(olddir);
- Deno.mkdirSync(emptydir);
- Deno.mkdirSync(fulldir);
- writeFileString(file, "world");
-
- assertThrows(
- () => {
- Deno.renameSync(oldfile, emptydir);
- },
- Error,
- "Is a directory",
- );
- try {
- assertThrows(
- () => {
- Deno.renameSync(olddir, fulldir);
- },
- Error,
- "Directory not empty",
- );
- } catch (e) {
- // rename syscall may also return EEXIST, e.g. with XFS
- assertIsError(
- e,
- AssertionError,
- `Expected error message to include "Directory not empty", but got "File exists`,
- );
- }
- assertThrows(
- () => {
- Deno.renameSync(olddir, file);
- },
- Error,
- "Not a directory",
- );
- assertThrows(
- () => {
- Deno.renameSync(olddir, file);
- },
- Error,
- `rename '${olddir}' -> '${file}'`,
- );
-
- const fileLink = testDir + "/fileLink";
- const dirLink = testDir + "/dirLink";
- const danglingLink = testDir + "/danglingLink";
- Deno.symlinkSync(file, fileLink);
- Deno.symlinkSync(emptydir, dirLink);
- Deno.symlinkSync(testDir + "/nonexistent", danglingLink);
-
- assertThrows(
- () => {
- Deno.renameSync(olddir, fileLink);
- },
- Error,
- "Not a directory",
- );
- assertThrows(
- () => {
- Deno.renameSync(olddir, dirLink);
- },
- Error,
- "Not a directory",
- );
- assertThrows(
- () => {
- Deno.renameSync(olddir, danglingLink);
- },
- Error,
- "Not a directory",
- );
-
- // should succeed on Unix
- Deno.renameSync(olddir, emptydir);
- Deno.renameSync(oldfile, dirLink);
- Deno.renameSync(dirLink, danglingLink);
- assertFile(danglingLink);
- assertEquals("Hello", readFileString(danglingLink));
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os !== "windows",
- permissions: { read: true, write: true },
- },
- function renameSyncErrorsWin() {
- const testDir = Deno.makeTempDirSync();
- const oldfile = testDir + "/oldfile";
- const olddir = testDir + "/olddir";
- const emptydir = testDir + "/empty";
- const fulldir = testDir + "/dir";
- const file = fulldir + "/file";
- writeFileString(oldfile, "Hello");
- Deno.mkdirSync(olddir);
- Deno.mkdirSync(emptydir);
- Deno.mkdirSync(fulldir);
- writeFileString(file, "world");
-
- assertThrows(
- () => {
- Deno.renameSync(oldfile, emptydir);
- },
- Deno.errors.PermissionDenied,
- "Access is denied",
- );
- assertThrows(
- () => {
- Deno.renameSync(olddir, fulldir);
- },
- Deno.errors.PermissionDenied,
- "Access is denied",
- );
- assertThrows(
- () => {
- Deno.renameSync(olddir, emptydir);
- },
- Deno.errors.PermissionDenied,
- "Access is denied",
- );
- assertThrows(
- () => {
- Deno.renameSync(olddir, emptydir);
- },
- Error,
- `rename '${olddir}' -> '${emptydir}'`,
- );
-
- // should succeed on Windows
- Deno.renameSync(olddir, file);
- assertDirectory(file);
- },
-);
diff --git a/cli/tests/unit/request_test.ts b/cli/tests/unit/request_test.ts
deleted file mode 100644
index fe34c20a5..000000000
--- a/cli/tests/unit/request_test.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertStringIncludes } from "./test_util.ts";
-
-Deno.test(async function fromInit() {
- const req = new Request("http://foo/", {
- body: "ahoyhoy",
- method: "POST",
- headers: {
- "test-header": "value",
- },
- });
-
- assertEquals("ahoyhoy", await req.text());
- assertEquals(req.url, "http://foo/");
- assertEquals(req.headers.get("test-header"), "value");
-});
-
-Deno.test(function requestNonString() {
- const nonString = {
- toString() {
- return "http://foo/";
- },
- };
- // deno-lint-ignore ban-ts-comment
- // @ts-expect-error
- assertEquals(new Request(nonString).url, "http://foo/");
-});
-
-Deno.test(function methodNonString() {
- assertEquals(new Request("http://foo/", { method: undefined }).method, "GET");
-});
-
-Deno.test(function requestRelativeUrl() {
- assertEquals(
- new Request("relative-url").url,
- "http://127.0.0.1:4545/relative-url",
- );
-});
-
-Deno.test(async function cloneRequestBodyStream() {
- // hack to get a stream
- const stream =
- new Request("http://foo/", { body: "a test body", method: "POST" }).body;
- const r1 = new Request("http://foo/", {
- body: stream,
- method: "POST",
- });
-
- const r2 = r1.clone();
-
- const b1 = await r1.text();
- const b2 = await r2.text();
-
- assertEquals(b1, b2);
-});
-
-Deno.test(function customInspectFunction() {
- const request = new Request("https://example.com");
- assertEquals(
- Deno.inspect(request),
- `Request {
- bodyUsed: false,
- headers: Headers {},
- method: "GET",
- redirect: "follow",
- url: "https://example.com/"
-}`,
- );
- assertStringIncludes(Deno.inspect(Request.prototype), "Request");
-});
-
-Deno.test(function requestConstructorTakeURLObjectAsParameter() {
- assertEquals(
- new Request(new URL("http://foo/")).url,
- "http://foo/",
- );
-});
diff --git a/cli/tests/unit/resources_test.ts b/cli/tests/unit/resources_test.ts
deleted file mode 100644
index 06558cdd1..000000000
--- a/cli/tests/unit/resources_test.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals, assertThrows } from "./test_util.ts";
-
-const listenPort = 4505;
-
-Deno.test(function resourcesCloseBadArgs() {
- assertThrows(() => {
- Deno.close((null as unknown) as number);
- }, TypeError);
-});
-
-Deno.test(function resourcesStdio() {
- const res = Deno.resources();
-
- assertEquals(res[0], "stdin");
- assertEquals(res[1], "stdout");
- assertEquals(res[2], "stderr");
-});
-
-Deno.test({ permissions: { net: true } }, async function resourcesNet() {
- const listener = Deno.listen({ port: listenPort });
- const dialerConn = await Deno.connect({ port: listenPort });
- const listenerConn = await listener.accept();
-
- const res = Deno.resources();
- assertEquals(
- Object.values(res).filter((r): boolean => r === "tcpListener").length,
- 1,
- );
- const tcpStreams = Object.values(res).filter(
- (r): boolean => r === "tcpStream",
- );
- assert(tcpStreams.length >= 2);
-
- listenerConn.close();
- dialerConn.close();
- listener.close();
-});
-
-Deno.test({ permissions: { read: true } }, async function resourcesFile() {
- const resourcesBefore = Deno.resources();
- const f = await Deno.open("cli/tests/testdata/assets/hello.txt");
- const resourcesAfter = Deno.resources();
- f.close();
-
- // check that exactly one new resource (file) was added
- assertEquals(
- Object.keys(resourcesAfter).length,
- Object.keys(resourcesBefore).length + 1,
- );
- const newRid = +Object.keys(resourcesAfter).find((rid): boolean => {
- return !Object.prototype.hasOwnProperty.call(resourcesBefore, rid);
- })!;
- assertEquals(resourcesAfter[newRid], "fsFile");
-});
diff --git a/cli/tests/unit/response_test.ts b/cli/tests/unit/response_test.ts
deleted file mode 100644
index bbdd5f481..000000000
--- a/cli/tests/unit/response_test.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertStringIncludes,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(async function responseText() {
- const response = new Response("hello world");
- const textPromise = response.text();
- assert(textPromise instanceof Promise);
- const text = await textPromise;
- assert(typeof text === "string");
- assertEquals(text, "hello world");
-});
-
-Deno.test(async function responseArrayBuffer() {
- const response = new Response(new Uint8Array([1, 2, 3]));
- const arrayBufferPromise = response.arrayBuffer();
- assert(arrayBufferPromise instanceof Promise);
- const arrayBuffer = await arrayBufferPromise;
- assert(arrayBuffer instanceof ArrayBuffer);
- assertEquals(new Uint8Array(arrayBuffer), new Uint8Array([1, 2, 3]));
-});
-
-Deno.test(async function responseJson() {
- const response = new Response('{"hello": "world"}');
- const jsonPromise = response.json();
- assert(jsonPromise instanceof Promise);
- const json = await jsonPromise;
- assert(json instanceof Object);
- assertEquals(json, { hello: "world" });
-});
-
-Deno.test(async function responseBlob() {
- const response = new Response(new Uint8Array([1, 2, 3]));
- const blobPromise = response.blob();
- assert(blobPromise instanceof Promise);
- const blob = await blobPromise;
- assert(blob instanceof Blob);
- assertEquals(blob.size, 3);
- assertEquals(await blob.arrayBuffer(), new Uint8Array([1, 2, 3]).buffer);
-});
-
-Deno.test(async function responseFormData() {
- const input = new FormData();
- input.append("hello", "world");
- const response = new Response(input);
- const contentType = response.headers.get("content-type")!;
- assert(contentType.startsWith("multipart/form-data"));
- const formDataPromise = response.formData();
- assert(formDataPromise instanceof Promise);
- const formData = await formDataPromise;
- assert(formData instanceof FormData);
- assertEquals([...formData], [...input]);
-});
-
-Deno.test(function responseInvalidInit() {
- // deno-lint-ignore ban-ts-comment
- // @ts-expect-error
- assertThrows(() => new Response("", 0));
- assertThrows(() => new Response("", { status: 0 }));
- // deno-lint-ignore ban-ts-comment
- // @ts-expect-error
- assertThrows(() => new Response("", { status: null }));
-});
-
-Deno.test(function responseNullInit() {
- // deno-lint-ignore ban-ts-comment
- // @ts-expect-error
- const response = new Response("", null);
- assertEquals(response.status, 200);
-});
-
-Deno.test(function customInspectFunction() {
- const response = new Response();
- assertEquals(
- Deno.inspect(response),
- `Response {
- body: null,
- bodyUsed: false,
- headers: Headers {},
- ok: true,
- redirected: false,
- status: 200,
- statusText: "",
- url: ""
-}`,
- );
- assertStringIncludes(Deno.inspect(Response.prototype), "Response");
-});
-
-Deno.test(async function responseBodyUsed() {
- const response = new Response("body");
- assert(!response.bodyUsed);
- await response.text();
- assert(response.bodyUsed);
- // .body getter is needed so we can test the faulty code path
- response.body;
- assert(response.bodyUsed);
-});
diff --git a/cli/tests/unit/serve_test.ts b/cli/tests/unit/serve_test.ts
deleted file mode 100644
index b5c966d6f..000000000
--- a/cli/tests/unit/serve_test.ts
+++ /dev/null
@@ -1,3932 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assertMatch, assertRejects } from "@test_util/std/assert/mod.ts";
-import { Buffer, BufReader, BufWriter } from "@test_util/std/io/mod.ts";
-import { TextProtoReader } from "../testdata/run/textproto.ts";
-import {
- assert,
- assertEquals,
- assertStringIncludes,
- assertThrows,
- execCode,
- fail,
- tmpUnixSocketPath,
-} from "./test_util.ts";
-
-// Since these tests may run in parallel, ensure this port is unique to this file
-const servePort = 4502;
-
-const {
- upgradeHttpRaw,
- addTrailers,
- serveHttpOnListener,
- serveHttpOnConnection,
- // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
-} = Deno[Deno.internal];
-
-function createOnErrorCb(ac: AbortController): (err: unknown) => Response {
- return (err) => {
- console.error(err);
- ac.abort();
- return new Response("Internal server error", { status: 500 });
- };
-}
-
-function onListen(
- resolve: (value: void | PromiseLike<void>) => void,
-): ({ hostname, port }: { hostname: string; port: number }) => void {
- return () => {
- resolve();
- };
-}
-
-async function makeServer(
- handler: (req: Request) => Response | Promise<Response>,
-): Promise<
- {
- finished: Promise<void>;
- abort: () => void;
- shutdown: () => Promise<void>;
- [Symbol.asyncDispose](): PromiseLike<void>;
- }
-> {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler,
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- });
-
- await promise;
- return {
- finished: server.finished,
- abort() {
- ac.abort();
- },
- async shutdown() {
- await server.shutdown();
- },
- [Symbol.asyncDispose]() {
- return server[Symbol.asyncDispose]();
- },
- };
-}
-
-Deno.test(async function httpServerShutsDownPortBeforeResolving() {
- const { finished, abort } = await makeServer((_req) => new Response("ok"));
- assertThrows(() => Deno.listen({ port: servePort }));
- abort();
- await finished;
-
- const listener = Deno.listen({ port: servePort });
- listener!.close();
-});
-
-// When shutting down abruptly, we require that all in-progress connections are aborted,
-// no new connections are allowed, and no new transactions are allowed on existing connections.
-Deno.test(
- { permissions: { net: true } },
- async function httpServerShutdownAbruptGuaranteeHttp11() {
- const deferredQueue: {
- input: ReturnType<typeof Promise.withResolvers<string>>;
- out: ReturnType<typeof Promise.withResolvers<void>>;
- }[] = [];
- const { finished, abort } = await makeServer((_req) => {
- const { input, out } = deferredQueue.shift()!;
- return new Response(
- new ReadableStream({
- async start(controller) {
- controller.enqueue(new Uint8Array([46]));
- out.resolve();
- controller.enqueue(encoder.encode(await input.promise));
- controller.close();
- },
- }),
- );
- });
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
- const conn = await Deno.connect({ port: servePort });
- const w = conn.writable.getWriter();
- const r = conn.readable.getReader();
-
- const deferred1 = {
- input: Promise.withResolvers<string>(),
- out: Promise.withResolvers<void>(),
- };
- deferredQueue.push(deferred1);
- const deferred2 = {
- input: Promise.withResolvers<string>(),
- out: Promise.withResolvers<void>(),
- };
- deferredQueue.push(deferred2);
- const deferred3 = {
- input: Promise.withResolvers<string>(),
- out: Promise.withResolvers<void>(),
- };
- deferredQueue.push(deferred3);
- deferred1.input.resolve("#");
- deferred2.input.resolve("$");
- await w.write(encoder.encode(`GET / HTTP/1.1\nConnection: keep-alive\n\n`));
- await w.write(encoder.encode(`GET / HTTP/1.1\nConnection: keep-alive\n\n`));
-
- // Fully read two responses
- let text = "";
- while (!text.includes("$\r\n")) {
- text += decoder.decode((await r.read()).value);
- }
-
- await w.write(encoder.encode(`GET / HTTP/1.1\nConnection: keep-alive\n\n`));
- await deferred3.out.promise;
-
- // This is half served, so wait for the chunk that has the first '.'
- text = "";
- while (!text.includes("1\r\n.\r\n")) {
- text += decoder.decode((await r.read()).value);
- }
-
- abort();
-
- // This doesn't actually write anything, but we release it after aborting
- deferred3.input.resolve("!");
-
- // Guarantee: can't connect to an aborted server (though this may not happen immediately)
- let failed = false;
- for (let i = 0; i < 10; i++) {
- try {
- const conn = await Deno.connect({ port: servePort });
- conn.close();
- // Give the runtime a few ticks to settle (required for Windows)
- await new Promise((r) => setTimeout(r, 2 ** i));
- continue;
- } catch (_) {
- failed = true;
- break;
- }
- }
- assert(failed, "The Deno.serve listener was not disabled promptly");
-
- // Guarantee: the pipeline is closed abruptly
- assert((await r.read()).done);
-
- try {
- conn.close();
- } catch (_) {
- // Ignore
- }
- await finished;
- },
-);
-
-// When shutting down abruptly, we require that all in-progress connections are aborted,
-// no new connections are allowed, and no new transactions are allowed on existing connections.
-Deno.test(
- { permissions: { net: true } },
- async function httpServerShutdownGracefulGuaranteeHttp11() {
- const deferredQueue: {
- input: ReturnType<typeof Promise.withResolvers<string>>;
- out: ReturnType<typeof Promise.withResolvers<void>>;
- }[] = [];
- const { finished, shutdown } = await makeServer((_req) => {
- const { input, out } = deferredQueue.shift()!;
- return new Response(
- new ReadableStream({
- async start(controller) {
- controller.enqueue(new Uint8Array([46]));
- out.resolve();
- controller.enqueue(encoder.encode(await input.promise));
- controller.close();
- },
- }),
- );
- });
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
- const conn = await Deno.connect({ port: servePort });
- const w = conn.writable.getWriter();
- const r = conn.readable.getReader();
-
- const deferred1 = {
- input: Promise.withResolvers<string>(),
- out: Promise.withResolvers<void>(),
- };
- deferredQueue.push(deferred1);
- const deferred2 = {
- input: Promise.withResolvers<string>(),
- out: Promise.withResolvers<void>(),
- };
- deferredQueue.push(deferred2);
- const deferred3 = {
- input: Promise.withResolvers<string>(),
- out: Promise.withResolvers<void>(),
- };
- deferredQueue.push(deferred3);
- deferred1.input.resolve("#");
- deferred2.input.resolve("$");
- await w.write(encoder.encode(`GET / HTTP/1.1\nConnection: keep-alive\n\n`));
- await w.write(encoder.encode(`GET / HTTP/1.1\nConnection: keep-alive\n\n`));
-
- // Fully read two responses
- let text = "";
- while (!text.includes("$\r\n")) {
- text += decoder.decode((await r.read()).value);
- }
-
- await w.write(encoder.encode(`GET / HTTP/1.1\nConnection: keep-alive\n\n`));
- await deferred3.out.promise;
-
- // This is half served, so wait for the chunk that has the first '.'
- text = "";
- while (!text.includes("1\r\n.\r\n")) {
- text += decoder.decode((await r.read()).value);
- }
-
- const shutdownPromise = shutdown();
-
- // Release the final response _after_ we shut down
- deferred3.input.resolve("!");
-
- // Guarantee: can't connect to an aborted server (though this may not happen immediately)
- let failed = false;
- for (let i = 0; i < 10; i++) {
- try {
- const conn = await Deno.connect({ port: servePort });
- conn.close();
- // Give the runtime a few ticks to settle (required for Windows)
- await new Promise((r) => setTimeout(r, 2 ** i));
- continue;
- } catch (_) {
- failed = true;
- break;
- }
- }
- assert(failed, "The Deno.serve listener was not disabled promptly");
-
- // Guarantee: existing connections fully drain
- while (!text.includes("!\r\n")) {
- text += decoder.decode((await r.read()).value);
- }
-
- await shutdownPromise;
-
- try {
- conn.close();
- } catch (_) {
- // Ignore
- }
- await finished;
- },
-);
-
-// Ensure that resources don't leak during a graceful shutdown
-Deno.test(
- { permissions: { net: true, write: true, read: true } },
- async function httpServerShutdownGracefulResources() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const { finished, shutdown } = await makeServer(async (_req) => {
- resolve();
- await new Promise((r) => setTimeout(r, 10));
- return new Response((await makeTempFile(1024 * 1024)).readable);
- });
-
- const f = fetch(`http://localhost:${servePort}`);
- await promise;
- assertEquals((await (await f).text()).length, 1048576);
- await shutdown();
- await finished;
- },
-);
-
-// Ensure that resources don't leak during a graceful shutdown
-Deno.test(
- { permissions: { net: true, write: true, read: true } },
- async function httpServerShutdownGracefulResources2() {
- const waitForAbort = Promise.withResolvers<void>();
- const waitForRequest = Promise.withResolvers<void>();
- const { finished, shutdown } = await makeServer(async (_req) => {
- waitForRequest.resolve();
- await waitForAbort.promise;
- await new Promise((r) => setTimeout(r, 10));
- return new Response((await makeTempFile(1024 * 1024)).readable);
- });
-
- const f = fetch(`http://localhost:${servePort}`);
- await waitForRequest.promise;
- const s = shutdown();
- waitForAbort.resolve();
- assertEquals((await (await f).text()).length, 1048576);
- await s;
- await finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true, write: true, read: true } },
- async function httpServerExplicitResourceManagement() {
- let dataPromise;
-
- {
- await using _server = await makeServer(async (_req) => {
- return new Response((await makeTempFile(1024 * 1024)).readable);
- });
-
- const resp = await fetch(`http://localhost:${servePort}`);
- dataPromise = resp.arrayBuffer();
- }
-
- assertEquals((await dataPromise).byteLength, 1048576);
- },
-);
-
-Deno.test(
- { permissions: { net: true, write: true, read: true } },
- async function httpServerExplicitResourceManagementManualClose() {
- await using server = await makeServer(async (_req) => {
- return new Response((await makeTempFile(1024 * 1024)).readable);
- });
-
- const resp = await fetch(`http://localhost:${servePort}`);
-
- const [_, data] = await Promise.all([
- server.shutdown(),
- resp.arrayBuffer(),
- ]);
-
- assertEquals(data.byteLength, 1048576);
- },
-);
-
-Deno.test(
- { permissions: { read: true, run: true } },
- async function httpServerUnref() {
- const [statusCode, _output] = await execCode(`
- async function main() {
- const server = Deno.serve({ port: ${servePort}, handler: () => null });
- server.unref();
- await server.finished; // This doesn't block the program from exiting
- }
- main();
- `);
- assertEquals(statusCode, 0);
- },
-);
-
-Deno.test(async function httpServerCanResolveHostnames() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: (_req) => new Response("ok"),
- hostname: "localhost",
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- await promise;
- const resp = await fetch(`http://localhost:${servePort}/`, {
- headers: { "connection": "close" },
- });
- const text = await resp.text();
- assertEquals(text, "ok");
- ac.abort();
- await server.finished;
-});
-
-Deno.test(async function httpServerRejectsOnAddrInUse() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: (_req) => new Response("ok"),
- hostname: "localhost",
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
- await promise;
-
- assertThrows(
- () =>
- Deno.serve({
- handler: (_req) => new Response("ok"),
- hostname: "localhost",
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- }),
- Deno.errors.AddrInUse,
- );
- ac.abort();
- await server.finished;
-});
-
-Deno.test({ permissions: { net: true } }, async function httpServerBasic() {
- const ac = new AbortController();
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: async (request, { remoteAddr }) => {
- // FIXME(bartlomieju):
- // make sure that request can be inspected
- console.log(request);
- assertEquals(new URL(request.url).href, `http://127.0.0.1:${servePort}/`);
- assertEquals(await request.text(), "");
- assertEquals(remoteAddr.hostname, "127.0.0.1");
- deferred.resolve();
- return new Response("Hello World", { headers: { "foo": "bar" } });
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- headers: { "connection": "close" },
- });
- await deferred.promise;
- const clone = resp.clone();
- const text = await resp.text();
- assertEquals(text, "Hello World");
- assertEquals(resp.headers.get("foo"), "bar");
- const cloneText = await clone.text();
- assertEquals(cloneText, "Hello World");
- ac.abort();
- await server.finished;
-});
-
-// Test serving of HTTP on an arbitrary listener.
-Deno.test(
- { permissions: { net: true } },
- async function httpServerOnListener() {
- const ac = new AbortController();
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const listener = Deno.listen({ port: servePort });
- const server = serveHttpOnListener(
- listener,
- ac.signal,
- async (
- request: Request,
- { remoteAddr }: { remoteAddr: { hostname: string } },
- ) => {
- assertEquals(
- new URL(request.url).href,
- `http://127.0.0.1:${servePort}/`,
- );
- assertEquals(await request.text(), "");
- assertEquals(remoteAddr.hostname, "127.0.0.1");
- deferred.resolve();
- return new Response("Hello World", { headers: { "foo": "bar" } });
- },
- createOnErrorCb(ac),
- onListen(listeningDeferred.resolve),
- );
-
- await listeningDeferred.promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- headers: { "connection": "close" },
- });
- await listeningDeferred.promise;
- const clone = resp.clone();
- const text = await resp.text();
- assertEquals(text, "Hello World");
- assertEquals(resp.headers.get("foo"), "bar");
- const cloneText = await clone.text();
- assertEquals(cloneText, "Hello World");
- ac.abort();
- await server.finished;
- },
-);
-
-// Test serving of HTTP on an arbitrary connection.
-Deno.test(
- { permissions: { net: true } },
- async function httpServerOnConnection() {
- const ac = new AbortController();
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const listener = Deno.listen({ port: servePort });
- const acceptPromise = listener.accept();
- const fetchPromise = fetch(`http://127.0.0.1:${servePort}/`, {
- headers: { "connection": "close" },
- });
-
- const server = serveHttpOnConnection(
- await acceptPromise,
- ac.signal,
- async (
- request: Request,
- { remoteAddr }: { remoteAddr: { hostname: string } },
- ) => {
- assertEquals(
- new URL(request.url).href,
- `http://127.0.0.1:${servePort}/`,
- );
- assertEquals(await request.text(), "");
- assertEquals(remoteAddr.hostname, "127.0.0.1");
- deferred.resolve();
- return new Response("Hello World", { headers: { "foo": "bar" } });
- },
- createOnErrorCb(ac),
- onListen(listeningDeferred.resolve),
- );
-
- const resp = await fetchPromise;
- await deferred.promise;
- const clone = resp.clone();
- const text = await resp.text();
- assertEquals(text, "Hello World");
- assertEquals(resp.headers.get("foo"), "bar");
- const cloneText = await clone.text();
- assertEquals(cloneText, "Hello World");
- // Note that we don't need to abort this server -- it closes when the connection does
- // ac.abort();
- await server.finished;
- listener.close();
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function httpServerOnError() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- let requestStash: Request | null;
-
- const server = Deno.serve({
- handler: async (request: Request) => {
- requestStash = request;
- await new Promise((r) => setTimeout(r, 100));
- throw "fail";
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: () => {
- return new Response("failed: " + requestStash!.url, { status: 500 });
- },
- });
-
- await promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- headers: { "connection": "close" },
- });
- const text = await resp.text();
- ac.abort();
- await server.finished;
-
- assertEquals(text, `failed: http://127.0.0.1:${servePort}/`);
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerOnErrorFails() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- // NOTE(bartlomieju): deno lint doesn't know that it's actually used later,
- // but TypeScript can't see that either ¯\_(ツ)_/¯
- // deno-lint-ignore no-unused-vars
- let requestStash: Request | null;
-
- const server = Deno.serve({
- handler: async (request: Request) => {
- requestStash = request;
- await new Promise((r) => setTimeout(r, 100));
- throw "fail";
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: () => {
- throw "again";
- },
- });
-
- await promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- headers: { "connection": "close" },
- });
- const text = await resp.text();
- ac.abort();
- await server.finished;
-
- assertEquals(text, "Internal Server Error");
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function httpServerOverload1() {
- const ac = new AbortController();
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- }, async (request) => {
- // FIXME(bartlomieju):
- // make sure that request can be inspected
- console.log(request);
- assertEquals(new URL(request.url).href, `http://127.0.0.1:${servePort}/`);
- assertEquals(await request.text(), "");
- deferred.resolve();
- return new Response("Hello World", { headers: { "foo": "bar" } });
- });
-
- await listeningDeferred.promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- headers: { "connection": "close" },
- });
- await deferred.promise;
- const clone = resp.clone();
- const text = await resp.text();
- assertEquals(text, "Hello World");
- assertEquals(resp.headers.get("foo"), "bar");
- const cloneText = await clone.text();
- assertEquals(cloneText, "Hello World");
- ac.abort();
- await server.finished;
-});
-
-Deno.test({ permissions: { net: true } }, async function httpServerOverload2() {
- const ac = new AbortController();
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- }, async (request) => {
- // FIXME(bartlomieju):
- // make sure that request can be inspected
- console.log(request);
- assertEquals(new URL(request.url).href, `http://127.0.0.1:${servePort}/`);
- assertEquals(await request.text(), "");
- deferred.resolve();
- return new Response("Hello World", { headers: { "foo": "bar" } });
- });
-
- await listeningDeferred.promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- headers: { "connection": "close" },
- });
- await deferred.promise;
- const clone = resp.clone();
- const text = await resp.text();
- assertEquals(text, "Hello World");
- assertEquals(resp.headers.get("foo"), "bar");
- const cloneText = await clone.text();
- assertEquals(cloneText, "Hello World");
- ac.abort();
- await server.finished;
-});
-
-Deno.test(
- { permissions: { net: true } },
- function httpServerErrorOverloadMissingHandler() {
- // @ts-ignore - testing invalid overload
- assertThrows(() => Deno.serve(), TypeError, "handler");
- // @ts-ignore - testing invalid overload
- assertThrows(() => Deno.serve({}), TypeError, "handler");
- assertThrows(
- // @ts-ignore - testing invalid overload
- () => Deno.serve({ handler: undefined }),
- TypeError,
- "handler",
- );
- assertThrows(
- // @ts-ignore - testing invalid overload
- () => Deno.serve(undefined, { handler: () => {} }),
- TypeError,
- "handler",
- );
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function httpServerPort0() {
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler() {
- return new Response("Hello World");
- },
- port: 0,
- signal: ac.signal,
- onListen({ port }) {
- assert(port > 0 && port < 65536);
- ac.abort();
- },
- });
- await server.finished;
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerDefaultOnListenCallback() {
- const ac = new AbortController();
-
- const consoleLog = console.log;
- console.log = (msg) => {
- try {
- const match = msg.match(/Listening on http:\/\/localhost:(\d+)\//);
- assert(!!match, `Didn't match ${msg}`);
- const port = +match[1];
- assert(port > 0 && port < 65536);
- } finally {
- ac.abort();
- }
- };
-
- try {
- const server = Deno.serve({
- handler() {
- return new Response("Hello World");
- },
- hostname: "0.0.0.0",
- port: 0,
- signal: ac.signal,
- });
-
- await server.finished;
- } finally {
- console.log = consoleLog;
- }
- },
-);
-
-// https://github.com/denoland/deno/issues/15107
-Deno.test(
- { permissions: { net: true } },
- async function httpLazyHeadersIssue15107() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- let headers: Headers;
- const server = Deno.serve({
- handler: async (request) => {
- await request.text();
- headers = request.headers;
- deferred.resolve();
- return new Response("");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- // Send GET request with a body + content-length.
- const encoder = new TextEncoder();
- const body =
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:2333\r\nContent-Length: 5\r\n\r\n12345`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
- conn.close();
- assertEquals(headers!.get("content-length"), "5");
- ac.abort();
- await server.finished;
- },
-);
-
-function createUrlTest(
- name: string,
- methodAndPath: string,
- host: string | null,
- expected: string,
-) {
- Deno.test(`httpServerUrl${name}`, async () => {
- const listeningDeferred = Promise.withResolvers<number>();
- const urlDeferred = Promise.withResolvers<string>();
- const ac = new AbortController();
- const server = Deno.serve({
- handler: (request: Request) => {
- urlDeferred.resolve(request.url);
- return new Response("");
- },
- port: 0,
- signal: ac.signal,
- onListen: ({ port }: { port: number }) => {
- listeningDeferred.resolve(port);
- },
- onError: createOnErrorCb(ac),
- });
-
- const port = await listeningDeferred.promise;
- const conn = await Deno.connect({ port });
-
- const encoder = new TextEncoder();
- const body = `${methodAndPath} HTTP/1.1\r\n${
- host ? ("Host: " + host + "\r\n") : ""
- }Content-Length: 5\r\n\r\n12345`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- try {
- const expectedResult = expected.replace("HOST", "localhost").replace(
- "PORT",
- `${port}`,
- );
- assertEquals(await urlDeferred.promise, expectedResult);
- } finally {
- ac.abort();
- await server.finished;
- conn.close();
- }
- });
-}
-
-createUrlTest("WithPath", "GET /path", null, "http://HOST:PORT/path");
-createUrlTest(
- "WithPathAndHost",
- "GET /path",
- "deno.land",
- "http://deno.land/path",
-);
-createUrlTest(
- "WithAbsolutePath",
- "GET http://localhost/path",
- null,
- "http://localhost/path",
-);
-createUrlTest(
- "WithAbsolutePathAndHost",
- "GET http://localhost/path",
- "deno.land",
- "http://localhost/path",
-);
-createUrlTest(
- "WithPortAbsolutePath",
- "GET http://localhost:1234/path",
- null,
- "http://localhost:1234/path",
-);
-createUrlTest(
- "WithPortAbsolutePathAndHost",
- "GET http://localhost:1234/path",
- "deno.land",
- "http://localhost:1234/path",
-);
-createUrlTest(
- "WithPortAbsolutePathAndHostWithPort",
- "GET http://localhost:1234/path",
- "deno.land:9999",
- "http://localhost:1234/path",
-);
-
-createUrlTest("WithAsterisk", "OPTIONS *", null, "*");
-createUrlTest(
- "WithAuthorityForm",
- "CONNECT deno.land:80",
- null,
- "deno.land:80",
-);
-
-// TODO(mmastrac): These should probably be 400 errors
-createUrlTest("WithInvalidAsterisk", "GET *", null, "*");
-createUrlTest("WithInvalidNakedPath", "GET path", null, "path");
-createUrlTest(
- "WithInvalidNakedAuthority",
- "GET deno.land:1234",
- null,
- "deno.land:1234",
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerGetRequestBody() {
- const deferred = Promise.withResolvers<void>();
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: (request) => {
- assertEquals(request.body, null);
- deferred.resolve();
- return new Response("", { headers: {} });
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- // Send GET request with a body + content-length.
- const encoder = new TextEncoder();
- const body =
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:${servePort}\r\nContent-Length: 5\r\n\r\n12345`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- const resp = new Uint8Array(200);
- const readResult = await conn.read(resp);
- assert(readResult);
- assert(readResult > 0);
-
- conn.close();
- await deferred.promise;
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerAbortedRequestBody() {
- const deferred = Promise.withResolvers<void>();
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: async (request) => {
- await assertRejects(async () => {
- await request.text();
- });
- deferred.resolve();
- // Not actually used
- return new Response();
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- // Send POST request with a body + content-length, but don't send it all
- const encoder = new TextEncoder();
- const body =
- `POST / HTTP/1.1\r\nHost: 127.0.0.1:${servePort}\r\nContent-Length: 10\r\n\r\n12345`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- conn.close();
- await deferred.promise;
- ac.abort();
- await server.finished;
- },
-);
-
-function createStreamTest(count: number, delay: number, action: string) {
- function doAction(controller: ReadableStreamDefaultController, i: number) {
- if (i == count) {
- if (action == "Throw") {
- controller.error(new Error("Expected error!"));
- } else {
- controller.close();
- }
- } else {
- controller.enqueue(`a${i}`);
-
- if (delay == 0) {
- doAction(controller, i + 1);
- } else {
- setTimeout(() => doAction(controller, i + 1), delay);
- }
- }
- }
-
- function makeStream(_count: number, delay: number): ReadableStream {
- return new ReadableStream({
- start(controller) {
- if (delay == 0) {
- doAction(controller, 0);
- } else {
- setTimeout(() => doAction(controller, 0), delay);
- }
- },
- }).pipeThrough(new TextEncoderStream());
- }
-
- Deno.test(`httpServerStreamCount${count}Delay${delay}${action}`, async () => {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: (_request) => {
- return new Response(makeStream(count, delay));
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- try {
- await promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`);
- if (action == "Throw") {
- await assertRejects(async () => {
- await resp.text();
- });
- } else {
- const text = await resp.text();
-
- let expected = "";
- for (let i = 0; i < count; i++) {
- expected += `a${i}`;
- }
-
- assertEquals(text, expected);
- }
- } finally {
- ac.abort();
- await server.shutdown();
- }
- });
-}
-
-for (const count of [0, 1, 2, 3]) {
- for (const delay of [0, 1, 25]) {
- // Creating a stream that errors in start will throw
- if (delay > 0) {
- createStreamTest(count, delay, "Throw");
- }
- createStreamTest(count, delay, "Close");
- }
-}
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerStreamRequest() {
- const stream = new TransformStream();
- const writer = stream.writable.getWriter();
- writer.write(new TextEncoder().encode("hello "));
- writer.write(new TextEncoder().encode("world"));
- writer.close();
- const { promise, resolve } = Promise.withResolvers<void>();
- const ac = new AbortController();
- const server = Deno.serve({
- handler: async (request) => {
- const reqBody = await request.text();
- assertEquals("hello world", reqBody);
- return new Response("yo");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- await promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- body: stream.readable,
- method: "POST",
- headers: { "connection": "close" },
- });
-
- assertEquals(await resp.text(), "yo");
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function httpServerClose() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: () => new Response("ok"),
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
- await promise;
- const client = await Deno.connect({ port: servePort });
- client.close();
- ac.abort();
- await server.finished;
-});
-
-// https://github.com/denoland/deno/issues/15427
-Deno.test({ permissions: { net: true } }, async function httpServerCloseGet() {
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
- const requestDeferred = Promise.withResolvers<void>();
- const responseDeferred = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: async () => {
- requestDeferred.resolve();
- await new Promise((r) => setTimeout(r, 500));
- responseDeferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const body =
- `GET / HTTP/1.1\r\nHost: example.domain\r\nConnection: close\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await requestDeferred.promise;
- conn.close();
- await responseDeferred.promise;
- ac.abort();
- await server.finished;
-});
-
-// FIXME:
-Deno.test(
- { permissions: { net: true } },
- async function httpServerEmptyBlobResponse() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: () => new Response(new Blob([])),
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- await promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`);
- const respBody = await resp.text();
-
- assertEquals("", respBody);
- ac.abort();
- await server.finished;
- },
-);
-
-// https://github.com/denoland/deno/issues/17291
-Deno.test(
- { permissions: { net: true } },
- async function httpServerIncorrectChunkedResponse() {
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
- const errorDeferred = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: () => {
- const body = new ReadableStream({
- start(controller) {
- // Non-encoded string is not a valid readable chunk.
- // @ts-ignore we're testing that input is invalid
- controller.enqueue("wat");
- },
- type: "bytes",
- });
- return new Response(body);
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: (err) => {
- const errResp = new Response(
- `Internal server error: ${(err as Error).message}`,
- { status: 500 },
- );
- errorDeferred.resolve();
- return errResp;
- },
- });
-
- await listeningDeferred.promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`);
- // Incorrectly implemented reader ReadableStream should reject.
- assertStringIncludes(await resp.text(), "Failed to execute 'enqueue'");
- await errorDeferred.promise;
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerCorrectLengthForUnicodeString() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: () => new Response("韓國".repeat(10)),
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- await promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- const body =
- `GET / HTTP/1.1\r\nHost: example.domain\r\nConnection: close\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assert(readResult);
- const msg = decoder.decode(buf.subarray(0, readResult));
-
- conn.close();
-
- ac.abort();
- await server.finished;
- assert(msg.includes("content-length: 60"));
- },
-);
-
-Deno.test({ permissions: { net: true } }, async function httpServerWebSocket() {
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
- const doneDeferred = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: (request) => {
- const {
- response,
- socket,
- } = Deno.upgradeWebSocket(request);
- socket.onerror = (e) => {
- console.error(e);
- fail();
- };
- socket.onmessage = (m) => {
- socket.send(m.data);
- socket.close(1001);
- };
- socket.onclose = () => doneDeferred.resolve();
- return response;
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const def = Promise.withResolvers<void>();
- const ws = new WebSocket(`ws://localhost:${servePort}`);
- ws.onmessage = (m) => assertEquals(m.data, "foo");
- ws.onerror = (e) => {
- console.error(e);
- fail();
- };
- ws.onclose = () => def.resolve();
- ws.onopen = () => ws.send("foo");
-
- await def.promise;
- await doneDeferred.promise;
- ac.abort();
- await server.finished;
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerWebSocketRaw() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: async (request) => {
- const { conn, response } = upgradeHttpRaw(request);
- const buf = new Uint8Array(1024);
- let read;
-
- // Write our fake HTTP upgrade
- await conn.write(
- new TextEncoder().encode(
- "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgraded\r\n\r\nExtra",
- ),
- );
-
- // Upgrade data
- read = await conn.read(buf);
- assertEquals(
- new TextDecoder().decode(buf.subarray(0, read!)),
- "Upgrade data",
- );
- // Read the packet to echo
- read = await conn.read(buf);
- // Echo
- await conn.write(buf.subarray(0, read!));
-
- conn.close();
- return response;
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- await promise;
-
- const conn = await Deno.connect({ port: servePort });
- await conn.write(
- new TextEncoder().encode(
- "GET / HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\nUpgrade data",
- ),
- );
- const buf = new Uint8Array(1024);
- let len;
-
- // Headers
- let headers = "";
- for (let i = 0; i < 2; i++) {
- len = await conn.read(buf);
- headers += new TextDecoder().decode(buf.subarray(0, len!));
- if (headers.endsWith("Extra")) {
- break;
- }
- }
- assertMatch(
- headers,
- /HTTP\/1\.1 101 Switching Protocols[ ,.A-Za-z:0-9\r\n]*Extra/im,
- );
-
- // Data to echo
- await conn.write(new TextEncoder().encode("buffer data"));
-
- // Echo
- len = await conn.read(buf);
- assertEquals(
- new TextDecoder().decode(buf.subarray(0, len!)),
- "buffer data",
- );
-
- conn.close();
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerWebSocketUpgradeTwice() {
- const ac = new AbortController();
- const done = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: (request) => {
- const {
- response,
- socket,
- } = Deno.upgradeWebSocket(request);
- assertThrows(
- () => {
- Deno.upgradeWebSocket(request);
- },
- Deno.errors.Http,
- "already upgraded",
- );
- socket.onerror = (e) => {
- console.error(e);
- fail();
- };
- socket.onmessage = (m) => {
- socket.send(m.data);
- socket.close(1001);
- };
- socket.onclose = () => done.resolve();
- return response;
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const def = Promise.withResolvers<void>();
- const ws = new WebSocket(`ws://localhost:${servePort}`);
- ws.onmessage = (m) => assertEquals(m.data, "foo");
- ws.onerror = (e) => {
- console.error(e);
- fail();
- };
- ws.onclose = () => def.resolve();
- ws.onopen = () => ws.send("foo");
-
- await def.promise;
- await done.promise;
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerWebSocketCloseFast() {
- const ac = new AbortController();
- const done = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: (request) => {
- const {
- response,
- socket,
- } = Deno.upgradeWebSocket(request);
- socket.onopen = () => socket.close();
- socket.onclose = () => done.resolve();
- return response;
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const def = Promise.withResolvers<void>();
- const ws = new WebSocket(`ws://localhost:${servePort}`);
- ws.onerror = (e) => {
- console.error(e);
- fail();
- };
- ws.onclose = () => def.resolve();
-
- await def.promise;
- await done.promise;
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerWebSocketCanAccessRequest() {
- const ac = new AbortController();
- const done = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: (request) => {
- const {
- response,
- socket,
- } = Deno.upgradeWebSocket(request);
- socket.onerror = (e) => {
- console.error(e);
- fail();
- };
- socket.onmessage = (_m) => {
- socket.send(request.url.toString());
- socket.close(1001);
- };
- socket.onclose = () => done.resolve();
- return response;
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const def = Promise.withResolvers<void>();
- const ws = new WebSocket(`ws://localhost:${servePort}`);
- ws.onmessage = (m) =>
- assertEquals(m.data, `http://localhost:${servePort}/`);
- ws.onerror = (e) => {
- console.error(e);
- fail();
- };
- ws.onclose = () => def.resolve();
- ws.onopen = () => ws.send("foo");
-
- await def.promise;
- await done.promise;
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpVeryLargeRequest() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- let headers: Headers;
- const server = Deno.serve({
- handler: (request) => {
- headers = request.headers;
- deferred.resolve();
- return new Response("");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- // Send GET request with a body + content-length.
- const encoder = new TextEncoder();
- const smthElse = "x".repeat(16 * 1024 + 256);
- const body =
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:2333\r\nContent-Length: 5\r\nSomething-Else: ${smthElse}\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
- conn.close();
- assertEquals(headers!.get("content-length"), "5");
- assertEquals(headers!.get("something-else"), smthElse);
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpVeryLargeRequestAndBody() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- let headers: Headers;
- let text: string;
- const server = Deno.serve({
- handler: async (request) => {
- headers = request.headers;
- text = await request.text();
- deferred.resolve();
- return new Response("");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- // Send GET request with a body + content-length.
- const encoder = new TextEncoder();
- const smthElse = "x".repeat(16 * 1024 + 256);
- const reqBody = "hello world".repeat(1024);
- let body =
- `PUT / HTTP/1.1\r\nHost: 127.0.0.1:2333\r\nContent-Length: ${reqBody.length}\r\nSomething-Else: ${smthElse}\r\n\r\n${reqBody}`;
-
- while (body.length > 0) {
- const writeResult = await conn.write(encoder.encode(body));
- body = body.slice(writeResult);
- }
-
- await deferred.promise;
- conn.close();
-
- assertEquals(headers!.get("content-length"), `${reqBody.length}`);
- assertEquals(headers!.get("something-else"), smthElse);
- assertEquals(text!, reqBody);
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpConnectionClose() {
- const deferred = Promise.withResolvers<void>();
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: () => {
- deferred.resolve();
- return new Response("");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- // Send GET request with a body + connection: close.
- const encoder = new TextEncoder();
- const body =
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:2333\r\nConnection: Close\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- await deferred.promise;
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-async function testDuplex(
- reader: ReadableStreamDefaultReader<Uint8Array>,
- writable: WritableStreamDefaultWriter<Uint8Array>,
-) {
- await writable.write(new Uint8Array([1]));
- const chunk1 = await reader.read();
- assert(!chunk1.done);
- assertEquals(chunk1.value, new Uint8Array([1]));
- await writable.write(new Uint8Array([2]));
- const chunk2 = await reader.read();
- assert(!chunk2.done);
- assertEquals(chunk2.value, new Uint8Array([2]));
- await writable.close();
- const chunk3 = await reader.read();
- assert(chunk3.done);
-}
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerStreamDuplexDirect() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve(
- { port: servePort, signal: ac.signal },
- (request: Request) => {
- assert(request.body);
- resolve();
- return new Response(request.body);
- },
- );
-
- const { readable, writable } = new TransformStream();
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- method: "POST",
- body: readable,
- });
-
- await promise;
- assert(resp.body);
- await testDuplex(resp.body.getReader(), writable.getWriter());
- ac.abort();
- await server.finished;
- },
-);
-
-// Test that a duplex stream passing through JavaScript also works (ie: that the request body resource
-// is still alive). https://github.com/denoland/deno/pull/20206
-Deno.test(
- { permissions: { net: true } },
- async function httpServerStreamDuplexJavascript() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve(
- { port: servePort, signal: ac.signal },
- (request: Request) => {
- assert(request.body);
- resolve();
- const reader = request.body.getReader();
- return new Response(
- new ReadableStream({
- async pull(controller) {
- await new Promise((r) => setTimeout(r, 100));
- const { done, value } = await reader.read();
- if (done) {
- controller.close();
- } else {
- controller.enqueue(value);
- }
- },
- }),
- );
- },
- );
-
- const { readable, writable } = new TransformStream();
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- method: "POST",
- body: readable,
- });
-
- await promise;
- assert(resp.body);
- await testDuplex(resp.body.getReader(), writable.getWriter());
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- // Issue: https://github.com/denoland/deno/issues/10930
- async function httpServerStreamingResponse() {
- // This test enqueues a single chunk for readable
- // stream and waits for client to read that chunk and signal
- // it before enqueueing subsequent chunk. Issue linked above
- // presented a situation where enqueued chunks were not
- // written to the HTTP connection until the next chunk was enqueued.
- const listeningDeferred = Promise.withResolvers<void>();
- const deferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- let counter = 0;
-
- const deferreds = [
- Promise.withResolvers<void>(),
- Promise.withResolvers<void>(),
- Promise.withResolvers<void>(),
- ];
-
- async function writeRequest(conn: Deno.Conn) {
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- const w = new BufWriter(conn);
- const r = new BufReader(conn);
- const body = `GET / HTTP/1.1\r\nHost: 127.0.0.1:${servePort}\r\n\r\n`;
- const writeResult = await w.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await w.flush();
- const tpr = new TextProtoReader(r);
- const statusLine = await tpr.readLine();
- assert(statusLine !== null);
- const headers = await tpr.readMimeHeader();
- assert(headers !== null);
-
- const chunkedReader = chunkedBodyReader(headers, r);
-
- const buf = new Uint8Array(5);
- const dest = new Buffer();
-
- let result: number | null;
-
- try {
- while ((result = await chunkedReader.read(buf)) !== null) {
- const len = Math.min(buf.byteLength, result);
-
- await dest.write(buf.subarray(0, len));
-
- // Resolve a deferred - this will make response stream to
- // enqueue next chunk.
- deferreds[counter - 1].resolve();
- }
- return decoder.decode(dest.bytes());
- } catch (e) {
- console.error(e);
- }
- }
-
- function periodicStream() {
- return new ReadableStream({
- start(controller) {
- controller.enqueue(`${counter}\n`);
- counter++;
- },
-
- async pull(controller) {
- if (counter >= 3) {
- return controller.close();
- }
-
- await deferreds[counter - 1].promise;
-
- controller.enqueue(`${counter}\n`);
- counter++;
- },
- }).pipeThrough(new TextEncoderStream());
- }
-
- const server = Deno.serve({
- handler: () => {
- deferred.resolve();
- return new Response(periodicStream());
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- // start a client
- const clientConn = await Deno.connect({ port: servePort });
-
- const r1 = await writeRequest(clientConn);
- assertEquals(r1, "0\n1\n2\n");
-
- ac.abort();
- await deferred.promise;
- await server.finished;
- clientConn.close();
- },
-);
-
-// Make sure that the chunks of a large response aren't repeated or corrupted in some other way by
-// scatterning sentinels throughout.
-// https://github.com/denoland/fresh/issues/1699
-Deno.test(
- { permissions: { net: true } },
- async function httpLargeReadableStreamChunk() {
- const ac = new AbortController();
- const server = Deno.serve({
- handler() {
- return new Response(
- new ReadableStream({
- start(controller) {
- const buffer = new Uint8Array(1024 * 1024);
- // Mark the buffer with sentinels
- for (let i = 0; i < 256; i++) {
- buffer[i * 4096] = i;
- }
- controller.enqueue(buffer);
- controller.close();
- },
- }),
- );
- },
- port: servePort,
- signal: ac.signal,
- });
- const response = await fetch(`http://localhost:${servePort}/`);
- const body = await response.arrayBuffer();
- assertEquals(1024 * 1024, body.byteLength);
- const buffer = new Uint8Array(body);
- for (let i = 0; i < 256; i++) {
- assertEquals(
- i,
- buffer[i * 4096],
- `sentinel mismatch at index ${i * 4096}`,
- );
- }
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpRequestLatin1Headers() {
- const listeningDeferred = Promise.withResolvers<void>();
- const deferred = Promise.withResolvers<void>();
- const ac = new AbortController();
- const server = Deno.serve({
- handler: (request) => {
- assertEquals(request.headers.get("X-Header-Test"), "á");
- deferred.resolve();
- return new Response("hello", { headers: { "X-Header-Test": "Æ" } });
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const clientConn = await Deno.connect({ port: servePort });
- const requestText =
- `GET / HTTP/1.1\r\nHost: 127.0.0.1:${servePort}\r\nX-Header-Test: á\r\n\r\n`;
- const requestBytes = new Uint8Array(requestText.length);
- for (let i = 0; i < requestText.length; i++) {
- requestBytes[i] = requestText.charCodeAt(i);
- }
- let written = 0;
- while (written < requestBytes.byteLength) {
- written += await clientConn.write(requestBytes.slice(written));
- }
-
- const buf = new Uint8Array(1024);
- await clientConn.read(buf);
-
- await deferred.promise;
- const responseText = new TextDecoder("iso-8859-1").decode(buf);
- clientConn.close();
-
- ac.abort();
- await server.finished;
-
- assertMatch(responseText, /\r\n[Xx]-[Hh]eader-[Tt]est: Æ\r\n/);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerRequestWithoutPath() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: async (request) => {
- // FIXME:
- // assertEquals(new URL(request.url).href, `http://127.0.0.1:${servePort}/`);
- assertEquals(await request.text(), "");
- deferred.resolve();
- return new Response("11");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const clientConn = await Deno.connect({ port: servePort });
-
- async function writeRequest(conn: Deno.Conn) {
- const encoder = new TextEncoder();
-
- const w = new BufWriter(conn);
- const r = new BufReader(conn);
- const body =
- `CONNECT 127.0.0.1:${servePort} HTTP/1.1\r\nHost: 127.0.0.1:${servePort}\r\n\r\n`;
- const writeResult = await w.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await w.flush();
- const tpr = new TextProtoReader(r);
- const statusLine = await tpr.readLine();
- assert(statusLine !== null);
- const m = statusLine.match(/^(.+?) (.+?) (.+?)$/);
- assert(m !== null, "must be matched");
- const [_, _proto, status, _ok] = m;
- assertEquals(status, "200");
- const headers = await tpr.readMimeHeader();
- assert(headers !== null);
- }
-
- await writeRequest(clientConn);
- clientConn.close();
- await deferred.promise;
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpCookieConcatenation() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: async (request) => {
- assertEquals(await request.text(), "");
- assertEquals(request.headers.get("cookie"), "foo=bar; bar=foo");
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- reusePort: true,
- });
-
- await listeningDeferred.promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- headers: [
- ["connection", "close"],
- ["cookie", "foo=bar"],
- ["cookie", "bar=foo"],
- ],
- });
- await deferred.promise;
-
- const text = await resp.text();
- assertEquals(text, "ok");
-
- ac.abort();
- await server.finished;
- },
-);
-
-// https://github.com/denoland/deno/issues/12741
-// https://github.com/denoland/deno/pull/12746
-// https://github.com/denoland/deno/pull/12798
-Deno.test(
- { permissions: { net: true, run: true } },
- async function httpServerDeleteRequestHasBody() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const hostname = "localhost";
-
- const server = Deno.serve({
- handler: () => {
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const url = `http://${hostname}:${servePort}/`;
- const args = ["-X", "DELETE", url];
- const { success } = await new Deno.Command("curl", {
- args,
- stdout: "null",
- stderr: "null",
- }).output();
- assert(success);
- await deferred.promise;
- ac.abort();
-
- await server.finished;
- },
-);
-
-// FIXME:
-Deno.test(
- { permissions: { net: true } },
- async function httpServerRespondNonAsciiUint8Array() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: (request) => {
- assertEquals(request.body, null);
- deferred.resolve();
- return new Response(new Uint8Array([128]));
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
- await listeningDeferred.resolve;
- const resp = await fetch(`http://localhost:${servePort}/`);
-
- await deferred.promise;
-
- assertEquals(resp.status, 200);
- const body = await resp.arrayBuffer();
- assertEquals(new Uint8Array(body), new Uint8Array([128]));
-
- ac.abort();
- await server.finished;
- },
-);
-
-// Some of these tests are ported from Hyper
-// https://github.com/hyperium/hyper/blob/889fa2d87252108eb7668b8bf034ffcc30985117/src/proto/h1/role.rs
-// https://github.com/hyperium/hyper/blob/889fa2d87252108eb7668b8bf034ffcc30985117/tests/server.rs
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerParseRequest() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: (request) => {
- assertEquals(request.method, "GET");
- assertEquals(request.headers.get("host"), "deno.land");
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const body = `GET /echo HTTP/1.1\r\nHost: deno.land\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerParseHeaderHtabs() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: (request) => {
- assertEquals(request.method, "GET");
- assertEquals(request.headers.get("server"), "hello\tworld");
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const body = `GET / HTTP/1.1\r\nserver: hello\tworld\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerGetShouldIgnoreBody() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: async (request) => {
- assertEquals(request.method, "GET");
- assertEquals(await request.text(), "");
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- // Connection: close = don't try to parse the body as a new request
- const body =
- `GET / HTTP/1.1\r\nHost: example.domain\r\nConnection: close\r\n\r\nI shouldn't be read.\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerPostWithBody() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: async (request) => {
- assertEquals(request.method, "POST");
- assertEquals(await request.text(), "I'm a good request.");
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const body =
- `POST / HTTP/1.1\r\nHost: example.domain\r\nContent-Length: 19\r\n\r\nI'm a good request.`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-type TestCase = {
- headers?: Record<string, string>;
- // deno-lint-ignore no-explicit-any
- body: any;
- expectsChunked?: boolean;
- expectsConnLen?: boolean;
-};
-
-function hasHeader(msg: string, name: string): boolean {
- const n = msg.indexOf("\r\n\r\n") || msg.length;
- return msg.slice(0, n).includes(name);
-}
-
-function createServerLengthTest(name: string, testCase: TestCase) {
- Deno.test(name, async function () {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: (request) => {
- assertEquals(request.method, "GET");
- deferred.resolve();
- return new Response(testCase.body, testCase.headers ?? {});
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const body =
- `GET / HTTP/1.1\r\nHost: example.domain\r\nConnection: close\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
-
- const decoder = new TextDecoder();
- let msg = "";
- while (true) {
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- if (!readResult) {
- break;
- }
- msg += decoder.decode(buf.subarray(0, readResult));
- try {
- assert(
- testCase.expectsChunked == hasHeader(msg, "Transfer-Encoding:"),
- );
- assert(testCase.expectsChunked == hasHeader(msg, "chunked"));
- assert(testCase.expectsConnLen == hasHeader(msg, "Content-Length:"));
-
- const n = msg.indexOf("\r\n\r\n") + 4;
-
- if (testCase.expectsChunked) {
- assertEquals(msg.slice(n + 1, n + 3), "\r\n");
- assertEquals(msg.slice(msg.length - 7), "\r\n0\r\n\r\n");
- }
-
- if (testCase.expectsConnLen && typeof testCase.body === "string") {
- assertEquals(msg.slice(n), testCase.body);
- }
- break;
- } catch {
- continue;
- }
- }
-
- conn.close();
-
- ac.abort();
- await server.finished;
- });
-}
-
-// Quick and dirty way to make a readable stream from a string. Alternatively,
-// `readableStreamFromReader(file)` could be used.
-function stream(s: string): ReadableStream<Uint8Array> {
- return new Response(s).body!;
-}
-
-createServerLengthTest("fixedResponseKnown", {
- headers: { "content-length": "11" },
- body: "foo bar baz",
- expectsChunked: false,
- expectsConnLen: true,
-});
-
-createServerLengthTest("fixedResponseUnknown", {
- headers: { "content-length": "11" },
- body: stream("foo bar baz"),
- expectsChunked: true,
- expectsConnLen: false,
-});
-
-createServerLengthTest("fixedResponseKnownEmpty", {
- headers: { "content-length": "0" },
- body: "",
- expectsChunked: false,
- expectsConnLen: true,
-});
-
-createServerLengthTest("chunkedRespondKnown", {
- headers: { "transfer-encoding": "chunked" },
- body: "foo bar baz",
- expectsChunked: false,
- expectsConnLen: true,
-});
-
-createServerLengthTest("chunkedRespondUnknown", {
- headers: { "transfer-encoding": "chunked" },
- body: stream("foo bar baz"),
- expectsChunked: true,
- expectsConnLen: false,
-});
-
-createServerLengthTest("autoResponseWithKnownLength", {
- body: "foo bar baz",
- expectsChunked: false,
- expectsConnLen: true,
-});
-
-createServerLengthTest("autoResponseWithUnknownLength", {
- body: stream("foo bar baz"),
- expectsChunked: true,
- expectsConnLen: false,
-});
-
-createServerLengthTest("autoResponseWithKnownLengthEmpty", {
- body: "",
- expectsChunked: false,
- expectsConnLen: true,
-});
-
-createServerLengthTest("autoResponseWithUnknownLengthEmpty", {
- body: stream(""),
- expectsChunked: true,
- expectsConnLen: false,
-});
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerPostWithContentLengthBody() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: async (request) => {
- assertEquals(request.method, "POST");
- assertEquals(request.headers.get("content-length"), "5");
- assertEquals(await request.text(), "hello");
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
-
- const body =
- `POST / HTTP/1.1\r\nHost: example.domain\r\nContent-Length: 5\r\n\r\nhello`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
-
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerPostWithInvalidPrefixContentLength() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: () => {
- throw new Error("unreachable");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- await promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- const body =
- `POST / HTTP/1.1\r\nHost: example.domain\r\nContent-Length: +5\r\n\r\nhello`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assert(readResult);
- const msg = decoder.decode(buf.subarray(0, readResult));
- assert(msg.includes("HTTP/1.1 400 Bad Request"));
-
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerPostWithChunkedBody() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: async (request) => {
- assertEquals(request.method, "POST");
- assertEquals(await request.text(), "qwert");
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
-
- const body =
- `POST / HTTP/1.1\r\nHost: example.domain\r\nTransfer-Encoding: chunked\r\n\r\n1\r\nq\r\n2\r\nwe\r\n2\r\nrt\r\n0\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
-
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerPostWithIncompleteBody() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: async (r) => {
- deferred.resolve();
- assertEquals(await r.text(), "12345");
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
-
- const body =
- `POST / HTTP/1.1\r\nHost: example.domain\r\nContent-Length: 10\r\n\r\n12345`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- await deferred.promise;
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerHeadResponseDoesntSendBody() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: () => {
- deferred.resolve();
- return new Response("NaN".repeat(100));
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- const body =
- `HEAD / HTTP/1.1\r\nHost: example.domain\r\nConnection: close\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- await deferred.promise;
-
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assert(readResult);
- const msg = decoder.decode(buf.subarray(0, readResult));
-
- assert(msg.includes("content-length: 300\r\n"));
-
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-function makeTempData(size: number) {
- return new Uint8Array(size).fill(1);
-}
-
-async function makeTempFile(size: number) {
- const tmpFile = await Deno.makeTempFile();
- using file = await Deno.open(tmpFile, { write: true, read: true });
- const data = makeTempData(size);
- await file.write(data);
-
- return await Deno.open(tmpFile, { write: true, read: true });
-}
-
-const compressionTestCases = [
- { name: "Empty", length: 0, in: {}, out: {}, expect: null },
- {
- name: "EmptyAcceptGzip",
- length: 0,
- in: { "Accept-Encoding": "gzip" },
- out: {},
- expect: null,
- },
- // This technically would be compressible if not for the size, however the size_hint is not implemented
- // for FileResource and we don't currently peek ahead on resources.
- // {
- // name: "EmptyAcceptGzip2",
- // length: 0,
- // in: { "Accept-Encoding": "gzip" },
- // out: { "Content-Type": "text/plain" },
- // expect: null,
- // },
- { name: "Incompressible", length: 1024, in: {}, out: {}, expect: null },
- {
- name: "IncompressibleAcceptGzip",
- length: 1024,
- in: { "Accept-Encoding": "gzip" },
- out: {},
- expect: null,
- },
- {
- name: "IncompressibleType",
- length: 1024,
- in: { "Accept-Encoding": "gzip" },
- out: { "Content-Type": "text/fake" },
- expect: null,
- },
- {
- name: "CompressibleType",
- length: 1024,
- in: { "Accept-Encoding": "gzip" },
- out: { "Content-Type": "text/plain" },
- expect: "gzip",
- },
- {
- name: "CompressibleType2",
- length: 1024,
- in: { "Accept-Encoding": "gzip, deflate, br" },
- out: { "Content-Type": "text/plain" },
- expect: "gzip",
- },
- {
- name: "CompressibleType3",
- length: 1024,
- in: { "Accept-Encoding": "br" },
- out: { "Content-Type": "text/plain" },
- expect: "br",
- },
- {
- name: "IncompressibleRange",
- length: 1024,
- in: { "Accept-Encoding": "gzip" },
- out: { "Content-Type": "text/plain", "Content-Range": "1" },
- expect: null,
- },
- {
- name: "IncompressibleCE",
- length: 1024,
- in: { "Accept-Encoding": "gzip" },
- out: { "Content-Type": "text/plain", "Content-Encoding": "random" },
- expect: null,
- },
- {
- name: "IncompressibleCC",
- length: 1024,
- in: { "Accept-Encoding": "gzip" },
- out: { "Content-Type": "text/plain", "Cache-Control": "no-transform" },
- expect: null,
- },
- {
- name: "BadHeader",
- length: 1024,
- in: { "Accept-Encoding": "\x81" },
- out: { "Content-Type": "text/plain", "Cache-Control": "no-transform" },
- expect: null,
- },
-];
-
-for (const testCase of compressionTestCases) {
- const name = `httpServerCompression${testCase.name}`;
- Deno.test(
- { permissions: { net: true, write: true, read: true } },
- {
- [name]: async function () {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
- const server = Deno.serve({
- handler: async (_request) => {
- const f = await makeTempFile(testCase.length);
- deferred.resolve();
- // deno-lint-ignore no-explicit-any
- const headers = testCase.out as any;
- headers["Content-Length"] = testCase.length.toString();
- return new Response(f.readable, {
- headers: headers as HeadersInit,
- });
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
- try {
- await listeningDeferred.promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- headers: testCase.in as HeadersInit,
- });
- await deferred.promise;
- const body = await resp.arrayBuffer();
- if (testCase.expect == null) {
- assertEquals(body.byteLength, testCase.length);
- assertEquals(
- resp.headers.get("content-length"),
- testCase.length.toString(),
- );
- assertEquals(
- resp.headers.get("content-encoding"),
- testCase.out["Content-Encoding"] || null,
- );
- } else if (testCase.expect == "gzip") {
- // Note the fetch will transparently decompress this response, BUT we can detect that a response
- // was compressed by the lack of a content length.
- assertEquals(body.byteLength, testCase.length);
- assertEquals(resp.headers.get("content-encoding"), null);
- assertEquals(resp.headers.get("content-length"), null);
- }
- } finally {
- ac.abort();
- await server.finished;
- }
- },
- }[name],
- );
-}
-
-Deno.test(
- { permissions: { net: true, write: true, read: true } },
- async function httpServerPostFile() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: async (request) => {
- assertEquals(
- new Uint8Array(await request.arrayBuffer()),
- makeTempData(70 * 1024),
- );
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const f = await makeTempFile(70 * 1024);
- const response = await fetch(`http://localhost:${servePort}/`, {
- method: "POST",
- body: f.readable,
- });
-
- await deferred.promise;
-
- assertEquals(response.status, 200);
- assertEquals(await response.text(), "ok");
-
- ac.abort();
- await server.finished;
- },
-);
-
-for (const delay of ["delay", "nodelay"]) {
- for (const url of ["text", "file", "stream"]) {
- // Ensure that we don't panic when the incoming TCP request was dropped
- // https://github.com/denoland/deno/issues/20315 and that we correctly
- // close/cancel the response
- Deno.test({
- permissions: { read: true, write: true, net: true },
- name: `httpServerTcpCancellation_${url}_${delay}`,
- fn: async function () {
- const ac = new AbortController();
- const streamCancelled = url == "stream"
- ? Promise.withResolvers<void>()
- : undefined;
- const listeningDeferred = Promise.withResolvers<void>();
- const waitForAbort = Promise.withResolvers<void>();
- const waitForRequest = Promise.withResolvers<void>();
- const server = Deno.serve({
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- handler: async (req: Request) => {
- let respBody = null;
- if (req.url.includes("/text")) {
- respBody = "text";
- } else if (req.url.includes("/file")) {
- respBody = (await makeTempFile(1024)).readable;
- } else if (req.url.includes("/stream")) {
- respBody = new ReadableStream({
- start(controller) {
- controller.enqueue(new Uint8Array([1]));
- },
- cancel(reason) {
- streamCancelled!.resolve(reason);
- },
- });
- } else {
- fail();
- }
- waitForRequest.resolve();
- await waitForAbort.promise;
-
- if (delay == "delay") {
- await new Promise((r) => setTimeout(r, 1000));
- }
- // Allocate the request body
- req.body;
- return new Response(respBody);
- },
- });
-
- await listeningDeferred.promise;
-
- // Create a POST request and drop it once the server has received it
- const conn = await Deno.connect({ port: servePort });
- const writer = conn.writable.getWriter();
- await writer.write(
- new TextEncoder().encode(`POST /${url} HTTP/1.0\n\n`),
- );
- await waitForRequest.promise;
- await writer.close();
-
- waitForAbort.resolve();
-
- // Wait for cancellation before we shut the server down
- if (streamCancelled !== undefined) {
- await streamCancelled;
- }
-
- // Since the handler has a chance of creating resources or running async
- // ops, we need to use a graceful shutdown here to ensure they have fully
- // drained.
- await server.shutdown();
-
- await server.finished;
- },
- });
- }
-}
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerCancelFetch() {
- const request2 = Promise.withResolvers<void>();
- const request2Aborted = Promise.withResolvers<string>();
- const { finished, abort } = await makeServer(async (req) => {
- if (req.url.endsWith("/1")) {
- const fetchRecursive = await fetch(`http://localhost:${servePort}/2`);
- return new Response(fetchRecursive.body);
- } else if (req.url.endsWith("/2")) {
- request2.resolve();
- return new Response(
- new ReadableStream({
- start(_controller) {/* just hang */},
- cancel(reason) {
- request2Aborted.resolve(reason);
- },
- }),
- );
- }
- fail();
- });
- const fetchAbort = new AbortController();
- const fetchPromise = await fetch(`http://localhost:${servePort}/1`, {
- signal: fetchAbort.signal,
- });
- await fetchPromise;
- await request2.promise;
- fetchAbort.abort();
- assertEquals("resource closed", await request2Aborted.promise);
-
- abort();
- await finished;
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function httpServerWithTls() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- const hostname = "127.0.0.1";
-
- const server = Deno.serve({
- handler: () => new Response("Hello World"),
- hostname,
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- cert: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.crt"),
- key: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.key"),
- });
-
- await promise;
- const caCert = Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem");
- const client = Deno.createHttpClient({ caCerts: [caCert] });
- const resp = await fetch(`https://localhost:${servePort}/`, {
- client,
- headers: { "connection": "close" },
- });
-
- const respBody = await resp.text();
- assertEquals("Hello World", respBody);
-
- client.close();
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true, write: true, read: true } },
- async function httpServerRequestCLTE() {
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
- const deferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: async (req) => {
- assertEquals(await req.text(), "");
- deferred.resolve();
- return new Response("ok");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
-
- const body =
- `POST / HTTP/1.1\r\nHost: example.domain\r\nContent-Length: 13\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nEXTRA`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await deferred.promise;
-
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true, write: true, read: true } },
- async function httpServerRequestTETE() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: () => {
- throw new Error("oops");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- const variations = [
- "Transfer-Encoding : chunked",
- "Transfer-Encoding: xchunked",
- "Transfer-Encoding: chunkedx",
- "Transfer-Encoding\n: chunked",
- ];
-
- await promise;
- for (const teHeader of variations) {
- const conn = await Deno.connect({ port: servePort });
- const body =
- `POST / HTTP/1.1\r\nHost: example.domain\r\n${teHeader}\r\n\r\n0\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assert(readResult);
- const msg = decoder.decode(buf.subarray(0, readResult));
- assert(msg.includes("HTTP/1.1 400 Bad Request\r\n"));
-
- conn.close();
- }
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServer204ResponseDoesntSendContentLength() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ac = new AbortController();
- const server = Deno.serve({
- handler: (_request) => new Response(null, { status: 204 }),
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- try {
- await promise;
- const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
- method: "GET",
- headers: { "connection": "close" },
- });
- assertEquals(resp.status, 204);
- assertEquals(resp.headers.get("Content-Length"), null);
- } finally {
- ac.abort();
- await server.finished;
- }
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServer304ResponseDoesntSendBody() {
- const deferred = Promise.withResolvers<void>();
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: () => {
- deferred.resolve();
- return new Response(null, { status: 304 });
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- const body =
- `GET / HTTP/1.1\r\nHost: example.domain\r\nConnection: close\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
-
- await deferred.promise;
-
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assert(readResult);
- const msg = decoder.decode(buf.subarray(0, readResult));
-
- assert(msg.startsWith("HTTP/1.1 304 Not Modified"));
- assert(msg.endsWith("\r\n\r\n"));
-
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerExpectContinue() {
- const deferred = Promise.withResolvers<void>();
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: async (req) => {
- deferred.resolve();
- assertEquals(await req.text(), "hello");
- return new Response(null, { status: 304 });
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- {
- const body =
- `POST / HTTP/1.1\r\nHost: example.domain\r\nExpect: 100-continue\r\nContent-Length: 5\r\nConnection: close\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- }
-
- await deferred.promise;
-
- {
- const msgExpected = "HTTP/1.1 100 Continue\r\n\r\n";
- const buf = new Uint8Array(encoder.encode(msgExpected).byteLength);
- const readResult = await conn.read(buf);
- assert(readResult);
- const msg = decoder.decode(buf.subarray(0, readResult));
- assert(msg.startsWith(msgExpected));
- }
-
- {
- const body = "hello";
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- }
-
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assert(readResult);
- const msg = decoder.decode(buf.subarray(0, readResult));
-
- assert(msg.startsWith("HTTP/1.1 304 Not Modified"));
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerExpectContinueButNoBodyLOL() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve({
- handler: async (req) => {
- deferred.resolve();
- assertEquals(await req.text(), "");
- return new Response(null, { status: 304 });
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(listeningDeferred.resolve),
- onError: createOnErrorCb(ac),
- });
-
- await listeningDeferred.promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- {
- // // no content-length or transfer-encoding means no body!
- const body =
- `POST / HTTP/1.1\r\nHost: example.domain\r\nExpect: 100-continue\r\nConnection: close\r\n\r\n`;
- const writeResult = await conn.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- }
-
- await deferred.promise;
-
- const buf = new Uint8Array(1024);
- const readResult = await conn.read(buf);
- assert(readResult);
- const msg = decoder.decode(buf.subarray(0, readResult));
-
- assert(msg.startsWith("HTTP/1.1 304 Not Modified"));
- conn.close();
-
- ac.abort();
- await server.finished;
- },
-);
-
-const badRequests = [
- ["weirdMethodName", "GE T / HTTP/1.1\r\n\r\n"],
- ["illegalRequestLength", "POST / HTTP/1.1\r\nContent-Length: foo\r\n\r\n"],
- ["illegalRequestLength2", "POST / HTTP/1.1\r\nContent-Length: -1\r\n\r\n"],
- ["illegalRequestLength3", "POST / HTTP/1.1\r\nContent-Length: 1.1\r\n\r\n"],
- ["illegalRequestLength4", "POST / HTTP/1.1\r\nContent-Length: 1.\r\n\r\n"],
-];
-
-for (const [name, req] of badRequests) {
- const testFn = {
- [name]: async () => {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: () => {
- throw new Error("oops");
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- await promise;
- const conn = await Deno.connect({ port: servePort });
- const encoder = new TextEncoder();
- const decoder = new TextDecoder();
-
- {
- const writeResult = await conn.write(encoder.encode(req));
- assertEquals(req.length, writeResult);
- }
-
- const buf = new Uint8Array(100);
- const readResult = await conn.read(buf);
- assert(readResult);
- const msg = decoder.decode(buf.subarray(0, readResult));
-
- assert(msg.startsWith("HTTP/1.1 400 "));
- conn.close();
-
- ac.abort();
- await server.finished;
- },
- }[name];
-
- Deno.test(
- { permissions: { net: true } },
- testFn,
- );
-}
-
-Deno.test(
- { permissions: { net: true } },
- async function httpServerConcurrentRequests() {
- const ac = new AbortController();
- const { resolve } = Promise.withResolvers<void>();
-
- let reqCount = -1;
- let timerId: number | undefined;
- const server = Deno.serve({
- handler: (_req) => {
- reqCount++;
- if (reqCount === 0) {
- const msg = new TextEncoder().encode("data: hello\r\n\r\n");
- // SSE
- const body = new ReadableStream({
- start(controller) {
- timerId = setInterval(() => {
- controller.enqueue(msg);
- }, 1000);
- },
- cancel() {
- if (typeof timerId === "number") {
- clearInterval(timerId);
- }
- },
- });
- return new Response(body, {
- headers: {
- "Content-Type": "text/event-stream",
- },
- });
- }
-
- return new Response(`hello ${reqCount}`);
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- const sseRequest = await fetch(`http://localhost:${servePort}/`);
-
- const decoder = new TextDecoder();
- const stream = sseRequest.body!.getReader();
- {
- const { done, value } = await stream.read();
- assert(!done);
- assertEquals(decoder.decode(value), "data: hello\r\n\r\n");
- }
-
- const helloRequest = await fetch(`http://localhost:${servePort}/`);
- assertEquals(helloRequest.status, 200);
- assertEquals(await helloRequest.text(), "hello 1");
-
- {
- const { done, value } = await stream.read();
- assert(!done);
- assertEquals(decoder.decode(value), "data: hello\r\n\r\n");
- }
-
- await stream.cancel();
- clearInterval(timerId);
- ac.abort();
- await server.finished;
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function serveWithPrototypePollution() {
- const originalThen = Promise.prototype.then;
- const originalSymbolIterator = Array.prototype[Symbol.iterator];
- try {
- Promise.prototype.then = Array.prototype[Symbol.iterator] = () => {
- throw new Error();
- };
- const ac = new AbortController();
- const { resolve } = Promise.withResolvers<void>();
- const server = Deno.serve({
- handler: (_req) => new Response("ok"),
- hostname: "localhost",
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
- ac.abort();
- await server.finished;
- } finally {
- Promise.prototype.then = originalThen;
- Array.prototype[Symbol.iterator] = originalSymbolIterator;
- }
- },
-);
-
-// https://github.com/denoland/deno/issues/15549
-Deno.test(
- { permissions: { net: true } },
- async function testIssue15549() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- let count = 0;
- const server = Deno.serve({
- async onListen({ port }: { port: number }) {
- const res1 = await fetch(`http://localhost:${port}/`);
- assertEquals(await res1.text(), "hello world 1");
-
- const res2 = await fetch(`http://localhost:${port}/`);
- assertEquals(await res2.text(), "hello world 2");
-
- resolve();
- ac.abort();
- },
- signal: ac.signal,
- }, () => {
- count++;
- return new Response(`hello world ${count}`);
- });
-
- await promise;
- await server.finished;
- },
-);
-
-// https://github.com/denoland/deno/issues/15858
-Deno.test(
- "Clone should work",
- { permissions: { net: true } },
- async function httpServerCanCloneRequest() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<number>();
-
- const server = Deno.serve({
- handler: async (req) => {
- const cloned = req.clone();
- assertEquals(req.headers, cloned.headers);
-
- assertEquals(cloned.url, req.url);
- assertEquals(cloned.cache, req.cache);
- assertEquals(cloned.destination, req.destination);
- assertEquals(cloned.headers, req.headers);
- assertEquals(cloned.integrity, req.integrity);
- assertEquals(cloned.isHistoryNavigation, req.isHistoryNavigation);
- assertEquals(cloned.isReloadNavigation, req.isReloadNavigation);
- assertEquals(cloned.keepalive, req.keepalive);
- assertEquals(cloned.method, req.method);
- assertEquals(cloned.mode, req.mode);
- assertEquals(cloned.redirect, req.redirect);
- assertEquals(cloned.referrer, req.referrer);
- assertEquals(cloned.referrerPolicy, req.referrerPolicy);
-
- // both requests can read body
- await req.text();
- await cloned.json();
-
- return new Response("ok");
- },
- signal: ac.signal,
- onListen: ({ port }: { port: number }) => resolve(port),
- onError: createOnErrorCb(ac),
- });
-
- try {
- const port = await promise;
- const resp = await fetch(`http://localhost:${port}/`, {
- headers: { connection: "close" },
- method: "POST",
- body: '{"sus":true}',
- });
- const text = await resp.text();
- assertEquals(text, "ok");
- } finally {
- ac.abort();
- await server.finished;
- }
- },
-);
-
-// https://fetch.spec.whatwg.org/#dom-request-clone
-Deno.test(
- "Throw if disturbed",
- { permissions: { net: true } },
- async function shouldThrowIfBodyIsUnusableDisturbed() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<number>();
-
- const server = Deno.serve({
- handler: async (req) => {
- await req.text();
-
- try {
- req.clone();
- fail();
- } catch (cloneError) {
- assert(cloneError instanceof TypeError);
- assert(
- cloneError.message.endsWith("Body is unusable."),
- );
-
- ac.abort();
- await server.finished;
- }
-
- return new Response("ok");
- },
- signal: ac.signal,
- onListen: ({ port }: { port: number }) => resolve(port),
- });
-
- try {
- const port = await promise;
- await fetch(`http://localhost:${port}/`, {
- headers: { connection: "close" },
- method: "POST",
- body: '{"bar":true}',
- });
- fail();
- } catch (clientError) {
- assert(clientError instanceof TypeError);
- assert(
- clientError.message.endsWith(
- "connection closed before message completed",
- ),
- );
- } finally {
- ac.abort();
- await server.finished;
- }
- },
-);
-
-// https://fetch.spec.whatwg.org/#dom-request-clone
-Deno.test({
- name: "Throw if locked",
- permissions: { net: true },
- fn: async function shouldThrowIfBodyIsUnusableLocked() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<number>();
-
- const server = Deno.serve({
- handler: async (req) => {
- const _reader = req.body?.getReader();
-
- try {
- req.clone();
- fail();
- } catch (cloneError) {
- assert(cloneError instanceof TypeError);
- assert(
- cloneError.message.endsWith("Body is unusable."),
- );
-
- ac.abort();
- await server.finished;
- }
- return new Response("ok");
- },
- signal: ac.signal,
- onListen: ({ port }: { port: number }) => resolve(port),
- });
-
- try {
- const port = await promise;
- await fetch(`http://localhost:${port}/`, {
- headers: { connection: "close" },
- method: "POST",
- body: '{"bar":true}',
- });
- fail();
- } catch (clientError) {
- assert(clientError instanceof TypeError);
- assert(
- clientError.message.endsWith(
- "connection closed before message completed",
- ),
- );
- } finally {
- ac.abort();
- await server.finished;
- }
- },
-});
-
-// Checks large streaming response
-// https://github.com/denoland/deno/issues/16567
-Deno.test(
- { permissions: { net: true } },
- async function testIssue16567() {
- const ac = new AbortController();
- const { promise, resolve } = Promise.withResolvers<void>();
- const server = Deno.serve({
- async onListen({ port }) {
- const res1 = await fetch(`http://localhost:${port}/`);
- assertEquals((await res1.text()).length, 40 * 50_000);
-
- resolve();
- ac.abort();
- },
- signal: ac.signal,
- }, () =>
- new Response(
- new ReadableStream({
- start(c) {
- // 2MB "a...a" response with 40 chunks
- for (const _ of Array(40)) {
- c.enqueue(new Uint8Array(50_000).fill(97));
- }
- c.close();
- },
- }),
- ));
-
- await promise;
- await server.finished;
- },
-);
-
-function chunkedBodyReader(h: Headers, r: BufReader): Deno.Reader {
- // Based on https://tools.ietf.org/html/rfc2616#section-19.4.6
- const tp = new TextProtoReader(r);
- let finished = false;
- const chunks: Array<{
- offset: number;
- data: Uint8Array;
- }> = [];
- async function read(buf: Uint8Array): Promise<number | null> {
- if (finished) return null;
- const [chunk] = chunks;
- if (chunk) {
- const chunkRemaining = chunk.data.byteLength - chunk.offset;
- const readLength = Math.min(chunkRemaining, buf.byteLength);
- for (let i = 0; i < readLength; i++) {
- buf[i] = chunk.data[chunk.offset + i];
- }
- chunk.offset += readLength;
- if (chunk.offset === chunk.data.byteLength) {
- chunks.shift();
- // Consume \r\n;
- if ((await tp.readLine()) === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- }
- return readLength;
- }
- const line = await tp.readLine();
- if (line === null) throw new Deno.errors.UnexpectedEof();
- // TODO(bartlomieju): handle chunk extension
- const [chunkSizeString] = line.split(";");
- const chunkSize = parseInt(chunkSizeString, 16);
- if (Number.isNaN(chunkSize) || chunkSize < 0) {
- throw new Deno.errors.InvalidData("Invalid chunk size");
- }
- if (chunkSize > 0) {
- if (chunkSize > buf.byteLength) {
- let eof = await r.readFull(buf);
- if (eof === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- const restChunk = new Uint8Array(chunkSize - buf.byteLength);
- eof = await r.readFull(restChunk);
- if (eof === null) {
- throw new Deno.errors.UnexpectedEof();
- } else {
- chunks.push({
- offset: 0,
- data: restChunk,
- });
- }
- return buf.byteLength;
- } else {
- const bufToFill = buf.subarray(0, chunkSize);
- const eof = await r.readFull(bufToFill);
- if (eof === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- // Consume \r\n
- if ((await tp.readLine()) === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- return chunkSize;
- }
- } else {
- assert(chunkSize === 0);
- // Consume \r\n
- if ((await r.readLine()) === null) {
- throw new Deno.errors.UnexpectedEof();
- }
- await readTrailers(h, r);
- finished = true;
- return null;
- }
- }
- return { read };
-}
-
-async function readTrailers(
- headers: Headers,
- r: BufReader,
-) {
- const trailers = parseTrailer(headers.get("trailer"));
- if (trailers == null) return;
- const trailerNames = [...trailers.keys()];
- const tp = new TextProtoReader(r);
- const result = await tp.readMimeHeader();
- if (result == null) {
- throw new Deno.errors.InvalidData("Missing trailer header.");
- }
- const undeclared = [...result.keys()].filter(
- (k) => !trailerNames.includes(k),
- );
- if (undeclared.length > 0) {
- throw new Deno.errors.InvalidData(
- `Undeclared trailers: ${Deno.inspect(undeclared)}.`,
- );
- }
- for (const [k, v] of result) {
- headers.append(k, v);
- }
- const missingTrailers = trailerNames.filter((k) => !result.has(k));
- if (missingTrailers.length > 0) {
- throw new Deno.errors.InvalidData(
- `Missing trailers: ${Deno.inspect(missingTrailers)}.`,
- );
- }
- headers.delete("trailer");
-}
-
-function parseTrailer(field: string | null): Headers | undefined {
- if (field == null) {
- return undefined;
- }
- const trailerNames = field.split(",").map((v) => v.trim().toLowerCase());
- if (trailerNames.length === 0) {
- throw new Deno.errors.InvalidData("Empty trailer header.");
- }
- const prohibited = trailerNames.filter((k) => isProhibitedForTrailer(k));
- if (prohibited.length > 0) {
- throw new Deno.errors.InvalidData(
- `Prohibited trailer names: ${Deno.inspect(prohibited)}.`,
- );
- }
- return new Headers(trailerNames.map((key) => [key, ""]));
-}
-
-function isProhibitedForTrailer(key: string): boolean {
- const s = new Set(["transfer-encoding", "content-length", "trailer"]);
- return s.has(key.toLowerCase());
-}
-
-// TODO(mmastrac): curl on Windows CI stopped supporting --http2?
-Deno.test(
- {
- permissions: { net: true, run: true },
- ignore: Deno.build.os === "windows",
- },
- async function httpServeCurlH2C() {
- const ac = new AbortController();
- const server = Deno.serve(
- { port: servePort, signal: ac.signal },
- () => new Response("hello world!"),
- );
-
- assertEquals(
- "hello world!",
- await curlRequest([`http://localhost:${servePort}/path`]),
- );
- assertEquals(
- "hello world!",
- await curlRequest([`http://localhost:${servePort}/path`, "--http2"]),
- );
- assertEquals(
- "hello world!",
- await curlRequest([
- `http://localhost:${servePort}/path`,
- "--http2",
- "--http2-prior-knowledge",
- ]),
- );
-
- ac.abort();
- await server.finished;
- },
-);
-
-// TODO(mmastrac): This test should eventually use fetch, when we support trailers there.
-// This test is ignored because it's flaky and relies on cURL's verbose output.
-Deno.test(
- { permissions: { net: true, run: true, read: true }, ignore: true },
- async function httpServerTrailers() {
- const ac = new AbortController();
- const { resolve } = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: () => {
- const response = new Response("Hello World", {
- headers: {
- "trailer": "baz",
- "transfer-encoding": "chunked",
- "foo": "bar",
- },
- });
- addTrailers(response, [["baz", "why"]]);
- return response;
- },
- port: servePort,
- signal: ac.signal,
- onListen: onListen(resolve),
- onError: createOnErrorCb(ac),
- });
-
- // We don't have a great way to access this right now, so just fetch the trailers with cURL
- const [_, stderr] = await curlRequestWithStdErr([
- `http://localhost:${servePort}/path`,
- "-v",
- "--http2",
- "--http2-prior-knowledge",
- ]);
- assertMatch(stderr, /baz: why/);
- ac.abort();
- await server.finished;
- },
-);
-
-// TODO(mmastrac): curl on CI stopped supporting --http2?
-Deno.test(
- {
- permissions: {
- net: true,
- run: true,
- read: true,
- },
- ignore: Deno.build.os === "windows",
- },
- async function httpsServeCurlH2C() {
- const ac = new AbortController();
- const server = Deno.serve(
- {
- signal: ac.signal,
- port: servePort,
- cert: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.crt"),
- key: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.key"),
- },
- () => new Response("hello world!"),
- );
-
- assertEquals(
- "hello world!",
- await curlRequest([`https://localhost:${servePort}/path`, "-k"]),
- );
- assertEquals(
- "hello world!",
- await curlRequest([
- `https://localhost:${servePort}/path`,
- "-k",
- "--http2",
- ]),
- );
- assertEquals(
- "hello world!",
- await curlRequest([
- `https://localhost:${servePort}/path`,
- "-k",
- "--http2",
- "--http2-prior-knowledge",
- ]),
- );
-
- ac.abort();
- await server.finished;
- },
-);
-
-async function curlRequest(args: string[]) {
- const { success, stdout, stderr } = await new Deno.Command("curl", {
- args,
- stdout: "piped",
- stderr: "piped",
- }).output();
- assert(
- success,
- `Failed to cURL ${args}: stdout\n\n${stdout}\n\nstderr:\n\n${stderr}`,
- );
- return new TextDecoder().decode(stdout);
-}
-
-async function curlRequestWithStdErr(args: string[]) {
- const { success, stdout, stderr } = await new Deno.Command("curl", {
- args,
- stdout: "piped",
- stderr: "piped",
- }).output();
- assert(
- success,
- `Failed to cURL ${args}: stdout\n\n${stdout}\n\nstderr:\n\n${stderr}`,
- );
- return [new TextDecoder().decode(stdout), new TextDecoder().decode(stderr)];
-}
-
-Deno.test("Deno.HttpServer is not thenable", async () => {
- // deno-lint-ignore require-await
- async function serveTest() {
- const server = Deno.serve({ port: servePort }, (_) => new Response(""));
- assert(!("then" in server));
- return server;
- }
- const server = await serveTest();
- await server.shutdown();
-});
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { run: true, read: true, write: true },
- },
- async function httpServerUnixDomainSocket() {
- const { promise, resolve } = Promise.withResolvers<{ path: string }>();
- const ac = new AbortController();
- const filePath = tmpUnixSocketPath();
- const server = Deno.serve(
- {
- signal: ac.signal,
- path: filePath,
- onListen(info) {
- resolve(info);
- },
- onError: createOnErrorCb(ac),
- },
- (_req, { remoteAddr }) => {
- assertEquals(remoteAddr, { path: filePath, transport: "unix" });
- return new Response("hello world!");
- },
- );
-
- assertEquals(await promise, { path: filePath });
- assertEquals(
- "hello world!",
- await curlRequest(["--unix-socket", filePath, "http://localhost"]),
- );
- ac.abort();
- await server.finished;
- },
-);
-
-// serve Handler must return Response class or promise that resolves Response class
-Deno.test(
- { permissions: { net: true, run: true } },
- async function handleServeCallbackReturn() {
- const deferred = Promise.withResolvers<void>();
- const listeningDeferred = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve(
- {
- port: servePort,
- onListen: onListen(listeningDeferred.resolve),
- signal: ac.signal,
- onError: (error) => {
- assert(error instanceof TypeError);
- assert(
- error.message ===
- "Return value from serve handler must be a response or a promise resolving to a response",
- );
- deferred.resolve();
- return new Response("Customized Internal Error from onError");
- },
- },
- () => {
- // Trick the typechecker
- return <Response> <unknown> undefined;
- },
- );
- await listeningDeferred.promise;
- const respText = await curlRequest([`http://localhost:${servePort}`]);
- await deferred.promise;
- ac.abort();
- await server.finished;
- assert(respText === "Customized Internal Error from onError");
- },
-);
-
-// onError Handler must return Response class or promise that resolves Response class
-Deno.test(
- { permissions: { net: true, run: true } },
- async function handleServeErrorCallbackReturn() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ac = new AbortController();
-
- const server = Deno.serve(
- {
- port: servePort,
- onListen: onListen(resolve),
- signal: ac.signal,
- onError: () => {
- // Trick the typechecker
- return <Response> <unknown> undefined;
- },
- },
- () => {
- // Trick the typechecker
- return <Response> <unknown> undefined;
- },
- );
- await promise;
- const respText = await curlRequest([`http://localhost:${servePort}`]);
- ac.abort();
- await server.finished;
- assert(respText === "Internal Server Error");
- },
-);
diff --git a/cli/tests/unit/signal_test.ts b/cli/tests/unit/signal_test.ts
deleted file mode 100644
index 2ba2ffb15..000000000
--- a/cli/tests/unit/signal_test.ts
+++ /dev/null
@@ -1,296 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertThrows, delay } from "./test_util.ts";
-
-Deno.test(
- { ignore: Deno.build.os !== "windows" },
- function signalsNotImplemented() {
- const msg =
- "Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK).";
- assertThrows(
- () => {
- Deno.addSignalListener("SIGALRM", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => {
- Deno.addSignalListener("SIGCHLD", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => {
- Deno.addSignalListener("SIGHUP", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => {
- Deno.addSignalListener("SIGIO", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => {
- Deno.addSignalListener("SIGPIPE", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => {
- Deno.addSignalListener("SIGQUIT", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => {
- Deno.addSignalListener("SIGTERM", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => {
- Deno.addSignalListener("SIGUSR1", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => {
- Deno.addSignalListener("SIGUSR2", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => {
- Deno.addSignalListener("SIGWINCH", () => {});
- },
- Error,
- msg,
- );
- assertThrows(
- () => Deno.addSignalListener("SIGKILL", () => {}),
- Error,
- msg,
- );
- assertThrows(
- () => Deno.addSignalListener("SIGSTOP", () => {}),
- Error,
- msg,
- );
- assertThrows(
- () => Deno.addSignalListener("SIGILL", () => {}),
- Error,
- msg,
- );
- assertThrows(
- () => Deno.addSignalListener("SIGFPE", () => {}),
- Error,
- msg,
- );
- assertThrows(
- () => Deno.addSignalListener("SIGSEGV", () => {}),
- Error,
- msg,
- );
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { run: true },
- },
- async function signalListenerTest() {
- let c = 0;
- const listener = () => {
- c += 1;
- };
- // This test needs to be careful that it doesn't accidentally aggregate multiple
- // signals into one. Sending two or more SIGxxx before the handler can be run will
- // result in signal coalescing.
- Deno.addSignalListener("SIGUSR1", listener);
- // Sends SIGUSR1 3 times.
- for (let i = 1; i <= 3; i++) {
- await delay(1);
- Deno.kill(Deno.pid, "SIGUSR1");
- while (c < i) {
- await delay(20);
- }
- }
- Deno.removeSignalListener("SIGUSR1", listener);
- await delay(100);
- assertEquals(c, 3);
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { run: true },
- },
- async function multipleSignalListenerTest() {
- let c = "";
- const listener0 = () => {
- c += "0";
- };
- const listener1 = () => {
- c += "1";
- };
- // This test needs to be careful that it doesn't accidentally aggregate multiple
- // signals into one. Sending two or more SIGxxx before the handler can be run will
- // result in signal coalescing.
- Deno.addSignalListener("SIGUSR2", listener0);
- Deno.addSignalListener("SIGUSR2", listener1);
-
- // Sends SIGUSR2 3 times.
- for (let i = 1; i <= 3; i++) {
- await delay(1);
- Deno.kill(Deno.pid, "SIGUSR2");
- while (c.length < i * 2) {
- await delay(20);
- }
- }
-
- Deno.removeSignalListener("SIGUSR2", listener1);
-
- // Sends SIGUSR2 3 times.
- for (let i = 1; i <= 3; i++) {
- await delay(1);
- Deno.kill(Deno.pid, "SIGUSR2");
- while (c.length < 6 + i) {
- await delay(20);
- }
- }
-
- // Sends SIGUSR1 (irrelevant signal) 3 times.
- for (const _ of Array(3)) {
- await delay(20);
- Deno.kill(Deno.pid, "SIGUSR1");
- }
-
- // No change
- assertEquals(c, "010101000");
-
- Deno.removeSignalListener("SIGUSR2", listener0);
-
- await delay(100);
-
- // The first 3 events are handled by both handlers
- // The last 3 events are handled only by handler0
- assertEquals(c, "010101000");
- },
-);
-
-// This tests that pending op_signal_poll doesn't block the runtime from exiting the process.
-Deno.test(
- {
- permissions: { run: true, read: true },
- },
- async function canExitWhileListeningToSignal() {
- const { code } = await new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "--unstable",
- "Deno.addSignalListener('SIGINT', () => {})",
- ],
- }).output();
- assertEquals(code, 0);
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os !== "windows",
- permissions: { run: true },
- },
- function windowsThrowsOnNegativeProcessIdTest() {
- assertThrows(
- () => {
- Deno.kill(-1, "SIGKILL");
- },
- TypeError,
- "Invalid pid",
- );
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os !== "windows",
- permissions: { run: true },
- },
- function noOpenSystemIdleProcessTest() {
- let signal: Deno.Signal = "SIGKILL";
-
- assertThrows(
- () => {
- Deno.kill(0, signal);
- },
- TypeError,
- `Invalid pid`,
- );
-
- signal = "SIGTERM";
- assertThrows(
- () => {
- Deno.kill(0, signal);
- },
- TypeError,
- `Invalid pid`,
- );
- },
-);
-
-Deno.test(function signalInvalidHandlerTest() {
- assertThrows(() => {
- // deno-lint-ignore no-explicit-any
- Deno.addSignalListener("SIGINT", "handler" as any);
- });
- assertThrows(() => {
- // deno-lint-ignore no-explicit-any
- Deno.removeSignalListener("SIGINT", "handler" as any);
- });
-});
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { run: true },
- },
- function signalForbiddenSignalTest() {
- assertThrows(
- () => Deno.addSignalListener("SIGKILL", () => {}),
- TypeError,
- "Binding to signal 'SIGKILL' is not allowed",
- );
- assertThrows(
- () => Deno.addSignalListener("SIGSTOP", () => {}),
- TypeError,
- "Binding to signal 'SIGSTOP' is not allowed",
- );
- assertThrows(
- () => Deno.addSignalListener("SIGILL", () => {}),
- TypeError,
- "Binding to signal 'SIGILL' is not allowed",
- );
- assertThrows(
- () => Deno.addSignalListener("SIGFPE", () => {}),
- TypeError,
- "Binding to signal 'SIGFPE' is not allowed",
- );
- assertThrows(
- () => Deno.addSignalListener("SIGSEGV", () => {}),
- TypeError,
- "Binding to signal 'SIGSEGV' is not allowed",
- );
- },
-);
diff --git a/cli/tests/unit/stat_test.ts b/cli/tests/unit/stat_test.ts
deleted file mode 100644
index ccb17b164..000000000
--- a/cli/tests/unit/stat_test.ts
+++ /dev/null
@@ -1,342 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
- pathToAbsoluteFileUrl,
-} from "./test_util.ts";
-
-Deno.test({ permissions: { read: true } }, function fstatSyncSuccess() {
- using file = Deno.openSync("README.md");
- const fileInfo = Deno.fstatSync(file.rid);
- assert(fileInfo.isFile);
- assert(!fileInfo.isSymlink);
- assert(!fileInfo.isDirectory);
- assert(fileInfo.size);
- assert(fileInfo.atime);
- assert(fileInfo.mtime);
- // The `birthtime` field is not available on Linux before kernel version 4.11.
- assert(fileInfo.birthtime || Deno.build.os === "linux");
-});
-
-Deno.test({ permissions: { read: true } }, async function fstatSuccess() {
- using file = await Deno.open("README.md");
- const fileInfo = await Deno.fstat(file.rid);
- assert(fileInfo.isFile);
- assert(!fileInfo.isSymlink);
- assert(!fileInfo.isDirectory);
- assert(fileInfo.size);
- assert(fileInfo.atime);
- assert(fileInfo.mtime);
- // The `birthtime` field is not available on Linux before kernel version 4.11.
- assert(fileInfo.birthtime || Deno.build.os === "linux");
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function statSyncSuccess() {
- const readmeInfo = Deno.statSync("README.md");
- assert(readmeInfo.isFile);
- assert(!readmeInfo.isSymlink);
-
- const modulesInfo = Deno.statSync("cli/tests/testdata/symlink_to_subdir");
- assert(modulesInfo.isDirectory);
- assert(!modulesInfo.isSymlink);
-
- const testsInfo = Deno.statSync("cli/tests");
- assert(testsInfo.isDirectory);
- assert(!testsInfo.isSymlink);
-
- const tempFile = Deno.makeTempFileSync();
- const tempInfo = Deno.statSync(tempFile);
- let now = Date.now();
- assert(tempInfo.atime !== null && now - tempInfo.atime.valueOf() < 1000);
- assert(tempInfo.mtime !== null && now - tempInfo.mtime.valueOf() < 1000);
- assert(
- tempInfo.birthtime === null || now - tempInfo.birthtime.valueOf() < 1000,
- );
-
- const readmeInfoByUrl = Deno.statSync(pathToAbsoluteFileUrl("README.md"));
- assert(readmeInfoByUrl.isFile);
- assert(!readmeInfoByUrl.isSymlink);
-
- const modulesInfoByUrl = Deno.statSync(
- pathToAbsoluteFileUrl("cli/tests/testdata/symlink_to_subdir"),
- );
- assert(modulesInfoByUrl.isDirectory);
- assert(!modulesInfoByUrl.isSymlink);
-
- const testsInfoByUrl = Deno.statSync(pathToAbsoluteFileUrl("cli/tests"));
- assert(testsInfoByUrl.isDirectory);
- assert(!testsInfoByUrl.isSymlink);
-
- const tempFileForUrl = Deno.makeTempFileSync();
- const tempInfoByUrl = Deno.statSync(
- new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempFileForUrl}`,
- ),
- );
- now = Date.now();
- assert(
- tempInfoByUrl.atime !== null &&
- now - tempInfoByUrl.atime.valueOf() < 1000,
- );
- assert(
- tempInfoByUrl.mtime !== null &&
- now - tempInfoByUrl.mtime.valueOf() < 1000,
- );
- assert(
- tempInfoByUrl.birthtime === null ||
- now - tempInfoByUrl.birthtime.valueOf() < 1000,
- );
-
- Deno.removeSync(tempFile, { recursive: true });
- Deno.removeSync(tempFileForUrl, { recursive: true });
- },
-);
-
-Deno.test({ permissions: { read: false } }, function statSyncPerm() {
- assertThrows(() => {
- Deno.statSync("README.md");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function statSyncNotFound() {
- assertThrows(
- () => {
- Deno.statSync("bad_file_name");
- },
- Deno.errors.NotFound,
- `stat 'bad_file_name'`,
- );
-});
-
-Deno.test({ permissions: { read: true } }, function lstatSyncSuccess() {
- const packageInfo = Deno.lstatSync("README.md");
- assert(packageInfo.isFile);
- assert(!packageInfo.isSymlink);
-
- const packageInfoByUrl = Deno.lstatSync(pathToAbsoluteFileUrl("README.md"));
- assert(packageInfoByUrl.isFile);
- assert(!packageInfoByUrl.isSymlink);
-
- const modulesInfo = Deno.lstatSync("cli/tests/testdata/symlink_to_subdir");
- assert(!modulesInfo.isDirectory);
- assert(modulesInfo.isSymlink);
-
- const modulesInfoByUrl = Deno.lstatSync(
- pathToAbsoluteFileUrl("cli/tests/testdata/symlink_to_subdir"),
- );
- assert(!modulesInfoByUrl.isDirectory);
- assert(modulesInfoByUrl.isSymlink);
-
- const coreInfo = Deno.lstatSync("cli");
- assert(coreInfo.isDirectory);
- assert(!coreInfo.isSymlink);
-
- const coreInfoByUrl = Deno.lstatSync(pathToAbsoluteFileUrl("cli"));
- assert(coreInfoByUrl.isDirectory);
- assert(!coreInfoByUrl.isSymlink);
-});
-
-Deno.test({ permissions: { read: false } }, function lstatSyncPerm() {
- assertThrows(() => {
- Deno.lstatSync("assets/hello.txt");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, function lstatSyncNotFound() {
- assertThrows(
- () => {
- Deno.lstatSync("bad_file_name");
- },
- Deno.errors.NotFound,
- `stat 'bad_file_name'`,
- );
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function statSuccess() {
- const readmeInfo = await Deno.stat("README.md");
- assert(readmeInfo.isFile);
- assert(!readmeInfo.isSymlink);
-
- const readmeInfoByUrl = await Deno.stat(
- pathToAbsoluteFileUrl("README.md"),
- );
- assert(readmeInfoByUrl.isFile);
- assert(!readmeInfoByUrl.isSymlink);
-
- const modulesInfo = await Deno.stat("cli/tests/testdata/symlink_to_subdir");
- assert(modulesInfo.isDirectory);
- assert(!modulesInfo.isSymlink);
-
- const modulesInfoByUrl = await Deno.stat(
- pathToAbsoluteFileUrl("cli/tests/testdata/symlink_to_subdir"),
- );
- assert(modulesInfoByUrl.isDirectory);
- assert(!modulesInfoByUrl.isSymlink);
-
- const testsInfo = await Deno.stat("cli/tests");
- assert(testsInfo.isDirectory);
- assert(!testsInfo.isSymlink);
-
- const testsInfoByUrl = await Deno.stat(pathToAbsoluteFileUrl("cli/tests"));
- assert(testsInfoByUrl.isDirectory);
- assert(!testsInfoByUrl.isSymlink);
-
- const tempFile = await Deno.makeTempFile();
- const tempInfo = await Deno.stat(tempFile);
- let now = Date.now();
- assert(tempInfo.atime !== null && now - tempInfo.atime.valueOf() < 1000);
- assert(tempInfo.mtime !== null && now - tempInfo.mtime.valueOf() < 1000);
-
- assert(
- tempInfo.birthtime === null || now - tempInfo.birthtime.valueOf() < 1000,
- );
-
- const tempFileForUrl = await Deno.makeTempFile();
- const tempInfoByUrl = await Deno.stat(
- new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempFileForUrl}`,
- ),
- );
- now = Date.now();
- assert(
- tempInfoByUrl.atime !== null &&
- now - tempInfoByUrl.atime.valueOf() < 1000,
- );
- assert(
- tempInfoByUrl.mtime !== null &&
- now - tempInfoByUrl.mtime.valueOf() < 1000,
- );
- assert(
- tempInfoByUrl.birthtime === null ||
- now - tempInfoByUrl.birthtime.valueOf() < 1000,
- );
-
- Deno.removeSync(tempFile, { recursive: true });
- Deno.removeSync(tempFileForUrl, { recursive: true });
- },
-);
-
-Deno.test({ permissions: { read: false } }, async function statPerm() {
- await assertRejects(async () => {
- await Deno.stat("README.md");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, async function statNotFound() {
- await assertRejects(
- async () => {
- await Deno.stat("bad_file_name");
- },
- Deno.errors.NotFound,
- `stat 'bad_file_name'`,
- );
-});
-
-Deno.test({ permissions: { read: true } }, async function lstatSuccess() {
- const readmeInfo = await Deno.lstat("README.md");
- assert(readmeInfo.isFile);
- assert(!readmeInfo.isSymlink);
-
- const readmeInfoByUrl = await Deno.lstat(pathToAbsoluteFileUrl("README.md"));
- assert(readmeInfoByUrl.isFile);
- assert(!readmeInfoByUrl.isSymlink);
-
- const modulesInfo = await Deno.lstat("cli/tests/testdata/symlink_to_subdir");
- assert(!modulesInfo.isDirectory);
- assert(modulesInfo.isSymlink);
-
- const modulesInfoByUrl = await Deno.lstat(
- pathToAbsoluteFileUrl("cli/tests/testdata/symlink_to_subdir"),
- );
- assert(!modulesInfoByUrl.isDirectory);
- assert(modulesInfoByUrl.isSymlink);
-
- const coreInfo = await Deno.lstat("cli");
- assert(coreInfo.isDirectory);
- assert(!coreInfo.isSymlink);
-
- const coreInfoByUrl = await Deno.lstat(pathToAbsoluteFileUrl("cli"));
- assert(coreInfoByUrl.isDirectory);
- assert(!coreInfoByUrl.isSymlink);
-});
-
-Deno.test({ permissions: { read: false } }, async function lstatPerm() {
- await assertRejects(async () => {
- await Deno.lstat("README.md");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { read: true } }, async function lstatNotFound() {
- await assertRejects(
- async () => {
- await Deno.lstat("bad_file_name");
- },
- Deno.errors.NotFound,
- `stat 'bad_file_name'`,
- );
-});
-
-Deno.test(
- {
- ignore: Deno.build.os !== "windows",
- permissions: { read: true, write: true },
- },
- function statNoUnixFields() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = Deno.makeTempDirSync();
- const filename = tempDir + "/test.txt";
- Deno.writeFileSync(filename, data, { mode: 0o666 });
- const s = Deno.statSync(filename);
- assert(s.dev !== 0);
- assert(s.ino === null);
- assert(s.mode === null);
- assert(s.nlink === null);
- assert(s.uid === null);
- assert(s.gid === null);
- assert(s.rdev === null);
- assert(s.blksize === null);
- assert(s.blocks === null);
- assert(s.isBlockDevice === null);
- assert(s.isCharDevice === null);
- assert(s.isFifo === null);
- assert(s.isSocket === null);
- },
-);
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- permissions: { read: true, write: true },
- },
- function statUnixFields() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = Deno.makeTempDirSync();
- const filename = tempDir + "/test.txt";
- const filename2 = tempDir + "/test2.txt";
- Deno.writeFileSync(filename, data, { mode: 0o666 });
- // Create a link
- Deno.linkSync(filename, filename2);
- const s = Deno.statSync(filename);
- assert(s.dev !== null);
- assert(s.ino !== null);
- assertEquals(s.mode! & 0o666, 0o666);
- assertEquals(s.nlink, 2);
- assert(s.uid !== null);
- assert(s.gid !== null);
- assert(s.rdev !== null);
- assert(s.blksize !== null);
- assert(s.blocks !== null);
- assert(!s.isBlockDevice);
- assert(!s.isCharDevice);
- assert(!s.isFifo);
- assert(!s.isSocket);
- },
-);
diff --git a/cli/tests/unit/stdio_test.ts b/cli/tests/unit/stdio_test.ts
deleted file mode 100644
index d24fdc8ef..000000000
--- a/cli/tests/unit/stdio_test.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-Deno.test(async function stdioStdinRead() {
- const nread = await Deno.stdin.read(new Uint8Array(0));
- assertEquals(nread, 0);
-});
-
-Deno.test(function stdioStdinReadSync() {
- const nread = Deno.stdin.readSync(new Uint8Array(0));
- assertEquals(nread, 0);
-});
-
-Deno.test(async function stdioStdoutWrite() {
- const nwritten = await Deno.stdout.write(new Uint8Array(0));
- assertEquals(nwritten, 0);
-});
-
-Deno.test(function stdioStdoutWriteSync() {
- const nwritten = Deno.stdout.writeSync(new Uint8Array(0));
- assertEquals(nwritten, 0);
-});
-
-Deno.test(async function stdioStderrWrite() {
- const nwritten = await Deno.stderr.write(new Uint8Array(0));
- assertEquals(nwritten, 0);
-});
-
-Deno.test(function stdioStderrWriteSync() {
- const nwritten = Deno.stderr.writeSync(new Uint8Array(0));
- assertEquals(nwritten, 0);
-});
diff --git a/cli/tests/unit/streams_test.ts b/cli/tests/unit/streams_test.ts
deleted file mode 100644
index 6db9f666c..000000000
--- a/cli/tests/unit/streams_test.ts
+++ /dev/null
@@ -1,478 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, fail } from "./test_util.ts";
-
-const {
- core,
- resourceForReadableStream,
- // @ts-expect-error TypeScript (as of 3.7) does not support indexing namespaces by symbol
-} = Deno[Deno.internal];
-
-const LOREM =
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
-
-// Hello world, with optional close
-function helloWorldStream(
- close?: boolean,
- cancelResolve?: (value: unknown) => void,
-) {
- return new ReadableStream({
- start(controller) {
- controller.enqueue("hello, world");
- if (close == true) {
- controller.close();
- }
- },
- cancel(reason) {
- if (cancelResolve != undefined) {
- cancelResolve(reason);
- }
- },
- }).pipeThrough(new TextEncoderStream());
-}
-
-// Hello world, with optional close
-function errorStream(type: "string" | "controller" | "TypeError") {
- return new ReadableStream({
- start(controller) {
- controller.enqueue("hello, world");
- },
- pull(controller) {
- if (type == "string") {
- throw "Uh oh (string)!";
- }
- if (type == "TypeError") {
- throw TypeError("Uh oh (TypeError)!");
- }
- controller.error("Uh oh (controller)!");
- },
- }).pipeThrough(new TextEncoderStream());
-}
-
-// Long stream with Lorem Ipsum text.
-function longStream() {
- return new ReadableStream({
- start(controller) {
- for (let i = 0; i < 4; i++) {
- setTimeout(() => {
- controller.enqueue(LOREM);
- if (i == 3) {
- controller.close();
- }
- }, i * 100);
- }
- },
- }).pipeThrough(new TextEncoderStream());
-}
-
-// Long stream with Lorem Ipsum text.
-function longAsyncStream(cancelResolve?: (value: unknown) => void) {
- let currentTimeout: number | undefined = undefined;
- return new ReadableStream({
- async start(controller) {
- for (let i = 0; i < 100; i++) {
- await new Promise((r) => currentTimeout = setTimeout(r, 1));
- currentTimeout = undefined;
- controller.enqueue(LOREM);
- }
- controller.close();
- },
- cancel(reason) {
- if (cancelResolve != undefined) {
- cancelResolve(reason);
- }
- if (currentTimeout !== undefined) {
- clearTimeout(currentTimeout);
- }
- },
- }).pipeThrough(new TextEncoderStream());
-}
-
-// Empty stream, closes either immediately or on a call to pull.
-function emptyStream(onPull: boolean) {
- return new ReadableStream({
- start(controller) {
- if (!onPull) {
- controller.close();
- }
- },
- pull(controller) {
- if (onPull) {
- controller.close();
- }
- },
- }).pipeThrough(new TextEncoderStream());
-}
-
-function largePacketStream(packetSize: number, count: number) {
- return new ReadableStream({
- pull(controller) {
- if (count-- > 0) {
- const buffer = new Uint8Array(packetSize);
- for (let i = 0; i < 256; i++) {
- buffer[i * (packetSize / 256)] = i;
- }
- controller.enqueue(buffer);
- } else {
- controller.close();
- }
- },
- });
-}
-
-// Include an empty chunk
-function emptyChunkStream() {
- return new ReadableStream({
- start(controller) {
- controller.enqueue(new Uint8Array([1]));
- controller.enqueue(new Uint8Array([]));
- controller.enqueue(new Uint8Array([2]));
- controller.close();
- },
- });
-}
-
-// Try to blow up any recursive reads.
-function veryLongTinyPacketStream(length: number) {
- return new ReadableStream({
- start(controller) {
- for (let i = 0; i < length; i++) {
- controller.enqueue(new Uint8Array([1]));
- }
- controller.close();
- },
- });
-}
-
-// Creates a stream with the given number of packets, a configurable delay between packets, and a final
-// action (either "Throw" or "Close").
-function makeStreamWithCount(
- count: number,
- delay: number,
- action: "Throw" | "Close",
-): ReadableStream {
- function doAction(controller: ReadableStreamDefaultController, i: number) {
- if (i == count) {
- if (action == "Throw") {
- controller.error(new Error("Expected error!"));
- } else {
- controller.close();
- }
- } else {
- controller.enqueue(String.fromCharCode("a".charCodeAt(0) + i));
-
- if (delay == 0) {
- doAction(controller, i + 1);
- } else {
- setTimeout(() => doAction(controller, i + 1), delay);
- }
- }
- }
-
- return new ReadableStream({
- start(controller) {
- if (delay == 0) {
- doAction(controller, 0);
- } else {
- setTimeout(() => doAction(controller, 0), delay);
- }
- },
- }).pipeThrough(new TextEncoderStream());
-}
-
-// Normal stream operation
-Deno.test(async function readableStream() {
- const rid = resourceForReadableStream(helloWorldStream());
- const buffer = new Uint8Array(1024);
- const nread = await core.read(rid, buffer);
- assertEquals(nread, 12);
- core.close(rid);
-});
-
-// Close the stream after reading everything
-Deno.test(async function readableStreamClose() {
- const cancel = Promise.withResolvers();
- const rid = resourceForReadableStream(
- helloWorldStream(false, cancel.resolve),
- );
- const buffer = new Uint8Array(1024);
- const nread = await core.read(rid, buffer);
- assertEquals(nread, 12);
- core.close(rid);
- assertEquals(await cancel.promise, "resource closed");
-});
-
-// Close the stream without reading everything
-Deno.test(async function readableStreamClosePartialRead() {
- const cancel = Promise.withResolvers();
- const rid = resourceForReadableStream(
- helloWorldStream(false, cancel.resolve),
- );
- const buffer = new Uint8Array(5);
- const nread = await core.read(rid, buffer);
- assertEquals(nread, 5);
- core.close(rid);
- assertEquals(await cancel.promise, "resource closed");
-});
-
-// Close the stream without reading anything
-Deno.test(async function readableStreamCloseWithoutRead() {
- const cancel = Promise.withResolvers();
- const rid = resourceForReadableStream(
- helloWorldStream(false, cancel.resolve),
- );
- core.close(rid);
- assertEquals(await cancel.promise, "resource closed");
-});
-
-// Close the stream without reading anything
-Deno.test(async function readableStreamCloseWithoutRead2() {
- const cancel = Promise.withResolvers();
- const rid = resourceForReadableStream(longAsyncStream(cancel.resolve));
- core.close(rid);
- assertEquals(await cancel.promise, "resource closed");
-});
-
-Deno.test(async function readableStreamPartial() {
- const rid = resourceForReadableStream(helloWorldStream());
- const buffer = new Uint8Array(5);
- const nread = await core.read(rid, buffer);
- assertEquals(nread, 5);
- const buffer2 = new Uint8Array(1024);
- const nread2 = await core.read(rid, buffer2);
- assertEquals(nread2, 7);
- core.close(rid);
-});
-
-Deno.test(async function readableStreamLongReadAll() {
- const rid = resourceForReadableStream(longStream());
- const buffer = await core.readAll(rid);
- assertEquals(buffer.length, LOREM.length * 4);
- core.close(rid);
-});
-
-Deno.test(async function readableStreamLongAsyncReadAll() {
- const rid = resourceForReadableStream(longAsyncStream());
- const buffer = await core.readAll(rid);
- assertEquals(buffer.length, LOREM.length * 100);
- core.close(rid);
-});
-
-Deno.test(async function readableStreamVeryLongReadAll() {
- const rid = resourceForReadableStream(veryLongTinyPacketStream(1_000_000));
- const buffer = await core.readAll(rid);
- assertEquals(buffer.length, 1_000_000);
- core.close(rid);
-});
-
-Deno.test(async function readableStreamLongByPiece() {
- const rid = resourceForReadableStream(longStream());
- let total = 0;
- for (let i = 0; i < 100; i++) {
- const length = await core.read(rid, new Uint8Array(16));
- total += length;
- if (length == 0) {
- break;
- }
- }
- assertEquals(total, LOREM.length * 4);
- core.close(rid);
-});
-
-for (
- const type of [
- "string",
- "TypeError",
- "controller",
- ] as ("string" | "TypeError" | "controller")[]
-) {
- Deno.test(`readableStreamError_${type}`, async function () {
- const rid = resourceForReadableStream(errorStream(type));
- let nread;
- try {
- nread = await core.read(rid, new Uint8Array(16));
- } catch (_) {
- fail("Should not have thrown");
- }
- assertEquals(12, nread);
- try {
- await core.read(rid, new Uint8Array(1));
- fail();
- } catch (e) {
- assertEquals(e.message, `Uh oh (${type})!`);
- }
- core.close(rid);
- });
-}
-
-Deno.test(async function readableStreamEmptyOnStart() {
- const rid = resourceForReadableStream(emptyStream(true));
- const buffer = new Uint8Array(1024);
- const nread = await core.read(rid, buffer);
- assertEquals(nread, 0);
- core.close(rid);
-});
-
-Deno.test(async function readableStreamEmptyOnPull() {
- const rid = resourceForReadableStream(emptyStream(false));
- const buffer = new Uint8Array(1024);
- const nread = await core.read(rid, buffer);
- assertEquals(nread, 0);
- core.close(rid);
-});
-
-Deno.test(async function readableStreamEmptyReadAll() {
- const rid = resourceForReadableStream(emptyStream(false));
- const buffer = await core.readAll(rid);
- assertEquals(buffer.length, 0);
- core.close(rid);
-});
-
-Deno.test(async function readableStreamWithEmptyChunk() {
- const rid = resourceForReadableStream(emptyChunkStream());
- const buffer = await core.readAll(rid);
- assertEquals(buffer, new Uint8Array([1, 2]));
- core.close(rid);
-});
-
-Deno.test(async function readableStreamWithEmptyChunkOneByOne() {
- const rid = resourceForReadableStream(emptyChunkStream());
- assertEquals(1, await core.read(rid, new Uint8Array(1)));
- assertEquals(1, await core.read(rid, new Uint8Array(1)));
- assertEquals(0, await core.read(rid, new Uint8Array(1)));
- core.close(rid);
-});
-
-// Ensure that we correctly transmit all the sub-chunks of the larger chunks.
-Deno.test(async function readableStreamReadSmallerChunks() {
- const packetSize = 16 * 1024;
- const rid = resourceForReadableStream(largePacketStream(packetSize, 1));
- const buffer = new Uint8Array(packetSize);
- for (let i = 0; i < packetSize / 1024; i++) {
- await core.read(rid, buffer.subarray(i * 1024, i * 1024 + 1024));
- }
- for (let i = 0; i < 256; i++) {
- assertEquals(
- i,
- buffer[i * (packetSize / 256)],
- `at index ${i * (packetSize / 256)}`,
- );
- }
- core.close(rid);
-});
-
-Deno.test(async function readableStreamLargePackets() {
- const packetSize = 128 * 1024;
- const rid = resourceForReadableStream(largePacketStream(packetSize, 1024));
- for (let i = 0; i < 1024; i++) {
- const buffer = new Uint8Array(packetSize);
- assertEquals(packetSize, await core.read(rid, buffer));
- for (let i = 0; i < 256; i++) {
- assertEquals(
- i,
- buffer[i * (packetSize / 256)],
- `at index ${i * (packetSize / 256)}`,
- );
- }
- }
- assertEquals(0, await core.read(rid, new Uint8Array(1)));
- core.close(rid);
-});
-
-Deno.test(async function readableStreamVeryLargePackets() {
- // 1024 packets of 1MB
- const rid = resourceForReadableStream(largePacketStream(1024 * 1024, 1024));
- let total = 0;
- // Read 96kB up to 12,288 times (96kB is not an even multiple of the 1MB packet size to test this)
- const readCounts: Record<number, number> = {};
- for (let i = 0; i < 12 * 1024; i++) {
- const nread = await core.read(rid, new Uint8Array(96 * 1024));
- total += nread;
- readCounts[nread] = (readCounts[nread] || 0) + 1;
- if (nread == 0) {
- break;
- }
- }
- assertEquals({ 0: 1, 65536: 1024, 98304: 10 * 1024 }, readCounts);
- assertEquals(total, 1024 * 1024 * 1024);
- core.close(rid);
-});
-
-for (const count of [0, 1, 2, 3]) {
- for (const delay of [0, 1, 10]) {
- // Creating a stream that errors in start will throw
- if (delay > 0) {
- createStreamTest(count, delay, "Throw");
- }
- createStreamTest(count, delay, "Close");
- }
-}
-
-function createStreamTest(
- count: number,
- delay: number,
- action: "Throw" | "Close",
-) {
- Deno.test(`streamCount${count}Delay${delay}${action}`, async () => {
- let rid;
- try {
- rid = resourceForReadableStream(
- makeStreamWithCount(count, delay, action),
- );
- for (let i = 0; i < count; i++) {
- const buffer = new Uint8Array(1);
- await core.read(rid, buffer);
- }
- if (action == "Throw") {
- try {
- const buffer = new Uint8Array(1);
- assertEquals(1, await core.read(rid, buffer));
- fail();
- } catch (e) {
- // We expect this to be thrown
- assertEquals(e.message, "Expected error!");
- }
- } else {
- const buffer = new Uint8Array(1);
- assertEquals(0, await core.read(rid, buffer));
- }
- } finally {
- core.close(rid);
- }
- });
-}
-
-// 1024 is the size of the internal packet buffer -- we want to make sure we fill the internal pipe fully.
-for (const packetCount of [1, 1024]) {
- Deno.test(`readableStreamWithAggressiveResourceClose_${packetCount}`, async function () {
- let first = true;
- const { promise, resolve } = Promise.withResolvers();
- const rid = resourceForReadableStream(
- new ReadableStream({
- pull(controller) {
- if (first) {
- // We queue this up and then immediately close the resource (not the reader)
- for (let i = 0; i < packetCount; i++) {
- controller.enqueue(new Uint8Array(1));
- }
- core.close(rid);
- // This doesn't throw, even though the resource is closed
- controller.enqueue(new Uint8Array(1));
- first = false;
- }
- },
- cancel(reason) {
- resolve(reason);
- },
- }),
- );
- try {
- for (let i = 0; i < packetCount; i++) {
- await core.read(rid, new Uint8Array(1));
- }
- fail();
- } catch (e) {
- assertEquals(e.message, "operation canceled");
- }
- assertEquals(await promise, "resource closed");
- });
-}
diff --git a/cli/tests/unit/structured_clone_test.ts b/cli/tests/unit/structured_clone_test.ts
deleted file mode 100644
index 314a276dd..000000000
--- a/cli/tests/unit/structured_clone_test.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assert, assertEquals, assertThrows } from "./test_util.ts";
-
-// Basic tests for the structured clone algorithm. Mainly tests TypeScript
-// typings. Actual functionality is tested in WPT.
-
-Deno.test("self.structuredClone", async () => {
- const arrayOriginal = ["hello world"];
- const channelOriginal = new MessageChannel();
- const [arrayCloned, portTransferred] = self
- .structuredClone([arrayOriginal, channelOriginal.port2], {
- transfer: [channelOriginal.port2],
- });
- assert(arrayOriginal !== arrayCloned); // not the same identity
- assertEquals(arrayCloned, arrayOriginal); // but same value
- channelOriginal.port1.postMessage("1");
- await new Promise((resolve) => portTransferred.onmessage = () => resolve(1));
- channelOriginal.port1.close();
- portTransferred.close();
-});
-
-Deno.test("correct DataCloneError message", () => {
- assertThrows(
- () => {
- const sab = new SharedArrayBuffer(1024);
- structuredClone(sab, { transfer: [sab] });
- },
- DOMException,
- "Value not transferable",
- );
-
- const ab = new ArrayBuffer(1);
- // detach ArrayBuffer
- structuredClone(ab, { transfer: [ab] });
- assertThrows(
- () => {
- structuredClone(ab, { transfer: [ab] });
- },
- DOMException,
- "ArrayBuffer at index 0 is already detached",
- );
-
- const ab2 = new ArrayBuffer(0);
- assertThrows(
- () => {
- structuredClone([ab2, ab], { transfer: [ab2, ab] });
- },
- DOMException,
- "ArrayBuffer at index 1 is already detached",
- );
-
- // ab2 should not be detached after above failure
- structuredClone(ab2, { transfer: [ab2] });
-});
diff --git a/cli/tests/unit/symbol_test.ts b/cli/tests/unit/symbol_test.ts
deleted file mode 100644
index 54db7f5ba..000000000
--- a/cli/tests/unit/symbol_test.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert } from "./test_util.ts";
-
-// Test that `Symbol.metadata` is defined. This file can be removed when V8
-// supports `Symbol.metadata` natively.
-
-Deno.test(
- function symbolMetadataIsDefined() {
- assert(typeof Symbol.metadata === "symbol");
- },
-);
diff --git a/cli/tests/unit/symlink_test.ts b/cli/tests/unit/symlink_test.ts
deleted file mode 100644
index 310c36930..000000000
--- a/cli/tests/unit/symlink_test.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertRejects,
- assertThrows,
- pathToAbsoluteFileUrl,
-} from "./test_util.ts";
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function symlinkSyncSuccess() {
- const testDir = Deno.makeTempDirSync();
- const oldname = testDir + "/oldname";
- const newname = testDir + "/newname";
- Deno.mkdirSync(oldname);
- Deno.symlinkSync(oldname, newname);
- const newNameInfoLStat = Deno.lstatSync(newname);
- const newNameInfoStat = Deno.statSync(newname);
- assert(newNameInfoLStat.isSymlink);
- assert(newNameInfoStat.isDirectory);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function symlinkSyncURL() {
- const testDir = Deno.makeTempDirSync();
- const oldname = testDir + "/oldname";
- const newname = testDir + "/newname";
- Deno.mkdirSync(oldname);
- Deno.symlinkSync(
- pathToAbsoluteFileUrl(oldname),
- pathToAbsoluteFileUrl(newname),
- );
- const newNameInfoLStat = Deno.lstatSync(newname);
- const newNameInfoStat = Deno.statSync(newname);
- assert(newNameInfoLStat.isSymlink);
- assert(newNameInfoStat.isDirectory);
- },
-);
-
-Deno.test(
- { permissions: { read: false, write: false } },
- function symlinkSyncPerm() {
- assertThrows(() => {
- Deno.symlinkSync("oldbaddir", "newbaddir");
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function symlinkSyncAlreadyExist() {
- const existingFile = Deno.makeTempFileSync();
- const existingFile2 = Deno.makeTempFileSync();
- assertThrows(
- () => {
- Deno.symlinkSync(existingFile, existingFile2);
- },
- Deno.errors.AlreadyExists,
- `symlink '${existingFile}' -> '${existingFile2}'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function symlinkSuccess() {
- const testDir = Deno.makeTempDirSync();
- const oldname = testDir + "/oldname";
- const newname = testDir + "/newname";
- Deno.mkdirSync(oldname);
- await Deno.symlink(oldname, newname);
- const newNameInfoLStat = Deno.lstatSync(newname);
- const newNameInfoStat = Deno.statSync(newname);
- assert(newNameInfoLStat.isSymlink, "NOT SYMLINK");
- assert(newNameInfoStat.isDirectory, "NOT DIRECTORY");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function symlinkURL() {
- const testDir = Deno.makeTempDirSync();
- const oldname = testDir + "/oldname";
- const newname = testDir + "/newname";
- Deno.mkdirSync(oldname);
- await Deno.symlink(
- pathToAbsoluteFileUrl(oldname),
- pathToAbsoluteFileUrl(newname),
- );
- const newNameInfoLStat = Deno.lstatSync(newname);
- const newNameInfoStat = Deno.statSync(newname);
- assert(newNameInfoLStat.isSymlink, "NOT SYMLINK");
- assert(newNameInfoStat.isDirectory, "NOT DIRECTORY");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function symlinkAlreadyExist() {
- const existingFile = Deno.makeTempFileSync();
- const existingFile2 = Deno.makeTempFileSync();
- await assertRejects(
- async () => {
- await Deno.symlink(existingFile, existingFile2);
- },
- Deno.errors.AlreadyExists,
- `symlink '${existingFile}' -> '${existingFile2}'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: ["."] } },
- async function symlinkNoFullWritePermissions() {
- await assertRejects(
- () => Deno.symlink("old", "new"),
- Deno.errors.PermissionDenied,
- );
- assertThrows(
- () => Deno.symlinkSync("old", "new"),
- Deno.errors.PermissionDenied,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: ["."], write: true } },
- async function symlinkNoFullReadPermissions() {
- await assertRejects(
- () => Deno.symlink("old", "new"),
- Deno.errors.PermissionDenied,
- );
- assertThrows(
- () => Deno.symlinkSync("old", "new"),
- Deno.errors.PermissionDenied,
- );
- },
-);
diff --git a/cli/tests/unit/sync_test.ts b/cli/tests/unit/sync_test.ts
deleted file mode 100644
index 40a8054c0..000000000
--- a/cli/tests/unit/sync_test.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function fdatasyncSyncSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_fdatasyncSync.txt";
- using file = Deno.openSync(filename, {
- read: true,
- write: true,
- create: true,
- });
- const data = new Uint8Array(64);
- Deno.writeSync(file.rid, data);
- Deno.fdatasyncSync(file.rid);
- Deno.removeSync(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function fdatasyncSuccess() {
- const filename = (await Deno.makeTempDir()) + "/test_fdatasync.txt";
- using file = await Deno.open(filename, {
- read: true,
- write: true,
- create: true,
- });
- const data = new Uint8Array(64);
- await file.write(data);
- await Deno.fdatasync(file.rid);
- assertEquals(await Deno.readFile(filename), data);
- await Deno.remove(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function fsyncSyncSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_fsyncSync.txt";
- using file = Deno.openSync(filename, {
- read: true,
- write: true,
- create: true,
- });
- const size = 64;
- file.truncateSync(size);
- Deno.fsyncSync(file.rid);
- assertEquals(Deno.statSync(filename).size, size);
- Deno.removeSync(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function fsyncSuccess() {
- const filename = (await Deno.makeTempDir()) + "/test_fsync.txt";
- using file = await Deno.open(filename, {
- read: true,
- write: true,
- create: true,
- });
- const size = 64;
- await file.truncate(size);
- await Deno.fsync(file.rid);
- assertEquals((await Deno.stat(filename)).size, size);
- await Deno.remove(filename);
- },
-);
diff --git a/cli/tests/unit/test_util.ts b/cli/tests/unit/test_util.ts
deleted file mode 100644
index 2f2730794..000000000
--- a/cli/tests/unit/test_util.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import * as colors from "@test_util/std/fmt/colors.ts";
-export { colors };
-import { join, resolve } from "@test_util/std/path/mod.ts";
-export {
- assert,
- assertEquals,
- assertFalse,
- AssertionError,
- assertIsError,
- assertMatch,
- assertNotEquals,
- assertNotStrictEquals,
- assertRejects,
- assertStrictEquals,
- assertStringIncludes,
- assertThrows,
- fail,
- unimplemented,
- unreachable,
-} from "@test_util/std/assert/mod.ts";
-export { delay } from "@test_util/std/async/delay.ts";
-export { readLines } from "@test_util/std/io/read_lines.ts";
-export { parse as parseArgs } from "@test_util/std/flags/mod.ts";
-
-export function pathToAbsoluteFileUrl(path: string): URL {
- path = resolve(path);
-
- return new URL(`file://${Deno.build.os === "windows" ? "/" : ""}${path}`);
-}
-
-export function execCode(code: string): Promise<readonly [number, string]> {
- return execCode2(code).finished();
-}
-
-export function execCode2(code: string) {
- const command = new Deno.Command(Deno.execPath(), {
- args: [
- "eval",
- "--unstable",
- "--no-check",
- code,
- ],
- stdout: "piped",
- stderr: "inherit",
- });
-
- const child = command.spawn();
- const stdout = child.stdout.pipeThrough(new TextDecoderStream()).getReader();
- let output = "";
-
- return {
- async waitStdoutText(text: string) {
- while (true) {
- const readData = await stdout.read();
- if (readData.value) {
- output += readData.value;
- if (output.includes(text)) {
- return;
- }
- }
- if (readData.done) {
- throw new Error(`Did not find text '${text}' in stdout.`);
- }
- }
- },
- async finished() {
- while (true) {
- const readData = await stdout.read();
- if (readData.value) {
- output += readData.value;
- }
- if (readData.done) {
- break;
- }
- }
- const status = await child.status;
- return [status.code, output] as const;
- },
- };
-}
-
-export function tmpUnixSocketPath(): string {
- const folder = Deno.makeTempDirSync();
- return join(folder, "socket");
-}
diff --git a/cli/tests/unit/testing_test.ts b/cli/tests/unit/testing_test.ts
deleted file mode 100644
index e04ab921c..000000000
--- a/cli/tests/unit/testing_test.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertRejects, assertThrows } from "./test_util.ts";
-
-Deno.test(function testWrongOverloads() {
- assertThrows(
- () => {
- // @ts-ignore Testing invalid overloads
- Deno.test("some name", { fn: () => {} }, () => {});
- },
- TypeError,
- "Unexpected 'fn' field in options, test function is already provided as the third argument.",
- );
- assertThrows(
- () => {
- // @ts-ignore Testing invalid overloads
- Deno.test("some name", { name: "some name2" }, () => {});
- },
- TypeError,
- "Unexpected 'name' field in options, test name is already provided as the first argument.",
- );
- assertThrows(
- () => {
- // @ts-ignore Testing invalid overloads
- Deno.test(() => {});
- },
- TypeError,
- "The test function must have a name",
- );
- assertThrows(
- () => {
- // @ts-ignore Testing invalid overloads
- Deno.test(function foo() {}, {});
- },
- TypeError,
- "Unexpected second argument to Deno.test()",
- );
- assertThrows(
- () => {
- // @ts-ignore Testing invalid overloads
- Deno.test({ fn: () => {} }, function foo() {});
- },
- TypeError,
- "Unexpected 'fn' field in options, test function is already provided as the second argument.",
- );
- assertThrows(
- () => {
- // @ts-ignore Testing invalid overloads
- Deno.test({});
- },
- TypeError,
- "Expected 'fn' field in the first argument to be a test function.",
- );
- assertThrows(
- () => {
- // @ts-ignore Testing invalid overloads
- Deno.test({ fn: "boo!" });
- },
- TypeError,
- "Expected 'fn' field in the first argument to be a test function.",
- );
-});
-
-Deno.test(function nameOfTestCaseCantBeEmpty() {
- assertThrows(
- () => {
- Deno.test("", () => {});
- },
- TypeError,
- "The test name can't be empty",
- );
- assertThrows(
- () => {
- Deno.test({
- name: "",
- fn: () => {},
- });
- },
- TypeError,
- "The test name can't be empty",
- );
-});
-
-Deno.test(async function invalidStepArguments(t) {
- await assertRejects(
- async () => {
- // deno-lint-ignore no-explicit-any
- await (t as any).step("test");
- },
- TypeError,
- "Expected function for second argument.",
- );
-
- await assertRejects(
- async () => {
- // deno-lint-ignore no-explicit-any
- await (t as any).step("test", "not a function");
- },
- TypeError,
- "Expected function for second argument.",
- );
-
- await assertRejects(
- async () => {
- // deno-lint-ignore no-explicit-any
- await (t as any).step();
- },
- TypeError,
- "Expected a test definition or name and function.",
- );
-
- await assertRejects(
- async () => {
- // deno-lint-ignore no-explicit-any
- await (t as any).step(() => {});
- },
- TypeError,
- "The step function must have a name.",
- );
-});
-
-Deno.test(async function nameOnTextContext(t1) {
- await assertEquals(t1.name, "nameOnTextContext");
- await t1.step("step", async (t2) => {
- await assertEquals(t2.name, "step");
- await t2.step("nested step", async (t3) => {
- await assertEquals(t3.name, "nested step");
- });
- });
-});
-
-Deno.test(async function originOnTextContext(t1) {
- await assertEquals(t1.origin, Deno.mainModule);
- await t1.step("step", async (t2) => {
- await assertEquals(t2.origin, Deno.mainModule);
- await t2.step("nested step", async (t3) => {
- await assertEquals(t3.origin, Deno.mainModule);
- });
- });
-});
-
-Deno.test(async function parentOnTextContext(t1) {
- await assertEquals(t1.parent, undefined);
- await t1.step("step", async (t2) => {
- await assertEquals(t1, t2.parent);
- await t2.step("nested step", async (t3) => {
- await assertEquals(t2, t3.parent);
- });
- });
-});
-
-Deno.test("explicit undefined for boolean options", {
- ignore: undefined,
- only: undefined,
-}, () => {});
diff --git a/cli/tests/unit/text_encoding_test.ts b/cli/tests/unit/text_encoding_test.ts
deleted file mode 100644
index 719e5907e..000000000
--- a/cli/tests/unit/text_encoding_test.ts
+++ /dev/null
@@ -1,326 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertStrictEquals,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(function btoaSuccess() {
- const text = "hello world";
- const encoded = btoa(text);
- assertEquals(encoded, "aGVsbG8gd29ybGQ=");
-});
-
-Deno.test(function atobSuccess() {
- const encoded = "aGVsbG8gd29ybGQ=";
- const decoded = atob(encoded);
- assertEquals(decoded, "hello world");
-});
-
-Deno.test(function atobWithAsciiWhitespace() {
- const encodedList = [
- " aGVsbG8gd29ybGQ=",
- " aGVsbG8gd29ybGQ=",
- "aGVsbG8gd29ybGQ= ",
- "aGVsbG8gd29ybGQ=\n",
- "aGVsbG\t8gd29ybGQ=",
- `aGVsbG\t8g
- d29ybGQ=`,
- ];
-
- for (const encoded of encodedList) {
- const decoded = atob(encoded);
- assertEquals(decoded, "hello world");
- }
-});
-
-Deno.test(function atobThrows() {
- let threw = false;
- try {
- atob("aGVsbG8gd29ybGQ==");
- } catch (_e) {
- threw = true;
- }
- assert(threw);
-});
-
-Deno.test(function atobThrows2() {
- let threw = false;
- try {
- atob("aGVsbG8gd29ybGQ===");
- } catch (_e) {
- threw = true;
- }
- assert(threw);
-});
-
-Deno.test(function atobThrows3() {
- let threw = false;
- try {
- atob("foobar!!");
- } catch (e) {
- if (
- e instanceof DOMException &&
- e.toString().startsWith("InvalidCharacterError:")
- ) {
- threw = true;
- }
- }
- assert(threw);
-});
-
-Deno.test(function btoaFailed() {
- const text = "你好";
- assertThrows(() => {
- btoa(text);
- }, DOMException);
-});
-
-Deno.test(function textDecoder2() {
- // deno-fmt-ignore
- const fixture = new Uint8Array([
- 0xf0, 0x9d, 0x93, 0xbd,
- 0xf0, 0x9d, 0x93, 0xae,
- 0xf0, 0x9d, 0x94, 0x81,
- 0xf0, 0x9d, 0x93, 0xbd
- ]);
- const decoder = new TextDecoder();
- assertEquals(decoder.decode(fixture), "𝓽𝓮𝔁𝓽");
-});
-
-// ignoreBOM is tested through WPT
-
-Deno.test(function textDecoderASCII() {
- const fixture = new Uint8Array([0x89, 0x95, 0x9f, 0xbf]);
- const decoder = new TextDecoder("ascii");
- assertEquals(decoder.decode(fixture), "‰•Ÿ¿");
-});
-
-Deno.test(function textDecoderErrorEncoding() {
- let didThrow = false;
- try {
- new TextDecoder("Foo");
- } catch (e) {
- didThrow = true;
- assert(e instanceof Error);
- assertEquals(e.message, "The encoding label provided ('Foo') is invalid.");
- }
- assert(didThrow);
-});
-
-Deno.test(function textEncoder() {
- const fixture = "𝓽𝓮𝔁𝓽";
- const encoder = new TextEncoder();
- // deno-fmt-ignore
- assertEquals(Array.from(encoder.encode(fixture)), [
- 0xf0, 0x9d, 0x93, 0xbd,
- 0xf0, 0x9d, 0x93, 0xae,
- 0xf0, 0x9d, 0x94, 0x81,
- 0xf0, 0x9d, 0x93, 0xbd
- ]);
-});
-
-Deno.test(function textEncodeInto() {
- const fixture = "text";
- const encoder = new TextEncoder();
- const bytes = new Uint8Array(5);
- const result = encoder.encodeInto(fixture, bytes);
- assertEquals(result.read, 4);
- assertEquals(result.written, 4);
- // deno-fmt-ignore
- assertEquals(Array.from(bytes), [
- 0x74, 0x65, 0x78, 0x74, 0x00,
- ]);
-});
-
-Deno.test(function textEncodeInto2() {
- const fixture = "𝓽𝓮𝔁𝓽";
- const encoder = new TextEncoder();
- const bytes = new Uint8Array(17);
- const result = encoder.encodeInto(fixture, bytes);
- assertEquals(result.read, 8);
- assertEquals(result.written, 16);
- // deno-fmt-ignore
- assertEquals(Array.from(bytes), [
- 0xf0, 0x9d, 0x93, 0xbd,
- 0xf0, 0x9d, 0x93, 0xae,
- 0xf0, 0x9d, 0x94, 0x81,
- 0xf0, 0x9d, 0x93, 0xbd, 0x00,
- ]);
-});
-
-Deno.test(function textEncodeInto3() {
- const fixture = "𝓽𝓮𝔁𝓽";
- const encoder = new TextEncoder();
- const bytes = new Uint8Array(5);
- const result = encoder.encodeInto(fixture, bytes);
- assertEquals(result.read, 2);
- assertEquals(result.written, 4);
- // deno-fmt-ignore
- assertEquals(Array.from(bytes), [
- 0xf0, 0x9d, 0x93, 0xbd, 0x00,
- ]);
-});
-
-Deno.test(function loneSurrogateEncodeInto() {
- const fixture = "lone𝄞\ud888surrogate";
- const encoder = new TextEncoder();
- const bytes = new Uint8Array(20);
- const result = encoder.encodeInto(fixture, bytes);
- assertEquals(result.read, 16);
- assertEquals(result.written, 20);
- // deno-fmt-ignore
- assertEquals(Array.from(bytes), [
- 0x6c, 0x6f, 0x6e, 0x65,
- 0xf0, 0x9d, 0x84, 0x9e,
- 0xef, 0xbf, 0xbd, 0x73,
- 0x75, 0x72, 0x72, 0x6f,
- 0x67, 0x61, 0x74, 0x65
- ]);
-});
-
-Deno.test(function loneSurrogateEncodeInto2() {
- const fixture = "\ud800";
- const encoder = new TextEncoder();
- const bytes = new Uint8Array(3);
- const result = encoder.encodeInto(fixture, bytes);
- assertEquals(result.read, 1);
- assertEquals(result.written, 3);
- // deno-fmt-ignore
- assertEquals(Array.from(bytes), [
- 0xef, 0xbf, 0xbd
- ]);
-});
-
-Deno.test(function loneSurrogateEncodeInto3() {
- const fixture = "\udc00";
- const encoder = new TextEncoder();
- const bytes = new Uint8Array(3);
- const result = encoder.encodeInto(fixture, bytes);
- assertEquals(result.read, 1);
- assertEquals(result.written, 3);
- // deno-fmt-ignore
- assertEquals(Array.from(bytes), [
- 0xef, 0xbf, 0xbd
- ]);
-});
-
-Deno.test(function swappedSurrogatePairEncodeInto4() {
- const fixture = "\udc00\ud800";
- const encoder = new TextEncoder();
- const bytes = new Uint8Array(8);
- const result = encoder.encodeInto(fixture, bytes);
- assertEquals(result.read, 2);
- assertEquals(result.written, 6);
- // deno-fmt-ignore
- assertEquals(Array.from(bytes), [
- 0xef, 0xbf, 0xbd, 0xef, 0xbf, 0xbd, 0x00, 0x00
- ]);
-});
-
-Deno.test(function textDecoderSharedUint8Array() {
- const ab = new SharedArrayBuffer(6);
- const dataView = new DataView(ab);
- const charCodeA = "A".charCodeAt(0);
- for (let i = 0; i < ab.byteLength; i++) {
- dataView.setUint8(i, charCodeA + i);
- }
- const ui8 = new Uint8Array(ab);
- const decoder = new TextDecoder();
- const actual = decoder.decode(ui8);
- assertEquals(actual, "ABCDEF");
-});
-
-Deno.test(function textDecoderSharedInt32Array() {
- const ab = new SharedArrayBuffer(8);
- const dataView = new DataView(ab);
- const charCodeA = "A".charCodeAt(0);
- for (let i = 0; i < ab.byteLength; i++) {
- dataView.setUint8(i, charCodeA + i);
- }
- const i32 = new Int32Array(ab);
- const decoder = new TextDecoder();
- const actual = decoder.decode(i32);
- assertEquals(actual, "ABCDEFGH");
-});
-
-Deno.test(function toStringShouldBeWebCompatibility() {
- const encoder = new TextEncoder();
- assertEquals(encoder.toString(), "[object TextEncoder]");
-
- const decoder = new TextDecoder();
- assertEquals(decoder.toString(), "[object TextDecoder]");
-});
-
-Deno.test(function textEncoderShouldCoerceToString() {
- const encoder = new TextEncoder();
- const fixtureText = "text";
- const fixture = {
- toString() {
- return fixtureText;
- },
- };
-
- const bytes = encoder.encode(fixture as unknown as string);
- const decoder = new TextDecoder();
- const decoded = decoder.decode(bytes);
- assertEquals(decoded, fixtureText);
-});
-
-Deno.test(function binaryEncode() {
- // @ts-ignore: Deno[Deno.internal].core allowed
- const core = Deno[Deno.internal].core;
- function asBinaryString(bytes: Uint8Array): string {
- return Array.from(bytes).map(
- (v: number) => String.fromCodePoint(v),
- ).join("");
- }
-
- function decodeBinary(binaryString: string) {
- const chars: string[] = Array.from(binaryString);
- return chars.map((v: string): number | undefined => v.codePointAt(0));
- }
- const inputs = [
- "σ😀",
- "Кириллица is Cyrillic",
- "𝓽𝓮𝔁𝓽",
- "lone𝄞\ud888surrogate",
- "\udc00\ud800",
- "\ud800",
- ];
- for (const input of inputs) {
- const bytes = new TextEncoder().encode(input);
- const binaryString = core.encodeBinaryString(bytes);
- assertEquals(
- binaryString,
- asBinaryString(bytes),
- );
-
- assertEquals(Array.from(bytes), decodeBinary(binaryString));
- }
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function textDecoderStreamCleansUpOnCancel() {
- let cancelled = false;
- const readable = new ReadableStream({
- start: (controller) => {
- controller.enqueue(new Uint8Array(12));
- },
- cancel: () => {
- cancelled = true;
- },
- }).pipeThrough(new TextDecoderStream());
- const chunks = [];
- for await (const chunk of readable) {
- chunks.push(chunk);
- // breaking out of the loop prevents normal shutdown at end of async iterator values and triggers the cancel method of the stream instead
- break;
- }
- assertEquals(chunks.length, 1);
- assertEquals(chunks[0].length, 12);
- assertStrictEquals(cancelled, true);
- },
-);
diff --git a/cli/tests/unit/timers_test.ts b/cli/tests/unit/timers_test.ts
deleted file mode 100644
index 17b137231..000000000
--- a/cli/tests/unit/timers_test.ts
+++ /dev/null
@@ -1,763 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertNotEquals,
- delay,
- execCode,
- unreachable,
-} from "./test_util.ts";
-
-Deno.test(async function functionParameterBindingSuccess() {
- const { promise, resolve } = Promise.withResolvers<void>();
- let count = 0;
-
- const nullProto = (newCount: number) => {
- count = newCount;
- resolve();
- };
-
- Reflect.setPrototypeOf(nullProto, null);
-
- setTimeout(nullProto, 500, 1);
- await promise;
- // count should be reassigned
- assertEquals(count, 1);
-});
-
-Deno.test(async function stringifyAndEvalNonFunctions() {
- // eval can only access global scope
- const global = globalThis as unknown as {
- globalPromise: ReturnType<typeof Promise.withResolvers<void>>;
- globalCount: number;
- };
-
- global.globalPromise = Promise.withResolvers<void>();
- global.globalCount = 0;
-
- const notAFunction =
- "globalThis.globalCount++; globalThis.globalPromise.resolve();" as unknown as () =>
- void;
-
- setTimeout(notAFunction, 500);
-
- await global.globalPromise.promise;
-
- // count should be incremented
- assertEquals(global.globalCount, 1);
-
- Reflect.deleteProperty(global, "globalPromise");
- Reflect.deleteProperty(global, "globalCount");
-});
-
-Deno.test(async function timeoutSuccess() {
- const { promise, resolve } = Promise.withResolvers<void>();
- let count = 0;
- setTimeout(() => {
- count++;
- resolve();
- }, 500);
- await promise;
- // count should increment
- assertEquals(count, 1);
-});
-
-Deno.test(async function timeoutEvalNoScopeLeak() {
- // eval can only access global scope
- const global = globalThis as unknown as {
- globalPromise: ReturnType<typeof Promise.withResolvers<Error>>;
- };
- global.globalPromise = Promise.withResolvers();
- setTimeout(
- `
- try {
- console.log(core);
- globalThis.globalPromise.reject(new Error("Didn't throw."));
- } catch (error) {
- globalThis.globalPromise.resolve(error);
- }` as unknown as () => void,
- 0,
- );
- const error = await global.globalPromise.promise;
- assertEquals(error.name, "ReferenceError");
- Reflect.deleteProperty(global, "globalPromise");
-});
-
-Deno.test(async function evalPrimordial() {
- const global = globalThis as unknown as {
- globalPromise: ReturnType<typeof Promise.withResolvers<void>>;
- };
- global.globalPromise = Promise.withResolvers<void>();
- const originalEval = globalThis.eval;
- let wasCalled = false;
- globalThis.eval = (argument) => {
- wasCalled = true;
- return originalEval(argument);
- };
- setTimeout(
- "globalThis.globalPromise.resolve();" as unknown as () => void,
- 0,
- );
- await global.globalPromise.promise;
- assert(!wasCalled);
- Reflect.deleteProperty(global, "globalPromise");
- globalThis.eval = originalEval;
-});
-
-Deno.test(async function timeoutArgs() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const arg = 1;
- let capturedArgs: unknown[] = [];
- setTimeout(
- function () {
- capturedArgs = [...arguments];
- resolve();
- },
- 10,
- arg,
- arg.toString(),
- [arg],
- );
- await promise;
- assertEquals(capturedArgs, [
- arg,
- arg.toString(),
- [arg],
- ]);
-});
-
-Deno.test(async function timeoutCancelSuccess() {
- let count = 0;
- const id = setTimeout(() => {
- count++;
- }, 1);
- // Cancelled, count should not increment
- clearTimeout(id);
- await delay(600);
- assertEquals(count, 0);
-});
-
-Deno.test(async function timeoutCancelMultiple() {
- function uncalled(): never {
- throw new Error("This function should not be called.");
- }
-
- // Set timers and cancel them in the same order.
- const t1 = setTimeout(uncalled, 10);
- const t2 = setTimeout(uncalled, 10);
- const t3 = setTimeout(uncalled, 10);
- clearTimeout(t1);
- clearTimeout(t2);
- clearTimeout(t3);
-
- // Set timers and cancel them in reverse order.
- const t4 = setTimeout(uncalled, 20);
- const t5 = setTimeout(uncalled, 20);
- const t6 = setTimeout(uncalled, 20);
- clearTimeout(t6);
- clearTimeout(t5);
- clearTimeout(t4);
-
- // Sleep until we're certain that the cancelled timers aren't gonna fire.
- await delay(50);
-});
-
-Deno.test(async function timeoutCancelInvalidSilentFail() {
- // Expect no panic
- const { promise, resolve } = Promise.withResolvers<void>();
- let count = 0;
- const id = setTimeout(() => {
- count++;
- // Should have no effect
- clearTimeout(id);
- resolve();
- }, 500);
- await promise;
- assertEquals(count, 1);
-
- // Should silently fail (no panic)
- clearTimeout(2147483647);
-});
-
-Deno.test(async function intervalSuccess() {
- const { promise, resolve } = Promise.withResolvers<void>();
- let count = 0;
- const id = setInterval(() => {
- count++;
- clearInterval(id);
- resolve();
- }, 100);
- await promise;
- // Clear interval
- clearInterval(id);
- // count should increment twice
- assertEquals(count, 1);
- // Similar false async leaking alarm.
- // Force next round of polling.
- await delay(0);
-});
-
-Deno.test(async function intervalCancelSuccess() {
- let count = 0;
- const id = setInterval(() => {
- count++;
- }, 1);
- clearInterval(id);
- await delay(500);
- assertEquals(count, 0);
-});
-
-Deno.test(async function intervalOrdering() {
- const timers: number[] = [];
- let timeouts = 0;
- function onTimeout() {
- ++timeouts;
- for (let i = 1; i < timers.length; i++) {
- clearTimeout(timers[i]);
- }
- }
- for (let i = 0; i < 10; i++) {
- timers[i] = setTimeout(onTimeout, 1);
- }
- await delay(500);
- assertEquals(timeouts, 1);
-});
-
-Deno.test(function intervalCancelInvalidSilentFail() {
- // Should silently fail (no panic)
- clearInterval(2147483647);
-});
-
-Deno.test(async function callbackTakesLongerThanInterval() {
- const { promise, resolve } = Promise.withResolvers<void>();
-
- let timeEndOfFirstCallback: number | undefined;
- const interval = setInterval(() => {
- if (timeEndOfFirstCallback === undefined) {
- // First callback
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 300);
- timeEndOfFirstCallback = Date.now();
- } else {
- // Second callback
- assert(Date.now() - 100 >= timeEndOfFirstCallback);
- clearInterval(interval);
- resolve();
- }
- }, 100);
-
- await promise;
-});
-
-// https://github.com/denoland/deno/issues/11398
-Deno.test(async function clearTimeoutAfterNextTimerIsDue1() {
- const { promise, resolve } = Promise.withResolvers<void>();
-
- setTimeout(() => {
- resolve();
- }, 300);
-
- const interval = setInterval(() => {
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 400);
- // Both the interval and the timeout's due times are now in the past.
- clearInterval(interval);
- }, 100);
-
- await promise;
-});
-
-// https://github.com/denoland/deno/issues/11398
-Deno.test(async function clearTimeoutAfterNextTimerIsDue2() {
- const { promise, resolve } = Promise.withResolvers<void>();
-
- const timeout1 = setTimeout(unreachable, 100);
-
- setTimeout(() => {
- resolve();
- }, 200);
-
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 300);
- // Both of the timeouts' due times are now in the past.
- clearTimeout(timeout1);
-
- await promise;
-});
-
-Deno.test(async function fireCallbackImmediatelyWhenDelayOverMaxValue() {
- let count = 0;
- setTimeout(() => {
- count++;
- }, 2 ** 31);
- await delay(1);
- assertEquals(count, 1);
-});
-
-Deno.test(async function timeoutCallbackThis() {
- const { promise, resolve } = Promise.withResolvers<void>();
- let capturedThis: unknown;
- const obj = {
- foo() {
- capturedThis = this;
- resolve();
- },
- };
- setTimeout(obj.foo, 1);
- await promise;
- assertEquals(capturedThis, window);
-});
-
-Deno.test(async function timeoutBindThis() {
- const thisCheckPassed = [null, undefined, window, globalThis];
-
- const thisCheckFailed = [
- 0,
- "",
- true,
- false,
- {},
- [],
- "foo",
- () => {},
- Object.prototype,
- ];
-
- for (const thisArg of thisCheckPassed) {
- const { promise, resolve } = Promise.withResolvers<void>();
- let hasThrown = 0;
- try {
- setTimeout.call(thisArg, () => resolve(), 1);
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
- await promise;
- assertEquals(hasThrown, 1);
- }
-
- for (const thisArg of thisCheckFailed) {
- let hasThrown = 0;
- try {
- setTimeout.call(thisArg, () => {}, 1);
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
- assertEquals(hasThrown, 2);
- }
-});
-
-Deno.test(function clearTimeoutShouldConvertToNumber() {
- let called = false;
- const obj = {
- valueOf(): number {
- called = true;
- return 1;
- },
- };
- clearTimeout((obj as unknown) as number);
- assert(called);
-});
-
-Deno.test(function setTimeoutShouldThrowWithBigint() {
- let hasThrown = 0;
- try {
- setTimeout(() => {}, (1n as unknown) as number);
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
- assertEquals(hasThrown, 2);
-});
-
-Deno.test(function clearTimeoutShouldThrowWithBigint() {
- let hasThrown = 0;
- try {
- clearTimeout((1n as unknown) as number);
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
- assertEquals(hasThrown, 2);
-});
-
-Deno.test(function testFunctionName() {
- assertEquals(clearTimeout.name, "clearTimeout");
- assertEquals(clearInterval.name, "clearInterval");
-});
-
-Deno.test(function testFunctionParamsLength() {
- assertEquals(setTimeout.length, 1);
- assertEquals(setInterval.length, 1);
- assertEquals(clearTimeout.length, 0);
- assertEquals(clearInterval.length, 0);
-});
-
-Deno.test(function clearTimeoutAndClearIntervalNotBeEquals() {
- assertNotEquals(clearTimeout, clearInterval);
-});
-
-Deno.test(async function timerOrdering() {
- const array: number[] = [];
- const { promise: donePromise, resolve } = Promise.withResolvers<void>();
-
- function push(n: number) {
- array.push(n);
- if (array.length === 6) {
- resolve();
- }
- }
-
- setTimeout(() => {
- push(1);
- setTimeout(() => push(4));
- }, 0);
- setTimeout(() => {
- push(2);
- setTimeout(() => push(5));
- }, 0);
- setTimeout(() => {
- push(3);
- setTimeout(() => push(6));
- }, 0);
-
- await donePromise;
-
- assertEquals(array, [1, 2, 3, 4, 5, 6]);
-});
-
-Deno.test(async function timerBasicMicrotaskOrdering() {
- let s = "";
- let count = 0;
- const { promise, resolve } = Promise.withResolvers<void>();
- setTimeout(() => {
- Promise.resolve().then(() => {
- count++;
- s += "de";
- if (count === 2) {
- resolve();
- }
- });
- });
- setTimeout(() => {
- count++;
- s += "no";
- if (count === 2) {
- resolve();
- }
- });
- await promise;
- assertEquals(s, "deno");
-});
-
-Deno.test(async function timerNestedMicrotaskOrdering() {
- let s = "";
- const { promise, resolve } = Promise.withResolvers<void>();
- s += "0";
- setTimeout(() => {
- s += "4";
- setTimeout(() => (s += "A"));
- Promise.resolve()
- .then(() => {
- setTimeout(() => {
- s += "B";
- resolve();
- });
- })
- .then(() => {
- s += "5";
- });
- });
- setTimeout(() => (s += "6"));
- Promise.resolve().then(() => (s += "2"));
- Promise.resolve().then(() =>
- setTimeout(() => {
- s += "7";
- Promise.resolve()
- .then(() => (s += "8"))
- .then(() => {
- s += "9";
- });
- })
- );
- Promise.resolve().then(() => Promise.resolve().then(() => (s += "3")));
- s += "1";
- await promise;
- assertEquals(s, "0123456789AB");
-});
-
-Deno.test(function testQueueMicrotask() {
- assertEquals(typeof queueMicrotask, "function");
-});
-
-Deno.test(async function timerIgnoresDateOverride() {
- const OriginalDate = Date;
- const { promise, resolve, reject } = Promise.withResolvers<void>();
- let hasThrown = 0;
- try {
- const overrideCalled: () => number = () => {
- reject("global Date override used over original Date object");
- return 0;
- };
- const DateOverride = () => {
- overrideCalled();
- };
- globalThis.Date = DateOverride as DateConstructor;
- globalThis.Date.now = overrideCalled;
- globalThis.Date.UTC = overrideCalled;
- globalThis.Date.parse = overrideCalled;
- queueMicrotask(() => {
- resolve();
- });
- await promise;
- hasThrown = 1;
- } catch (err) {
- if (typeof err === "string") {
- assertEquals(err, "global Date override used over original Date object");
- hasThrown = 2;
- } else if (err instanceof TypeError) {
- hasThrown = 3;
- } else {
- hasThrown = 4;
- }
- } finally {
- globalThis.Date = OriginalDate;
- }
- assertEquals(hasThrown, 1);
-});
-
-Deno.test({
- name: "unrefTimer",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- const timer = setTimeout(() => console.log("1"), 1);
- Deno.unrefTimer(timer);
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "");
- },
-});
-
-Deno.test({
- name: "unrefTimer - mix ref and unref 1",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- const timer1 = setTimeout(() => console.log("1"), 200);
- const timer2 = setTimeout(() => console.log("2"), 400);
- const timer3 = setTimeout(() => console.log("3"), 600);
- Deno.unrefTimer(timer3);
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "1\n2\n");
- },
-});
-
-Deno.test({
- name: "unrefTimer - mix ref and unref 2",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- const timer1 = setTimeout(() => console.log("1"), 200);
- const timer2 = setTimeout(() => console.log("2"), 400);
- const timer3 = setTimeout(() => console.log("3"), 600);
- Deno.unrefTimer(timer1);
- Deno.unrefTimer(timer2);
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "1\n2\n3\n");
- },
-});
-
-Deno.test({
- name: "unrefTimer - unref interval",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- let i = 0;
- const timer1 = setInterval(() => {
- console.log("1");
- i++;
- if (i === 5) {
- Deno.unrefTimer(timer1);
- }
- }, 10);
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "1\n1\n1\n1\n1\n");
- },
-});
-
-Deno.test({
- name: "unrefTimer - unref then ref 1",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- const timer1 = setTimeout(() => console.log("1"), 10);
- Deno.unrefTimer(timer1);
- Deno.refTimer(timer1);
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "1\n");
- },
-});
-
-Deno.test({
- name: "unrefTimer - unref then ref",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- const timer1 = setTimeout(() => {
- console.log("1");
- Deno.refTimer(timer2);
- }, 10);
- const timer2 = setTimeout(() => console.log("2"), 20);
- Deno.unrefTimer(timer2);
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "1\n2\n");
- },
-});
-
-Deno.test({
- name: "unrefTimer - invalid calls do nothing",
- fn: () => {
- Deno.unrefTimer(NaN);
- Deno.refTimer(NaN);
- },
-});
-
-Deno.test({
- name: "AbortSignal.timeout() with no listeners",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- const signal = AbortSignal.timeout(2000);
-
- // This unref timer expires before the signal, and if it does expire, then
- // it means the signal has kept the event loop alive.
- const timer = setTimeout(() => console.log("Unexpected!"), 1500);
- Deno.unrefTimer(timer);
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "");
- },
-});
-
-Deno.test({
- name: "AbortSignal.timeout() with listeners",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- const signal = AbortSignal.timeout(1000);
- signal.addEventListener("abort", () => console.log("Event fired!"));
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "Event fired!\n");
- },
-});
-
-Deno.test({
- name: "AbortSignal.timeout() with removed listeners",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- const signal = AbortSignal.timeout(2000);
-
- const callback = () => console.log("Unexpected: Event fired");
- signal.addEventListener("abort", callback);
-
- setTimeout(() => {
- console.log("Removing the listener.");
- signal.removeEventListener("abort", callback);
- }, 500);
-
- Deno.unrefTimer(
- setTimeout(() => console.log("Unexpected: Unref timer"), 1500)
- );
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "Removing the listener.\n");
- },
-});
-
-Deno.test({
- name: "AbortSignal.timeout() with listener for a non-abort event",
- permissions: { run: true, read: true },
- fn: async () => {
- const [statusCode, output] = await execCode(`
- const signal = AbortSignal.timeout(2000);
-
- signal.addEventListener("someOtherEvent", () => {
- console.log("Unexpected: someOtherEvent called");
- });
-
- Deno.unrefTimer(
- setTimeout(() => console.log("Unexpected: Unref timer"), 1500)
- );
- `);
- assertEquals(statusCode, 0);
- assertEquals(output, "");
- },
-});
-
-// Regression test for https://github.com/denoland/deno/issues/19866
-Deno.test({
- name: "regression for #19866",
- fn: async () => {
- const timeoutsFired = [];
-
- // deno-lint-ignore require-await
- async function start(n: number) {
- let i = 0;
- const intervalId = setInterval(() => {
- i++;
- if (i > 2) {
- clearInterval(intervalId!);
- }
- timeoutsFired.push(n);
- }, 20);
- }
-
- for (let n = 0; n < 100; n++) {
- start(n);
- }
-
- // 3s should be plenty of time for all the intervals to fire
- // but it might still be flaky on CI.
- await new Promise((resolve) => setTimeout(resolve, 3000));
- assertEquals(timeoutsFired.length, 300);
- },
-});
-
-// Regression test for https://github.com/denoland/deno/issues/20367
-Deno.test({
- name: "regression for #20367",
- fn: async () => {
- const { promise, resolve } = Promise.withResolvers<number>();
- const start = performance.now();
- setTimeout(() => {
- const end = performance.now();
- resolve(end - start);
- }, 1000);
- clearTimeout(setTimeout(() => {}, 1000));
-
- const result = await promise;
- assert(result >= 1000);
- },
-});
diff --git a/cli/tests/unit/tls_test.ts b/cli/tests/unit/tls_test.ts
deleted file mode 100644
index bbf48cf8f..000000000
--- a/cli/tests/unit/tls_test.ts
+++ /dev/null
@@ -1,1546 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertNotEquals,
- assertRejects,
- assertStrictEquals,
- assertThrows,
-} from "./test_util.ts";
-import { BufReader, BufWriter } from "@test_util/std/io/mod.ts";
-import { readAll } from "@test_util/std/streams/read_all.ts";
-import { writeAll } from "@test_util/std/streams/write_all.ts";
-import { TextProtoReader } from "../testdata/run/textproto.ts";
-
-const encoder = new TextEncoder();
-const decoder = new TextDecoder();
-const cert = await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt");
-const key = await Deno.readTextFile("cli/tests/testdata/tls/localhost.key");
-const caCerts = [await Deno.readTextFile("cli/tests/testdata/tls/RootCA.pem")];
-
-async function sleep(msec: number) {
- await new Promise((res, _rej) => setTimeout(res, msec));
-}
-
-function unreachable(): never {
- throw new Error("Unreachable code reached");
-}
-
-Deno.test({ permissions: { net: false } }, async function connectTLSNoPerm() {
- await assertRejects(async () => {
- await Deno.connectTls({ hostname: "deno.land", port: 443 });
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function connectTLSInvalidHost() {
- await assertRejects(async () => {
- await Deno.connectTls({ hostname: "256.0.0.0", port: 3567 });
- }, TypeError);
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: false } },
- async function connectTLSCertFileNoReadPerm() {
- await assertRejects(async () => {
- await Deno.connectTls({
- hostname: "deno.land",
- port: 443,
- certFile: "cli/tests/testdata/tls/RootCA.crt",
- });
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- function listenTLSNonExistentCertKeyFiles() {
- const options = {
- hostname: "localhost",
- port: 3500,
- certFile: "cli/tests/testdata/tls/localhost.crt",
- keyFile: "cli/tests/testdata/tls/localhost.key",
- };
-
- assertThrows(() => {
- Deno.listenTls({
- ...options,
- certFile: "./non/existent/file",
- });
- }, Deno.errors.NotFound);
-
- assertThrows(() => {
- Deno.listenTls({
- ...options,
- keyFile: "./non/existent/file",
- });
- }, Deno.errors.NotFound);
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: false } },
- function listenTLSNoReadPerm() {
- assertThrows(() => {
- Deno.listenTls({
- hostname: "localhost",
- port: 3500,
- certFile: "cli/tests/testdata/tls/localhost.crt",
- keyFile: "cli/tests/testdata/tls/localhost.key",
- });
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- {
- permissions: { read: true, write: true, net: true },
- },
- function listenTLSEmptyKeyFile() {
- const options = {
- hostname: "localhost",
- port: 3500,
- certFile: "cli/tests/testdata/tls/localhost.crt",
- keyFile: "cli/tests/testdata/tls/localhost.key",
- };
-
- const testDir = Deno.makeTempDirSync();
- const keyFilename = testDir + "/key.pem";
- Deno.writeFileSync(keyFilename, new Uint8Array([]), {
- mode: 0o666,
- });
-
- assertThrows(() => {
- Deno.listenTls({
- ...options,
- keyFile: keyFilename,
- });
- }, Error);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true, net: true } },
- function listenTLSEmptyCertFile() {
- const options = {
- hostname: "localhost",
- port: 3500,
- certFile: "cli/tests/testdata/tls/localhost.crt",
- keyFile: "cli/tests/testdata/tls/localhost.key",
- };
-
- const testDir = Deno.makeTempDirSync();
- const certFilename = testDir + "/cert.crt";
- Deno.writeFileSync(certFilename, new Uint8Array([]), {
- mode: 0o666,
- });
-
- assertThrows(() => {
- Deno.listenTls({
- ...options,
- certFile: certFilename,
- });
- }, Error);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function startTlsWithoutExclusiveAccessToTcpConn() {
- const hostname = "localhost";
- const port = getPort();
-
- const tcpListener = Deno.listen({ hostname, port });
- const [serverConn, clientConn] = await Promise.all([
- tcpListener.accept(),
- Deno.connect({ hostname, port }),
- ]);
-
- const buf = new Uint8Array(128);
- const readPromise = clientConn.read(buf);
- // `clientConn` is being used by a pending promise (`readPromise`) so
- // `Deno.startTls` cannot consume the connection.
- await assertRejects(
- () => Deno.startTls(clientConn, { hostname }),
- Deno.errors.BadResource,
- );
-
- serverConn.close();
- tcpListener.close();
- await readPromise;
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function dialAndListenTLS() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const hostname = "localhost";
- const port = 3500;
-
- const listener = Deno.listenTls({
- hostname,
- port,
- cert: await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"),
- key: await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"),
- });
-
- const response = encoder.encode(
- "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n",
- );
-
- listener.accept().then(
- async (conn) => {
- assert(conn.remoteAddr != null);
- assert(conn.localAddr != null);
- await conn.write(response);
- // TODO(bartlomieju): this might be a bug
- setTimeout(() => {
- conn.close();
- resolve();
- }, 0);
- },
- );
-
- const conn = await Deno.connectTls({ hostname, port, caCerts });
- assert(conn.rid > 0);
- const w = new BufWriter(conn);
- const r = new BufReader(conn);
- const body = `GET / HTTP/1.1\r\nHost: ${hostname}:${port}\r\n\r\n`;
- const writeResult = await w.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await w.flush();
- const tpr = new TextProtoReader(r);
- const statusLine = await tpr.readLine();
- assert(statusLine !== null, `line must be read: ${String(statusLine)}`);
- const m = statusLine.match(/^(.+?) (.+?) (.+?)$/);
- assert(m !== null, "must be matched");
- const [_, proto, status, ok] = m;
- assertEquals(proto, "HTTP/1.1");
- assertEquals(status, "200");
- assertEquals(ok, "OK");
- const headers = await tpr.readMimeHeader();
- assert(headers !== null);
- const contentLength = parseInt(headers.get("content-length")!);
- const bodyBuf = new Uint8Array(contentLength);
- await r.readFull(bodyBuf);
- assertEquals(decoder.decode(bodyBuf), "Hello World\n");
- conn.close();
- listener.close();
- await promise;
- },
-);
-Deno.test(
- { permissions: { read: false, net: true } },
- async function listenTlsWithCertAndKey() {
- const { promise, resolve } = Promise.withResolvers<void>();
- const hostname = "localhost";
- const port = 3500;
-
- const listener = Deno.listenTls({ hostname, port, cert, key });
-
- const response = encoder.encode(
- "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n",
- );
-
- listener.accept().then(
- async (conn) => {
- assert(conn.remoteAddr != null);
- assert(conn.localAddr != null);
- await conn.write(response);
- setTimeout(() => {
- conn.close();
- resolve();
- }, 0);
- },
- );
-
- const conn = await Deno.connectTls({ hostname, port, caCerts });
- assert(conn.rid > 0);
- const w = new BufWriter(conn);
- const r = new BufReader(conn);
- const body = `GET / HTTP/1.1\r\nHost: ${hostname}:${port}\r\n\r\n`;
- const writeResult = await w.write(encoder.encode(body));
- assertEquals(body.length, writeResult);
- await w.flush();
- const tpr = new TextProtoReader(r);
- const statusLine = await tpr.readLine();
- assert(statusLine !== null, `line must be read: ${String(statusLine)}`);
- const m = statusLine.match(/^(.+?) (.+?) (.+?)$/);
- assert(m !== null, "must be matched");
- const [_, proto, status, ok] = m;
- assertEquals(proto, "HTTP/1.1");
- assertEquals(status, "200");
- assertEquals(ok, "OK");
- const headers = await tpr.readMimeHeader();
- assert(headers !== null);
- const contentLength = parseInt(headers.get("content-length")!);
- const bodyBuf = new Uint8Array(contentLength);
- await r.readFull(bodyBuf);
- assertEquals(decoder.decode(bodyBuf), "Hello World\n");
- conn.close();
- listener.close();
- await promise;
- },
-);
-
-let nextPort = 3501;
-function getPort() {
- return nextPort++;
-}
-
-async function tlsPair(): Promise<[Deno.Conn, Deno.Conn]> {
- const port = getPort();
- const listener = Deno.listenTls({
- hostname: "localhost",
- port,
- cert: await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"),
- key: await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"),
- });
-
- const acceptPromise = listener.accept();
- const connectPromise = Deno.connectTls({
- hostname: "localhost",
- port,
- caCerts: [Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem")],
- });
- const endpoints = await Promise.all([acceptPromise, connectPromise]);
-
- listener.close();
-
- return endpoints;
-}
-
-async function tlsAlpn(
- useStartTls: boolean,
-): Promise<[Deno.TlsConn, Deno.TlsConn]> {
- const port = getPort();
- const listener = Deno.listenTls({
- hostname: "localhost",
- port,
- cert: await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"),
- key: await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"),
- alpnProtocols: ["deno", "rocks"],
- });
-
- const acceptPromise = listener.accept();
-
- const caCerts = [Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem")];
- const clientAlpnProtocols = ["rocks", "rises"];
- let endpoints: [Deno.TlsConn, Deno.TlsConn];
-
- if (!useStartTls) {
- const connectPromise = Deno.connectTls({
- hostname: "localhost",
- port,
- caCerts,
- alpnProtocols: clientAlpnProtocols,
- });
- endpoints = await Promise.all([acceptPromise, connectPromise]);
- } else {
- const client = await Deno.connect({
- hostname: "localhost",
- port,
- });
- const connectPromise = Deno.startTls(client, {
- hostname: "localhost",
- caCerts,
- alpnProtocols: clientAlpnProtocols,
- });
- endpoints = await Promise.all([acceptPromise, connectPromise]);
- }
-
- listener.close();
- return endpoints;
-}
-
-async function sendThenCloseWriteThenReceive(
- conn: Deno.Conn,
- chunkCount: number,
- chunkSize: number,
-) {
- const byteCount = chunkCount * chunkSize;
- const buf = new Uint8Array(chunkSize); // Note: buf is size of _chunk_.
- let n: number;
-
- // Slowly send 42s.
- buf.fill(42);
- for (let remaining = byteCount; remaining > 0; remaining -= n) {
- n = await conn.write(buf.subarray(0, remaining));
- assert(n >= 1);
- await sleep(10);
- }
-
- // Send EOF.
- await conn.closeWrite();
-
- // Receive 69s.
- for (let remaining = byteCount; remaining > 0; remaining -= n) {
- buf.fill(0);
- n = await conn.read(buf) as number;
- assert(n >= 1);
- assertStrictEquals(buf[0], 69);
- assertStrictEquals(buf[n - 1], 69);
- }
-
- conn.close();
-}
-
-async function receiveThenSend(
- conn: Deno.Conn,
- chunkCount: number,
- chunkSize: number,
-) {
- const byteCount = chunkCount * chunkSize;
- const buf = new Uint8Array(byteCount); // Note: buf size equals `byteCount`.
- let n: number;
-
- // Receive 42s.
- for (let remaining = byteCount; remaining > 0; remaining -= n) {
- buf.fill(0);
- n = await conn.read(buf) as number;
- assert(n >= 1);
- assertStrictEquals(buf[0], 42);
- assertStrictEquals(buf[n - 1], 42);
- }
-
- // Slowly send 69s.
- buf.fill(69);
- for (let remaining = byteCount; remaining > 0; remaining -= n) {
- n = await conn.write(buf.subarray(0, remaining));
- assert(n >= 1);
- await sleep(10);
- }
-
- conn.close();
-}
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsServerAlpnListenConnect() {
- const [serverConn, clientConn] = await tlsAlpn(false);
- const [serverHS, clientHS] = await Promise.all([
- serverConn.handshake(),
- clientConn.handshake(),
- ]);
- assertStrictEquals(serverHS.alpnProtocol, "rocks");
- assertStrictEquals(clientHS.alpnProtocol, "rocks");
-
- serverConn.close();
- clientConn.close();
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsServerAlpnListenStartTls() {
- const [serverConn, clientConn] = await tlsAlpn(true);
- const [serverHS, clientHS] = await Promise.all([
- serverConn.handshake(),
- clientConn.handshake(),
- ]);
- assertStrictEquals(serverHS.alpnProtocol, "rocks");
- assertStrictEquals(clientHS.alpnProtocol, "rocks");
-
- serverConn.close();
- clientConn.close();
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsServerStreamHalfCloseSendOneByte() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendThenCloseWriteThenReceive(serverConn, 1, 1),
- receiveThenSend(clientConn, 1, 1),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsClientStreamHalfCloseSendOneByte() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendThenCloseWriteThenReceive(clientConn, 1, 1),
- receiveThenSend(serverConn, 1, 1),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsServerStreamHalfCloseSendOneChunk() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendThenCloseWriteThenReceive(serverConn, 1, 1 << 20 /* 1 MB */),
- receiveThenSend(clientConn, 1, 1 << 20 /* 1 MB */),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsClientStreamHalfCloseSendOneChunk() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendThenCloseWriteThenReceive(clientConn, 1, 1 << 20 /* 1 MB */),
- receiveThenSend(serverConn, 1, 1 << 20 /* 1 MB */),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsServerStreamHalfCloseSendManyBytes() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendThenCloseWriteThenReceive(serverConn, 100, 1),
- receiveThenSend(clientConn, 100, 1),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsClientStreamHalfCloseSendManyBytes() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendThenCloseWriteThenReceive(clientConn, 100, 1),
- receiveThenSend(serverConn, 100, 1),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsServerStreamHalfCloseSendManyChunks() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendThenCloseWriteThenReceive(serverConn, 100, 1 << 16 /* 64 kB */),
- receiveThenSend(clientConn, 100, 1 << 16 /* 64 kB */),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsClientStreamHalfCloseSendManyChunks() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendThenCloseWriteThenReceive(clientConn, 100, 1 << 16 /* 64 kB */),
- receiveThenSend(serverConn, 100, 1 << 16 /* 64 kB */),
- ]);
- },
-);
-
-const largeAmount = 1 << 20 /* 1 MB */;
-
-async function sendAlotReceiveNothing(conn: Deno.Conn) {
- // Start receive op.
- const readBuf = new Uint8Array(1024);
- const readPromise = conn.read(readBuf);
-
- const timeout = setTimeout(() => {
- throw new Error("Failed to send buffer in a reasonable amount of time");
- }, 10_000);
-
- // Send 1 MB of data.
- const writeBuf = new Uint8Array(largeAmount);
- writeBuf.fill(42);
- await writeAll(conn, writeBuf);
-
- clearTimeout(timeout);
-
- // Send EOF.
- await conn.closeWrite();
-
- // Close the connection.
- conn.close();
-
- // Read op should be canceled.
- await assertRejects(
- async () => await readPromise,
- Deno.errors.Interrupted,
- );
-}
-
-async function receiveAlotSendNothing(conn: Deno.Conn) {
- const readBuf = new Uint8Array(1024);
- let n: number | null;
- let nread = 0;
-
- const timeout = setTimeout(() => {
- throw new Error(
- `Failed to read buffer in a reasonable amount of time (got ${nread}/${largeAmount})`,
- );
- }, 10_000);
-
- // Receive 1 MB of data.
- try {
- for (; nread < largeAmount; nread += n!) {
- n = await conn.read(readBuf);
- assertStrictEquals(typeof n, "number");
- assert(n! > 0);
- assertStrictEquals(readBuf[0], 42);
- }
- } catch (e) {
- throw new Error(
- `Got an error (${e.message}) after reading ${nread}/${largeAmount} bytes`,
- { cause: e },
- );
- }
- clearTimeout(timeout);
-
- // Close the connection, without sending anything at all.
- conn.close();
-}
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsServerStreamCancelRead() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendAlotReceiveNothing(serverConn),
- receiveAlotSendNothing(clientConn),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsClientStreamCancelRead() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendAlotReceiveNothing(clientConn),
- receiveAlotSendNothing(serverConn),
- ]);
- },
-);
-
-async function sendReceiveEmptyBuf(conn: Deno.Conn) {
- const byteBuf = new Uint8Array([1]);
- const emptyBuf = new Uint8Array(0);
- let n: number | null;
-
- n = await conn.write(emptyBuf);
- assertStrictEquals(n, 0);
-
- n = await conn.read(emptyBuf);
- assertStrictEquals(n, 0);
-
- n = await conn.write(byteBuf);
- assertStrictEquals(n, 1);
-
- n = await conn.read(byteBuf);
- assertStrictEquals(n, 1);
-
- await conn.closeWrite();
-
- n = await conn.write(emptyBuf);
- assertStrictEquals(n, 0);
-
- await assertRejects(async () => {
- await conn.write(byteBuf);
- }, Deno.errors.NotConnected);
-
- n = await conn.write(emptyBuf);
- assertStrictEquals(n, 0);
-
- n = await conn.read(byteBuf);
- assertStrictEquals(n, null);
-
- conn.close();
-}
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsStreamSendReceiveEmptyBuf() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- sendReceiveEmptyBuf(serverConn),
- sendReceiveEmptyBuf(clientConn),
- ]);
- },
-);
-
-function immediateClose(conn: Deno.Conn) {
- conn.close();
- return Promise.resolve();
-}
-
-async function closeWriteAndClose(conn: Deno.Conn) {
- await conn.closeWrite();
-
- if (await conn.read(new Uint8Array(1)) !== null) {
- throw new Error("did not expect to receive data on TLS stream");
- }
-
- conn.close();
-}
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsServerStreamImmediateClose() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- immediateClose(serverConn),
- closeWriteAndClose(clientConn),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsClientStreamImmediateClose() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- closeWriteAndClose(serverConn),
- immediateClose(clientConn),
- ]);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsClientAndServerStreamImmediateClose() {
- const [serverConn, clientConn] = await tlsPair();
- await Promise.all([
- immediateClose(serverConn),
- immediateClose(clientConn),
- ]);
- },
-);
-
-async function tlsWithTcpFailureTestImpl(
- phase: "handshake" | "traffic",
- cipherByteCount: number,
- failureMode: "corruption" | "shutdown",
- reverse: boolean,
-) {
- const tlsPort = getPort();
- const tlsListener = Deno.listenTls({
- hostname: "localhost",
- port: tlsPort,
- cert: await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"),
- key: await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"),
- });
-
- const tcpPort = getPort();
- const tcpListener = Deno.listen({ hostname: "localhost", port: tcpPort });
-
- const [tlsServerConn, tcpServerConn] = await Promise.all([
- tlsListener.accept(),
- Deno.connect({ hostname: "localhost", port: tlsPort }),
- ]);
-
- const [tcpClientConn, tlsClientConn] = await Promise.all([
- tcpListener.accept(),
- Deno.connectTls({
- hostname: "localhost",
- port: tcpPort,
- caCerts: [Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem")],
- }),
- ]);
-
- tlsListener.close();
- tcpListener.close();
-
- const {
- tlsConn1,
- tlsConn2,
- tcpConn1,
- tcpConn2,
- } = reverse
- ? {
- tlsConn1: tlsClientConn,
- tlsConn2: tlsServerConn,
- tcpConn1: tcpClientConn,
- tcpConn2: tcpServerConn,
- }
- : {
- tlsConn1: tlsServerConn,
- tlsConn2: tlsClientConn,
- tcpConn1: tcpServerConn,
- tcpConn2: tcpClientConn,
- };
-
- const tcpForwardingInterruptDeferred1 = Promise.withResolvers<void>();
- const tcpForwardingPromise1 = forwardBytes(
- tcpConn2,
- tcpConn1,
- cipherByteCount,
- tcpForwardingInterruptDeferred1,
- );
-
- const tcpForwardingInterruptDeferred2 = Promise.withResolvers<void>();
- const tcpForwardingPromise2 = forwardBytes(
- tcpConn1,
- tcpConn2,
- Infinity,
- tcpForwardingInterruptDeferred2,
- );
-
- switch (phase) {
- case "handshake": {
- let expectedError;
- switch (failureMode) {
- case "corruption":
- expectedError = Deno.errors.InvalidData;
- break;
- case "shutdown":
- expectedError = Deno.errors.UnexpectedEof;
- break;
- default:
- unreachable();
- }
-
- const tlsTrafficPromise1 = Promise.all([
- assertRejects(
- () => sendBytes(tlsConn1, 0x01, 1),
- expectedError,
- ),
- assertRejects(
- () => receiveBytes(tlsConn1, 0x02, 1),
- expectedError,
- ),
- ]);
-
- const tlsTrafficPromise2 = Promise.all([
- assertRejects(
- () => sendBytes(tlsConn2, 0x02, 1),
- Deno.errors.UnexpectedEof,
- ),
- assertRejects(
- () => receiveBytes(tlsConn2, 0x01, 1),
- Deno.errors.UnexpectedEof,
- ),
- ]);
-
- await tcpForwardingPromise1;
-
- switch (failureMode) {
- case "corruption":
- await sendBytes(tcpConn1, 0xff, 1 << 14 /* 16 kB */);
- break;
- case "shutdown":
- await tcpConn1.closeWrite();
- break;
- default:
- unreachable();
- }
- await tlsTrafficPromise1;
-
- tcpForwardingInterruptDeferred2.resolve();
- await tcpForwardingPromise2;
- await tcpConn2.closeWrite();
- await tlsTrafficPromise2;
-
- break;
- }
-
- case "traffic": {
- await Promise.all([
- sendBytes(tlsConn2, 0x88, 8888),
- receiveBytes(tlsConn1, 0x88, 8888),
- sendBytes(tlsConn1, 0x99, 99999),
- receiveBytes(tlsConn2, 0x99, 99999),
- ]);
-
- tcpForwardingInterruptDeferred1.resolve();
- await tcpForwardingInterruptDeferred1.promise;
-
- switch (failureMode) {
- case "corruption":
- await sendBytes(tcpConn1, 0xff, 1 << 14 /* 16 kB */);
- await assertRejects(
- () => receiveEof(tlsConn1),
- Deno.errors.InvalidData,
- );
- tcpForwardingInterruptDeferred2.resolve();
- break;
- case "shutdown":
- await Promise.all([
- tcpConn1.closeWrite(),
- await assertRejects(
- () => receiveEof(tlsConn1),
- Deno.errors.UnexpectedEof,
- ),
- await tlsConn1.closeWrite(),
- await receiveEof(tlsConn2),
- ]);
- break;
- default:
- unreachable();
- }
-
- await tcpForwardingPromise2;
-
- break;
- }
-
- default:
- unreachable();
- }
-
- tlsServerConn.close();
- tlsClientConn.close();
- tcpServerConn.close();
- tcpClientConn.close();
-
- async function sendBytes(
- conn: Deno.Conn,
- byte: number,
- count: number,
- ) {
- let buf = new Uint8Array(1 << 12 /* 4 kB */);
- buf.fill(byte);
-
- while (count > 0) {
- buf = buf.subarray(0, Math.min(buf.length, count));
- const nwritten = await conn.write(buf);
- assertStrictEquals(nwritten, buf.length);
- count -= nwritten;
- }
- }
-
- async function receiveBytes(
- conn: Deno.Conn,
- byte: number,
- count: number,
- ) {
- let buf = new Uint8Array(1 << 12 /* 4 kB */);
- while (count > 0) {
- buf = buf.subarray(0, Math.min(buf.length, count));
- const r = await conn.read(buf);
- assertNotEquals(r, null);
- assert(buf.subarray(0, r!).every((b) => b === byte));
- count -= r!;
- }
- }
-
- async function receiveEof(conn: Deno.Conn) {
- const buf = new Uint8Array(1);
- const r = await conn.read(buf);
- assertStrictEquals(r, null);
- }
-
- async function forwardBytes(
- source: Deno.Conn,
- sink: Deno.Conn,
- count: number,
- interruptPromise: ReturnType<typeof Promise.withResolvers<void>>,
- ) {
- let buf = new Uint8Array(1 << 12 /* 4 kB */);
- while (count > 0) {
- buf = buf.subarray(0, Math.min(buf.length, count));
- const nread = await Promise.race([
- source.read(buf),
- interruptPromise.promise,
- ]);
- if (nread == null) break; // Either EOF or interrupted.
- const nwritten = await sink.write(buf.subarray(0, nread));
- assertStrictEquals(nread, nwritten);
- count -= nwritten;
- }
- }
-}
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsHandshakeWithTcpCorruptionImmediately() {
- await tlsWithTcpFailureTestImpl("handshake", 0, "corruption", false);
- await tlsWithTcpFailureTestImpl("handshake", 0, "corruption", true);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsHandshakeWithTcpShutdownImmediately() {
- await tlsWithTcpFailureTestImpl("handshake", 0, "shutdown", false);
- await tlsWithTcpFailureTestImpl("handshake", 0, "shutdown", true);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsHandshakeWithTcpCorruptionAfter70Bytes() {
- await tlsWithTcpFailureTestImpl("handshake", 76, "corruption", false);
- await tlsWithTcpFailureTestImpl("handshake", 78, "corruption", true);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsHandshakeWithTcpShutdownAfter70bytes() {
- await tlsWithTcpFailureTestImpl("handshake", 77, "shutdown", false);
- await tlsWithTcpFailureTestImpl("handshake", 79, "shutdown", true);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsHandshakeWithTcpCorruptionAfter200Bytes() {
- await tlsWithTcpFailureTestImpl("handshake", 200, "corruption", false);
- await tlsWithTcpFailureTestImpl("handshake", 202, "corruption", true);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsHandshakeWithTcpShutdownAfter200bytes() {
- await tlsWithTcpFailureTestImpl("handshake", 201, "shutdown", false);
- await tlsWithTcpFailureTestImpl("handshake", 203, "shutdown", true);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsTrafficWithTcpCorruption() {
- await tlsWithTcpFailureTestImpl("traffic", Infinity, "corruption", false);
- await tlsWithTcpFailureTestImpl("traffic", Infinity, "corruption", true);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsTrafficWithTcpShutdown() {
- await tlsWithTcpFailureTestImpl("traffic", Infinity, "shutdown", false);
- await tlsWithTcpFailureTestImpl("traffic", Infinity, "shutdown", true);
- },
-);
-
-function createHttpsListener(port: number): Deno.Listener {
- // Query format: `curl --insecure https://localhost:8443/z/12345`
- // The server returns a response consisting of 12345 times the letter 'z'.
- const listener = Deno.listenTls({
- hostname: "localhost",
- port,
- cert: Deno.readTextFileSync("./cli/tests/testdata/tls/localhost.crt"),
- key: Deno.readTextFileSync("./cli/tests/testdata/tls/localhost.key"),
- });
-
- serve(listener);
- return listener;
-
- async function serve(listener: Deno.Listener) {
- for await (const conn of listener) {
- const EOL = "\r\n";
-
- // Read GET request plus headers.
- const buf = new Uint8Array(1 << 12 /* 4 kB */);
- const decoder = new TextDecoder();
- let req = "";
- while (!req.endsWith(EOL + EOL)) {
- const n = await conn.read(buf);
- if (n === null) throw new Error("Unexpected EOF");
- req += decoder.decode(buf.subarray(0, n));
- }
-
- // Parse GET request.
- const { filler, count, version } =
- /^GET \/(?<filler>[^\/]+)\/(?<count>\d+) HTTP\/(?<version>1\.\d)\r\n/
- .exec(req)!.groups as {
- filler: string;
- count: string;
- version: string;
- };
-
- // Generate response.
- const resBody = new TextEncoder().encode(filler.repeat(+count));
- const resHead = new TextEncoder().encode(
- [
- `HTTP/${version} 200 OK`,
- `Content-Length: ${resBody.length}`,
- "Content-Type: text/plain",
- ].join(EOL) + EOL + EOL,
- );
-
- // Send response.
- await writeAll(conn, resHead);
- await writeAll(conn, resBody);
-
- // Close TCP connection.
- conn.close();
- }
- }
-}
-
-async function curl(url: string): Promise<string> {
- const { success, code, stdout, stderr } = await new Deno.Command("curl", {
- args: ["--insecure", url],
- }).output();
-
- if (!success) {
- throw new Error(
- `curl ${url} failed: ${code}:\n${new TextDecoder().decode(stderr)}`,
- );
- }
- return new TextDecoder().decode(stdout);
-}
-
-Deno.test(
- { permissions: { read: true, net: true, run: true } },
- async function curlFakeHttpsServer() {
- const port = getPort();
- const listener = createHttpsListener(port);
-
- const res1 = await curl(`https://localhost:${port}/d/1`);
- assertStrictEquals(res1, "d");
-
- const res2 = await curl(`https://localhost:${port}/e/12345`);
- assertStrictEquals(res2, "e".repeat(12345));
-
- const count3 = 1 << 17; // 128 kB.
- const res3 = await curl(`https://localhost:${port}/n/${count3}`);
- assertStrictEquals(res3, "n".repeat(count3));
-
- const count4 = 12345678;
- const res4 = await curl(`https://localhost:${port}/o/${count4}`);
- assertStrictEquals(res4, "o".repeat(count4));
-
- listener.close();
- },
-);
-
-Deno.test(
- // Ignored because gmail appears to reject us on CI sometimes
- { ignore: true, permissions: { read: true, net: true } },
- async function startTls() {
- const hostname = "smtp.gmail.com";
- const port = 587;
- const encoder = new TextEncoder();
-
- const conn = await Deno.connect({
- hostname,
- port,
- });
-
- let writer = new BufWriter(conn);
- let reader = new TextProtoReader(new BufReader(conn));
-
- let line: string | null = (await reader.readLine()) as string;
- assert(line.startsWith("220"));
-
- await writer.write(encoder.encode(`EHLO ${hostname}\r\n`));
- await writer.flush();
-
- while ((line = (await reader.readLine()) as string)) {
- assert(line.startsWith("250"));
- if (line.startsWith("250 ")) break;
- }
-
- await writer.write(encoder.encode("STARTTLS\r\n"));
- await writer.flush();
-
- line = await reader.readLine();
-
- // Received the message that the server is ready to establish TLS
- assertEquals(line, "220 2.0.0 Ready to start TLS");
-
- const tlsConn = await Deno.startTls(conn, { hostname });
- writer = new BufWriter(tlsConn);
- reader = new TextProtoReader(new BufReader(tlsConn));
-
- // After that use TLS communication again
- await writer.write(encoder.encode(`EHLO ${hostname}\r\n`));
- await writer.flush();
-
- while ((line = (await reader.readLine()) as string)) {
- assert(line.startsWith("250"));
- if (line.startsWith("250 ")) break;
- }
-
- tlsConn.close();
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function connectTLSBadClientCertPrivateKey(): Promise<void> {
- await assertRejects(async () => {
- await Deno.connectTls({
- hostname: "deno.land",
- port: 443,
- certChain: "bad data",
- privateKey: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.key",
- ),
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function connectTLSBadPrivateKey(): Promise<void> {
- await assertRejects(async () => {
- await Deno.connectTls({
- hostname: "deno.land",
- port: 443,
- certChain: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.crt",
- ),
- privateKey: "bad data",
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function connectTLSNotPrivateKey(): Promise<void> {
- await assertRejects(async () => {
- await Deno.connectTls({
- hostname: "deno.land",
- port: 443,
- certChain: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.crt",
- ),
- privateKey: "",
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function connectWithClientCert() {
- // The test_server running on port 4552 responds with 'PASS' if client
- // authentication was successful. Try it by running test_server and
- // curl --key cli/tests/testdata/tls/localhost.key \
- // --cert cli/tests/testdata/tls/localhost.crt \
- // --cacert cli/tests/testdata/tls/RootCA.crt https://localhost:4552/
- const conn = await Deno.connectTls({
- hostname: "localhost",
- port: 4552,
- certChain: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.crt",
- ),
- privateKey: await Deno.readTextFile(
- "cli/tests/testdata/tls/localhost.key",
- ),
- caCerts: [Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem")],
- });
- const result = decoder.decode(await readAll(conn));
- assertEquals(result, "PASS");
- conn.close();
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function connectTLSCaCerts() {
- const conn = await Deno.connectTls({
- hostname: "localhost",
- port: 4557,
- caCerts: [Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem")],
- });
- const result = decoder.decode(await readAll(conn));
- assertEquals(result, "PASS");
- conn.close();
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function connectTLSCertFile() {
- const conn = await Deno.connectTls({
- hostname: "localhost",
- port: 4557,
- certFile: "cli/tests/testdata/tls/RootCA.pem",
- });
- const result = decoder.decode(await readAll(conn));
- assertEquals(result, "PASS");
- conn.close();
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function startTLSCaCerts() {
- const plainConn = await Deno.connect({
- hostname: "localhost",
- port: 4557,
- });
- const conn = await Deno.startTls(plainConn, {
- hostname: "localhost",
- caCerts: [Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem")],
- });
- const result = decoder.decode(await readAll(conn));
- assertEquals(result, "PASS");
- conn.close();
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsHandshakeSuccess() {
- const hostname = "localhost";
- const port = getPort();
-
- const listener = Deno.listenTls({
- hostname,
- port,
- cert: await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt"),
- key: await Deno.readTextFile("cli/tests/testdata/tls/localhost.key"),
- });
- const acceptPromise = listener.accept();
- const connectPromise = Deno.connectTls({
- hostname,
- port,
- certFile: "cli/tests/testdata/tls/RootCA.crt",
- });
- const [conn1, conn2] = await Promise.all([acceptPromise, connectPromise]);
- listener.close();
-
- await Promise.all([conn1.handshake(), conn2.handshake()]);
-
- // Begin sending a 10mb blob over the TLS connection.
- const whole = new Uint8Array(10 << 20); // 10mb.
- whole.fill(42);
- const sendPromise = writeAll(conn1, whole);
- // Set up the other end to receive half of the large blob.
- const half = new Uint8Array(whole.byteLength / 2);
- const receivePromise = readFull(conn2, half);
-
- await conn1.handshake();
- await conn2.handshake();
-
- // Finish receiving the first 5mb.
- assertEquals(await receivePromise, half.length);
-
- // See that we can call `handshake()` in the middle of large reads and writes.
- await conn1.handshake();
- await conn2.handshake();
-
- // Receive second half of large blob. Wait for the send promise and check it.
- assertEquals(await readFull(conn2, half), half.length);
- await sendPromise;
-
- await conn1.handshake();
- await conn2.handshake();
-
- await conn1.closeWrite();
- await conn2.closeWrite();
-
- await conn1.handshake();
- await conn2.handshake();
-
- conn1.close();
- conn2.close();
-
- async function readFull(conn: Deno.Conn, buf: Uint8Array) {
- let offset, n;
- for (offset = 0; offset < buf.length; offset += n) {
- n = await conn.read(buf.subarray(offset, buf.length));
- assert(n != null && n > 0);
- }
- return offset;
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, net: true } },
- async function tlsHandshakeFailure() {
- const hostname = "localhost";
- const port = getPort();
-
- async function server() {
- const listener = Deno.listenTls({
- hostname,
- port,
- cert: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.crt"),
- key: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.key"),
- });
- for await (const conn of listener) {
- for (let i = 0; i < 10; i++) {
- // Handshake fails because the client rejects the server certificate.
- await assertRejects(
- () => conn.handshake(),
- Deno.errors.InvalidData,
- "received fatal alert",
- );
- }
- conn.close();
- break;
- }
- }
-
- async function connectTlsClient() {
- const conn = await Deno.connectTls({ hostname, port });
- // Handshake fails because the server presents a self-signed certificate.
- await assertRejects(
- () => conn.handshake(),
- Deno.errors.InvalidData,
- "invalid peer certificate: UnknownIssuer",
- );
- conn.close();
- }
-
- await Promise.all([server(), connectTlsClient()]);
-
- async function startTlsClient() {
- const tcpConn = await Deno.connect({ hostname, port });
- const tlsConn = await Deno.startTls(tcpConn, {
- hostname: "foo.land",
- caCerts: [Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem")],
- });
- // Handshake fails because hostname doesn't match the certificate.
- await assertRejects(
- () => tlsConn.handshake(),
- Deno.errors.InvalidData,
- "NotValidForName",
- );
- tlsConn.close();
- }
-
- await Promise.all([server(), startTlsClient()]);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function listenTlsWithReuseAddr() {
- const deferred1 = Promise.withResolvers<void>();
- const hostname = "localhost";
- const port = 3500;
-
- const listener1 = Deno.listenTls({ hostname, port, cert, key });
-
- listener1.accept().then((conn) => {
- conn.close();
- deferred1.resolve();
- });
-
- const conn1 = await Deno.connectTls({ hostname, port, caCerts });
- conn1.close();
- await deferred1.promise;
- listener1.close();
-
- const deferred2 = Promise.withResolvers<void>();
- const listener2 = Deno.listenTls({ hostname, port, cert, key });
-
- listener2.accept().then((conn) => {
- conn.close();
- deferred2.resolve();
- });
-
- const conn2 = await Deno.connectTls({ hostname, port, caCerts });
- conn2.close();
- await deferred2.promise;
- listener2.close();
- },
-);
-
-Deno.test({
- ignore: Deno.build.os !== "linux",
- permissions: { net: true },
-}, async function listenTlsReusePort() {
- const hostname = "localhost";
- const port = 4003;
- const listener1 = Deno.listenTls({
- hostname,
- port,
- cert,
- key,
- reusePort: true,
- });
- const listener2 = Deno.listenTls({
- hostname,
- port,
- cert,
- key,
- reusePort: true,
- });
- let p1;
- let p2;
- let listener1Recv = false;
- let listener2Recv = false;
- while (!listener1Recv || !listener2Recv) {
- if (!p1) {
- p1 = listener1.accept().then((conn) => {
- conn.close();
- listener1Recv = true;
- p1 = undefined;
- }).catch(() => {});
- }
- if (!p2) {
- p2 = listener2.accept().then((conn) => {
- conn.close();
- listener2Recv = true;
- p2 = undefined;
- }).catch(() => {});
- }
- const conn = await Deno.connectTls({ hostname, port, caCerts });
- conn.close();
- await Promise.race([p1, p2]);
- }
- listener1.close();
- listener2.close();
-});
-
-Deno.test({
- ignore: Deno.build.os === "linux",
- permissions: { net: true },
-}, function listenTlsReusePortDoesNothing() {
- const hostname = "localhost";
- const port = 4003;
- const listener1 = Deno.listenTls({
- hostname,
- port,
- cert,
- key,
- reusePort: true,
- });
- assertThrows(() => {
- Deno.listenTls({ hostname, port, cert, key, reusePort: true });
- }, Deno.errors.AddrInUse);
- listener1.close();
-});
-
-Deno.test({
- permissions: { net: true },
-}, function listenTlsDoesNotThrowOnStringPort() {
- const listener = Deno.listenTls({
- hostname: "localhost",
- // @ts-ignore String port is not allowed by typing, but it shouldn't throw
- // for backwards compatibility.
- port: "0",
- cert,
- key,
- });
- listener.close();
-});
-
-Deno.test(
- { permissions: { net: true, read: true } },
- function listenTLSInvalidCert() {
- assertThrows(() => {
- Deno.listenTls({
- hostname: "localhost",
- port: 3500,
- certFile: "cli/tests/testdata/tls/invalid.crt",
- keyFile: "cli/tests/testdata/tls/localhost.key",
- });
- }, Deno.errors.InvalidData);
- },
-);
-
-Deno.test(
- { permissions: { net: true, read: true } },
- function listenTLSInvalidKey() {
- assertThrows(() => {
- Deno.listenTls({
- hostname: "localhost",
- port: 3500,
- certFile: "cli/tests/testdata/tls/localhost.crt",
- keyFile: "cli/tests/testdata/tls/invalid.key",
- });
- }, Deno.errors.InvalidData);
- },
-);
diff --git a/cli/tests/unit/truncate_test.ts b/cli/tests/unit/truncate_test.ts
deleted file mode 100644
index 95b76052d..000000000
--- a/cli/tests/unit/truncate_test.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals, assertRejects, assertThrows } from "./test_util.ts";
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function ftruncateSyncSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_ftruncateSync.txt";
- using file = Deno.openSync(filename, {
- create: true,
- read: true,
- write: true,
- });
-
- file.truncateSync(20);
- assertEquals(Deno.readFileSync(filename).byteLength, 20);
- file.truncateSync(5);
- assertEquals(Deno.readFileSync(filename).byteLength, 5);
- file.truncateSync(-5);
- assertEquals(Deno.readFileSync(filename).byteLength, 0);
-
- Deno.removeSync(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function ftruncateSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_ftruncate.txt";
- using file = await Deno.open(filename, {
- create: true,
- read: true,
- write: true,
- });
-
- await file.truncate(20);
- assertEquals((await Deno.readFile(filename)).byteLength, 20);
- await file.truncate(5);
- assertEquals((await Deno.readFile(filename)).byteLength, 5);
- await file.truncate(-5);
- assertEquals((await Deno.readFile(filename)).byteLength, 0);
-
- await Deno.remove(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function truncateSyncSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_truncateSync.txt";
- Deno.writeFileSync(filename, new Uint8Array(5));
- Deno.truncateSync(filename, 20);
- assertEquals(Deno.readFileSync(filename).byteLength, 20);
- Deno.truncateSync(filename, 5);
- assertEquals(Deno.readFileSync(filename).byteLength, 5);
- Deno.truncateSync(filename, -5);
- assertEquals(Deno.readFileSync(filename).byteLength, 0);
- Deno.removeSync(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function truncateSuccess() {
- const filename = Deno.makeTempDirSync() + "/test_truncate.txt";
- await Deno.writeFile(filename, new Uint8Array(5));
- await Deno.truncate(filename, 20);
- assertEquals((await Deno.readFile(filename)).byteLength, 20);
- await Deno.truncate(filename, 5);
- assertEquals((await Deno.readFile(filename)).byteLength, 5);
- await Deno.truncate(filename, -5);
- assertEquals((await Deno.readFile(filename)).byteLength, 0);
- await Deno.remove(filename);
- },
-);
-
-Deno.test({ permissions: { write: false } }, function truncateSyncPerm() {
- assertThrows(() => {
- Deno.truncateSync("/test_truncateSyncPermission.txt");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test({ permissions: { write: false } }, async function truncatePerm() {
- await assertRejects(async () => {
- await Deno.truncate("/test_truncatePermission.txt");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function truncateSyncNotFound() {
- const filename = "/badfile.txt";
- assertThrows(
- () => {
- Deno.truncateSync(filename);
- },
- Deno.errors.NotFound,
- `truncate '${filename}'`,
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function truncateSyncNotFound() {
- const filename = "/badfile.txt";
- await assertRejects(
- async () => {
- await Deno.truncate(filename);
- },
- Deno.errors.NotFound,
- `truncate '${filename}'`,
- );
- },
-);
diff --git a/cli/tests/unit/tty_color_test.ts b/cli/tests/unit/tty_color_test.ts
deleted file mode 100644
index 6f26891e3..000000000
--- a/cli/tests/unit/tty_color_test.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-// Note tests for Deno.stdin.setRaw is in integration tests.
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function noColorIfNotTty() {
- const { stdout } = await new Deno.Command(Deno.execPath(), {
- args: ["eval", "console.log(1)"],
- }).output();
- const output = new TextDecoder().decode(stdout);
- assertEquals(output, "1\n");
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function denoNoColorIsNotAffectedByNonTty() {
- const { stdout } = await new Deno.Command(Deno.execPath(), {
- args: ["eval", "console.log(Deno.noColor)"],
- }).output();
- const output = new TextDecoder().decode(stdout);
- assertEquals(output, "false\n");
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function denoNoColorTrueEmptyVar() {
- const { stdout } = await new Deno.Command(Deno.execPath(), {
- args: ["eval", "console.log(Deno.noColor)"],
- env: {
- // https://no-color.org/ -- should not be true when empty
- NO_COLOR: "",
- },
- }).output();
- const output = new TextDecoder().decode(stdout);
- assertEquals(output, "false\n");
- },
-);
-
-Deno.test(
- { permissions: { run: true, read: true } },
- async function denoNoColorTrueEmptyVar() {
- const { stdout } = await new Deno.Command(Deno.execPath(), {
- args: ["eval", "console.log(Deno.noColor)"],
- env: {
- NO_COLOR: "1",
- },
- }).output();
- const output = new TextDecoder().decode(stdout);
- assertEquals(output, "true\n");
- },
-);
diff --git a/cli/tests/unit/tty_test.ts b/cli/tests/unit/tty_test.ts
deleted file mode 100644
index 8ca9a5d5b..000000000
--- a/cli/tests/unit/tty_test.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert } from "./test_util.ts";
-
-// Note tests for Deno.stdin.setRaw is in integration tests.
-
-Deno.test(function consoleSize() {
- if (!Deno.stdout.isTerminal()) {
- return;
- }
- const result = Deno.consoleSize();
- assert(typeof result.columns !== "undefined");
- assert(typeof result.rows !== "undefined");
-});
-
-Deno.test({ permissions: { read: true } }, function isatty() {
- // CI not under TTY, so cannot test stdin/stdout/stderr.
- const f = Deno.openSync("cli/tests/testdata/assets/hello.txt");
- assert(!Deno.isatty(f.rid));
- f.close();
-});
-
-Deno.test(function isattyError() {
- let caught = false;
- try {
- // Absurdly large rid.
- Deno.isatty(0x7fffffff);
- } catch (e) {
- caught = true;
- assert(e instanceof Deno.errors.BadResource);
- }
- assert(caught);
-});
diff --git a/cli/tests/unit/umask_test.ts b/cli/tests/unit/umask_test.ts
deleted file mode 100644
index 0e97f0d35..000000000
--- a/cli/tests/unit/umask_test.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-Deno.test(
- {
- ignore: Deno.build.os === "windows",
- },
- function umaskSuccess() {
- const prevMask = Deno.umask(0o020);
- const newMask = Deno.umask(prevMask);
- const finalMask = Deno.umask();
- assertEquals(newMask, 0o020);
- assertEquals(finalMask, prevMask);
- },
-);
diff --git a/cli/tests/unit/url_search_params_test.ts b/cli/tests/unit/url_search_params_test.ts
deleted file mode 100644
index c547ef938..000000000
--- a/cli/tests/unit/url_search_params_test.ts
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals } from "./test_util.ts";
-
-Deno.test(function urlSearchParamsWithMultipleSpaces() {
- const init = { str: "this string has spaces in it" };
- const searchParams = new URLSearchParams(init).toString();
- assertEquals(searchParams, "str=this+string+has+spaces+in+it");
-});
-
-Deno.test(function urlSearchParamsWithExclamation() {
- const init = [
- ["str", "hello, world!"],
- ];
- const searchParams = new URLSearchParams(init).toString();
- assertEquals(searchParams, "str=hello%2C+world%21");
-});
-
-Deno.test(function urlSearchParamsWithQuotes() {
- const init = [
- ["str", "'hello world'"],
- ];
- const searchParams = new URLSearchParams(init).toString();
- assertEquals(searchParams, "str=%27hello+world%27");
-});
-
-Deno.test(function urlSearchParamsWithBracket() {
- const init = [
- ["str", "(hello world)"],
- ];
- const searchParams = new URLSearchParams(init).toString();
- assertEquals(searchParams, "str=%28hello+world%29");
-});
-
-Deno.test(function urlSearchParamsWithTilde() {
- const init = [
- ["str", "hello~world"],
- ];
- const searchParams = new URLSearchParams(init).toString();
- assertEquals(searchParams, "str=hello%7Eworld");
-});
-
-Deno.test(function urlSearchParamsInitString() {
- const init = "c=4&a=2&b=3&%C3%A1=1";
- const searchParams = new URLSearchParams(init);
- assert(
- init === searchParams.toString(),
- "The init query string does not match",
- );
-});
-
-Deno.test(function urlSearchParamsInitStringWithPlusCharacter() {
- let params = new URLSearchParams("q=a+b");
- assertEquals(params.toString(), "q=a+b");
- assertEquals(params.get("q"), "a b");
-
- params = new URLSearchParams("q=a+b+c");
- assertEquals(params.toString(), "q=a+b+c");
- assertEquals(params.get("q"), "a b c");
-});
-
-Deno.test(function urlSearchParamsInitStringWithMalformedParams() {
- // These test cases are copied from Web Platform Tests
- // https://github.com/web-platform-tests/wpt/blob/54c6d64/url/urlsearchparams-constructor.any.js#L60-L80
- let params = new URLSearchParams("id=0&value=%");
- assert(params != null, "constructor returned non-null value.");
- assert(params.has("id"), 'Search params object has name "id"');
- assert(params.has("value"), 'Search params object has name "value"');
- assertEquals(params.get("id"), "0");
- assertEquals(params.get("value"), "%");
-
- params = new URLSearchParams("b=%2sf%2a");
- assert(params != null, "constructor returned non-null value.");
- assert(params.has("b"), 'Search params object has name "b"');
- assertEquals(params.get("b"), "%2sf*");
-
- params = new URLSearchParams("b=%2%2af%2a");
- assert(params != null, "constructor returned non-null value.");
- assert(params.has("b"), 'Search params object has name "b"');
- assertEquals(params.get("b"), "%2*f*");
-
- params = new URLSearchParams("b=%%2a");
- assert(params != null, "constructor returned non-null value.");
- assert(params.has("b"), 'Search params object has name "b"');
- assertEquals(params.get("b"), "%*");
-});
-
-Deno.test(function urlSearchParamsInitIterable() {
- const init = [
- ["a", "54"],
- ["b", "true"],
- ];
- const searchParams = new URLSearchParams(init);
- assertEquals(searchParams.toString(), "a=54&b=true");
-});
-
-Deno.test(function urlSearchParamsInitRecord() {
- const init = { a: "54", b: "true" };
- const searchParams = new URLSearchParams(init);
- assertEquals(searchParams.toString(), "a=54&b=true");
-});
-
-Deno.test(function urlSearchParamsInit() {
- const params1 = new URLSearchParams("a=b");
- assertEquals(params1.toString(), "a=b");
- const params2 = new URLSearchParams(params1);
- assertEquals(params2.toString(), "a=b");
-});
-
-Deno.test(function urlSearchParamsAppendSuccess() {
- const searchParams = new URLSearchParams();
- searchParams.append("a", "true");
- assertEquals(searchParams.toString(), "a=true");
-});
-
-Deno.test(function urlSearchParamsDeleteSuccess() {
- const init = "a=54&b=true";
- const searchParams = new URLSearchParams(init);
- searchParams.delete("b");
- assertEquals(searchParams.toString(), "a=54");
-});
-
-Deno.test(function urlSearchParamsGetAllSuccess() {
- const init = "a=54&b=true&a=true";
- const searchParams = new URLSearchParams(init);
- assertEquals(searchParams.getAll("a"), ["54", "true"]);
- assertEquals(searchParams.getAll("b"), ["true"]);
- assertEquals(searchParams.getAll("c"), []);
-});
-
-Deno.test(function urlSearchParamsGetSuccess() {
- const init = "a=54&b=true&a=true";
- const searchParams = new URLSearchParams(init);
- assertEquals(searchParams.get("a"), "54");
- assertEquals(searchParams.get("b"), "true");
- assertEquals(searchParams.get("c"), null);
-});
-
-Deno.test(function urlSearchParamsHasSuccess() {
- const init = "a=54&b=true&a=true";
- const searchParams = new URLSearchParams(init);
- assert(searchParams.has("a"));
- assert(searchParams.has("b"));
- assert(!searchParams.has("c"));
-});
-
-Deno.test(function urlSearchParamsSetReplaceFirstAndRemoveOthers() {
- const init = "a=54&b=true&a=true";
- const searchParams = new URLSearchParams(init);
- searchParams.set("a", "false");
- assertEquals(searchParams.toString(), "a=false&b=true");
-});
-
-Deno.test(function urlSearchParamsSetAppendNew() {
- const init = "a=54&b=true&a=true";
- const searchParams = new URLSearchParams(init);
- searchParams.set("c", "foo");
- assertEquals(searchParams.toString(), "a=54&b=true&a=true&c=foo");
-});
-
-Deno.test(function urlSearchParamsSortSuccess() {
- const init = "c=4&a=2&b=3&a=1";
- const searchParams = new URLSearchParams(init);
- searchParams.sort();
- assertEquals(searchParams.toString(), "a=2&a=1&b=3&c=4");
-});
-
-Deno.test(function urlSearchParamsForEachSuccess() {
- const init = [
- ["a", "54"],
- ["b", "true"],
- ];
- const searchParams = new URLSearchParams(init);
- let callNum = 0;
- searchParams.forEach((value, key, parent) => {
- assertEquals(searchParams, parent);
- assertEquals(value, init[callNum][1]);
- assertEquals(key, init[callNum][0]);
- callNum++;
- });
- assertEquals(callNum, init.length);
-});
-
-Deno.test(function urlSearchParamsMissingName() {
- const init = "=4";
- const searchParams = new URLSearchParams(init);
- assertEquals(searchParams.get(""), "4");
- assertEquals(searchParams.toString(), "=4");
-});
-
-Deno.test(function urlSearchParamsMissingValue() {
- const init = "4=";
- const searchParams = new URLSearchParams(init);
- assertEquals(searchParams.get("4"), "");
- assertEquals(searchParams.toString(), "4=");
-});
-
-Deno.test(function urlSearchParamsMissingEqualSign() {
- const init = "4";
- const searchParams = new URLSearchParams(init);
- assertEquals(searchParams.get("4"), "");
- assertEquals(searchParams.toString(), "4=");
-});
-
-Deno.test(function urlSearchParamsMissingPair() {
- const init = "c=4&&a=54&";
- const searchParams = new URLSearchParams(init);
- assertEquals(searchParams.toString(), "c=4&a=54");
-});
-
-Deno.test(function urlSearchParamsForShortEncodedChar() {
- const init = { linefeed: "\n", tab: "\t" };
- const searchParams = new URLSearchParams(init);
- assertEquals(searchParams.toString(), "linefeed=%0A&tab=%09");
-});
-
-// If pair does not contain exactly two items, then throw a TypeError.
-// ref https://url.spec.whatwg.org/#interface-urlsearchparams
-Deno.test(function urlSearchParamsShouldThrowTypeError() {
- let hasThrown = 0;
-
- try {
- new URLSearchParams([["1"]]);
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
-
- assertEquals(hasThrown, 2);
-
- try {
- new URLSearchParams([["1", "2", "3"]]);
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
-
- assertEquals(hasThrown, 2);
-});
-
-Deno.test(function urlSearchParamsAppendArgumentsCheck() {
- const methodRequireOneParam = ["delete", "getAll", "get", "has", "forEach"];
-
- const methodRequireTwoParams = ["append", "set"];
-
- methodRequireOneParam
- .concat(methodRequireTwoParams)
- .forEach((method: string) => {
- const searchParams = new URLSearchParams();
- let hasThrown = 0;
- try {
- // deno-lint-ignore no-explicit-any
- (searchParams as any)[method]();
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
- assertEquals(hasThrown, 2);
- });
-
- methodRequireTwoParams.forEach((method: string) => {
- const searchParams = new URLSearchParams();
- let hasThrown = 0;
- try {
- // deno-lint-ignore no-explicit-any
- (searchParams as any)[method]("foo");
- hasThrown = 1;
- } catch (err) {
- if (err instanceof TypeError) {
- hasThrown = 2;
- } else {
- hasThrown = 3;
- }
- }
- assertEquals(hasThrown, 2);
- });
-});
-
-// ref: https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-delete.any.js
-Deno.test(function urlSearchParamsDeletingAppendedMultiple() {
- const params = new URLSearchParams();
- params.append("first", (1 as unknown) as string);
- assert(params.has("first"));
- assertEquals(params.get("first"), "1");
- params.delete("first");
- assertEquals(params.has("first"), false);
- params.append("first", (1 as unknown) as string);
- params.append("first", (10 as unknown) as string);
- params.delete("first");
- assertEquals(params.has("first"), false);
-});
-
-// ref: https://github.com/web-platform-tests/wpt/blob/master/url/urlsearchparams-constructor.any.js#L176-L182
-Deno.test(function urlSearchParamsCustomSymbolIterator() {
- const params = new URLSearchParams();
- params[Symbol.iterator] = function* (): IterableIterator<[string, string]> {
- yield ["a", "b"];
- };
- const params1 = new URLSearchParams((params as unknown) as string[][]);
- assertEquals(params1.get("a"), "b");
-});
-
-Deno.test(
- function urlSearchParamsCustomSymbolIteratorWithNonStringParams() {
- const params = {};
- // deno-lint-ignore no-explicit-any
- (params as any)[Symbol.iterator] = function* (): IterableIterator<
- [number, number]
- > {
- yield [1, 2];
- };
- const params1 = new URLSearchParams((params as unknown) as string[][]);
- assertEquals(params1.get("1"), "2");
- },
-);
-
-// If a class extends URLSearchParams, override one method should not change another's behavior.
-Deno.test(
- function urlSearchParamsOverridingAppendNotChangeConstructorAndSet() {
- let overriddenAppendCalled = 0;
- class CustomSearchParams extends URLSearchParams {
- append(name: string, value: string) {
- ++overriddenAppendCalled;
- super.append(name, value);
- }
- }
- new CustomSearchParams("foo=bar");
- new CustomSearchParams([["foo", "bar"]]);
- new CustomSearchParams(new CustomSearchParams({ foo: "bar" }));
- new CustomSearchParams().set("foo", "bar");
- assertEquals(overriddenAppendCalled, 0);
- },
-);
-
-Deno.test(function urlSearchParamsOverridingEntriesNotChangeForEach() {
- class CustomSearchParams extends URLSearchParams {
- *entries(): IterableIterator<[string, string]> {
- yield* [];
- }
- }
- let loopCount = 0;
- const params = new CustomSearchParams({ foo: "bar" });
- params.forEach(() => void ++loopCount);
- assertEquals(loopCount, 1);
-});
diff --git a/cli/tests/unit/url_test.ts b/cli/tests/unit/url_test.ts
deleted file mode 100644
index b0dc86232..000000000
--- a/cli/tests/unit/url_test.ts
+++ /dev/null
@@ -1,529 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertStrictEquals,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(function urlParsing() {
- const url = new URL(
- "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat",
- );
- assertEquals(url.hash, "#qat");
- assertEquals(url.host, "baz.qat:8000");
- assertEquals(url.hostname, "baz.qat");
- assertEquals(
- url.href,
- "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat",
- );
- assertEquals(url.origin, "https://baz.qat:8000");
- assertEquals(url.password, "bar");
- assertEquals(url.pathname, "/qux/quux");
- assertEquals(url.port, "8000");
- assertEquals(url.protocol, "https:");
- assertEquals(url.search, "?foo=bar&baz=12");
- assertEquals(url.searchParams.getAll("foo"), ["bar"]);
- assertEquals(url.searchParams.getAll("baz"), ["12"]);
- assertEquals(url.username, "foo");
- assertEquals(
- String(url),
- "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat",
- );
-});
-
-Deno.test(function emptyUrl() {
- assertThrows(
- // @ts-ignore for test
- () => new URL(),
- TypeError,
- "1 argument required, but only 0 present",
- );
- assertThrows(
- // @ts-ignore for test
- () => URL.canParse(),
- TypeError,
- "1 argument required, but only 0 present",
- );
-});
-
-Deno.test(function urlProtocolParsing() {
- assertEquals(new URL("Aa+-.1://foo").protocol, "aa+-.1:");
- assertEquals(new URL("aA+-.1://foo").protocol, "aa+-.1:");
- assertThrows(() => new URL("1://foo"), TypeError, "Invalid URL: '1://foo'");
- assertThrows(() => new URL("+://foo"), TypeError, "Invalid URL: '+://foo'");
- assertThrows(() => new URL("-://foo"), TypeError, "Invalid URL: '-://foo'");
- assertThrows(() => new URL(".://foo"), TypeError, "Invalid URL: '.://foo'");
- assertThrows(() => new URL("_://foo"), TypeError, "Invalid URL: '_://foo'");
- assertThrows(() => new URL("=://foo"), TypeError, "Invalid URL: '=://foo'");
- assertThrows(() => new URL("!://foo"), TypeError, "Invalid URL: '!://foo'");
- assertThrows(() => new URL(`"://foo`), TypeError, `Invalid URL: '"://foo'`);
- assertThrows(() => new URL("$://foo"), TypeError, "Invalid URL: '$://foo'");
- assertThrows(() => new URL("%://foo"), TypeError, "Invalid URL: '%://foo'");
- assertThrows(() => new URL("^://foo"), TypeError, "Invalid URL: '^://foo'");
- assertThrows(() => new URL("*://foo"), TypeError, "Invalid URL: '*://foo'");
- assertThrows(() => new URL("*://foo"), TypeError, "Invalid URL: '*://foo'");
- assertThrows(
- () => new URL("!:", "*://foo"),
- TypeError,
- "Invalid URL: '!:' with base '*://foo'",
- );
-});
-
-Deno.test(function urlAuthenticationParsing() {
- const specialUrl = new URL("http://foo:bar@baz");
- assertEquals(specialUrl.username, "foo");
- assertEquals(specialUrl.password, "bar");
- assertEquals(specialUrl.hostname, "baz");
- assertThrows(() => new URL("file://foo:bar@baz"), TypeError, "Invalid URL");
- const nonSpecialUrl = new URL("abcd://foo:bar@baz");
- assertEquals(nonSpecialUrl.username, "foo");
- assertEquals(nonSpecialUrl.password, "bar");
- assertEquals(nonSpecialUrl.hostname, "baz");
-});
-
-Deno.test(function urlHostnameParsing() {
- // IPv6.
- assertEquals(new URL("http://[::1]").hostname, "[::1]");
- assertEquals(new URL("file://[::1]").hostname, "[::1]");
- assertEquals(new URL("abcd://[::1]").hostname, "[::1]");
- assertEquals(new URL("http://[0:f:0:0:f:f:0:0]").hostname, "[0:f::f:f:0:0]");
-
- // Forbidden host code point.
- assertThrows(() => new URL("http:// a"), TypeError, "Invalid URL");
- assertThrows(() => new URL("file:// a"), TypeError, "Invalid URL");
- assertThrows(() => new URL("abcd:// a"), TypeError, "Invalid URL");
- assertThrows(() => new URL("http://%"), TypeError, "Invalid URL");
- assertThrows(() => new URL("file://%"), TypeError, "Invalid URL");
- assertEquals(new URL("abcd://%").hostname, "%");
-
- // Percent-decode.
- assertEquals(new URL("http://%21").hostname, "!");
- assertEquals(new URL("file://%21").hostname, "!");
- assertEquals(new URL("abcd://%21").hostname, "%21");
-
- // IPv4 parsing.
- assertEquals(new URL("http://260").hostname, "0.0.1.4");
- assertEquals(new URL("file://260").hostname, "0.0.1.4");
- assertEquals(new URL("abcd://260").hostname, "260");
- assertEquals(new URL("http://255.0.0.0").hostname, "255.0.0.0");
- assertThrows(() => new URL("http://256.0.0.0"), TypeError, "Invalid URL");
- assertEquals(new URL("http://0.255.0.0").hostname, "0.255.0.0");
- assertThrows(() => new URL("http://0.256.0.0"), TypeError, "Invalid URL");
- assertEquals(new URL("http://0.0.255.0").hostname, "0.0.255.0");
- assertThrows(() => new URL("http://0.0.256.0"), TypeError, "Invalid URL");
- assertEquals(new URL("http://0.0.0.255").hostname, "0.0.0.255");
- assertThrows(() => new URL("http://0.0.0.256"), TypeError, "Invalid URL");
- assertEquals(new URL("http://0.0.65535").hostname, "0.0.255.255");
- assertThrows(() => new URL("http://0.0.65536"), TypeError, "Invalid URL");
- assertEquals(new URL("http://0.16777215").hostname, "0.255.255.255");
- assertThrows(() => new URL("http://0.16777216"), TypeError, "Invalid URL");
- assertEquals(new URL("http://4294967295").hostname, "255.255.255.255");
- assertThrows(() => new URL("http://4294967296"), TypeError, "Invalid URL");
-});
-
-Deno.test(function urlPortParsing() {
- const specialUrl = new URL("http://foo:8000");
- assertEquals(specialUrl.hostname, "foo");
- assertEquals(specialUrl.port, "8000");
- assertThrows(() => new URL("file://foo:8000"), TypeError, "Invalid URL");
- const nonSpecialUrl = new URL("abcd://foo:8000");
- assertEquals(nonSpecialUrl.hostname, "foo");
- assertEquals(nonSpecialUrl.port, "8000");
-});
-
-Deno.test(function urlModifications() {
- const url = new URL(
- "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat",
- );
- url.hash = "";
- assertEquals(
- url.href,
- "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12",
- );
- url.host = "qat.baz:8080";
- assertEquals(
- url.href,
- "https://foo:bar@qat.baz:8080/qux/quux?foo=bar&baz=12",
- );
- url.hostname = "foo.bar";
- assertEquals(
- url.href,
- "https://foo:bar@foo.bar:8080/qux/quux?foo=bar&baz=12",
- );
- url.password = "qux";
- assertEquals(
- url.href,
- "https://foo:qux@foo.bar:8080/qux/quux?foo=bar&baz=12",
- );
- url.pathname = "/foo/bar%qat";
- assertEquals(
- url.href,
- "https://foo:qux@foo.bar:8080/foo/bar%qat?foo=bar&baz=12",
- );
- url.port = "";
- assertEquals(url.href, "https://foo:qux@foo.bar/foo/bar%qat?foo=bar&baz=12");
- url.protocol = "http:";
- assertEquals(url.href, "http://foo:qux@foo.bar/foo/bar%qat?foo=bar&baz=12");
- url.search = "?foo=bar&foo=baz";
- assertEquals(url.href, "http://foo:qux@foo.bar/foo/bar%qat?foo=bar&foo=baz");
- assertEquals(url.searchParams.getAll("foo"), ["bar", "baz"]);
- url.username = "foo@bar";
- assertEquals(
- url.href,
- "http://foo%40bar:qux@foo.bar/foo/bar%qat?foo=bar&foo=baz",
- );
- url.searchParams.set("bar", "qat");
- assertEquals(
- url.href,
- "http://foo%40bar:qux@foo.bar/foo/bar%qat?foo=bar&foo=baz&bar=qat",
- );
- url.searchParams.delete("foo");
- assertEquals(url.href, "http://foo%40bar:qux@foo.bar/foo/bar%qat?bar=qat");
- url.searchParams.append("foo", "bar");
- assertEquals(
- url.href,
- "http://foo%40bar:qux@foo.bar/foo/bar%qat?bar=qat&foo=bar",
- );
-});
-
-Deno.test(function urlModifyHref() {
- const url = new URL("http://example.com/");
- url.href = "https://foo:bar@example.com:8080/baz/qat#qux";
- assertEquals(url.protocol, "https:");
- assertEquals(url.username, "foo");
- assertEquals(url.password, "bar");
- assertEquals(url.host, "example.com:8080");
- assertEquals(url.hostname, "example.com");
- assertEquals(url.pathname, "/baz/qat");
- assertEquals(url.hash, "#qux");
-});
-
-Deno.test(function urlNormalize() {
- const url = new URL("http://example.com");
- assertEquals(url.pathname, "/");
- assertEquals(url.href, "http://example.com/");
-});
-
-Deno.test(function urlModifyPathname() {
- const url = new URL("http://foo.bar/baz%qat/qux%quux");
- assertEquals(url.pathname, "/baz%qat/qux%quux");
- // Self-assignment is to invoke the setter.
- // deno-lint-ignore no-self-assign
- url.pathname = url.pathname;
- assertEquals(url.pathname, "/baz%qat/qux%quux");
- url.pathname = "baz#qat qux";
- assertEquals(url.pathname, "/baz%23qat%20qux");
- // deno-lint-ignore no-self-assign
- url.pathname = url.pathname;
- assertEquals(url.pathname, "/baz%23qat%20qux");
- url.pathname = "\\a\\b\\c";
- assertEquals(url.pathname, "/a/b/c");
-});
-
-Deno.test(function urlModifyHash() {
- const url = new URL("http://foo.bar");
- url.hash = "%foo bar/qat%qux#bar";
- assertEquals(url.hash, "#%foo%20bar/qat%qux#bar");
- // deno-lint-ignore no-self-assign
- url.hash = url.hash;
- assertEquals(url.hash, "#%foo%20bar/qat%qux#bar");
-});
-
-Deno.test(function urlSearchParamsReuse() {
- const url = new URL(
- "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat",
- );
- const sp = url.searchParams;
- url.host = "baz.qat";
- assert(sp === url.searchParams, "Search params should be reused.");
-});
-
-Deno.test(function urlBackSlashes() {
- const url = new URL(
- "https:\\\\foo:bar@baz.qat:8000\\qux\\quux?foo=bar&baz=12#qat",
- );
- assertEquals(
- url.href,
- "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat",
- );
-});
-
-Deno.test(function urlProtocolSlashes() {
- assertEquals(new URL("http:foo").href, "http://foo/");
- assertEquals(new URL("http://foo").href, "http://foo/");
- assertEquals(new URL("file:foo").href, "file:///foo");
- assertEquals(new URL("file://foo").href, "file://foo/");
- assertEquals(new URL("abcd:foo").href, "abcd:foo");
- assertEquals(new URL("abcd://foo").href, "abcd://foo");
-});
-
-Deno.test(function urlRequireHost() {
- assertEquals(new URL("file:///").href, "file:///");
- assertThrows(() => new URL("ftp:///"), TypeError, "Invalid URL");
- assertThrows(() => new URL("http:///"), TypeError, "Invalid URL");
- assertThrows(() => new URL("https:///"), TypeError, "Invalid URL");
- assertThrows(() => new URL("ws:///"), TypeError, "Invalid URL");
- assertThrows(() => new URL("wss:///"), TypeError, "Invalid URL");
-});
-
-Deno.test(function urlDriveLetter() {
- assertEquals(new URL("file:///C:").href, "file:///C:");
- assertEquals(new URL("file:///C:/").href, "file:///C:/");
- assertEquals(new URL("file:///C:/..").href, "file:///C:/");
-
- // Don't recognise drive letters with extra leading slashes.
- // FIXME(nayeemrmn): This is true according to
- // https://jsdom.github.io/whatwg-url/#url=ZmlsZTovLy8vQzovLi4=&base=ZmlsZTovLy8=
- // but not the behavior of rust-url.
- // assertEquals(new URL("file:////C:/..").href, "file:///");
-
- // Drop the hostname if a drive letter is parsed.
- assertEquals(new URL("file://foo/C:").href, "file:///C:");
-
- // Don't recognise drive letters in non-file protocols.
- // FIXME(nayeemrmn): This is true according to
- // https://jsdom.github.io/whatwg-url/#url=YWJjZDovL2Zvby9DOi8uLg==&base=ZmlsZTovLy8=
- // but not the behavior of rust-url.
- // assertEquals(new URL("http://foo/C:/..").href, "http://foo/");
- // assertEquals(new URL("abcd://foo/C:/..").href, "abcd://foo/");
-});
-
-Deno.test(function urlHostnameUpperCase() {
- assertEquals(new URL("http://EXAMPLE.COM").href, "http://example.com/");
- assertEquals(new URL("abcd://EXAMPLE.COM").href, "abcd://EXAMPLE.COM");
-});
-
-Deno.test(function urlEmptyPath() {
- assertEquals(new URL("http://foo").pathname, "/");
- assertEquals(new URL("file://foo").pathname, "/");
- assertEquals(new URL("abcd://foo").pathname, "");
-});
-
-Deno.test(function urlPathRepeatedSlashes() {
- assertEquals(new URL("http://foo//bar//").pathname, "//bar//");
- assertEquals(new URL("file://foo///bar//").pathname, "/bar//");
- assertEquals(new URL("abcd://foo//bar//").pathname, "//bar//");
-});
-
-Deno.test(function urlTrim() {
- assertEquals(new URL(" http://example.com ").href, "http://example.com/");
-});
-
-Deno.test(function urlEncoding() {
- assertEquals(
- new URL("http://a !$&*()=,;+'\"@example.com").username,
- "a%20!$&*()%3D,%3B+'%22",
- );
- assertEquals(
- new URL("http://:a !$&*()=,;+'\"@example.com").password,
- "a%20!$&*()%3D,%3B+'%22",
- );
- // https://url.spec.whatwg.org/#idna
- assertEquals(new URL("http://mañana/c?d#e").hostname, "xn--maana-pta");
- assertEquals(new URL("abcd://mañana/c?d#e").hostname, "ma%C3%B1ana");
- assertEquals(
- new URL("http://example.com/a ~!@$&*()=:/,;+'\"\\").pathname,
- "/a%20~!@$&*()=:/,;+'%22/",
- );
- assertEquals(
- new URL("http://example.com?a ~!@$&*()=:/,;?+'\"\\").search,
- "?a%20~!@$&*()=:/,;?+%27%22\\",
- );
- assertEquals(
- new URL("abcd://example.com?a ~!@$&*()=:/,;?+'\"\\").search,
- "?a%20~!@$&*()=:/,;?+'%22\\",
- );
- assertEquals(
- new URL("http://example.com#a ~!@#$&*()=:/,;?+'\"\\").hash,
- "#a%20~!@#$&*()=:/,;?+'%22\\",
- );
-});
-
-Deno.test(function urlBase() {
- assertEquals(new URL("d", new URL("http://foo/a?b#c")).href, "http://foo/d");
-
- assertEquals(new URL("", "http://foo/a/b?c#d").href, "http://foo/a/b?c");
- assertEquals(new URL("", "file://foo/a/b?c#d").href, "file://foo/a/b?c");
- assertEquals(new URL("", "abcd://foo/a/b?c#d").href, "abcd://foo/a/b?c");
-
- assertEquals(new URL("#e", "http://foo/a/b?c#d").href, "http://foo/a/b?c#e");
- assertEquals(new URL("#e", "file://foo/a/b?c#d").href, "file://foo/a/b?c#e");
- assertEquals(new URL("#e", "abcd://foo/a/b?c#d").href, "abcd://foo/a/b?c#e");
-
- assertEquals(new URL("?e", "http://foo/a/b?c#d").href, "http://foo/a/b?e");
- assertEquals(new URL("?e", "file://foo/a/b?c#d").href, "file://foo/a/b?e");
- assertEquals(new URL("?e", "abcd://foo/a/b?c#d").href, "abcd://foo/a/b?e");
-
- assertEquals(new URL("e", "http://foo/a/b?c#d").href, "http://foo/a/e");
- assertEquals(new URL("e", "file://foo/a/b?c#d").href, "file://foo/a/e");
- assertEquals(new URL("e", "abcd://foo/a/b?c#d").href, "abcd://foo/a/e");
-
- assertEquals(new URL(".", "http://foo/a/b?c#d").href, "http://foo/a/");
- assertEquals(new URL(".", "file://foo/a/b?c#d").href, "file://foo/a/");
- assertEquals(new URL(".", "abcd://foo/a/b?c#d").href, "abcd://foo/a/");
-
- assertEquals(new URL("..", "http://foo/a/b?c#d").href, "http://foo/");
- assertEquals(new URL("..", "file://foo/a/b?c#d").href, "file://foo/");
- assertEquals(new URL("..", "abcd://foo/a/b?c#d").href, "abcd://foo/");
-
- assertEquals(new URL("/e", "http://foo/a/b?c#d").href, "http://foo/e");
- assertEquals(new URL("/e", "file://foo/a/b?c#d").href, "file://foo/e");
- assertEquals(new URL("/e", "abcd://foo/a/b?c#d").href, "abcd://foo/e");
-
- assertEquals(new URL("//bar", "http://foo/a/b?c#d").href, "http://bar/");
- assertEquals(new URL("//bar", "file://foo/a/b?c#d").href, "file://bar/");
- assertEquals(new URL("//bar", "abcd://foo/a/b?c#d").href, "abcd://bar");
-
- assertEquals(new URL("efgh:", "http://foo/a/b?c#d").href, "efgh:");
- assertEquals(new URL("efgh:", "file://foo/a/b?c#d").href, "efgh:");
- assertEquals(new URL("efgh:", "abcd://foo/a/b?c#d").href, "efgh:");
-
- assertEquals(new URL("/foo", "abcd:/").href, "abcd:/foo");
-});
-
-Deno.test(function urlDriveLetterBase() {
- assertEquals(new URL("/b", "file:///C:/a/b").href, "file:///C:/b");
- assertEquals(new URL("/D:", "file:///C:/a/b").href, "file:///D:");
-});
-
-Deno.test(function urlSameProtocolBase() {
- assertEquals(new URL("http:", "http://foo/a").href, "http://foo/a");
- assertEquals(new URL("file:", "file://foo/a").href, "file://foo/a");
- assertEquals(new URL("abcd:", "abcd://foo/a").href, "abcd:");
-
- assertEquals(new URL("http:b", "http://foo/a").href, "http://foo/b");
- assertEquals(new URL("file:b", "file://foo/a").href, "file://foo/b");
- assertEquals(new URL("abcd:b", "abcd://foo/a").href, "abcd:b");
-});
-
-Deno.test(function deletingAllParamsRemovesQuestionMarkFromURL() {
- const url = new URL("http://example.com/?param1&param2");
- url.searchParams.delete("param1");
- url.searchParams.delete("param2");
- assertEquals(url.href, "http://example.com/");
- assertEquals(url.search, "");
-});
-
-Deno.test(function removingNonExistentParamRemovesQuestionMarkFromURL() {
- const url = new URL("http://example.com/?");
- assertEquals(url.href, "http://example.com/?");
- url.searchParams.delete("param1");
- assertEquals(url.href, "http://example.com/");
- assertEquals(url.search, "");
-});
-
-Deno.test(function sortingNonExistentParamRemovesQuestionMarkFromURL() {
- const url = new URL("http://example.com/?");
- assertEquals(url.href, "http://example.com/?");
- url.searchParams.sort();
- assertEquals(url.href, "http://example.com/");
- assertEquals(url.search, "");
-});
-
-Deno.test(function customInspectFunction() {
- const url = new URL("http://example.com/?");
- assertEquals(
- Deno.inspect(url),
- `URL {
- href: "http://example.com/?",
- origin: "http://example.com",
- protocol: "http:",
- username: "",
- password: "",
- host: "example.com",
- hostname: "example.com",
- port: "",
- pathname: "/",
- hash: "",
- search: ""
-}`,
- );
-});
-
-Deno.test(function protocolNotHttpOrFile() {
- const url = new URL("about:blank");
- assertEquals(url.href, "about:blank");
- assertEquals(url.protocol, "about:");
- assertEquals(url.origin, "null");
-});
-
-Deno.test(function throwForInvalidPortConstructor() {
- const urls = [
- // If port is greater than 2^16 − 1, validation error, return failure.
- `https://baz.qat:${2 ** 16}`,
- "https://baz.qat:-32",
- "https://baz.qat:deno",
- "https://baz.qat:9land",
- "https://baz.qat:10.5",
- ];
-
- for (const url of urls) {
- assertThrows(() => new URL(url), TypeError, "Invalid URL");
- }
-
- // Do not throw for 0 & 65535
- new URL("https://baz.qat:65535");
- new URL("https://baz.qat:0");
-});
-
-Deno.test(function doNotOverridePortIfInvalid() {
- const initialPort = "3000";
- const url = new URL(`https://deno.land:${initialPort}`);
- // If port is greater than 2^16 − 1, validation error, return failure.
- url.port = `${2 ** 16}`;
- assertEquals(url.port, initialPort);
-});
-
-Deno.test(function emptyPortForSchemeDefaultPort() {
- const nonDefaultPort = "3500";
-
- const url = new URL("ftp://baz.qat:21");
- assertEquals(url.port, "");
- url.port = nonDefaultPort;
- assertEquals(url.port, nonDefaultPort);
- url.port = "21";
- assertEquals(url.port, "");
- url.protocol = "http";
- assertEquals(url.port, "");
-
- const url2 = new URL("https://baz.qat:443");
- assertEquals(url2.port, "");
- url2.port = nonDefaultPort;
- assertEquals(url2.port, nonDefaultPort);
- url2.port = "443";
- assertEquals(url2.port, "");
- url2.protocol = "http";
- assertEquals(url2.port, "");
-});
-
-Deno.test(function assigningPortPropertyAffectsReceiverOnly() {
- // Setting `.port` should update only the receiver.
- const u1 = new URL("http://google.com/");
- // deno-lint-ignore no-explicit-any
- const u2 = new URL(u1 as any);
- u2.port = "123";
- assertStrictEquals(u1.port, "");
- assertStrictEquals(u2.port, "123");
-});
-
-Deno.test(function urlSearchParamsIdentityPreserved() {
- // URLSearchParams identity should not be lost when URL is updated.
- const u = new URL("http://foo.com/");
- const sp1 = u.searchParams;
- u.href = "http://bar.com/?baz=42";
- const sp2 = u.searchParams;
- assertStrictEquals(sp1, sp2);
-});
-
-Deno.test(function urlTakeURLObjectAsParameter() {
- const url = new URL(
- new URL(
- "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat",
- ),
- );
- assertEquals(
- url.href,
- "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat",
- );
-});
diff --git a/cli/tests/unit/urlpattern_test.ts b/cli/tests/unit/urlpattern_test.ts
deleted file mode 100644
index 7730dbe40..000000000
--- a/cli/tests/unit/urlpattern_test.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals } from "./test_util.ts";
-import { assertType, IsExact } from "@test_util/std/testing/types.ts";
-
-Deno.test(function urlPatternFromString() {
- const pattern = new URLPattern("https://deno.land/foo/:bar");
- assertEquals(pattern.protocol, "https");
- assertEquals(pattern.hostname, "deno.land");
- assertEquals(pattern.pathname, "/foo/:bar");
-
- assert(pattern.test("https://deno.land/foo/x"));
- assert(!pattern.test("https://deno.com/foo/x"));
- const match = pattern.exec("https://deno.land/foo/x");
- assert(match);
- assertEquals(match.pathname.input, "/foo/x");
- assertEquals(match.pathname.groups, { bar: "x" });
-
- // group values should be nullable
- const val = match.pathname.groups.val;
- assertType<IsExact<typeof val, string | undefined>>(true);
-});
-
-Deno.test(function urlPatternFromStringWithBase() {
- const pattern = new URLPattern("/foo/:bar", "https://deno.land");
- assertEquals(pattern.protocol, "https");
- assertEquals(pattern.hostname, "deno.land");
- assertEquals(pattern.pathname, "/foo/:bar");
-
- assert(pattern.test("https://deno.land/foo/x"));
- assert(!pattern.test("https://deno.com/foo/x"));
- const match = pattern.exec("https://deno.land/foo/x");
- assert(match);
- assertEquals(match.pathname.input, "/foo/x");
- assertEquals(match.pathname.groups, { bar: "x" });
-});
-
-Deno.test(function urlPatternFromInit() {
- const pattern = new URLPattern({
- pathname: "/foo/:bar",
- });
- assertEquals(pattern.protocol, "*");
- assertEquals(pattern.hostname, "*");
- assertEquals(pattern.pathname, "/foo/:bar");
-
- assert(pattern.test("https://deno.land/foo/x"));
- assert(pattern.test("https://deno.com/foo/x"));
- assert(!pattern.test("https://deno.com/bar/x"));
-
- assert(pattern.test({ pathname: "/foo/x" }));
-});
-
-Deno.test(function urlPatternWithPrototypePollution() {
- const originalExec = RegExp.prototype.exec;
- try {
- RegExp.prototype.exec = () => {
- throw Error();
- };
- const pattern = new URLPattern({
- pathname: "/foo/:bar",
- });
- assert(pattern.test("https://deno.land/foo/x"));
- } finally {
- RegExp.prototype.exec = originalExec;
- }
-});
diff --git a/cli/tests/unit/utime_test.ts b/cli/tests/unit/utime_test.ts
deleted file mode 100644
index 9f5f25bee..000000000
--- a/cli/tests/unit/utime_test.ts
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assertEquals,
- assertRejects,
- assertThrows,
- pathToAbsoluteFileUrl,
-} from "./test_util.ts";
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function futimeSyncSuccess() {
- const testDir = await Deno.makeTempDir();
- const filename = testDir + "/file.txt";
- using file = await Deno.open(filename, {
- create: true,
- write: true,
- });
-
- const atime = 1000;
- const mtime = 50000;
- await Deno.futime(file.rid, atime, mtime);
- await file.syncData();
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, new Date(atime * 1000));
- assertEquals(fileInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function fsFileUtimeSyncSuccess() {
- const testDir = await Deno.makeTempDir();
- const filename = testDir + "/file.txt";
- using file = await Deno.open(filename, {
- create: true,
- write: true,
- });
-
- const atime = 1000;
- const mtime = 50000;
- await file.utime(atime, mtime);
- await file.syncData();
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, new Date(atime * 1000));
- assertEquals(fileInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function futimeSyncSuccess() {
- const testDir = Deno.makeTempDirSync();
- const filename = testDir + "/file.txt";
- using file = Deno.openSync(filename, {
- create: true,
- write: true,
- });
-
- const atime = 1000;
- const mtime = 50000;
- Deno.futimeSync(file.rid, atime, mtime);
- file.syncDataSync();
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, new Date(atime * 1000));
- assertEquals(fileInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function futimeSyncSuccess() {
- const testDir = Deno.makeTempDirSync();
- const filename = testDir + "/file.txt";
- using file = Deno.openSync(filename, {
- create: true,
- write: true,
- });
-
- const atime = 1000;
- const mtime = 50000;
- file.utimeSync(atime, mtime);
- file.syncDataSync();
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, new Date(atime * 1000));
- assertEquals(fileInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function utimeSyncFileSuccess() {
- const testDir = Deno.makeTempDirSync();
- const filename = testDir + "/file.txt";
- Deno.writeFileSync(filename, new TextEncoder().encode("hello"), {
- mode: 0o666,
- });
-
- const atime = 1000;
- const mtime = 50000;
- Deno.utimeSync(filename, atime, mtime);
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, new Date(atime * 1000));
- assertEquals(fileInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function utimeSyncUrlSuccess() {
- const testDir = Deno.makeTempDirSync();
- const filename = testDir + "/file.txt";
- Deno.writeFileSync(filename, new TextEncoder().encode("hello"), {
- mode: 0o666,
- });
-
- const atime = 1000;
- const mtime = 50000;
- Deno.utimeSync(pathToAbsoluteFileUrl(filename), atime, mtime);
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, new Date(atime * 1000));
- assertEquals(fileInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function utimeSyncDirectorySuccess() {
- const testDir = Deno.makeTempDirSync();
-
- const atime = 1000;
- const mtime = 50000;
- Deno.utimeSync(testDir, atime, mtime);
-
- const dirInfo = Deno.statSync(testDir);
- assertEquals(dirInfo.atime, new Date(atime * 1000));
- assertEquals(dirInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function utimeSyncDateSuccess() {
- const testDir = Deno.makeTempDirSync();
-
- const atime = new Date(1000_000);
- const mtime = new Date(50000_000);
- Deno.utimeSync(testDir, atime, mtime);
-
- const dirInfo = Deno.statSync(testDir);
- assertEquals(dirInfo.atime, atime);
- assertEquals(dirInfo.mtime, mtime);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function utimeSyncFileDateSuccess() {
- const testDir = Deno.makeTempDirSync();
- const filename = testDir + "/file.txt";
- Deno.writeFileSync(filename, new TextEncoder().encode("hello"), {
- mode: 0o666,
- });
- const atime = new Date();
- const mtime = new Date();
- Deno.utimeSync(filename, atime, mtime);
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, atime);
- assertEquals(fileInfo.mtime, mtime);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function utimeSyncLargeNumberSuccess() {
- const testDir = Deno.makeTempDirSync();
-
- // There are Rust side caps (might be fs relate),
- // so JUST make them slightly larger than UINT32_MAX.
- const atime = 0x100000001;
- const mtime = 0x100000002;
- Deno.utimeSync(testDir, atime, mtime);
-
- const dirInfo = Deno.statSync(testDir);
- assertEquals(dirInfo.atime, new Date(atime * 1000));
- assertEquals(dirInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function utimeSyncNotFound() {
- const atime = 1000;
- const mtime = 50000;
-
- assertThrows(
- () => {
- Deno.utimeSync("/baddir", atime, mtime);
- },
- Deno.errors.NotFound,
- "utime '/baddir'",
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: false } },
- function utimeSyncPerm() {
- const atime = 1000;
- const mtime = 50000;
-
- assertThrows(() => {
- Deno.utimeSync("/some_dir", atime, mtime);
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function utimeFileSuccess() {
- const testDir = Deno.makeTempDirSync();
- const filename = testDir + "/file.txt";
- Deno.writeFileSync(filename, new TextEncoder().encode("hello"), {
- mode: 0o666,
- });
-
- const atime = 1000;
- const mtime = 50000;
- await Deno.utime(filename, atime, mtime);
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, new Date(atime * 1000));
- assertEquals(fileInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function utimeUrlSuccess() {
- const testDir = Deno.makeTempDirSync();
- const filename = testDir + "/file.txt";
- Deno.writeFileSync(filename, new TextEncoder().encode("hello"), {
- mode: 0o666,
- });
-
- const atime = 1000;
- const mtime = 50000;
- await Deno.utime(pathToAbsoluteFileUrl(filename), atime, mtime);
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, new Date(atime * 1000));
- assertEquals(fileInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function utimeDirectorySuccess() {
- const testDir = Deno.makeTempDirSync();
-
- const atime = 1000;
- const mtime = 50000;
- await Deno.utime(testDir, atime, mtime);
-
- const dirInfo = Deno.statSync(testDir);
- assertEquals(dirInfo.atime, new Date(atime * 1000));
- assertEquals(dirInfo.mtime, new Date(mtime * 1000));
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function utimeDateSuccess() {
- const testDir = Deno.makeTempDirSync();
-
- const atime = new Date(100_000);
- const mtime = new Date(5000_000);
- await Deno.utime(testDir, atime, mtime);
-
- const dirInfo = Deno.statSync(testDir);
- assertEquals(dirInfo.atime, atime);
- assertEquals(dirInfo.mtime, mtime);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function utimeFileDateSuccess() {
- const testDir = Deno.makeTempDirSync();
- const filename = testDir + "/file.txt";
- Deno.writeFileSync(filename, new TextEncoder().encode("hello"), {
- mode: 0o666,
- });
-
- const atime = new Date();
- const mtime = new Date();
- await Deno.utime(filename, atime, mtime);
-
- const fileInfo = Deno.statSync(filename);
- assertEquals(fileInfo.atime, atime);
- assertEquals(fileInfo.mtime, mtime);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function utimeNotFound() {
- const atime = 1000;
- const mtime = 50000;
-
- await assertRejects(
- async () => {
- await Deno.utime("/baddir", atime, mtime);
- },
- Deno.errors.NotFound,
- "utime '/baddir'",
- );
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: false } },
- async function utimeSyncPerm() {
- const atime = 1000;
- const mtime = 50000;
-
- await assertRejects(async () => {
- await Deno.utime("/some_dir", atime, mtime);
- }, Deno.errors.PermissionDenied);
- },
-);
diff --git a/cli/tests/unit/version_test.ts b/cli/tests/unit/version_test.ts
deleted file mode 100644
index 4eadb7620..000000000
--- a/cli/tests/unit/version_test.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assert, assertEquals } from "./test_util.ts";
-
-Deno.test(function version() {
- const pattern = /^\d+\.\d+\.\d+/;
- assert(pattern.test(Deno.version.deno));
- assert(pattern.test(Deno.version.v8));
- assertEquals(Deno.version.typescript, "5.3.3");
-});
diff --git a/cli/tests/unit/wasm_test.ts b/cli/tests/unit/wasm_test.ts
deleted file mode 100644
index fab9c9308..000000000
--- a/cli/tests/unit/wasm_test.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assert, assertEquals, assertRejects } from "./test_util.ts";
-
-// The following blob can be created by taking the following s-expr and pass
-// it through wat2wasm.
-// (module
-// (func $add (param $a i32) (param $b i32) (result i32)
-// local.get $a
-// local.get $b
-// i32.add)
-// (export "add" (func $add))
-// )
-// deno-fmt-ignore
-const simpleWasm = new Uint8Array([
- 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x60,
- 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07, 0x01,
- 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01, 0x07, 0x00, 0x20,
- 0x00, 0x20, 0x01, 0x6a, 0x0b
-]);
-
-Deno.test(async function wasmInstantiateWorksWithBuffer() {
- const { module, instance } = await WebAssembly.instantiate(simpleWasm);
- assertEquals(WebAssembly.Module.exports(module), [{
- name: "add",
- kind: "function",
- }]);
- assertEquals(WebAssembly.Module.imports(module), []);
- assert(typeof instance.exports.add === "function");
- const add = instance.exports.add as (a: number, b: number) => number;
- assertEquals(add(1, 3), 4);
-});
-
-// V8's default implementation of `WebAssembly.instantiateStreaming()` if you
-// don't set the WASM streaming callback, is to take a byte source. Here we
-// check that our implementation of the callback disallows it.
-Deno.test(
- async function wasmInstantiateStreamingFailsWithBuffer() {
- await assertRejects(async () => {
- await WebAssembly.instantiateStreaming(
- // Bypassing the type system
- simpleWasm as unknown as Promise<Response>,
- );
- }, TypeError);
- },
-);
-
-Deno.test(
- async function wasmInstantiateStreamingNoContentType() {
- const response = new Response(simpleWasm);
- // Rejects, not throws.
- const wasmPromise = WebAssembly.instantiateStreaming(response);
- await assertRejects(
- () => wasmPromise,
- TypeError,
- "Invalid WebAssembly content type.",
- );
- },
-);
-
-Deno.test(async function wasmInstantiateStreaming() {
- let isomorphic = "";
- for (const byte of simpleWasm) {
- isomorphic += String.fromCharCode(byte);
- }
- const base64Url = "data:application/wasm;base64," + btoa(isomorphic);
-
- const { module, instance } = await WebAssembly.instantiateStreaming(
- fetch(base64Url),
- );
- assertEquals(WebAssembly.Module.exports(module), [{
- name: "add",
- kind: "function",
- }]);
- assertEquals(WebAssembly.Module.imports(module), []);
- assert(typeof instance.exports.add === "function");
- const add = instance.exports.add as (a: number, b: number) => number;
- assertEquals(add(1, 3), 4);
-});
-
-Deno.test(
- { permissions: { read: true } },
- async function wasmFileStreaming() {
- const url = import.meta.resolve("../testdata/assets/unreachable.wasm");
- assert(url.startsWith("file://"));
-
- const { module } = await WebAssembly.instantiateStreaming(fetch(url));
- assertEquals(WebAssembly.Module.exports(module), [{
- name: "unreachable",
- kind: "function",
- }]);
- },
-);
-
-Deno.test(
- { permissions: { net: true } },
- async function wasmStreamingNonTrivial() {
- // deno-dom's WASM file is a real-world non-trivial case that gave us
- // trouble when implementing this.
- await WebAssembly.instantiateStreaming(fetch(
- "http://localhost:4545/assets/deno_dom_0.1.3-alpha2.wasm",
- ));
- },
-);
diff --git a/cli/tests/unit/webcrypto_test.ts b/cli/tests/unit/webcrypto_test.ts
deleted file mode 100644
index 829330eba..000000000
--- a/cli/tests/unit/webcrypto_test.ts
+++ /dev/null
@@ -1,2047 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import {
- assert,
- assertEquals,
- assertNotEquals,
- assertRejects,
-} from "./test_util.ts";
-
-// https://github.com/denoland/deno/issues/11664
-Deno.test(async function testImportArrayBufferKey() {
- const subtle = window.crypto.subtle;
- assert(subtle);
-
- // deno-fmt-ignore
- const key = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
-
- const cryptoKey = await subtle.importKey(
- "raw",
- key.buffer,
- { name: "HMAC", hash: "SHA-1" },
- true,
- ["sign"],
- );
- assert(cryptoKey);
-
- // Test key usage
- await subtle.sign({ name: "HMAC" }, cryptoKey, new Uint8Array(8));
-});
-
-Deno.test(async function testSignVerify() {
- const subtle = window.crypto.subtle;
- assert(subtle);
- for (const algorithm of ["RSA-PSS", "RSASSA-PKCS1-v1_5"]) {
- for (
- const hash of [
- "SHA-1",
- "SHA-256",
- "SHA-384",
- "SHA-512",
- ]
- ) {
- const keyPair = await subtle.generateKey(
- {
- name: algorithm,
- modulusLength: 2048,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash,
- },
- true,
- ["sign", "verify"],
- );
-
- const data = new Uint8Array([1, 2, 3]);
-
- const signAlgorithm = { name: algorithm, saltLength: 32 };
-
- const signature = await subtle.sign(
- signAlgorithm,
- keyPair.privateKey,
- data,
- );
-
- assert(signature);
- assert(signature.byteLength > 0);
- assert(signature.byteLength % 8 == 0);
- assert(signature instanceof ArrayBuffer);
-
- const verified = await subtle.verify(
- signAlgorithm,
- keyPair.publicKey,
- signature,
- data,
- );
- assert(verified);
- }
- }
-});
-
-// deno-fmt-ignore
-const plainText = new Uint8Array([95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248, 62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213, 93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60, 177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162, 175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206, 2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149, 44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234, 93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77, 131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108, 215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19, 137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204, 157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72, 2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171]);
-
-// Passing
-const hashPlainTextVector = [
- {
- hash: "SHA-1",
- plainText: plainText.slice(0, 214),
- },
- {
- hash: "SHA-256",
- plainText: plainText.slice(0, 190),
- },
- {
- hash: "SHA-384",
- plainText: plainText.slice(0, 158),
- },
- {
- hash: "SHA-512",
- plainText: plainText.slice(0, 126),
- },
-];
-
-Deno.test(async function testEncryptDecrypt() {
- const subtle = window.crypto.subtle;
- assert(subtle);
- for (
- const { hash, plainText } of hashPlainTextVector
- ) {
- const keyPair = await subtle.generateKey(
- {
- name: "RSA-OAEP",
- modulusLength: 2048,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash,
- },
- true,
- ["encrypt", "decrypt"],
- );
-
- const encryptAlgorithm = { name: "RSA-OAEP" };
- const cipherText = await subtle.encrypt(
- encryptAlgorithm,
- keyPair.publicKey,
- plainText,
- );
-
- assert(cipherText);
- assert(cipherText.byteLength > 0);
- assertEquals(cipherText.byteLength * 8, 2048);
- assert(cipherText instanceof ArrayBuffer);
-
- const decrypted = await subtle.decrypt(
- encryptAlgorithm,
- keyPair.privateKey,
- cipherText,
- );
- assert(decrypted);
- assert(decrypted instanceof ArrayBuffer);
- assertEquals(new Uint8Array(decrypted), plainText);
-
- const badPlainText = new Uint8Array(plainText.byteLength + 1);
- badPlainText.set(plainText, 0);
- badPlainText.set(new Uint8Array([32]), plainText.byteLength);
- await assertRejects(async () => {
- // Should fail
- await subtle.encrypt(
- encryptAlgorithm,
- keyPair.publicKey,
- badPlainText,
- );
- throw new TypeError("unreachable");
- }, DOMException);
- }
-});
-
-Deno.test(async function testGenerateRSAKey() {
- const subtle = window.crypto.subtle;
- assert(subtle);
-
- const keyPair = await subtle.generateKey(
- {
- name: "RSA-PSS",
- modulusLength: 2048,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash: "SHA-256",
- },
- true,
- ["sign", "verify"],
- );
-
- assert(keyPair.privateKey);
- assert(keyPair.publicKey);
- assertEquals(keyPair.privateKey.extractable, true);
- assert(keyPair.privateKey.usages.includes("sign"));
-});
-
-Deno.test(async function testGenerateHMACKey() {
- const key = await window.crypto.subtle.generateKey(
- {
- name: "HMAC",
- hash: "SHA-512",
- },
- true,
- ["sign", "verify"],
- );
-
- assert(key);
- assertEquals(key.extractable, true);
- assert(key.usages.includes("sign"));
-});
-
-Deno.test(async function testECDSASignVerify() {
- const key = await window.crypto.subtle.generateKey(
- {
- name: "ECDSA",
- namedCurve: "P-384",
- },
- true,
- ["sign", "verify"],
- );
-
- const encoder = new TextEncoder();
- const encoded = encoder.encode("Hello, World!");
- const signature = await window.crypto.subtle.sign(
- { name: "ECDSA", hash: "SHA-384" },
- key.privateKey,
- encoded,
- );
-
- assert(signature);
- assert(signature instanceof ArrayBuffer);
-
- const verified = await window.crypto.subtle.verify(
- { hash: { name: "SHA-384" }, name: "ECDSA" },
- key.publicKey,
- signature,
- encoded,
- );
- assert(verified);
-});
-
-// Tests the "bad paths" as a temporary replacement for sign_verify/ecdsa WPT.
-Deno.test(async function testECDSASignVerifyFail() {
- const key = await window.crypto.subtle.generateKey(
- {
- name: "ECDSA",
- namedCurve: "P-384",
- },
- true,
- ["sign", "verify"],
- );
-
- const encoded = new Uint8Array([1]);
- // Signing with a public key (InvalidAccessError)
- await assertRejects(async () => {
- await window.crypto.subtle.sign(
- { name: "ECDSA", hash: "SHA-384" },
- key.publicKey,
- new Uint8Array([1]),
- );
- throw new TypeError("unreachable");
- }, DOMException);
-
- // Do a valid sign for later verifying.
- const signature = await window.crypto.subtle.sign(
- { name: "ECDSA", hash: "SHA-384" },
- key.privateKey,
- encoded,
- );
-
- // Verifying with a private key (InvalidAccessError)
- await assertRejects(async () => {
- await window.crypto.subtle.verify(
- { hash: { name: "SHA-384" }, name: "ECDSA" },
- key.privateKey,
- signature,
- encoded,
- );
- throw new TypeError("unreachable");
- }, DOMException);
-});
-
-// https://github.com/denoland/deno/issues/11313
-Deno.test(async function testSignRSASSAKey() {
- const subtle = window.crypto.subtle;
- assert(subtle);
-
- const keyPair = await subtle.generateKey(
- {
- name: "RSASSA-PKCS1-v1_5",
- modulusLength: 2048,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash: "SHA-256",
- },
- true,
- ["sign", "verify"],
- );
-
- assert(keyPair.privateKey);
- assert(keyPair.publicKey);
- assertEquals(keyPair.privateKey.extractable, true);
- assert(keyPair.privateKey.usages.includes("sign"));
-
- const encoder = new TextEncoder();
- const encoded = encoder.encode("Hello, World!");
-
- const signature = await window.crypto.subtle.sign(
- { name: "RSASSA-PKCS1-v1_5" },
- keyPair.privateKey,
- encoded,
- );
-
- assert(signature);
-});
-
-// deno-fmt-ignore
-const rawKey = new Uint8Array([
- 1, 2, 3, 4, 5, 6, 7, 8,
- 9, 10, 11, 12, 13, 14, 15, 16
-]);
-
-const jwk: JsonWebKey = {
- kty: "oct",
- // unpadded base64 for rawKey.
- k: "AQIDBAUGBwgJCgsMDQ4PEA",
- alg: "HS256",
- ext: true,
- "key_ops": ["sign"],
-};
-
-Deno.test(async function subtleCryptoHmacImportExport() {
- const key1 = await crypto.subtle.importKey(
- "raw",
- rawKey,
- { name: "HMAC", hash: "SHA-256" },
- true,
- ["sign"],
- );
- const key2 = await crypto.subtle.importKey(
- "jwk",
- jwk,
- { name: "HMAC", hash: "SHA-256" },
- true,
- ["sign"],
- );
- const actual1 = await crypto.subtle.sign(
- { name: "HMAC" },
- key1,
- new Uint8Array([1, 2, 3, 4]),
- );
-
- const actual2 = await crypto.subtle.sign(
- { name: "HMAC" },
- key2,
- new Uint8Array([1, 2, 3, 4]),
- );
- // deno-fmt-ignore
- const expected = new Uint8Array([
- 59, 170, 255, 216, 51, 141, 51, 194,
- 213, 48, 41, 191, 184, 40, 216, 47,
- 130, 165, 203, 26, 163, 43, 38, 71,
- 23, 122, 222, 1, 146, 46, 182, 87,
- ]);
- assertEquals(
- new Uint8Array(actual1),
- expected,
- );
- assertEquals(
- new Uint8Array(actual2),
- expected,
- );
-
- const exportedKey1 = await crypto.subtle.exportKey("raw", key1);
- assertEquals(new Uint8Array(exportedKey1), rawKey);
-
- const exportedKey2 = await crypto.subtle.exportKey("jwk", key2);
- assertEquals(exportedKey2, jwk);
-});
-
-// https://github.com/denoland/deno/issues/12085
-Deno.test(async function generateImportHmacJwk() {
- const key = await crypto.subtle.generateKey(
- {
- name: "HMAC",
- hash: "SHA-512",
- },
- true,
- ["sign"],
- );
- assert(key);
- assertEquals(key.type, "secret");
- assertEquals(key.extractable, true);
- assertEquals(key.usages, ["sign"]);
-
- const exportedKey = await crypto.subtle.exportKey("jwk", key);
- assertEquals(exportedKey.kty, "oct");
- assertEquals(exportedKey.alg, "HS512");
- assertEquals(exportedKey.key_ops, ["sign"]);
- assertEquals(exportedKey.ext, true);
- assert(typeof exportedKey.k == "string");
- assertEquals(exportedKey.k.length, 171);
-});
-
-// 2048-bits publicExponent=65537
-const pkcs8TestVectors = [
- // rsaEncryption
- { pem: "cli/tests/testdata/webcrypto/id_rsaEncryption.pem", hash: "SHA-256" },
-];
-
-Deno.test({ permissions: { read: true } }, async function importRsaPkcs8() {
- const pemHeader = "-----BEGIN PRIVATE KEY-----";
- const pemFooter = "-----END PRIVATE KEY-----";
- for (const { pem, hash } of pkcs8TestVectors) {
- const keyFile = await Deno.readTextFile(pem);
- const pemContents = keyFile.substring(
- pemHeader.length,
- keyFile.length - pemFooter.length,
- );
- const binaryDerString = atob(pemContents);
- const binaryDer = new Uint8Array(binaryDerString.length);
- for (let i = 0; i < binaryDerString.length; i++) {
- binaryDer[i] = binaryDerString.charCodeAt(i);
- }
-
- const key = await crypto.subtle.importKey(
- "pkcs8",
- binaryDer,
- { name: "RSA-PSS", hash },
- true,
- ["sign"],
- );
-
- assert(key);
- assertEquals(key.type, "private");
- assertEquals(key.extractable, true);
- assertEquals(key.usages, ["sign"]);
- const algorithm = key.algorithm as RsaHashedKeyAlgorithm;
- assertEquals(algorithm.name, "RSA-PSS");
- assertEquals(algorithm.hash.name, hash);
- assertEquals(algorithm.modulusLength, 2048);
- assertEquals(algorithm.publicExponent, new Uint8Array([1, 0, 1]));
- }
-});
-
-const nonInteroperableVectors = [
- // id-RSASSA-PSS (sha256)
- // `openssl genpkey -algorithm rsa-pss -pkeyopt rsa_pss_keygen_md:sha256 -out id_rsassaPss.pem`
- { pem: "cli/tests/testdata/webcrypto/id_rsassaPss.pem", hash: "SHA-256" },
- // id-RSASSA-PSS (default parameters)
- // `openssl genpkey -algorithm rsa-pss -out id_rsassaPss.pem`
- {
- pem: "cli/tests/testdata/webcrypto/id_rsassaPss_default.pem",
- hash: "SHA-1",
- },
- // id-RSASSA-PSS (default hash)
- // `openssl genpkey -algorithm rsa-pss -pkeyopt rsa_pss_keygen_saltlen:30 -out rsaPss_saltLen_30.pem`
- {
- pem: "cli/tests/testdata/webcrypto/id_rsassaPss_saltLen_30.pem",
- hash: "SHA-1",
- },
-];
-
-Deno.test(
- { permissions: { read: true } },
- async function importNonInteroperableRsaPkcs8() {
- const pemHeader = "-----BEGIN PRIVATE KEY-----";
- const pemFooter = "-----END PRIVATE KEY-----";
- for (const { pem, hash } of nonInteroperableVectors) {
- const keyFile = await Deno.readTextFile(pem);
- const pemContents = keyFile.substring(
- pemHeader.length,
- keyFile.length - pemFooter.length,
- );
- const binaryDerString = atob(pemContents);
- const binaryDer = new Uint8Array(binaryDerString.length);
- for (let i = 0; i < binaryDerString.length; i++) {
- binaryDer[i] = binaryDerString.charCodeAt(i);
- }
-
- await assertRejects(
- () =>
- crypto.subtle.importKey(
- "pkcs8",
- binaryDer,
- { name: "RSA-PSS", hash },
- true,
- ["sign"],
- ),
- DOMException,
- "unsupported algorithm",
- );
- }
- },
-);
-
-// deno-fmt-ignore
-const asn1AlgorithmIdentifier = new Uint8Array([
- 0x02, 0x01, 0x00, // INTEGER
- 0x30, 0x0d, // SEQUENCE (2 elements)
- 0x06, 0x09, // OBJECT IDENTIFIER
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, // 1.2.840.113549.1.1.1 (rsaEncryption)
- 0x05, 0x00, // NULL
-]);
-
-Deno.test(async function rsaExport() {
- for (const algorithm of ["RSASSA-PKCS1-v1_5", "RSA-PSS", "RSA-OAEP"]) {
- const keyPair = await crypto.subtle.generateKey(
- {
- name: algorithm,
- modulusLength: 2048,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash: "SHA-256",
- },
- true,
- algorithm !== "RSA-OAEP" ? ["sign", "verify"] : ["encrypt", "decrypt"],
- );
-
- assert(keyPair.privateKey);
- assert(keyPair.publicKey);
- assertEquals(keyPair.privateKey.extractable, true);
-
- const exportedPrivateKey = await crypto.subtle.exportKey(
- "pkcs8",
- keyPair.privateKey,
- );
-
- assert(exportedPrivateKey);
- assert(exportedPrivateKey instanceof ArrayBuffer);
-
- const pkcs8 = new Uint8Array(exportedPrivateKey);
- assert(pkcs8.length > 0);
-
- assertEquals(
- pkcs8.slice(4, asn1AlgorithmIdentifier.byteLength + 4),
- asn1AlgorithmIdentifier,
- );
-
- const exportedPublicKey = await crypto.subtle.exportKey(
- "spki",
- keyPair.publicKey,
- );
-
- const spki = new Uint8Array(exportedPublicKey);
- assert(spki.length > 0);
-
- assertEquals(
- spki.slice(4, asn1AlgorithmIdentifier.byteLength + 1),
- asn1AlgorithmIdentifier.slice(3),
- );
- }
-});
-
-Deno.test(async function testHkdfDeriveBits() {
- const rawKey = crypto.getRandomValues(new Uint8Array(16));
- const key = await crypto.subtle.importKey(
- "raw",
- rawKey,
- { name: "HKDF", hash: "SHA-256" },
- false,
- ["deriveBits"],
- );
- const salt = crypto.getRandomValues(new Uint8Array(16));
- const info = crypto.getRandomValues(new Uint8Array(16));
- const result = await crypto.subtle.deriveBits(
- {
- name: "HKDF",
- hash: "SHA-256",
- salt: salt,
- info: info,
- },
- key,
- 128,
- );
- assertEquals(result.byteLength, 128 / 8);
-});
-
-Deno.test(async function testHkdfDeriveBitsWithLargeKeySize() {
- const key = await crypto.subtle.importKey(
- "raw",
- new Uint8Array([0x00]),
- "HKDF",
- false,
- ["deriveBits"],
- );
- await assertRejects(
- () =>
- crypto.subtle.deriveBits(
- {
- name: "HKDF",
- hash: "SHA-1",
- salt: new Uint8Array(),
- info: new Uint8Array(),
- },
- key,
- ((20 * 255) << 3) + 8,
- ),
- DOMException,
- "The length provided for HKDF is too large",
- );
-});
-
-Deno.test(async function testEcdhDeriveBitsWithShorterLength() {
- const keypair = await crypto.subtle.generateKey(
- {
- name: "ECDH",
- namedCurve: "P-384",
- },
- true,
- ["deriveBits", "deriveKey"],
- );
- const result = await crypto.subtle.deriveBits(
- {
- name: "ECDH",
- public: keypair.publicKey,
- },
- keypair.privateKey,
- 256,
- );
- assertEquals(result.byteLength * 8, 256);
-});
-
-Deno.test(async function testEcdhDeriveBitsWithLongerLength() {
- const keypair = await crypto.subtle.generateKey(
- {
- name: "ECDH",
- namedCurve: "P-384",
- },
- true,
- ["deriveBits", "deriveKey"],
- );
- await assertRejects(
- () =>
- crypto.subtle.deriveBits(
- {
- name: "ECDH",
- public: keypair.publicKey,
- },
- keypair.privateKey,
- 512,
- ),
- DOMException,
- "Invalid length",
- );
-});
-
-Deno.test(async function testEcdhDeriveBitsWithNullLength() {
- const keypair = await crypto.subtle.generateKey(
- {
- name: "ECDH",
- namedCurve: "P-384",
- },
- true,
- ["deriveBits", "deriveKey"],
- );
- const result = await crypto.subtle.deriveBits(
- {
- name: "ECDH",
- public: keypair.publicKey,
- },
- keypair.privateKey,
- // @ts-ignore: necessary until .d.ts file allows passing null (see https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1416)
- null,
- );
- assertEquals(result.byteLength * 8, 384);
-});
-
-Deno.test(async function testDeriveKey() {
- // Test deriveKey
- const rawKey = crypto.getRandomValues(new Uint8Array(16));
- const key = await crypto.subtle.importKey(
- "raw",
- rawKey,
- "PBKDF2",
- false,
- ["deriveKey", "deriveBits"],
- );
-
- const salt = crypto.getRandomValues(new Uint8Array(16));
- const derivedKey = await crypto.subtle.deriveKey(
- {
- name: "PBKDF2",
- salt,
- iterations: 1000,
- hash: "SHA-256",
- },
- key,
- { name: "HMAC", hash: "SHA-256" },
- true,
- ["sign"],
- );
-
- assert(derivedKey instanceof CryptoKey);
- assertEquals(derivedKey.type, "secret");
- assertEquals(derivedKey.extractable, true);
- assertEquals(derivedKey.usages, ["sign"]);
-
- const algorithm = derivedKey.algorithm as HmacKeyAlgorithm;
- assertEquals(algorithm.name, "HMAC");
- assertEquals(algorithm.hash.name, "SHA-256");
- assertEquals(algorithm.length, 512);
-});
-
-Deno.test(async function testAesCbcEncryptDecrypt() {
- const key = await crypto.subtle.generateKey(
- { name: "AES-CBC", length: 128 },
- true,
- ["encrypt", "decrypt"],
- );
-
- const iv = crypto.getRandomValues(new Uint8Array(16));
- const encrypted = await crypto.subtle.encrypt(
- {
- name: "AES-CBC",
- iv,
- },
- key as CryptoKey,
- new Uint8Array([1, 2, 3, 4, 5, 6]),
- );
-
- assert(encrypted instanceof ArrayBuffer);
- assertEquals(encrypted.byteLength, 16);
-
- const decrypted = await crypto.subtle.decrypt(
- {
- name: "AES-CBC",
- iv,
- },
- key as CryptoKey,
- encrypted,
- );
-
- assert(decrypted instanceof ArrayBuffer);
- assertEquals(decrypted.byteLength, 6);
- assertEquals(new Uint8Array(decrypted), new Uint8Array([1, 2, 3, 4, 5, 6]));
-});
-
-Deno.test(async function testAesCtrEncryptDecrypt() {
- async function aesCtrRoundTrip(
- key: CryptoKey,
- counter: Uint8Array,
- length: number,
- plainText: Uint8Array,
- ) {
- const cipherText = await crypto.subtle.encrypt(
- {
- name: "AES-CTR",
- counter,
- length,
- },
- key,
- plainText,
- );
-
- assert(cipherText instanceof ArrayBuffer);
- assertEquals(cipherText.byteLength, plainText.byteLength);
- assertNotEquals(new Uint8Array(cipherText), plainText);
-
- const decryptedText = await crypto.subtle.decrypt(
- {
- name: "AES-CTR",
- counter,
- length,
- },
- key,
- cipherText,
- );
-
- assert(decryptedText instanceof ArrayBuffer);
- assertEquals(decryptedText.byteLength, plainText.byteLength);
- assertEquals(new Uint8Array(decryptedText), plainText);
- }
- for (const keySize of [128, 192, 256]) {
- const key = await crypto.subtle.generateKey(
- { name: "AES-CTR", length: keySize },
- true,
- ["encrypt", "decrypt"],
- ) as CryptoKey;
-
- // test normal operation
- for (const length of [128 /*, 64, 128 */]) {
- const counter = crypto.getRandomValues(new Uint8Array(16));
-
- await aesCtrRoundTrip(
- key,
- counter,
- length,
- new Uint8Array([1, 2, 3, 4, 5, 6]),
- );
- }
-
- // test counter-wrapping
- for (const length of [32, 64, 128]) {
- const plaintext1 = crypto.getRandomValues(new Uint8Array(32));
- const counter = new Uint8Array(16);
-
- // fixed upper part
- for (let off = 0; off < 16 - (length / 8); ++off) {
- counter[off] = off;
- }
- const ciphertext1 = await crypto.subtle.encrypt(
- {
- name: "AES-CTR",
- counter,
- length,
- },
- key,
- plaintext1,
- );
-
- // Set lower [length] counter bits to all '1's
- for (let off = 16 - (length / 8); off < 16; ++off) {
- counter[off] = 0xff;
- }
-
- // = [ 1 block of 0x00 + plaintext1 ]
- const plaintext2 = new Uint8Array(48);
- plaintext2.set(plaintext1, 16);
-
- const ciphertext2 = await crypto.subtle.encrypt(
- {
- name: "AES-CTR",
- counter,
- length,
- },
- key,
- plaintext2,
- );
-
- // If counter wrapped, 2nd block of ciphertext2 should be equal to 1st block of ciphertext1
- // since ciphertext1 used counter = 0x00...00
- // and ciphertext2 used counter = 0xFF..FF which should wrap to 0x00..00 without affecting
- // higher bits
- assertEquals(
- new Uint8Array(ciphertext1),
- new Uint8Array(ciphertext2).slice(16),
- );
- }
- }
-});
-
-Deno.test(async function testECDH() {
- for (const keySize of [256, 384]) {
- const keyPair = await crypto.subtle.generateKey(
- {
- name: "ECDH",
- namedCurve: "P-" + keySize,
- },
- true,
- ["deriveBits"],
- );
-
- const derivedKey = await crypto.subtle.deriveBits(
- {
- name: "ECDH",
- public: keyPair.publicKey,
- },
- keyPair.privateKey,
- keySize,
- );
-
- assert(derivedKey instanceof ArrayBuffer);
- assertEquals(derivedKey.byteLength, keySize / 8);
- }
-});
-
-Deno.test(async function testWrapKey() {
- // Test wrapKey
- const key = await crypto.subtle.generateKey(
- {
- name: "RSA-OAEP",
- modulusLength: 4096,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash: "SHA-256",
- },
- true,
- ["wrapKey", "unwrapKey"],
- );
-
- const hmacKey = await crypto.subtle.generateKey(
- {
- name: "HMAC",
- hash: "SHA-256",
- length: 128,
- },
- true,
- ["sign"],
- );
-
- const wrappedKey = await crypto.subtle.wrapKey(
- "raw",
- hmacKey,
- key.publicKey,
- {
- name: "RSA-OAEP",
- label: new Uint8Array(8),
- },
- );
-
- assert(wrappedKey instanceof ArrayBuffer);
- assertEquals(wrappedKey.byteLength, 512);
-});
-
-// Doesn't need to cover all cases.
-// Only for testing types.
-Deno.test(async function testAesKeyGen() {
- const key = await crypto.subtle.generateKey(
- {
- name: "AES-GCM",
- length: 256,
- },
- true,
- ["encrypt", "decrypt"],
- );
-
- assert(key);
- assertEquals(key.type, "secret");
- assertEquals(key.extractable, true);
- assertEquals(key.usages, ["encrypt", "decrypt"]);
- const algorithm = key.algorithm as AesKeyAlgorithm;
- assertEquals(algorithm.name, "AES-GCM");
- assertEquals(algorithm.length, 256);
-});
-
-Deno.test(async function testUnwrapKey() {
- const subtle = crypto.subtle;
-
- const AES_KEY: AesKeyAlgorithm & AesCbcParams = {
- name: "AES-CBC",
- length: 128,
- iv: new Uint8Array(16),
- };
-
- const RSA_KEY: RsaHashedKeyGenParams & RsaOaepParams = {
- name: "RSA-OAEP",
- modulusLength: 2048,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash: "SHA-1",
- };
-
- const aesKey = await subtle.generateKey(AES_KEY, true, [
- "encrypt",
- "decrypt",
- ]);
-
- const rsaKeyPair = await subtle.generateKey(
- {
- name: "RSA-OAEP",
- hash: "SHA-1",
- publicExponent: new Uint8Array([1, 0, 1]),
- modulusLength: 2048,
- },
- false,
- ["wrapKey", "encrypt", "unwrapKey", "decrypt"],
- );
-
- const enc = await subtle.wrapKey(
- "raw",
- aesKey,
- rsaKeyPair.publicKey,
- RSA_KEY,
- );
- const unwrappedKey = await subtle.unwrapKey(
- "raw",
- enc,
- rsaKeyPair.privateKey,
- RSA_KEY,
- AES_KEY,
- false,
- ["encrypt", "decrypt"],
- );
-
- assert(unwrappedKey instanceof CryptoKey);
- assertEquals(unwrappedKey.type, "secret");
- assertEquals(unwrappedKey.extractable, false);
- assertEquals(unwrappedKey.usages, ["encrypt", "decrypt"]);
-});
-
-Deno.test(async function testDecryptWithInvalidIntializationVector() {
- // deno-fmt-ignore
- const data = new Uint8Array([42,42,42,42,42,42,42,42,42,42,42,42,42,42,42]);
- const key = await crypto.subtle.importKey(
- "raw",
- new Uint8Array(16),
- { name: "AES-CBC", length: 256 },
- true,
- ["encrypt", "decrypt"],
- );
- // deno-fmt-ignore
- const initVector = new Uint8Array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]);
- const encrypted = await crypto.subtle.encrypt(
- { name: "AES-CBC", iv: initVector },
- key,
- data,
- );
- // deno-fmt-ignore
- const initVector2 = new Uint8Array([15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0]);
- await assertRejects(async () => {
- await crypto.subtle.decrypt(
- { name: "AES-CBC", iv: initVector2 },
- key,
- encrypted,
- );
- }, DOMException);
-});
-
-const jwtRSAKeys = {
- "1024": {
- size: 1024,
- publicJWK: {
- kty: "RSA",
- n: "zZn4sRGfjQos56yL_Qy1R9NI-THMnFynn94g5RxA6wGrJh4BJT3x6I9x0IbpS3q-d4ORA6R2vuDMh8dDFRr9RDH6XY-gUScc9U5Jz3UA2KmVfsCbnUPvcAmMV_ENA7_TF0ivVjuIFodyDTx7EKHNVTrHHSlrbt7spbmcivs23Zc",
- e: "AQAB",
- },
- privateJWK: {
- kty: "RSA",
- n: "zZn4sRGfjQos56yL_Qy1R9NI-THMnFynn94g5RxA6wGrJh4BJT3x6I9x0IbpS3q-d4ORA6R2vuDMh8dDFRr9RDH6XY-gUScc9U5Jz3UA2KmVfsCbnUPvcAmMV_ENA7_TF0ivVjuIFodyDTx7EKHNVTrHHSlrbt7spbmcivs23Zc",
- e: "AQAB",
- d: "YqIK_GdH85F-GWZdgfgmv15NE78gOaL5h2g4v7DeM9-JC7A5PHSLKNYn87HFGcC4vv0PBIBRtyCA_mJJfEaGWORVCOXSBpWNepMYpio52n3w5uj5UZEsBnbtZc0EtWhVF2Auqa7VbiKrWcQUEgEI8V0gE5D4tyBg8GXv9975dQE",
- p: "9BrAg5L1zfqGPuWJDuDCBX-TmtZdrOI3Ys4ZaN-yMPlTjwWSEPO0qnfjEZcw2VgXHgJJmbVco6TxckJCmEYqeQ",
- q: "157jDJ1Ya5nmQvTPbhKAPAeMWogxCyaQTkBrp30pEKd6mGSB385hqr4BIk8s3f7MdXpM-USpaZgUoT4o_2VEjw",
- dp:
- "qdd_QUzcaB-6jkKo1Ug-1xKIAgDLFsIjJUUfWt_iHL8ti2Kl2dOnTcCypgebPm5TT1bqHN-agGYAdK5zpX2UiQ",
- dq:
- "hNRfwOSplNfhLvxLUN7a2qA3yYm-1MSz_1DWQP7srlLORlUcYPht2FZmsnEeDcAqynBGPQUcbG2Av_hgHz2OZw",
- qi:
- "zbpJQAhinrxSbVKxBQ2EZGFUD2e3WCXbAJRYpk8HVQ5AA52OhKTicOye2hEHnrgpFKzC8iznTsCG3FMkvwcj4Q",
- },
- },
-
- "2048": {
- size: 2048,
- publicJWK: {
- kty: "RSA",
- // unpadded base64 for rawKey.
- n: "09eVwAhT9SPBxdEN-74BBeEANGaVGwqH-YglIc4VV7jfhR2by5ivzVq8NCeQ1_ACDIlTDY8CTMQ5E1c1SEXmo_T7q84XUGXf8U9mx6uRg46sV7fF-hkwJR80BFVsvWxp4ahPlVJYj__94ft7rIVvchb5tyalOjrYFCJoFnSgq-i3ZjU06csI9XnO5klINucD_Qq0vUhO23_Add2HSYoRjab8YiJJR_Eths7Pq6HHd2RSXmwYp5foRnwe0_U75XmesHWDJlJUHYbwCZo0kP9G8g4QbucwU-MSNBkZOO2x2ZtZNexpHd0ThkATbnNlpVG_z2AGNORp_Ve3rlXwrGIXXw",
- e: "AQAB",
- },
- privateJWK: {
- kty: "RSA",
- // unpadded base64 for rawKey.
- n: "09eVwAhT9SPBxdEN-74BBeEANGaVGwqH-YglIc4VV7jfhR2by5ivzVq8NCeQ1_ACDIlTDY8CTMQ5E1c1SEXmo_T7q84XUGXf8U9mx6uRg46sV7fF-hkwJR80BFVsvWxp4ahPlVJYj__94ft7rIVvchb5tyalOjrYFCJoFnSgq-i3ZjU06csI9XnO5klINucD_Qq0vUhO23_Add2HSYoRjab8YiJJR_Eths7Pq6HHd2RSXmwYp5foRnwe0_U75XmesHWDJlJUHYbwCZo0kP9G8g4QbucwU-MSNBkZOO2x2ZtZNexpHd0ThkATbnNlpVG_z2AGNORp_Ve3rlXwrGIXXw",
- e: "AQAB",
- d: "H4xboN2co0VP9kXL71G8lUOM5EDis8Q9u8uqu_4U75t4rjpamVeD1vFMVfgOehokM_m_hKVnkkcmuNqj9L90ObaiRFPM5QxG7YkFpXbHlPAKeoXD1hsqMF0VQg_2wb8DhberInHA_rEA_kaVhHvavQLu7Xez45gf1d_J4I4931vjlCB6cupbLL0H5hHsxbMsX_5nnmAJdL_U3gD-U7ZdQheUPhDBJR2KeGzvnTm3KVKpOnwn-1Cd45MU4-KDdP0FcBVEuBsSrsQHliTaciBgkbyj__BangPj3edDxTkb-fKkEvhkXRjAoJs1ixt8nfSGDce9cM_GqAX9XGb4s2QkAQ",
- dp:
- "mM82RBwzGzi9LAqjGbi-badLtHRRBoH9sfMrJuOtzxRnmwBFccg_lwy-qAhUTqnN9kvD0H1FzXWzoFPFJbyi-AOmumYGpWm_PvzQGldne5CPJ02pYaeg-t1BePsT3OpIq0Am8E2Kjf9polpRJwIjO7Kx8UJKkhg5bISnsy0V8wE",
- dq:
- "ZlM4AvrWIpXwqsH_5Q-6BsLJdbnN_GypFCXoT9VXniXncSBZIWCkgDndBdWkSzyzIN65NiMRBfZaf9yduTFj4kvOPwb3ch3J0OxGJk0Ary4OGSlS1zNwMl93ALGal1FzpWUuiia9L9RraGqXAUr13L7TIIMRobRjpAV-z7M-ruM",
- p: "7VwGt_tJcAFQHrmDw5dM1EBru6fidM45NDv6VVOEbxKuD5Sh2EfAHfm5c6oouA1gZqwvKH0sn_XpB1NsyYyHEQd3sBVdK0zRjTo-E9mRP-1s-LMd5YDXVq6HE339nxpXsmO25slQEF6zBrj1bSNNXBFc7fgDnlq-HIeleMvsY_E",
- q: "5HqMHLzb4IgXhUl4pLz7E4kjY8PH2YGzaQfK805zJMbOXzmlZK0hizKo34Qqd2nB9xos7QgzOYQrNfSWheARwVsSQzAE0vGvw3zHIPP_lTtChBlCTPctQcURjw4dXcnK1oQ-IT321FNOW3EO-YTsyGcypJqJujlZrLbxYjOjQE8",
- qi:
- "OQXzi9gypDnpdHatIi0FaUGP8LSzfVH0AUugURJXs4BTJpvA9y4hcpBQLrcl7H_vq6kbGmvC49V-9I5HNVX_AuxGIXKuLZr5WOxPq8gLTqHV7X5ZJDtWIP_nq2NNgCQQyNNRrxebiWlwGK9GnX_unewT6jopI_oFhwp0Q13rBR0",
- },
- },
- "4096": {
- size: 4096,
- publicJWK: {
- kty: "RSA",
- n: "2qr2TL2c2JmbsN0OLIRnaAB_ZKb1-Gh9H0qb4lrBuDaqkW_eFPwT-JIsvnNJvDT7BLJ57tTMIj56ZMtv6efSSTWSk9MOoW2J1K_iEretZ2cegB_aRX7qQVjnoFsz9U02BKfAIUT0o_K7b9G08d1rrAUohi_SVQhwObodg7BddMbKUmz70QNIS487LN44WUVnn9OgE9atTYUARNukT0DuQb3J-K20ksTuVujXbSelohDmLobqlGoi5sY_548Qs9BtFmQ2nGuEHNB2zdlZ5EvEqbUFVZ2QboG6jXdoos6qcwdgUvAhj1Hz10Ngic_RFqL7bNDoIOzNp66hdA35uxbwuaygZ16ikxoPj7eTYud1hrkyQCgeGw2YhCiKIE6eos_U5dL7WHRD5aSkkzsgXtnF8pVmStsuf0QcdAoC-eeCex0tSTgRw9AtGTz8Yr1tGQD9l_580zAXnE6jmrwRRQ68EEA7vohGov3tnG8pGyg_zcxeADLtPlfTc1tEwmh3SGrioDClioYCipm1JvkweEgP9eMPpEC8SgRU1VNDSVe1SF4uNsH8vA7PHFKfg6juqJEc5ht-l10FYER-Qq6bZXsU2oNcfE5SLDeLTWmxiHmxK00M8ABMFIV5gUkPoMiWcl87O6XwzA2chsIERp7Vb-Vn2O-EELiXzv7lPhc6fTGQ0Nc",
- e: "AQAB",
- },
- privateJWK: {
- kty: "RSA",
- n: "2qr2TL2c2JmbsN0OLIRnaAB_ZKb1-Gh9H0qb4lrBuDaqkW_eFPwT-JIsvnNJvDT7BLJ57tTMIj56ZMtv6efSSTWSk9MOoW2J1K_iEretZ2cegB_aRX7qQVjnoFsz9U02BKfAIUT0o_K7b9G08d1rrAUohi_SVQhwObodg7BddMbKUmz70QNIS487LN44WUVnn9OgE9atTYUARNukT0DuQb3J-K20ksTuVujXbSelohDmLobqlGoi5sY_548Qs9BtFmQ2nGuEHNB2zdlZ5EvEqbUFVZ2QboG6jXdoos6qcwdgUvAhj1Hz10Ngic_RFqL7bNDoIOzNp66hdA35uxbwuaygZ16ikxoPj7eTYud1hrkyQCgeGw2YhCiKIE6eos_U5dL7WHRD5aSkkzsgXtnF8pVmStsuf0QcdAoC-eeCex0tSTgRw9AtGTz8Yr1tGQD9l_580zAXnE6jmrwRRQ68EEA7vohGov3tnG8pGyg_zcxeADLtPlfTc1tEwmh3SGrioDClioYCipm1JvkweEgP9eMPpEC8SgRU1VNDSVe1SF4uNsH8vA7PHFKfg6juqJEc5ht-l10FYER-Qq6bZXsU2oNcfE5SLDeLTWmxiHmxK00M8ABMFIV5gUkPoMiWcl87O6XwzA2chsIERp7Vb-Vn2O-EELiXzv7lPhc6fTGQ0Nc",
- e: "AQAB",
- d: "uXPRXBhcE5-DWabBRKQuhxgU8ype5gTISWefeYP7U96ZHqu_sBByZ5ihdgyU9pgAZGVx4Ep9rnVKnH2lNr2zrP9Qhyqy99nM0aMxmypIWLAuP__DwLj4t99M4sU29c48CAq1egHfccSFjzpNuetOTCA71EJuokt70pm0OmGzgTyvjuR7VTLxd5PMXitBowSn8_cphmnFpT8tkTiuy8CH0R3DU7MOuINomDD1s8-yPBcVAVTPUnwJiauNuzestLQKMLlhT5wn-cAbYk36XRKdgkjSc2AkhHRl4WDqT1nzWYdh_DVIYSLiKSktkPO9ovMrRYiPtozfhl0m9SR9Ll0wXtcnnDlWXc_MSGpw18vmUBSJ4PIhkiFsvLn-db3wUkA8uve-iqqfk0sxlGWughWx03kGmZDmprWbXugCBHfsI4X93w4exznXH_tapxPnmjbhVUQR6p41MvO2lcHWPLwGJgLIoejBHpnn3TmMN0UjFZki7q9B_dJ3fXh0mX9DzAlC0sil1NgCPhMPq02393_giinQquMknrBvgKxGSfGUrDKuflCx611ZZlRM3R7YMX2OIy1g4DyhPzBVjxRMtm8PnIs3m3Hi-O-C_PHF93w9J8Wqd0yIw7SpavDqZXLPC6Cqi8K7MBZyVECXHtRj1bBqT-h_xZmFCDjSU0NqfOdgApE",
- p: "9NrXwq4kY9kBBOwLoFZVQc4kJI_NbKa_W9FLdQdRIbMsZZHXJ3XDUR9vJAcaaR75WwIC7X6N55nVtWTq28Bys9flJ9RrCTfciOntHEphBhYaL5ZTUl-6khYmsOf_psff2VaOOCvHGff5ejuOmBQxkw2E-cv7knRgWFHoLWpku2NJIMuGHt9ks7OAUfIZVYl9YJnw4FYUzhgaxemknjLeZ8XTkGW2zckzF-d95YI9i8zD80Umubsw-YxriSfqFQ0rGHBsbQ8ZOTd_KJju42BWnXIjNDYmjFUqdzVjI4XQ8EGrCEf_8_iwphGyXD7LOJ4fqd97B3bYpoRTPnCgY_SEHQ",
- q: "5J758_NeKr1XPZiLxXohYQQnh0Lb4QtGZ1xzCgjhBQLcIBeTOG_tYjCues9tmLt93LpJfypSJ-SjDLwkR2s069_IByYGpxyeGtV-ulqYhSw1nD2CXKMDGyO5jXDs9tJrS_UhfobXKQH03CRdFugyPkSNmXY-AafFynG7xLr7oYBC05FnhUXPm3VBTPt9K-BpqwYd_h9vkAWeprSPo83UlwcLMupSJY9LaHxhRdz2yi0ZKNwXXHRwcszGjDBvvzUcCYbqWqjzbEvFY6KtH8Jh4LhM46rHaoEOTernJsDF6a6W8Df88RthqTExcwnaQf0O_dlbjSxEIPfbxx8t1EQugw",
- dp:
- "4Y7Hu5tYAnLhMXuQqj9dgqU3PkcKYdCp7xc6f7Ah2P2JJHfYz4z4RD7Ez1eLyNKzulZ8A_PVHUjlSZiRkaYTBAEaJDrV70P6cFWuC6WpA0ZREQ1V7EgrQnANbGILa8QsPbYyhSQu4YlB1IwQq5_OmzyVBtgWA7AZIMMzMsMT0FuB_if-gWohBjmRN-vh0p45VUf6UW568-_YmgDFmMYbg1UFs7s_TwrNenPR0h7MO4CB8hP9vJLoZrooRczzIjljPbwy5bRG9CJfjTJ0vhj9MUT3kR1hHV1HJVGU5iBbfTfBKnvJGSI6-IDM4ZUm-B0R5hbs6s9cfOjhFmACIJIbMQ",
- dq:
- "gT4iPbfyHyVEwWyQb4X4grjvg7bXSKSwG1SXMDAOzV9tg7LwJjKYNy8gJAtJgNNVdsfVLs-E_Epzpoph1AIWO9YZZXkov6Yc9zyEVONMX9S7ReU74hTBd8E9b2lMfMg9ogYk9jtSPTt-6kigW4fOh4cHqZ6_tP3cgfLD3JZ8FDPHE4WaySvLDq49yUBO5dQKyIU_xV6OGhQjOUjP_yEoMmzn9tOittsIHTxbXTxqQ6c1FvU9O6YTv8Jl5_Cl66khfX1I1RG38xvurcHULyUbYgeuZ_Iuo9XreT73h9_owo9RguGT29XH4vcNZmRGf5GIvRb4e5lvtleIZkwJA3u78w",
- qi:
- "JHmVKb1zwW5iRR6RCeexYnh2fmY-3DrPSdM8Dxhr0F8dayi-tlRqEdnG0hvp45n8gLUskWWcB9EXlUJObZGKDfGuxgMa3g_xeLA2vmFQ12MxPsyH4iCNZvsgmGxx7TuOHrnDh5EBVnM4_de63crEJON2sYI8Ozi-xp2OEmAr2seWKq4sxkFni6exLhqb-NE4m9HMKlng1EtQh2rLBFG1VYD3SYYpMLc5fxzqGvSxn3Fa-Xgg-IZPY3ubrcm52KYgmLUGmnYStfVqGSWSdhDXHlNgI5pdAA0FzpyBk3ZX-JsxhwcnneKrYBBweq06kRMGWgvdbdAQ-7wSeGqqj5VPwA",
- },
- },
-};
-
-Deno.test(async function testImportRsaJwk() {
- const subtle = window.crypto.subtle;
- assert(subtle);
-
- for (const [_key, jwkData] of Object.entries(jwtRSAKeys)) {
- const { size, publicJWK, privateJWK } = jwkData;
- if (size < 2048) {
- continue;
- }
-
- // 1. Test import PSS
- for (const hash of ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]) {
- const hashMapPSS: Record<string, string> = {
- "SHA-1": "PS1",
- "SHA-256": "PS256",
- "SHA-384": "PS384",
- "SHA-512": "PS512",
- };
-
- if (size == 1024 && hash == "SHA-512") {
- continue;
- }
-
- const privateKeyPSS = await crypto.subtle.importKey(
- "jwk",
- {
- alg: hashMapPSS[hash],
- ...privateJWK,
- ext: true,
- "key_ops": ["sign"],
- },
- { name: "RSA-PSS", hash },
- true,
- ["sign"],
- );
-
- const publicKeyPSS = await crypto.subtle.importKey(
- "jwk",
- {
- alg: hashMapPSS[hash],
- ...publicJWK,
- ext: true,
- "key_ops": ["verify"],
- },
- { name: "RSA-PSS", hash },
- true,
- ["verify"],
- );
-
- const signaturePSS = await crypto.subtle.sign(
- { name: "RSA-PSS", saltLength: 32 },
- privateKeyPSS,
- new Uint8Array([1, 2, 3, 4]),
- );
-
- const verifyPSS = await crypto.subtle.verify(
- { name: "RSA-PSS", saltLength: 32 },
- publicKeyPSS,
- signaturePSS,
- new Uint8Array([1, 2, 3, 4]),
- );
- assert(verifyPSS);
- }
-
- // 2. Test import PKCS1
- for (const hash of ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]) {
- const hashMapPKCS1: Record<string, string> = {
- "SHA-1": "RS1",
- "SHA-256": "RS256",
- "SHA-384": "RS384",
- "SHA-512": "RS512",
- };
-
- if (size == 1024 && hash == "SHA-512") {
- continue;
- }
-
- const privateKeyPKCS1 = await crypto.subtle.importKey(
- "jwk",
- {
- alg: hashMapPKCS1[hash],
- ...privateJWK,
- ext: true,
- "key_ops": ["sign"],
- },
- { name: "RSASSA-PKCS1-v1_5", hash },
- true,
- ["sign"],
- );
-
- const publicKeyPKCS1 = await crypto.subtle.importKey(
- "jwk",
- {
- alg: hashMapPKCS1[hash],
- ...publicJWK,
- ext: true,
- "key_ops": ["verify"],
- },
- { name: "RSASSA-PKCS1-v1_5", hash },
- true,
- ["verify"],
- );
-
- const signaturePKCS1 = await crypto.subtle.sign(
- { name: "RSASSA-PKCS1-v1_5", saltLength: 32 },
- privateKeyPKCS1,
- new Uint8Array([1, 2, 3, 4]),
- );
-
- const verifyPKCS1 = await crypto.subtle.verify(
- { name: "RSASSA-PKCS1-v1_5", saltLength: 32 },
- publicKeyPKCS1,
- signaturePKCS1,
- new Uint8Array([1, 2, 3, 4]),
- );
- assert(verifyPKCS1);
- }
-
- // 3. Test import OAEP
- for (
- const { hash, plainText } of hashPlainTextVector
- ) {
- const hashMapOAEP: Record<string, string> = {
- "SHA-1": "RSA-OAEP",
- "SHA-256": "RSA-OAEP-256",
- "SHA-384": "RSA-OAEP-384",
- "SHA-512": "RSA-OAEP-512",
- };
-
- if (size == 1024 && hash == "SHA-512") {
- continue;
- }
-
- const encryptAlgorithm = { name: "RSA-OAEP" };
-
- const privateKeyOAEP = await crypto.subtle.importKey(
- "jwk",
- {
- alg: hashMapOAEP[hash],
- ...privateJWK,
- ext: true,
- "key_ops": ["decrypt"],
- },
- { ...encryptAlgorithm, hash },
- true,
- ["decrypt"],
- );
-
- const publicKeyOAEP = await crypto.subtle.importKey(
- "jwk",
- {
- alg: hashMapOAEP[hash],
- ...publicJWK,
- ext: true,
- "key_ops": ["encrypt"],
- },
- { ...encryptAlgorithm, hash },
- true,
- ["encrypt"],
- );
- const cipherText = await subtle.encrypt(
- encryptAlgorithm,
- publicKeyOAEP,
- plainText,
- );
-
- assert(cipherText);
- assert(cipherText.byteLength > 0);
- assertEquals(cipherText.byteLength * 8, size);
- assert(cipherText instanceof ArrayBuffer);
-
- const decrypted = await subtle.decrypt(
- encryptAlgorithm,
- privateKeyOAEP,
- cipherText,
- );
- assert(decrypted);
- assert(decrypted instanceof ArrayBuffer);
- assertEquals(new Uint8Array(decrypted), plainText);
- }
- }
-});
-
-const jwtECKeys = {
- "256": {
- size: 256,
- algo: "ES256",
- publicJWK: {
- kty: "EC",
- crv: "P-256",
- x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXdE",
- y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg",
- },
- privateJWK: {
- kty: "EC",
- crv: "P-256",
- x: "0hCwpvnZ8BKGgFi0P6T0cQGFQ7ugDJJQ35JXwqyuXdE",
- y: "zgN1UtSBRQzjm00QlXAbF1v6s0uObAmeGPHBmDWDYeg",
- d: "E9M6LVq_nPnrsh_4YNSu_m5W53eQ9N7ptAiE69M1ROo",
- },
- },
- "384": {
- size: 384,
- algo: "ES384",
- publicJWK: {
- kty: "EC",
- crv: "P-384",
- x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1",
- y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo",
- },
- privateJWK: {
- kty: "EC",
- crv: "P-384",
- x: "IZwU1mYXs27G2IVrOFtzp000T9iude8EZDXdpU47RL1fvevR0I3Wni19wdwhjLQ1",
- y: "vSgTjMd4M3qEL2vWGyQOdCSfJGZ8KlgQp2v8KOAzX4imUB3sAZdtqFr7AIactqzo",
- d: "RTe1mQeE08LSLpao-S-hqkku6HPldqQVguFEGDyYiNEOa560ztSyzEAS5KxeqEBz",
- },
- },
-};
-
-type JWK = Record<string, string>;
-
-function equalJwk(expected: JWK, got: JWK): boolean {
- const fields = Object.keys(expected);
-
- for (let i = 0; i < fields.length; i++) {
- const fieldName = fields[i];
-
- if (!(fieldName in got)) {
- return false;
- }
- if (expected[fieldName] !== got[fieldName]) {
- return false;
- }
- }
-
- return true;
-}
-
-Deno.test(async function testImportExportEcDsaJwk() {
- const subtle = crypto.subtle;
- assert(subtle);
-
- for (
- const [_key, keyData] of Object.entries(jwtECKeys)
- ) {
- const { publicJWK, privateJWK, algo } = keyData;
-
- // 1. Test import EcDsa
- const privateKeyECDSA = await subtle.importKey(
- "jwk",
- {
- alg: algo,
- ...privateJWK,
- ext: true,
- "key_ops": ["sign"],
- },
- { name: "ECDSA", namedCurve: privateJWK.crv },
- true,
- ["sign"],
- );
- const expPrivateKeyJWK = await subtle.exportKey(
- "jwk",
- privateKeyECDSA,
- );
- assert(equalJwk(privateJWK, expPrivateKeyJWK as JWK));
-
- const publicKeyECDSA = await subtle.importKey(
- "jwk",
- {
- alg: algo,
- ...publicJWK,
- ext: true,
- "key_ops": ["verify"],
- },
- { name: "ECDSA", namedCurve: publicJWK.crv },
- true,
- ["verify"],
- );
-
- const expPublicKeyJWK = await subtle.exportKey(
- "jwk",
- publicKeyECDSA,
- );
-
- assert(equalJwk(publicJWK, expPublicKeyJWK as JWK));
-
- const signatureECDSA = await subtle.sign(
- { name: "ECDSA", hash: `SHA-${keyData.size}` },
- privateKeyECDSA,
- new Uint8Array([1, 2, 3, 4]),
- );
-
- const verifyECDSA = await subtle.verify(
- { name: "ECDSA", hash: `SHA-${keyData.size}` },
- publicKeyECDSA,
- signatureECDSA,
- new Uint8Array([1, 2, 3, 4]),
- );
- assert(verifyECDSA);
- }
-});
-
-Deno.test(async function testImportEcDhJwk() {
- const subtle = crypto.subtle;
- assert(subtle);
-
- for (
- const [_key, jwkData] of Object.entries(jwtECKeys)
- ) {
- const { size, publicJWK, privateJWK } = jwkData;
-
- // 1. Test import EcDsa
- const privateKeyECDH = await subtle.importKey(
- "jwk",
- {
- ...privateJWK,
- ext: true,
- "key_ops": ["deriveBits"],
- },
- { name: "ECDH", namedCurve: privateJWK.crv },
- true,
- ["deriveBits"],
- );
-
- const expPrivateKeyJWK = await subtle.exportKey(
- "jwk",
- privateKeyECDH,
- );
- assert(equalJwk(privateJWK, expPrivateKeyJWK as JWK));
-
- const publicKeyECDH = await subtle.importKey(
- "jwk",
- {
- ...publicJWK,
- ext: true,
- "key_ops": [],
- },
- { name: "ECDH", namedCurve: publicJWK.crv },
- true,
- [],
- );
- const expPublicKeyJWK = await subtle.exportKey(
- "jwk",
- publicKeyECDH,
- );
- assert(equalJwk(publicJWK, expPublicKeyJWK as JWK));
-
- const derivedKey = await subtle.deriveBits(
- {
- name: "ECDH",
- public: publicKeyECDH,
- },
- privateKeyECDH,
- size,
- );
-
- assert(derivedKey instanceof ArrayBuffer);
- assertEquals(derivedKey.byteLength, size / 8);
- }
-});
-
-const ecTestKeys = [
- {
- size: 256,
- namedCurve: "P-256",
- signatureLength: 64,
- // deno-fmt-ignore
- raw: new Uint8Array([
- 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63, 164, 244,
- 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172, 174, 93,
- 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149, 112, 27,
- 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53, 131, 97,
- 232,
- ]),
- // deno-fmt-ignore
- spki: new Uint8Array([
- 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206,
- 61, 3, 1, 7, 3, 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128,
- 88, 180, 63, 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146,
- 87, 194, 172, 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155,
- 77, 16, 149, 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241,
- 193, 152, 53, 131, 97, 232,
- ]),
- // deno-fmt-ignore
- pkcs8: new Uint8Array([
- 48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42,
- 134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 19, 211, 58,
- 45, 90, 191, 156, 249, 235, 178, 31, 248, 96, 212, 174, 254, 110, 86, 231,
- 119, 144, 244, 222, 233, 180, 8, 132, 235, 211, 53, 68, 234, 161, 68, 3,
- 66, 0, 4, 210, 16, 176, 166, 249, 217, 240, 18, 134, 128, 88, 180, 63,
- 164, 244, 113, 1, 133, 67, 187, 160, 12, 146, 80, 223, 146, 87, 194, 172,
- 174, 93, 209, 206, 3, 117, 82, 212, 129, 69, 12, 227, 155, 77, 16, 149,
- 112, 27, 23, 91, 250, 179, 75, 142, 108, 9, 158, 24, 241, 193, 152, 53,
- 131, 97, 232,
- ]),
- },
- {
- size: 384,
- namedCurve: "P-384",
- signatureLength: 96,
- // deno-fmt-ignore
- raw: new Uint8Array([
- 4, 118, 64, 176, 165, 100, 177, 112, 49, 254, 58, 53, 158, 63, 73, 200,
- 148, 248, 242, 216, 186, 80, 92, 160, 53, 64, 232, 157, 19, 1, 12, 226,
- 115, 51, 42, 143, 98, 206, 55, 220, 108, 78, 24, 71, 157, 21, 120, 126,
- 104, 157, 86, 48, 226, 110, 96, 52, 48, 77, 170, 9, 231, 159, 26, 165,
- 200, 26, 164, 99, 46, 227, 169, 105, 172, 225, 60, 102, 141, 145, 139,
- 165, 47, 72, 53, 17, 17, 246, 161, 220, 26, 21, 23, 219, 1, 107, 185,
- 163, 215,
- ]),
- // deno-fmt-ignore
- spki: new Uint8Array([
- 48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0,
- 34, 3, 98, 0, 4, 118, 64, 176, 165, 100, 177, 112, 49, 254, 58, 53, 158,
- 63, 73, 200, 148, 248, 242, 216, 186, 80, 92, 160, 53, 64, 232, 157, 19,
- 1, 12, 226, 115, 51, 42, 143, 98, 206, 55, 220, 108, 78, 24, 71, 157, 21,
- 120, 126, 104, 157, 86, 48, 226, 110, 96, 52, 48, 77, 170, 9, 231, 159,
- 26, 165, 200, 26, 164, 99, 46, 227, 169, 105, 172, 225, 60, 102, 141,
- 145, 139, 165, 47, 72, 53, 17, 17, 246, 161, 220, 26, 21, 23, 219, 1,
- 107, 185, 163, 215,
- ]),
- // deno-fmt-ignore
- pkcs8: new Uint8Array([
- 48, 129, 182, 2, 1, 0, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43,
- 129, 4, 0, 34, 4, 129, 158, 48, 129, 155, 2, 1, 1, 4, 48, 202, 7, 195,
- 169, 124, 170, 81, 169, 253, 127, 56, 28, 98, 90, 255, 165, 72, 142, 133,
- 138, 237, 200, 176, 92, 179, 192, 83, 28, 47, 118, 157, 152, 47, 65, 133,
- 140, 50, 83, 182, 191, 224, 96, 216, 179, 59, 150, 15, 233, 161, 100, 3,
- 98, 0, 4, 118, 64, 176, 165, 100, 177, 112, 49, 254, 58, 53, 158, 63, 73,
- 200, 148, 248, 242, 216, 186, 80, 92, 160, 53, 64, 232, 157, 19, 1, 12,
- 226, 115, 51, 42, 143, 98, 206, 55, 220, 108, 78, 24, 71, 157, 21, 120,
- 126, 104, 157, 86, 48, 226, 110, 96, 52, 48, 77, 170, 9, 231, 159, 26,
- 165, 200, 26, 164, 99, 46, 227, 169, 105, 172, 225, 60, 102, 141, 145,
- 139, 165, 47, 72, 53, 17, 17, 246, 161, 220, 26, 21, 23, 219, 1, 107,
- 185, 163, 215,
- ]),
- },
-];
-
-Deno.test(async function testImportEcSpkiPkcs8() {
- const subtle = window.crypto.subtle;
- assert(subtle);
-
- for (
- const { namedCurve, raw, spki, pkcs8, signatureLength } of ecTestKeys
- ) {
- const rawPublicKeyECDSA = await subtle.importKey(
- "raw",
- raw,
- { name: "ECDSA", namedCurve },
- true,
- ["verify"],
- );
-
- const expPublicKeyRaw = await subtle.exportKey(
- "raw",
- rawPublicKeyECDSA,
- );
-
- assertEquals(new Uint8Array(expPublicKeyRaw), raw);
-
- const privateKeyECDSA = await subtle.importKey(
- "pkcs8",
- pkcs8,
- { name: "ECDSA", namedCurve },
- true,
- ["sign"],
- );
-
- const expPrivateKeyPKCS8 = await subtle.exportKey(
- "pkcs8",
- privateKeyECDSA,
- );
-
- assertEquals(new Uint8Array(expPrivateKeyPKCS8), pkcs8);
-
- const expPrivateKeyJWK = await subtle.exportKey(
- "jwk",
- privateKeyECDSA,
- );
-
- assertEquals(expPrivateKeyJWK.crv, namedCurve);
-
- const publicKeyECDSA = await subtle.importKey(
- "spki",
- spki,
- { name: "ECDSA", namedCurve },
- true,
- ["verify"],
- );
-
- const expPublicKeySPKI = await subtle.exportKey(
- "spki",
- publicKeyECDSA,
- );
-
- assertEquals(new Uint8Array(expPublicKeySPKI), spki);
-
- const expPublicKeyJWK = await subtle.exportKey(
- "jwk",
- publicKeyECDSA,
- );
-
- assertEquals(expPublicKeyJWK.crv, namedCurve);
-
- for (
- const hash of ["SHA-1", "SHA-256", "SHA-384", "SHA-512"]
- ) {
- if (
- (hash == "SHA-256" && namedCurve == "P-256") ||
- (hash == "SHA-384" && namedCurve == "P-384")
- ) {
- const signatureECDSA = await subtle.sign(
- { name: "ECDSA", hash },
- privateKeyECDSA,
- new Uint8Array([1, 2, 3, 4]),
- );
-
- const verifyECDSA = await subtle.verify(
- { name: "ECDSA", hash },
- publicKeyECDSA,
- signatureECDSA,
- new Uint8Array([1, 2, 3, 4]),
- );
- assert(verifyECDSA);
- } else {
- await assertRejects(
- async () => {
- await subtle.sign(
- { name: "ECDSA", hash },
- privateKeyECDSA,
- new Uint8Array([1, 2, 3, 4]),
- );
- },
- DOMException,
- "Not implemented",
- );
- await assertRejects(
- async () => {
- await subtle.verify(
- { name: "ECDSA", hash },
- publicKeyECDSA,
- new Uint8Array(signatureLength),
- new Uint8Array([1, 2, 3, 4]),
- );
- },
- DOMException,
- "Not implemented",
- );
- }
- }
- }
-});
-
-Deno.test(async function testAesGcmEncrypt() {
- const key = await crypto.subtle.importKey(
- "raw",
- new Uint8Array(16),
- { name: "AES-GCM", length: 256 },
- true,
- ["encrypt", "decrypt"],
- );
-
- const nonces = [{
- iv: new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]),
- ciphertext: new Uint8Array([
- 50,
- 223,
- 112,
- 178,
- 166,
- 156,
- 255,
- 110,
- 125,
- 138,
- 95,
- 141,
- 82,
- 47,
- 14,
- 164,
- 134,
- 247,
- 22,
- ]),
- }, {
- iv: new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
- ciphertext: new Uint8Array([
- 210,
- 101,
- 81,
- 216,
- 151,
- 9,
- 192,
- 197,
- 62,
- 254,
- 28,
- 132,
- 89,
- 106,
- 40,
- 29,
- 175,
- 232,
- 201,
- ]),
- }];
- for (const { iv, ciphertext: fixture } of nonces) {
- const data = new Uint8Array([1, 2, 3]);
-
- const cipherText = await crypto.subtle.encrypt(
- { name: "AES-GCM", iv },
- key,
- data,
- );
-
- assert(cipherText instanceof ArrayBuffer);
- assertEquals(cipherText.byteLength, 19);
- assertEquals(
- new Uint8Array(cipherText),
- fixture,
- );
-
- const plainText = await crypto.subtle.decrypt(
- { name: "AES-GCM", iv },
- key,
- cipherText,
- );
- assert(plainText instanceof ArrayBuffer);
- assertEquals(plainText.byteLength, 3);
- assertEquals(new Uint8Array(plainText), data);
- }
-});
-
-async function roundTripSecretJwk(
- jwk: JsonWebKey,
- algId: AlgorithmIdentifier | HmacImportParams,
- ops: KeyUsage[],
- validateKeys: (
- key: CryptoKey,
- originalJwk: JsonWebKey,
- exportedJwk: JsonWebKey,
- ) => void,
-) {
- const key = await crypto.subtle.importKey(
- "jwk",
- jwk,
- algId,
- true,
- ops,
- );
-
- assert(key instanceof CryptoKey);
- assertEquals(key.type, "secret");
-
- const exportedKey = await crypto.subtle.exportKey("jwk", key);
-
- validateKeys(key, jwk, exportedKey);
-}
-
-Deno.test(async function testSecretJwkBase64Url() {
- // Test 16bits with "overflow" in 3rd pos of 'quartet', no padding
- const keyData = `{
- "kty": "oct",
- "k": "xxx",
- "alg": "HS512",
- "key_ops": ["sign", "verify"],
- "ext": true
- }`;
-
- await roundTripSecretJwk(
- JSON.parse(keyData),
- { name: "HMAC", hash: "SHA-512" },
- ["sign", "verify"],
- (key, _orig, exp) => {
- assertEquals((key.algorithm as HmacKeyAlgorithm).length, 16);
-
- assertEquals(exp.k, "xxw");
- },
- );
-
- // HMAC 128bits with base64url characters (-_)
- await roundTripSecretJwk(
- {
- kty: "oct",
- k: "HnZXRyDKn-_G5Fx4JWR1YA",
- alg: "HS256",
- "key_ops": ["sign", "verify"],
- ext: true,
- },
- { name: "HMAC", hash: "SHA-256" },
- ["sign", "verify"],
- (key, orig, exp) => {
- assertEquals((key.algorithm as HmacKeyAlgorithm).length, 128);
-
- assertEquals(orig.k, exp.k);
- },
- );
-
- // HMAC 104bits/(12+1) bytes with base64url characters (-_), padding and overflow in 2rd pos of "quartet"
- await roundTripSecretJwk(
- {
- kty: "oct",
- k: "a-_AlFa-2-OmEGa_-z==",
- alg: "HS384",
- "key_ops": ["sign", "verify"],
- ext: true,
- },
- { name: "HMAC", hash: "SHA-384" },
- ["sign", "verify"],
- (key, _orig, exp) => {
- assertEquals((key.algorithm as HmacKeyAlgorithm).length, 104);
-
- assertEquals("a-_AlFa-2-OmEGa_-w", exp.k);
- },
- );
-
- // AES-CBC 128bits with base64url characters (-_) no padding
- await roundTripSecretJwk(
- {
- kty: "oct",
- k: "_u3K_gEjRWf-7cr-ASNFZw",
- alg: "A128CBC",
- "key_ops": ["encrypt", "decrypt"],
- ext: true,
- },
- { name: "AES-CBC" },
- ["encrypt", "decrypt"],
- (_key, orig, exp) => {
- assertEquals(orig.k, exp.k);
- },
- );
-
- // AES-CBC 128bits of '1' with padding chars
- await roundTripSecretJwk(
- {
- kty: "oct",
- k: "_____________________w==",
- alg: "A128CBC",
- "key_ops": ["encrypt", "decrypt"],
- ext: true,
- },
- { name: "AES-CBC" },
- ["encrypt", "decrypt"],
- (_key, _orig, exp) => {
- assertEquals(exp.k, "_____________________w");
- },
- );
-});
-
-Deno.test(async function testAESWrapKey() {
- const key = await crypto.subtle.generateKey(
- {
- name: "AES-KW",
- length: 128,
- },
- true,
- ["wrapKey", "unwrapKey"],
- );
-
- const hmacKey = await crypto.subtle.generateKey(
- {
- name: "HMAC",
- hash: "SHA-256",
- length: 128,
- },
- true,
- ["sign"],
- );
-
- //round-trip
- // wrap-unwrap-export compare
- const wrappedKey = await crypto.subtle.wrapKey(
- "raw",
- hmacKey,
- key,
- {
- name: "AES-KW",
- },
- );
-
- assert(wrappedKey instanceof ArrayBuffer);
- assertEquals(wrappedKey.byteLength, 16 + 8); // 8 = 'auth tag'
-
- const unwrappedKey = await crypto.subtle.unwrapKey(
- "raw",
- wrappedKey,
- key,
- {
- name: "AES-KW",
- },
- {
- name: "HMAC",
- hash: "SHA-256",
- },
- true,
- ["sign"],
- );
-
- assert(unwrappedKey instanceof CryptoKey);
- assertEquals((unwrappedKey.algorithm as HmacKeyAlgorithm).length, 128);
-
- const hmacKeyBytes = await crypto.subtle.exportKey("raw", hmacKey);
- const unwrappedKeyBytes = await crypto.subtle.exportKey("raw", unwrappedKey);
-
- assertEquals(new Uint8Array(hmacKeyBytes), new Uint8Array(unwrappedKeyBytes));
-});
-
-// https://github.com/denoland/deno/issues/13534
-Deno.test(async function testAesGcmTagLength() {
- const key = await crypto.subtle.importKey(
- "raw",
- new Uint8Array(32),
- "AES-GCM",
- false,
- ["encrypt", "decrypt"],
- );
-
- const iv = crypto.getRandomValues(new Uint8Array(12));
-
- // encrypt won't fail, it will simply truncate the tag
- // as expected.
- const encrypted = await crypto.subtle.encrypt(
- { name: "AES-GCM", iv, tagLength: 96 },
- key,
- new Uint8Array(32),
- );
-
- await assertRejects(async () => {
- await crypto.subtle.decrypt(
- { name: "AES-GCM", iv, tagLength: 96 },
- key,
- encrypted,
- );
- });
-});
-
-Deno.test(async function ecPrivateKeyMaterialExportSpki() {
- // `generateKey` generates a key pair internally stored as "private" key.
- const keys = await crypto.subtle.generateKey(
- { name: "ECDSA", namedCurve: "P-256" },
- true,
- ["sign", "verify"],
- );
-
- assert(keys.privateKey instanceof CryptoKey);
- assert(keys.publicKey instanceof CryptoKey);
-
- // `exportKey` should be able to perform necessary conversion to export spki.
- const spki = await crypto.subtle.exportKey("spki", keys.publicKey);
- assert(spki instanceof ArrayBuffer);
-});
-
-// https://github.com/denoland/deno/issues/13911
-Deno.test(async function importJwkWithUse() {
- const jwk = {
- "kty": "EC",
- "use": "sig",
- "crv": "P-256",
- "x": "FWZ9rSkLt6Dx9E3pxLybhdM6xgR5obGsj5_pqmnz5J4",
- "y": "_n8G69C-A2Xl4xUW2lF0i8ZGZnk_KPYrhv4GbTGu5G4",
- };
-
- const algorithm = { name: "ECDSA", namedCurve: "P-256" };
-
- const key = await crypto.subtle.importKey(
- "jwk",
- jwk,
- algorithm,
- true,
- ["verify"],
- );
-
- assert(key instanceof CryptoKey);
-});
-
-// https://github.com/denoland/deno/issues/14215
-Deno.test(async function exportKeyNotExtractable() {
- const key = await crypto.subtle.generateKey(
- {
- name: "HMAC",
- hash: "SHA-512",
- },
- false,
- ["sign", "verify"],
- );
-
- assert(key);
- assertEquals(key.extractable, false);
-
- await assertRejects(async () => {
- // Should fail
- await crypto.subtle.exportKey("raw", key);
- }, DOMException);
-});
-
-// https://github.com/denoland/deno/issues/15126
-Deno.test(async function testImportLeadingZeroesKey() {
- const alg = { name: "ECDSA", namedCurve: "P-256" };
-
- const jwk = {
- kty: "EC",
- crv: "P-256",
- alg: "ES256",
- x: "EvidcdFB1xC6tgfakqZsU9aIURxAJkcX62zHe1Nt6xU",
- y: "AHsk6BioGM7MZWeXOE_49AGmtuaXFT3Ill3DYtz9uYg",
- d: "WDeYo4o1heCF9l_2VIaClRyIeO16zsMlN8UG6Le9dU8",
- "key_ops": ["sign"],
- ext: true,
- };
-
- const key = await crypto.subtle.importKey(
- "jwk",
- jwk,
- alg,
- true,
- ["sign"],
- );
-
- assert(key instanceof CryptoKey);
- assertEquals(key.type, "private");
-});
-
-// https://github.com/denoland/deno/issues/15523
-Deno.test(async function testECspkiRoundTrip() {
- const alg = { name: "ECDH", namedCurve: "P-256" };
- const { publicKey } = await crypto.subtle.generateKey(alg, true, [
- "deriveBits",
- ]);
- const spki = await crypto.subtle.exportKey("spki", publicKey);
- await crypto.subtle.importKey("spki", spki, alg, true, []);
-});
-
-Deno.test(async function testHmacJwkImport() {
- await crypto.subtle.importKey(
- "jwk",
- {
- kty: "oct",
- use: "sig",
- alg: "HS256",
- k: "hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg",
- },
- { name: "HMAC", hash: "SHA-256" },
- false,
- ["sign", "verify"],
- );
-});
-
-Deno.test(async function p521Import() {
- const jwk = {
- "crv": "P-521",
- "ext": true,
- "key_ops": [
- "verify",
- ],
- "kty": "EC",
- "x":
- "AXkSI8nfkc6bu3fifXGuKKbu08g5LKPfxUNQJJYzzPgmN8XLDzx0C9Sdeejl1XoWGrheKPHl0k4tUmHw0cdInpfj",
- "y":
- "AT4vjsO0bzVRlN3Wthv9DewncDXS2tlTob5QojV8WX1GzOAikRfWFEP3nspoSv88U447acZAsk5IvgGJuVjgMDlx",
- };
- const algorithm = { name: "ECDSA", namedCurve: "P-521" };
-
- const key = await crypto.subtle.importKey(
- "jwk",
- jwk,
- algorithm,
- true,
- ["verify"],
- );
-
- assert(key instanceof CryptoKey);
-});
-
-Deno.test(async function p521Generate() {
- const algorithm = { name: "ECDSA", namedCurve: "P-521" };
-
- const key = await crypto.subtle.generateKey(
- algorithm,
- true,
- ["sign", "verify"],
- );
-
- assert(key.privateKey instanceof CryptoKey);
- assert(key.publicKey instanceof CryptoKey);
-});
diff --git a/cli/tests/unit/webgpu_test.ts b/cli/tests/unit/webgpu_test.ts
deleted file mode 100644
index 75ae34981..000000000
--- a/cli/tests/unit/webgpu_test.ts
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import { assert, assertEquals, assertThrows } from "./test_util.ts";
-
-let isCI: boolean;
-try {
- isCI = (Deno.env.get("CI")?.length ?? 0) > 0;
-} catch {
- isCI = true;
-}
-
-// Skip these tests on linux CI, because the vulkan emulator is not good enough
-// yet, and skip on macOS CI because these do not have virtual GPUs.
-const isLinuxOrMacCI =
- (Deno.build.os === "linux" || Deno.build.os === "darwin") && isCI;
-// Skip these tests in WSL because it doesn't have good GPU support.
-const isWsl = await checkIsWsl();
-
-Deno.test({
- permissions: { read: true, env: true },
- ignore: isWsl || isLinuxOrMacCI,
-}, async function webgpuComputePass() {
- const adapter = await navigator.gpu.requestAdapter();
- assert(adapter);
-
- const numbers = [1, 4, 3, 295];
-
- const device = await adapter.requestDevice();
- assert(device);
-
- const shaderCode = await Deno.readTextFile(
- "cli/tests/testdata/webgpu/computepass_shader.wgsl",
- );
-
- const shaderModule = device.createShaderModule({
- code: shaderCode,
- });
-
- const size = new Uint32Array(numbers).byteLength;
-
- const stagingBuffer = device.createBuffer({
- size: size,
- usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
- });
-
- const storageBuffer = device.createBuffer({
- label: "Storage Buffer",
- size: size,
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST |
- GPUBufferUsage.COPY_SRC,
- mappedAtCreation: true,
- });
-
- const buf = new Uint32Array(storageBuffer.getMappedRange());
-
- buf.set(numbers);
-
- storageBuffer.unmap();
-
- const computePipeline = device.createComputePipeline({
- layout: "auto",
- compute: {
- module: shaderModule,
- entryPoint: "main",
- },
- });
- const bindGroupLayout = computePipeline.getBindGroupLayout(0);
-
- const bindGroup = device.createBindGroup({
- layout: bindGroupLayout,
- entries: [
- {
- binding: 0,
- resource: {
- buffer: storageBuffer,
- },
- },
- ],
- });
-
- const encoder = device.createCommandEncoder();
-
- const computePass = encoder.beginComputePass();
- computePass.setPipeline(computePipeline);
- computePass.setBindGroup(0, bindGroup);
- computePass.insertDebugMarker("compute collatz iterations");
- computePass.dispatchWorkgroups(numbers.length);
- computePass.end();
-
- encoder.copyBufferToBuffer(storageBuffer, 0, stagingBuffer, 0, size);
-
- device.queue.submit([encoder.finish()]);
-
- await stagingBuffer.mapAsync(1);
-
- const data = stagingBuffer.getMappedRange();
-
- assertEquals(new Uint32Array(data), new Uint32Array([0, 2, 7, 55]));
-
- stagingBuffer.unmap();
-
- device.destroy();
-
- // TODO(lucacasonato): webgpu spec should add a explicit destroy method for
- // adapters.
- const resources = Object.keys(Deno.resources());
- Deno.close(Number(resources[resources.length - 1]));
-});
-
-Deno.test({
- permissions: { read: true, env: true },
- ignore: isWsl || isLinuxOrMacCI,
-}, async function webgpuHelloTriangle() {
- const adapter = await navigator.gpu.requestAdapter();
- assert(adapter);
-
- const device = await adapter.requestDevice();
- assert(device);
-
- const shaderCode = await Deno.readTextFile(
- "cli/tests/testdata/webgpu/hellotriangle_shader.wgsl",
- );
-
- const shaderModule = device.createShaderModule({
- code: shaderCode,
- });
-
- const pipelineLayout = device.createPipelineLayout({
- bindGroupLayouts: [],
- });
-
- const renderPipeline = device.createRenderPipeline({
- layout: pipelineLayout,
- vertex: {
- module: shaderModule,
- entryPoint: "vs_main",
- },
- fragment: {
- module: shaderModule,
- entryPoint: "fs_main",
- targets: [
- {
- format: "rgba8unorm-srgb",
- },
- ],
- },
- });
-
- const dimensions = {
- width: 200,
- height: 200,
- };
- const unpaddedBytesPerRow = dimensions.width * 4;
- const align = 256;
- const paddedBytesPerRowPadding = (align - unpaddedBytesPerRow % align) %
- align;
- const paddedBytesPerRow = unpaddedBytesPerRow + paddedBytesPerRowPadding;
-
- const outputBuffer = device.createBuffer({
- label: "Capture",
- size: paddedBytesPerRow * dimensions.height,
- usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
- });
- const texture = device.createTexture({
- label: "Capture",
- size: dimensions,
- format: "rgba8unorm-srgb",
- usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
- });
-
- const encoder = device.createCommandEncoder();
- const view = texture.createView();
- const renderPass = encoder.beginRenderPass({
- colorAttachments: [
- {
- view,
- storeOp: "store",
- loadOp: "clear",
- clearValue: [0, 1, 0, 1],
- },
- ],
- });
- renderPass.setPipeline(renderPipeline);
- renderPass.draw(3, 1);
- renderPass.end();
-
- encoder.copyTextureToBuffer(
- {
- texture,
- },
- {
- buffer: outputBuffer,
- bytesPerRow: paddedBytesPerRow,
- rowsPerImage: 0,
- },
- dimensions,
- );
-
- const bundle = encoder.finish();
- device.queue.submit([bundle]);
-
- await outputBuffer.mapAsync(1);
- const data = new Uint8Array(outputBuffer.getMappedRange());
-
- assertEquals(
- data,
- await Deno.readFile("cli/tests/testdata/webgpu/hellotriangle.out"),
- );
-
- outputBuffer.unmap();
-
- device.destroy();
-
- // TODO(lucacasonato): webgpu spec should add a explicit destroy method for
- // adapters.
- const resources = Object.keys(Deno.resources());
- Deno.close(Number(resources[resources.length - 1]));
-});
-
-Deno.test({
- ignore: isWsl || isLinuxOrMacCI,
-}, async function webgpuAdapterHasFeatures() {
- const adapter = await navigator.gpu.requestAdapter();
- assert(adapter);
- assert(adapter.features);
- const resources = Object.keys(Deno.resources());
- Deno.close(Number(resources[resources.length - 1]));
-});
-
-Deno.test({
- ignore: isWsl || isLinuxOrMacCI,
-}, async function webgpuNullWindowSurfaceThrows() {
- const adapter = await navigator.gpu.requestAdapter();
- assert(adapter);
-
- const device = await adapter.requestDevice();
- assert(device);
-
- assertThrows(
- () => {
- new Deno.UnsafeWindowSurface("cocoa", null, null);
- },
- );
-
- device.destroy();
- const resources = Object.keys(Deno.resources());
- Deno.close(Number(resources[resources.length - 1]));
-});
-
-Deno.test(function getPreferredCanvasFormat() {
- const preferredFormat = navigator.gpu.getPreferredCanvasFormat();
- assert(preferredFormat === "bgra8unorm" || preferredFormat === "rgba8unorm");
-});
-
-async function checkIsWsl() {
- return Deno.build.os === "linux" && await hasMicrosoftProcVersion();
-
- async function hasMicrosoftProcVersion() {
- // https://github.com/microsoft/WSL/issues/423#issuecomment-221627364
- try {
- const procVersion = await Deno.readTextFile("/proc/version");
- return /microsoft/i.test(procVersion);
- } catch {
- return false;
- }
- }
-}
diff --git a/cli/tests/unit/websocket_test.ts b/cli/tests/unit/websocket_test.ts
deleted file mode 100644
index 42681c187..000000000
--- a/cli/tests/unit/websocket_test.ts
+++ /dev/null
@@ -1,738 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assert, assertEquals, assertThrows, fail } from "./test_util.ts";
-
-const servePort = 4248;
-const serveUrl = `ws://localhost:${servePort}/`;
-
-Deno.test({ permissions: "none" }, function websocketPermissionless() {
- assertThrows(
- () => new WebSocket("ws://localhost"),
- Deno.errors.PermissionDenied,
- );
-});
-
-Deno.test(async function websocketConstructorTakeURLObjectAsParameter() {
- const { promise, resolve, reject } = Promise.withResolvers<void>();
- const ws = new WebSocket(new URL("ws://localhost:4242/"));
- assertEquals(ws.url, "ws://localhost:4242/");
- ws.onerror = (e) => reject(e);
- ws.onopen = () => ws.close();
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test(async function websocketH2SendSmallPacket() {
- const { promise, resolve, reject } = Promise.withResolvers<void>();
- const ws = new WebSocket(new URL("wss://localhost:4249/"));
- assertEquals(ws.url, "wss://localhost:4249/");
- let messageCount = 0;
- ws.onerror = (e) => reject(e);
- ws.onopen = () => {
- ws.send("a".repeat(16));
- ws.send("a".repeat(16));
- ws.send("a".repeat(16));
- };
- ws.onmessage = () => {
- if (++messageCount == 3) {
- ws.close();
- }
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test(async function websocketH2SendLargePacket() {
- const { promise, resolve, reject } = Promise.withResolvers<void>();
- const ws = new WebSocket(new URL("wss://localhost:4249/"));
- assertEquals(ws.url, "wss://localhost:4249/");
- let messageCount = 0;
- ws.onerror = (e) => reject(e);
- ws.onopen = () => {
- ws.send("a".repeat(65000));
- ws.send("a".repeat(65000));
- ws.send("a".repeat(65000));
- };
- ws.onmessage = () => {
- if (++messageCount == 3) {
- ws.close();
- }
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test(async function websocketSendLargePacket() {
- const { promise, resolve, reject } = Promise.withResolvers<void>();
- const ws = new WebSocket(new URL("wss://localhost:4243/"));
- assertEquals(ws.url, "wss://localhost:4243/");
- ws.onerror = (e) => reject(e);
- ws.onopen = () => {
- ws.send("a".repeat(65000));
- };
- ws.onmessage = () => {
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test(async function websocketSendLargeBinaryPacket() {
- const { promise, resolve, reject } = Promise.withResolvers<void>();
- const ws = new WebSocket(new URL("wss://localhost:4243/"));
- ws.binaryType = "arraybuffer";
- assertEquals(ws.url, "wss://localhost:4243/");
- ws.onerror = (e) => reject(e);
- ws.onopen = () => {
- ws.send(new Uint8Array(65000));
- };
- ws.onmessage = (msg: MessageEvent) => {
- assertEquals(msg.data.byteLength, 65000);
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test(async function websocketSendLargeBlobPacket() {
- const { promise, resolve, reject } = Promise.withResolvers<void>();
- const ws = new WebSocket(new URL("wss://localhost:4243/"));
- ws.binaryType = "arraybuffer";
- assertEquals(ws.url, "wss://localhost:4243/");
- ws.onerror = (e) => reject(e);
- ws.onopen = () => {
- ws.send(new Blob(["a".repeat(65000)]));
- };
- ws.onmessage = (msg: MessageEvent) => {
- assertEquals(msg.data.byteLength, 65000);
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-// https://github.com/denoland/deno/pull/17762
-// https://github.com/denoland/deno/issues/17761
-Deno.test(async function websocketPingPong() {
- const { promise, resolve, reject } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4245/");
- assertEquals(ws.url, "ws://localhost:4245/");
- ws.onerror = (e) => reject(e);
- ws.onmessage = (e) => {
- ws.send(e.data);
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
- ws.close();
-});
-
-// TODO(mmastrac): This requires us to ignore bad certs
-// Deno.test(async function websocketSecureConnect() {
-// const { promise, resolve } = Promise.withResolvers<void>();
-// const ws = new WebSocket("wss://localhost:4243/");
-// assertEquals(ws.url, "wss://localhost:4243/");
-// ws.onerror = (error) => {
-// console.log(error);
-// fail();
-// };
-// ws.onopen = () => ws.close();
-// ws.onclose = () => {
-// resolve();
-// };
-// await promise;
-// });
-
-// https://github.com/denoland/deno/issues/18700
-Deno.test(
- { sanitizeOps: false, sanitizeResources: false },
- async function websocketWriteLock() {
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: (req) => {
- const { socket, response } = Deno.upgradeWebSocket(req);
- socket.onopen = function () {
- setTimeout(() => socket.send("Hello"), 500);
- };
- socket.onmessage = function (e) {
- assertEquals(e.data, "Hello");
- ac.abort();
- };
- return response;
- },
- signal: ac.signal,
- onListen: () => listeningDeferred.resolve(),
- hostname: "localhost",
- port: servePort,
- });
-
- await listeningDeferred.promise;
- const deferred = Promise.withResolvers<void>();
- const ws = new WebSocket(serveUrl);
- assertEquals(ws.url, serveUrl);
- ws.onerror = () => fail();
- ws.onmessage = (e) => {
- assertEquals(e.data, "Hello");
- setTimeout(() => {
- ws.send(e.data);
- }, 1000);
- deferred.resolve();
- };
- ws.onclose = () => {
- deferred.resolve();
- };
-
- await Promise.all([deferred.promise, server.finished]);
- ws.close();
- },
-);
-
-// https://github.com/denoland/deno/issues/18775
-Deno.test({
- sanitizeOps: false,
- sanitizeResources: false,
-}, async function websocketDoubleClose() {
- const deferred = Promise.withResolvers<void>();
-
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: (req) => {
- const { response, socket } = Deno.upgradeWebSocket(req);
- let called = false;
- socket.onopen = () => socket.send("Hello");
- socket.onmessage = () => {
- assert(!called);
- called = true;
- socket.send("bye");
- socket.close();
- };
- socket.onclose = () => ac.abort();
- socket.onerror = () => fail();
- return response;
- },
- signal: ac.signal,
- onListen: () => listeningDeferred.resolve(),
- hostname: "localhost",
- port: servePort,
- });
-
- await listeningDeferred.promise;
-
- const ws = new WebSocket(serveUrl);
- assertEquals(ws.url, serveUrl);
- ws.onerror = () => fail();
- ws.onmessage = (m: MessageEvent) => {
- if (m.data == "Hello") ws.send("bye");
- };
- ws.onclose = () => {
- deferred.resolve();
- };
- await Promise.all([deferred.promise, server.finished]);
-});
-
-// https://github.com/denoland/deno/issues/19483
-Deno.test({
- sanitizeOps: false,
- sanitizeResources: false,
-}, async function websocketCloseFlushes() {
- const deferred = Promise.withResolvers<void>();
-
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: (req) => {
- const { response, socket } = Deno.upgradeWebSocket(req);
- socket.onopen = () => socket.send("Hello");
- socket.onmessage = () => {
- socket.send("Bye");
- socket.close();
- };
- socket.onclose = () => ac.abort();
- socket.onerror = () => fail();
- return response;
- },
- signal: ac.signal,
- onListen: () => listeningDeferred.resolve(),
- hostname: "localhost",
- port: servePort,
- });
-
- await listeningDeferred.promise;
-
- const ws = new WebSocket(serveUrl);
- assertEquals(ws.url, serveUrl);
- let seenBye = false;
- ws.onerror = () => fail();
- ws.onmessage = ({ data }) => {
- if (data == "Hello") {
- ws.send("Hello!");
- } else {
- assertEquals(data, "Bye");
- seenBye = true;
- }
- };
- ws.onclose = () => {
- deferred.resolve();
- };
- await Promise.all([deferred.promise, server.finished]);
-
- assert(seenBye);
-});
-
-Deno.test(
- { sanitizeOps: false },
- function websocketConstructorWithPrototypePollution() {
- const originalSymbolIterator = Array.prototype[Symbol.iterator];
- try {
- Array.prototype[Symbol.iterator] = () => {
- throw Error("unreachable");
- };
- assertThrows(() => {
- new WebSocket(
- new URL("ws://localhost:4242/"),
- // Allow `Symbol.iterator` to be called in WebIDL conversion to `sequence<DOMString>`
- // deno-lint-ignore no-explicit-any
- ["soap", "soap"].values() as any,
- );
- }, DOMException);
- } finally {
- Array.prototype[Symbol.iterator] = originalSymbolIterator;
- }
- },
-);
-
-Deno.test(async function websocketTlsSocketWorks() {
- const cert = await Deno.readTextFile("cli/tests/testdata/tls/localhost.crt");
- const key = await Deno.readTextFile("cli/tests/testdata/tls/localhost.key");
-
- const messages: string[] = [],
- errors: { server?: Event; client?: Event }[] = [];
- const promise = new Promise((okay, nope) => {
- const ac = new AbortController();
- const server = Deno.serve({
- handler: (req) => {
- const { response, socket } = Deno.upgradeWebSocket(req);
- socket.onopen = () => socket.send("ping");
- socket.onmessage = (e) => {
- messages.push(e.data);
- socket.close();
- };
- socket.onerror = (e) => errors.push({ server: e });
- socket.onclose = () => ac.abort();
- return response;
- },
- signal: ac.signal,
- hostname: "localhost",
- port: servePort,
- cert,
- key,
- });
- setTimeout(() => {
- const ws = new WebSocket(`wss://localhost:${servePort}`);
- ws.onmessage = (e) => {
- messages.push(e.data);
- ws.send("pong");
- };
- ws.onerror = (e) => {
- errors.push({ client: e });
- nope();
- };
- ws.onclose = () => okay(server.finished);
- }, 1000);
- });
-
- const finished = await promise;
-
- assertEquals(errors, []);
- assertEquals(messages, ["ping", "pong"]);
-
- await finished;
-});
-
-// https://github.com/denoland/deno/issues/15340
-Deno.test(
- async function websocketServerFieldInit() {
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: (req) => {
- const { socket, response } = Deno.upgradeWebSocket(req, {
- idleTimeout: 0,
- });
- socket.onopen = function () {
- assert(typeof socket.url == "string");
- assert(socket.readyState == WebSocket.OPEN);
- assert(socket.protocol == "");
- assert(socket.binaryType == "arraybuffer");
- socket.close();
- };
- socket.onclose = () => ac.abort();
- return response;
- },
- signal: ac.signal,
- onListen: () => listeningDeferred.resolve(),
- hostname: "localhost",
- port: servePort,
- });
-
- await listeningDeferred.promise;
- const deferred = Promise.withResolvers<void>();
- const ws = new WebSocket(serveUrl);
- assertEquals(ws.url, serveUrl);
- ws.onerror = () => fail();
- ws.onclose = () => {
- deferred.resolve();
- };
-
- await Promise.all([deferred.promise, server.finished]);
- },
-);
-
-Deno.test(
- { sanitizeOps: false },
- async function websocketServerGetsGhosted() {
- const ac = new AbortController();
- const listeningDeferred = Promise.withResolvers<void>();
-
- const server = Deno.serve({
- handler: (req) => {
- const { socket, response } = Deno.upgradeWebSocket(req, {
- idleTimeout: 2,
- });
- socket.onerror = () => socket.close();
- socket.onclose = () => ac.abort();
- return response;
- },
- signal: ac.signal,
- onListen: () => listeningDeferred.resolve(),
- hostname: "localhost",
- port: servePort,
- });
-
- await listeningDeferred.promise;
- const r = await fetch("http://localhost:4545/ghost_ws_client");
- assertEquals(r.status, 200);
- await r.body?.cancel();
-
- await server.finished;
- },
-);
-
-Deno.test("invalid scheme", () => {
- assertThrows(() => new WebSocket("foo://localhost:4242"));
-});
-
-Deno.test("fragment", () => {
- assertThrows(() => new WebSocket("ws://localhost:4242/#"));
- assertThrows(() => new WebSocket("ws://localhost:4242/#foo"));
-});
-
-Deno.test("duplicate protocols", () => {
- assertThrows(() => new WebSocket("ws://localhost:4242", ["foo", "foo"]));
-});
-
-Deno.test("invalid server", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:2121");
- let err = false;
- ws.onerror = () => {
- err = true;
- };
- ws.onclose = () => {
- if (err) {
- resolve();
- } else {
- fail();
- }
- };
- ws.onopen = () => fail();
- await promise;
-});
-
-Deno.test("connect & close", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.onerror = () => fail();
- ws.onopen = () => {
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("connect & abort", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.close();
- let err = false;
- ws.onerror = () => {
- err = true;
- };
- ws.onclose = () => {
- if (err) {
- resolve();
- } else {
- fail();
- }
- };
- ws.onopen = () => fail();
- await promise;
-});
-
-Deno.test("connect & close custom valid code", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.onerror = () => fail();
- ws.onopen = () => ws.close(1000);
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("connect & close custom invalid code", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.onerror = () => fail();
- ws.onopen = () => {
- assertThrows(() => ws.close(1001));
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("connect & close custom valid reason", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.onerror = () => fail();
- ws.onopen = () => ws.close(1000, "foo");
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("connect & close custom invalid reason", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.onerror = () => fail();
- ws.onopen = () => {
- assertThrows(() => ws.close(1000, "".padEnd(124, "o")));
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("echo string", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.onerror = () => fail();
- ws.onopen = () => ws.send("foo");
- ws.onmessage = (e) => {
- assertEquals(e.data, "foo");
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("echo string tls", async () => {
- const deferred1 = Promise.withResolvers<void>();
- const deferred2 = Promise.withResolvers<void>();
- const ws = new WebSocket("wss://localhost:4243");
- ws.onerror = () => fail();
- ws.onopen = () => ws.send("foo");
- ws.onmessage = (e) => {
- assertEquals(e.data, "foo");
- ws.close();
- deferred1.resolve();
- };
- ws.onclose = () => {
- deferred2.resolve();
- };
- await deferred1.promise;
- await deferred2.promise;
-});
-
-Deno.test("websocket error", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("wss://localhost:4242");
- ws.onopen = () => fail();
- ws.onerror = (err) => {
- assert(err instanceof ErrorEvent);
- assertEquals(
- err.message,
- "NetworkError: failed to connect to WebSocket: received corrupt message of type InvalidContentType",
- );
- resolve();
- };
- await promise;
-});
-
-Deno.test("echo blob with binaryType blob", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- const blob = new Blob(["foo"]);
- ws.onerror = () => fail();
- ws.onopen = () => ws.send(blob);
- ws.onmessage = (e) => {
- e.data.text().then((actual: string) => {
- blob.text().then((expected) => {
- assertEquals(actual, expected);
- });
- });
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("echo blob with binaryType arraybuffer", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.binaryType = "arraybuffer";
- const blob = new Blob(["foo"]);
- ws.onerror = () => fail();
- ws.onopen = () => ws.send(blob);
- ws.onmessage = (e) => {
- blob.arrayBuffer().then((expected) => {
- assertEquals(e.data, expected);
- });
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("echo uint8array with binaryType blob", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- const uint = new Uint8Array([102, 111, 111]);
- ws.onerror = () => fail();
- ws.onopen = () => ws.send(uint);
- ws.onmessage = (e) => {
- e.data.arrayBuffer().then((actual: ArrayBuffer) => {
- assertEquals(actual, uint.buffer);
- });
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("echo uint8array with binaryType arraybuffer", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.binaryType = "arraybuffer";
- const uint = new Uint8Array([102, 111, 111]);
- ws.onerror = () => fail();
- ws.onopen = () => ws.send(uint);
- ws.onmessage = (e) => {
- assertEquals(e.data, uint.buffer);
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("echo arraybuffer with binaryType blob", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- const buffer = new ArrayBuffer(3);
- ws.onerror = () => fail();
- ws.onopen = () => ws.send(buffer);
- ws.onmessage = (e) => {
- e.data.arrayBuffer().then((actual: ArrayBuffer) => {
- assertEquals(actual, buffer);
- });
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("echo arraybuffer with binaryType arraybuffer", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- ws.binaryType = "arraybuffer";
- const buffer = new ArrayBuffer(3);
- ws.onerror = () => fail();
- ws.onopen = () => ws.send(buffer);
- ws.onmessage = (e) => {
- assertEquals(e.data, buffer);
- ws.close();
- };
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("Event Handlers order", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4242");
- const arr: number[] = [];
- ws.onerror = () => fail();
- ws.addEventListener("message", () => arr.push(1));
- ws.onmessage = () => fail();
- ws.addEventListener("message", () => {
- arr.push(3);
- ws.close();
- assertEquals(arr, [1, 2, 3]);
- });
- ws.onmessage = () => arr.push(2);
- ws.onopen = () => ws.send("Echo");
- ws.onclose = () => {
- resolve();
- };
- await promise;
-});
-
-Deno.test("Close without frame", async () => {
- const { promise, resolve } = Promise.withResolvers<void>();
- const ws = new WebSocket("ws://localhost:4244");
- ws.onerror = () => fail();
- ws.onclose = (e) => {
- assertEquals(e.code, 1005);
- resolve();
- };
- await promise;
-});
diff --git a/cli/tests/unit/websocketstream_test.ts.disabled b/cli/tests/unit/websocketstream_test.ts.disabled
deleted file mode 100644
index eaedb71bd..000000000
--- a/cli/tests/unit/websocketstream_test.ts.disabled
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import {
- assertEquals,
- assertNotEquals,
- assertRejects,
- assertThrows,
- unreachable,
-} from "@test_util/std/assert/mod.ts";
-
-Deno.test("fragment", () => {
- assertThrows(() => new WebSocketStream("ws://localhost:4242/#"));
- assertThrows(() => new WebSocketStream("ws://localhost:4242/#foo"));
-});
-
-Deno.test("duplicate protocols", () => {
- assertThrows(() =>
- new WebSocketStream("ws://localhost:4242", {
- protocols: ["foo", "foo"],
- })
- );
-});
-
-Deno.test(
- "connect & close custom valid code",
- { sanitizeOps: false },
- async () => {
- const ws = new WebSocketStream("ws://localhost:4242");
- await ws.opened;
- ws.close({ code: 1000 });
- await ws.closed;
- },
-);
-
-Deno.test(
- "connect & close custom invalid reason",
- { sanitizeOps: false },
- async () => {
- const ws = new WebSocketStream("ws://localhost:4242");
- await ws.opened;
- assertThrows(() => ws.close({ code: 1000, reason: "".padEnd(124, "o") }));
- ws.close();
- await ws.closed;
- },
-);
-
-Deno.test("echo string", { sanitizeOps: false }, async () => {
- const ws = new WebSocketStream("ws://localhost:4242");
- const { readable, writable } = await ws.opened;
- await writable.getWriter().write("foo");
- const res = await readable.getReader().read();
- assertEquals(res.value, "foo");
- ws.close();
- await ws.closed;
-});
-
-// TODO(mmastrac): This fails -- perhaps it isn't respecting the TLS settings?
-Deno.test("echo string tls", { ignore: true }, async () => {
- const ws = new WebSocketStream("wss://localhost:4243");
- const { readable, writable } = await ws.opened;
- await writable.getWriter().write("foo");
- const res = await readable.getReader().read();
- assertEquals(res.value, "foo");
- ws.close();
- await ws.closed;
-});
-
-Deno.test("websocket error", { sanitizeOps: false }, async () => {
- const ws = new WebSocketStream("wss://localhost:4242");
- await Promise.all([
- // TODO(mmastrac): this exception should be tested
- assertRejects(
- () => ws.opened,
- // Deno.errors.UnexpectedEof,
- // "tls handshake eof",
- ),
- // TODO(mmastrac): this exception should be tested
- assertRejects(
- () => ws.closed,
- // Deno.errors.UnexpectedEof,
- // "tls handshake eof",
- ),
- ]);
-});
-
-Deno.test("echo uint8array", { sanitizeOps: false }, async () => {
- const ws = new WebSocketStream("ws://localhost:4242");
- const { readable, writable } = await ws.opened;
- const uint = new Uint8Array([102, 111, 111]);
- await writable.getWriter().write(uint);
- const res = await readable.getReader().read();
- assertEquals(res.value, uint);
- ws.close();
- await ws.closed;
-});
-
-Deno.test("aborting immediately throws an AbortError", async () => {
- const controller = new AbortController();
- const wss = new WebSocketStream("ws://localhost:4242", {
- signal: controller.signal,
- });
- controller.abort();
- // TODO(mmastrac): this exception should be tested
- await assertRejects(
- () => wss.opened,
- // (error: Error) => {
- // assert(error instanceof DOMException);
- // assertEquals(error.name, "AbortError");
- // },
- );
- // TODO(mmastrac): this exception should be tested
- await assertRejects(
- () => wss.closed,
- // (error: Error) => {
- // assert(error instanceof DOMException);
- // assertEquals(error.name, "AbortError");
- // },
- );
-});
-
-Deno.test("aborting immediately with a reason throws that reason", async () => {
- const controller = new AbortController();
- const wss = new WebSocketStream("ws://localhost:4242", {
- signal: controller.signal,
- });
- const abortReason = new Error();
- controller.abort(abortReason);
- // TODO(mmastrac): this exception should be tested
- await assertRejects(
- () => wss.opened,
- // (error: Error) => assertEquals(error, abortReason),
- );
- // TODO(mmastrac): this exception should be tested
- await assertRejects(
- () => wss.closed,
- // (error: Error) => assertEquals(error, abortReason),
- );
-});
-
-Deno.test("aborting immediately with a primitive as reason throws that primitive", async () => {
- const controller = new AbortController();
- const wss = new WebSocketStream("ws://localhost:4242", {
- signal: controller.signal,
- });
- controller.abort("Some string");
- await wss.opened.then(
- () => unreachable(),
- (e) => assertEquals(e, "Some string"),
- );
- await wss.closed.then(
- () => unreachable(),
- (e) => assertEquals(e, "Some string"),
- );
-});
-
-Deno.test("headers", { sanitizeOps: false }, async () => {
- const listener = Deno.listen({ port: 4512 });
- const promise = (async () => {
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const { request, respondWith } = (await httpConn.nextRequest())!;
- assertEquals(request.headers.get("x-some-header"), "foo");
- const { response, socket } = Deno.upgradeWebSocket(request);
- socket.onopen = () => socket.close();
- const p = new Promise<void>((resolve) => {
- socket.onopen = () => socket.close();
- socket.onclose = () => resolve();
- });
- await respondWith(response);
- await p;
- })();
-
- const ws = new WebSocketStream("ws://localhost:4512", {
- headers: [["x-some-header", "foo"]],
- });
- await ws.opened;
- await promise;
- await ws.closed;
- listener.close();
-});
-
-Deno.test("forbidden headers", async () => {
- const forbiddenHeaders = [
- "sec-websocket-accept",
- "sec-websocket-extensions",
- "sec-websocket-key",
- "sec-websocket-protocol",
- "sec-websocket-version",
- "upgrade",
- "connection",
- ];
-
- const listener = Deno.listen({ port: 4512 });
- const promise = (async () => {
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const { request, respondWith } = (await httpConn.nextRequest())!;
- for (const [key] of request.headers) {
- assertNotEquals(key, "foo");
- }
- const { response, socket } = Deno.upgradeWebSocket(request);
- const p = new Promise<void>((resolve) => {
- socket.onopen = () => socket.close();
- socket.onclose = () => resolve();
- });
- await respondWith(response);
- await p;
- })();
-
- const ws = new WebSocketStream("ws://localhost:4512", {
- headers: forbiddenHeaders.map((header) => [header, "foo"]),
- });
- await ws.opened;
- await promise;
- await ws.closed;
- listener.close();
-});
-
-Deno.test("sync close with empty stream", { sanitizeOps: false }, async () => {
- const listener = Deno.listen({ port: 4512 });
- const promise = (async () => {
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const { request, respondWith } = (await httpConn.nextRequest())!;
- const { response, socket } = Deno.upgradeWebSocket(request);
- const p = new Promise<void>((resolve) => {
- socket.onopen = () => {
- socket.send("first message");
- socket.send("second message");
- };
- socket.onclose = () => resolve();
- });
- await respondWith(response);
- await p;
- })();
-
- const ws = new WebSocketStream("ws://localhost:4512");
- const { readable } = await ws.opened;
- const reader = readable.getReader();
- const firstMessage = await reader.read();
- assertEquals(firstMessage.value, "first message");
- const secondMessage = await reader.read();
- assertEquals(secondMessage.value, "second message");
- ws.close({ code: 1000 });
- await ws.closed;
- await promise;
- listener.close();
-});
-
-Deno.test(
- "sync close with unread messages in stream",
- { sanitizeOps: false },
- async () => {
- const listener = Deno.listen({ port: 4512 });
- const promise = (async () => {
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const { request, respondWith } = (await httpConn.nextRequest())!;
- const { response, socket } = Deno.upgradeWebSocket(request);
- const p = new Promise<void>((resolve) => {
- socket.onopen = () => {
- socket.send("first message");
- socket.send("second message");
- socket.send("third message");
- socket.send("fourth message");
- };
- socket.onclose = () => resolve();
- });
- await respondWith(response);
- await p;
- })();
-
- const ws = new WebSocketStream("ws://localhost:4512");
- const { readable } = await ws.opened;
- const reader = readable.getReader();
- const firstMessage = await reader.read();
- assertEquals(firstMessage.value, "first message");
- const secondMessage = await reader.read();
- assertEquals(secondMessage.value, "second message");
- ws.close({ code: 1000 });
- await ws.closed;
- await promise;
- listener.close();
- },
-);
-
-// TODO(mmastrac): Failed on CI, disabled
-Deno.test("async close with empty stream", { ignore: true }, async () => {
- const listener = Deno.listen({ port: 4512 });
- const promise = (async () => {
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const { request, respondWith } = (await httpConn.nextRequest())!;
- const { response, socket } = Deno.upgradeWebSocket(request);
- const p = new Promise<void>((resolve) => {
- socket.onopen = () => {
- socket.send("first message");
- socket.send("second message");
- };
- socket.onclose = () => resolve();
- });
- await respondWith(response);
- await p;
- })();
-
- const ws = new WebSocketStream("ws://localhost:4512");
- const { readable } = await ws.opened;
- const reader = readable.getReader();
- const firstMessage = await reader.read();
- assertEquals(firstMessage.value, "first message");
- const secondMessage = await reader.read();
- assertEquals(secondMessage.value, "second message");
- setTimeout(() => {
- ws.close({ code: 1000 });
- }, 0);
- await ws.closed;
- await promise;
- listener.close();
-});
-
-// TODO(mmastrac): Failed on CI, disabled
-Deno.test(
- "async close with unread messages in stream",
- { ignore: true },
- async () => {
- const listener = Deno.listen({ port: 4512 });
- const promise = (async () => {
- const conn = await listener.accept();
- const httpConn = Deno.serveHttp(conn);
- const { request, respondWith } = (await httpConn.nextRequest())!;
- const { response, socket } = Deno.upgradeWebSocket(request);
- const p = new Promise<void>((resolve) => {
- socket.onopen = () => {
- socket.send("first message");
- socket.send("second message");
- socket.send("third message");
- socket.send("fourth message");
- };
- socket.onclose = () => resolve();
- });
- await respondWith(response);
- await p;
- })();
-
- const ws = new WebSocketStream("ws://localhost:4512");
- const { readable } = await ws.opened;
- const reader = readable.getReader();
- const firstMessage = await reader.read();
- assertEquals(firstMessage.value, "first message");
- const secondMessage = await reader.read();
- assertEquals(secondMessage.value, "second message");
- setTimeout(() => {
- ws.close({ code: 1000 });
- }, 0);
- await ws.closed;
- await promise;
- listener.close();
- },
-);
diff --git a/cli/tests/unit/webstorage_test.ts b/cli/tests/unit/webstorage_test.ts
deleted file mode 100644
index 9dc560af1..000000000
--- a/cli/tests/unit/webstorage_test.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-// deno-lint-ignore-file no-explicit-any
-
-import { assert, assertEquals, assertThrows } from "./test_util.ts";
-
-Deno.test({ permissions: "none" }, function webStoragesReassignable() {
- // Can reassign to web storages
- globalThis.localStorage = 1 as any;
- globalThis.sessionStorage = 1 as any;
- // The actual values don't change
- assert(globalThis.localStorage instanceof globalThis.Storage);
- assert(globalThis.sessionStorage instanceof globalThis.Storage);
-});
-
-Deno.test(function webstorageSizeLimit() {
- localStorage.clear();
- assertThrows(
- () => {
- localStorage.setItem("k", "v".repeat(15 * 1024 * 1024));
- },
- Error,
- "Exceeded maximum storage size",
- );
- assertEquals(localStorage.getItem("k"), null);
- assertThrows(
- () => {
- localStorage.setItem("k".repeat(15 * 1024 * 1024), "v");
- },
- Error,
- "Exceeded maximum storage size",
- );
- assertThrows(
- () => {
- localStorage.setItem(
- "k".repeat(5 * 1024 * 1024),
- "v".repeat(5 * 1024 * 1024),
- );
- },
- Error,
- "Exceeded maximum storage size",
- );
-});
-
-Deno.test(function webstorageProxy() {
- localStorage.clear();
- localStorage.foo = "foo";
- assertEquals(localStorage.foo, "foo");
- const symbol = Symbol("bar");
- localStorage[symbol as any] = "bar";
- assertEquals(localStorage[symbol as any], "bar");
- assertEquals(symbol in localStorage, true);
-});
diff --git a/cli/tests/unit/worker_permissions_test.ts b/cli/tests/unit/worker_permissions_test.ts
deleted file mode 100644
index 28bf9f92a..000000000
--- a/cli/tests/unit/worker_permissions_test.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import { assertEquals } from "./test_util.ts";
-
-Deno.test(
- { permissions: { env: true, read: true } },
- async function workerEnvArrayPermissions() {
- const { promise, resolve } = Promise.withResolvers<boolean[]>();
-
- const worker = new Worker(
- import.meta.resolve(
- "../testdata/workers/env_read_check_worker.js",
- ),
- { type: "module", deno: { permissions: { env: ["test", "OTHER"] } } },
- );
-
- worker.onmessage = ({ data }) => {
- resolve(data.permissions);
- };
-
- worker.postMessage({
- names: ["test", "TEST", "asdf", "OTHER"],
- });
-
- const permissions = await promise;
- worker.terminate();
-
- if (Deno.build.os === "windows") {
- // windows ignores case
- assertEquals(permissions, [true, true, false, true]);
- } else {
- assertEquals(permissions, [true, false, false, true]);
- }
- },
-);
diff --git a/cli/tests/unit/worker_test.ts b/cli/tests/unit/worker_test.ts
deleted file mode 100644
index eea0e8106..000000000
--- a/cli/tests/unit/worker_test.ts
+++ /dev/null
@@ -1,843 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-// Requires to be run with `--allow-net` flag
-
-import {
- assert,
- assertEquals,
- assertMatch,
- assertThrows,
-} from "@test_util/std/assert/mod.ts";
-
-function resolveWorker(worker: string): string {
- return import.meta.resolve(`../testdata/workers/${worker}`);
-}
-
-Deno.test(
- { permissions: { read: true } },
- function utimeSyncFileSuccess() {
- const w = new Worker(
- resolveWorker("worker_types.ts"),
- { type: "module" },
- );
- assert(w);
- w.terminate();
- },
-);
-
-Deno.test({
- name: "worker terminate",
- fn: async function () {
- const jsWorker = new Worker(
- resolveWorker("test_worker.js"),
- { type: "module" },
- );
- const tsWorker = new Worker(
- resolveWorker("test_worker.ts"),
- { type: "module", name: "tsWorker" },
- );
-
- const deferred1 = Promise.withResolvers<string>();
- jsWorker.onmessage = (e) => {
- deferred1.resolve(e.data);
- };
-
- const deferred2 = Promise.withResolvers<string>();
- tsWorker.onmessage = (e) => {
- deferred2.resolve(e.data);
- };
-
- jsWorker.postMessage("Hello World");
- assertEquals(await deferred1.promise, "Hello World");
- tsWorker.postMessage("Hello World");
- assertEquals(await deferred2.promise, "Hello World");
- tsWorker.terminate();
- jsWorker.terminate();
- },
-});
-
-Deno.test({
- name: "worker from data url",
- async fn() {
- const tsWorker = new Worker(
- "data:application/typescript;base64,aWYgKHNlbGYubmFtZSAhPT0gInRzV29ya2VyIikgewogIHRocm93IEVycm9yKGBJbnZhbGlkIHdvcmtlciBuYW1lOiAke3NlbGYubmFtZX0sIGV4cGVjdGVkIHRzV29ya2VyYCk7Cn0KCm9ubWVzc2FnZSA9IGZ1bmN0aW9uIChlKTogdm9pZCB7CiAgcG9zdE1lc3NhZ2UoZS5kYXRhKTsKICBjbG9zZSgpOwp9Owo=",
- { type: "module", name: "tsWorker" },
- );
-
- const { promise, resolve } = Promise.withResolvers<string>();
- tsWorker.onmessage = (e) => {
- resolve(e.data);
- };
-
- tsWorker.postMessage("Hello World");
- assertEquals(await promise, "Hello World");
- tsWorker.terminate();
- },
-});
-
-Deno.test({
- name: "worker nested",
- fn: async function () {
- const nestedWorker = new Worker(
- resolveWorker("nested_worker.js"),
- { type: "module", name: "nested" },
- );
-
- // deno-lint-ignore no-explicit-any
- const { promise, resolve } = Promise.withResolvers<any>();
- nestedWorker.onmessage = (e) => {
- resolve(e.data);
- };
-
- nestedWorker.postMessage("Hello World");
- assertEquals(await promise, { type: "msg", text: "Hello World" });
- nestedWorker.terminate();
- },
-});
-
-Deno.test({
- name: "worker throws when executing",
- fn: async function () {
- const throwingWorker = new Worker(
- resolveWorker("throwing_worker.js"),
- { type: "module" },
- );
-
- const { promise, resolve } = Promise.withResolvers<string>();
- // deno-lint-ignore no-explicit-any
- throwingWorker.onerror = (e: any) => {
- e.preventDefault();
- resolve(e.message);
- };
-
- assertMatch(
- await promise as string,
- /Uncaught \(in promise\) Error: Thrown error/,
- );
- throwingWorker.terminate();
- },
-});
-
-Deno.test({
- name: "worker globals",
- fn: async function () {
- const workerOptions: WorkerOptions = { type: "module" };
- const w = new Worker(
- resolveWorker("worker_globals.ts"),
- workerOptions,
- );
-
- const { promise, resolve } = Promise.withResolvers<string>();
- w.onmessage = (e) => {
- resolve(e.data);
- };
-
- w.postMessage("Hello, world!");
- assertEquals(await promise, "true, true, true, true");
- w.terminate();
- },
-});
-
-Deno.test({
- name: "worker navigator",
- fn: async function () {
- const workerOptions: WorkerOptions = { type: "module" };
- const w = new Worker(
- resolveWorker("worker_navigator.ts"),
- workerOptions,
- );
-
- const { promise, resolve } = Promise.withResolvers<string>();
- w.onmessage = (e) => {
- resolve(e.data);
- };
-
- w.postMessage("Hello, world!");
- assertEquals(await promise, "string, object, string, number");
- w.terminate();
- },
-});
-
-Deno.test({
- name: "worker fetch API",
- fn: async function () {
- const fetchingWorker = new Worker(
- resolveWorker("fetching_worker.js"),
- { type: "module" },
- );
-
- const { promise, resolve, reject } = Promise.withResolvers<string>();
- // deno-lint-ignore no-explicit-any
- fetchingWorker.onerror = (e: any) => {
- e.preventDefault();
- reject(e.message);
- };
- // Defer promise.resolve() to allow worker to shut down
- fetchingWorker.onmessage = (e) => {
- resolve(e.data);
- };
-
- assertEquals(await promise, "Done!");
- fetchingWorker.terminate();
- },
-});
-
-Deno.test({
- name: "worker terminate busy loop",
- fn: async function () {
- const { promise, resolve } = Promise.withResolvers<number>();
-
- const busyWorker = new Worker(
- resolveWorker("busy_worker.js"),
- { type: "module" },
- );
-
- let testResult = 0;
-
- busyWorker.onmessage = (e) => {
- testResult = e.data;
- if (testResult >= 10000) {
- busyWorker.terminate();
- busyWorker.onmessage = (_e) => {
- throw new Error("unreachable");
- };
- setTimeout(() => {
- resolve(testResult);
- }, 100);
- }
- };
-
- busyWorker.postMessage("ping");
- assertEquals(await promise, 10000);
- },
-});
-
-Deno.test({
- name: "worker race condition",
- fn: async function () {
- // See issue for details
- // https://github.com/denoland/deno/issues/4080
- const { promise, resolve } = Promise.withResolvers<void>();
-
- const racyWorker = new Worker(
- resolveWorker("racy_worker.js"),
- { type: "module" },
- );
-
- racyWorker.onmessage = (_e) => {
- setTimeout(() => {
- resolve();
- }, 100);
- };
-
- racyWorker.postMessage("START");
- await promise;
- },
-});
-
-Deno.test({
- name: "worker is event listener",
- fn: async function () {
- let messageHandlersCalled = 0;
- let errorHandlersCalled = 0;
-
- const deferred1 = Promise.withResolvers<void>();
- const deferred2 = Promise.withResolvers<void>();
-
- const worker = new Worker(
- resolveWorker("event_worker.js"),
- { type: "module" },
- );
-
- worker.onmessage = (_e: Event) => {
- messageHandlersCalled++;
- };
- worker.addEventListener("message", (_e: Event) => {
- messageHandlersCalled++;
- });
- worker.addEventListener("message", (_e: Event) => {
- messageHandlersCalled++;
- deferred1.resolve();
- });
-
- worker.onerror = (e) => {
- errorHandlersCalled++;
- e.preventDefault();
- };
- worker.addEventListener("error", (_e: Event) => {
- errorHandlersCalled++;
- });
- worker.addEventListener("error", (_e: Event) => {
- errorHandlersCalled++;
- deferred2.resolve();
- });
-
- worker.postMessage("ping");
- await deferred1.promise;
- assertEquals(messageHandlersCalled, 3);
-
- worker.postMessage("boom");
- await deferred2.promise;
- assertEquals(errorHandlersCalled, 3);
- worker.terminate();
- },
-});
-
-Deno.test({
- name: "worker scope is event listener",
- fn: async function () {
- const worker = new Worker(
- resolveWorker("event_worker_scope.js"),
- { type: "module" },
- );
-
- // deno-lint-ignore no-explicit-any
- const { promise, resolve } = Promise.withResolvers<any>();
- worker.onmessage = (e: MessageEvent) => {
- resolve(e.data);
- };
- worker.onerror = (_e) => {
- throw new Error("unreachable");
- };
-
- worker.postMessage("boom");
- worker.postMessage("ping");
- assertEquals(await promise, {
- messageHandlersCalled: 4,
- errorHandlersCalled: 4,
- });
- worker.terminate();
- },
-});
-
-Deno.test({
- name: "worker with Deno namespace",
- fn: async function () {
- const denoWorker = new Worker(
- resolveWorker("deno_worker.ts"),
- { type: "module", deno: { permissions: "inherit" } },
- );
-
- const { promise, resolve } = Promise.withResolvers<string>();
- denoWorker.onmessage = (e) => {
- denoWorker.terminate();
- resolve(e.data);
- };
-
- denoWorker.postMessage("Hello World");
- assertEquals(await promise, "Hello World");
- },
-});
-
-Deno.test({
- name: "worker with crypto in scope",
- fn: async function () {
- const w = new Worker(
- resolveWorker("worker_crypto.js"),
- { type: "module" },
- );
-
- const { promise, resolve } = Promise.withResolvers<boolean>();
- w.onmessage = (e) => {
- resolve(e.data);
- };
-
- w.postMessage(null);
- assertEquals(await promise, true);
- w.terminate();
- },
-});
-
-Deno.test({
- name: "Worker event handler order",
- fn: async function () {
- const { promise, resolve } = Promise.withResolvers<void>();
- const w = new Worker(
- resolveWorker("test_worker.ts"),
- { type: "module", name: "tsWorker" },
- );
- const arr: number[] = [];
- w.addEventListener("message", () => arr.push(1));
- w.onmessage = (_e) => {
- arr.push(2);
- };
- w.addEventListener("message", () => arr.push(3));
- w.addEventListener("message", () => {
- resolve();
- });
- w.postMessage("Hello World");
- await promise;
- assertEquals(arr, [1, 2, 3]);
- w.terminate();
- },
-});
-
-Deno.test({
- name: "Worker immediate close",
- fn: async function () {
- const { promise, resolve } = Promise.withResolvers<void>();
- const w = new Worker(
- resolveWorker("immediately_close_worker.js"),
- { type: "module" },
- );
- setTimeout(() => {
- resolve();
- }, 1000);
- await promise;
- w.terminate();
- },
-});
-
-Deno.test({
- name: "Worker post undefined",
- fn: async function () {
- const { promise, resolve } = Promise.withResolvers<void>();
- const worker = new Worker(
- resolveWorker("post_undefined.ts"),
- { type: "module" },
- );
-
- const handleWorkerMessage = (e: MessageEvent) => {
- console.log("main <- worker:", e.data);
- worker.terminate();
- resolve();
- };
-
- worker.addEventListener("messageerror", () => console.log("message error"));
- worker.addEventListener("error", () => console.log("error"));
- worker.addEventListener("message", handleWorkerMessage);
-
- console.log("\npost from parent");
- worker.postMessage(undefined);
- await promise;
- },
-});
-
-Deno.test("Worker inherits permissions", async function () {
- const worker = new Worker(
- resolveWorker("read_check_worker.js"),
- { type: "module", deno: { permissions: "inherit" } },
- );
-
- const { promise, resolve } = Promise.withResolvers<boolean>();
- worker.onmessage = (e) => {
- resolve(e.data);
- };
-
- worker.postMessage(null);
- assertEquals(await promise, true);
- worker.terminate();
-});
-
-Deno.test("Worker limit children permissions", async function () {
- const worker = new Worker(
- resolveWorker("read_check_worker.js"),
- { type: "module", deno: { permissions: { read: false } } },
- );
-
- const { promise, resolve } = Promise.withResolvers<boolean>();
- worker.onmessage = (e) => {
- resolve(e.data);
- };
-
- worker.postMessage(null);
- assertEquals(await promise, false);
- worker.terminate();
-});
-
-Deno.test("Worker limit children permissions granularly", async function () {
- const workerUrl = resolveWorker("read_check_granular_worker.js");
- const worker = new Worker(
- workerUrl,
- {
- type: "module",
- deno: {
- permissions: {
- env: ["foo"],
- hrtime: true,
- net: ["foo", "bar:8000"],
- ffi: [new URL("foo", workerUrl), "bar"],
- read: [new URL("foo", workerUrl), "bar"],
- run: [new URL("foo", workerUrl), "bar", "./baz"],
- write: [new URL("foo", workerUrl), "bar"],
- },
- },
- },
- );
- // deno-lint-ignore no-explicit-any
- const { promise, resolve } = Promise.withResolvers<any>();
- worker.onmessage = ({ data }) => resolve(data);
- assertEquals(await promise, {
- envGlobal: "prompt",
- envFoo: "granted",
- envAbsent: "prompt",
- hrtime: "granted",
- netGlobal: "prompt",
- netFoo: "granted",
- netFoo8000: "granted",
- netBar: "prompt",
- netBar8000: "granted",
- ffiGlobal: "prompt",
- ffiFoo: "granted",
- ffiBar: "granted",
- ffiAbsent: "prompt",
- readGlobal: "prompt",
- readFoo: "granted",
- readBar: "granted",
- readAbsent: "prompt",
- runGlobal: "prompt",
- runFoo: "granted",
- runBar: "granted",
- runBaz: "granted",
- runAbsent: "prompt",
- writeGlobal: "prompt",
- writeFoo: "granted",
- writeBar: "granted",
- writeAbsent: "prompt",
- });
- worker.terminate();
-});
-
-Deno.test("Nested worker limit children permissions", async function () {
- /** This worker has permissions but doesn't grant them to its children */
- const worker = new Worker(
- resolveWorker("parent_read_check_worker.js"),
- { type: "module", deno: { permissions: "inherit" } },
- );
- // deno-lint-ignore no-explicit-any
- const { promise, resolve } = Promise.withResolvers<any>();
- worker.onmessage = ({ data }) => resolve(data);
- assertEquals(await promise, {
- envGlobal: "prompt",
- envFoo: "prompt",
- envAbsent: "prompt",
- hrtime: "prompt",
- netGlobal: "prompt",
- netFoo: "prompt",
- netFoo8000: "prompt",
- netBar: "prompt",
- netBar8000: "prompt",
- ffiGlobal: "prompt",
- ffiFoo: "prompt",
- ffiBar: "prompt",
- ffiAbsent: "prompt",
- readGlobal: "prompt",
- readFoo: "prompt",
- readBar: "prompt",
- readAbsent: "prompt",
- runGlobal: "prompt",
- runFoo: "prompt",
- runBar: "prompt",
- runBaz: "prompt",
- runAbsent: "prompt",
- writeGlobal: "prompt",
- writeFoo: "prompt",
- writeBar: "prompt",
- writeAbsent: "prompt",
- });
- worker.terminate();
-});
-
-// This test relies on env permissions not being granted on main thread
-Deno.test({
- name:
- "Worker initialization throws on worker permissions greater than parent thread permissions",
- permissions: { env: false },
- fn: function () {
- assertThrows(
- () => {
- const worker = new Worker(
- resolveWorker("deno_worker.ts"),
- { type: "module", deno: { permissions: { env: true } } },
- );
- worker.terminate();
- },
- Deno.errors.PermissionDenied,
- "Can't escalate parent thread permissions",
- );
- },
-});
-
-Deno.test("Worker with disabled permissions", async function () {
- const worker = new Worker(
- resolveWorker("no_permissions_worker.js"),
- { type: "module", deno: { permissions: "none" } },
- );
-
- const { promise, resolve } = Promise.withResolvers<boolean>();
- worker.onmessage = (e) => {
- resolve(e.data);
- };
-
- worker.postMessage(null);
- assertEquals(await promise, true);
- worker.terminate();
-});
-
-Deno.test("Worker permissions are not inherited with empty permission object", async function () {
- const worker = new Worker(
- resolveWorker("permission_echo.js"),
- { type: "module", deno: { permissions: {} } },
- );
-
- // deno-lint-ignore no-explicit-any
- const { promise, resolve } = Promise.withResolvers<any>();
- worker.onmessage = (e) => {
- resolve(e.data);
- };
-
- worker.postMessage(null);
- assertEquals(await promise, {
- env: "prompt",
- hrtime: "prompt",
- net: "prompt",
- ffi: "prompt",
- read: "prompt",
- run: "prompt",
- write: "prompt",
- });
- worker.terminate();
-});
-
-Deno.test("Worker permissions are not inherited with single specified permission", async function () {
- const worker = new Worker(
- resolveWorker("permission_echo.js"),
- { type: "module", deno: { permissions: { net: true } } },
- );
-
- // deno-lint-ignore no-explicit-any
- const { promise, resolve } = Promise.withResolvers<any>();
- worker.onmessage = (e) => {
- resolve(e.data);
- };
-
- worker.postMessage(null);
- assertEquals(await promise, {
- env: "prompt",
- hrtime: "prompt",
- net: "granted",
- ffi: "prompt",
- read: "prompt",
- run: "prompt",
- write: "prompt",
- });
- worker.terminate();
-});
-
-Deno.test("Worker with invalid permission arg", function () {
- assertThrows(
- () =>
- new Worker(`data:,close();`, {
- type: "module",
- // @ts-expect-error invalid env value
- deno: { permissions: { env: "foo" } },
- }),
- TypeError,
- '(deno.permissions.env) invalid value: string "foo", expected "inherit" or boolean or string[]',
- );
-});
-
-Deno.test({
- name: "worker location",
- fn: async function () {
- const { promise, resolve } = Promise.withResolvers<string>();
- const workerModuleHref = resolveWorker("worker_location.ts");
- const w = new Worker(workerModuleHref, { type: "module" });
- w.onmessage = (e) => {
- resolve(e.data);
- };
- w.postMessage("Hello, world!");
- assertEquals(await promise, `${workerModuleHref}, true`);
- w.terminate();
- },
-});
-
-Deno.test({
- name: "Worker with top-level-await",
- fn: async function () {
- const { promise, resolve, reject } = Promise.withResolvers<void>();
- const worker = new Worker(
- resolveWorker("worker_with_top_level_await.ts"),
- { type: "module" },
- );
- worker.onmessage = (e) => {
- if (e.data == "ready") {
- worker.postMessage("trigger worker handler");
- } else if (e.data == "triggered worker handler") {
- resolve();
- } else {
- reject(new Error("Handler didn't run during top-level delay."));
- }
- };
- await promise;
- worker.terminate();
- },
-});
-
-Deno.test({
- name: "Worker with native HTTP",
- fn: async function () {
- const { promise, resolve } = Promise.withResolvers<void>();
- const worker = new Worker(
- resolveWorker("http_worker.js"),
- { type: "module", deno: { permissions: "inherit" } },
- );
- worker.onmessage = () => {
- resolve();
- };
- await promise;
-
- assert(worker);
- const response = await fetch("http://localhost:4506");
- assert(await response.arrayBuffer());
- worker.terminate();
- },
-});
-
-Deno.test({
- name: "structured cloning postMessage",
- fn: async function () {
- const worker = new Worker(
- resolveWorker("worker_structured_cloning.ts"),
- { type: "module" },
- );
-
- // deno-lint-ignore no-explicit-any
- const { promise, resolve } = Promise.withResolvers<any>();
- worker.onmessage = (e) => {
- resolve(e.data);
- };
-
- worker.postMessage("START");
- const data = await promise;
- // self field should reference itself (circular ref)
- assert(data === data.self);
- // fields a and b refer to the same array
- assertEquals(data.a, ["a", true, 432]);
- assertEquals(data.b, ["a", true, 432]);
- data.b[0] = "b";
- data.a[2] += 5;
- assertEquals(data.a, ["b", true, 437]);
- assertEquals(data.b, ["b", true, 437]);
- // c is a set
- const len = data.c.size;
- data.c.add(1); // This value is already in the set.
- data.c.add(2);
- assertEquals(len + 1, data.c.size);
- worker.terminate();
- },
-});
-
-Deno.test({
- name: "worker with relative specifier",
- fn: async function () {
- assertEquals(location.href, "http://127.0.0.1:4545/");
- const w = new Worker(
- "./workers/test_worker.ts",
- { type: "module", name: "tsWorker" },
- );
- const { promise, resolve } = Promise.withResolvers<string>();
- w.onmessage = (e) => {
- resolve(e.data);
- };
- w.postMessage("Hello, world!");
- assertEquals(await promise, "Hello, world!");
- w.terminate();
- },
-});
-
-Deno.test({
- name: "worker SharedArrayBuffer",
- fn: async function () {
- const { promise, resolve } = Promise.withResolvers<void>();
- const workerOptions: WorkerOptions = { type: "module" };
- const w = new Worker(
- resolveWorker("shared_array_buffer.ts"),
- workerOptions,
- );
- const sab1 = new SharedArrayBuffer(1);
- const sab2 = new SharedArrayBuffer(1);
- const bytes1 = new Uint8Array(sab1);
- const bytes2 = new Uint8Array(sab2);
- assertEquals(bytes1[0], 0);
- assertEquals(bytes2[0], 0);
- w.onmessage = () => {
- w.postMessage([sab1, sab2]);
- w.onmessage = () => {
- resolve();
- };
- };
- await promise;
- assertEquals(bytes1[0], 1);
- assertEquals(bytes2[0], 2);
- w.terminate();
- },
-});
-
-Deno.test({
- name: "Send MessagePorts from / to workers",
- fn: async function () {
- const worker = new Worker(
- resolveWorker("message_port.ts"),
- { type: "module" },
- );
- const channel = new MessageChannel();
-
- // deno-lint-ignore no-explicit-any
- const deferred1 = Promise.withResolvers<any>();
- const deferred2 = Promise.withResolvers<boolean>();
- const deferred3 = Promise.withResolvers<boolean>();
- const result = Promise.withResolvers<void>();
- worker.onmessage = (e) => {
- deferred1.resolve([e.data, e.ports.length]);
- const port1 = e.ports[0];
- port1.onmessage = (e) => {
- deferred2.resolve(e.data);
- port1.close();
- worker.postMessage("3", [channel.port1]);
- };
- port1.postMessage("2");
- };
- channel.port2.onmessage = (e) => {
- deferred3.resolve(e.data);
- channel.port2.close();
- result.resolve();
- };
-
- assertEquals(await deferred1.promise, ["1", 1]);
- assertEquals(await deferred2.promise, true);
- assertEquals(await deferred3.promise, true);
- await result.promise;
- worker.terminate();
- },
-});
-
-Deno.test({
- name: "worker Deno.memoryUsage",
- fn: async function () {
- const w = new Worker(
- /**
- * Source code
- * self.onmessage = function() {self.postMessage(Deno.memoryUsage())}
- */
- "data:application/typescript;base64,c2VsZi5vbm1lc3NhZ2UgPSBmdW5jdGlvbigpIHtzZWxmLnBvc3RNZXNzYWdlKERlbm8ubWVtb3J5VXNhZ2UoKSl9",
- { type: "module", name: "tsWorker" },
- );
-
- w.postMessage(null);
-
- // deno-lint-ignore no-explicit-any
- const { promise, resolve } = Promise.withResolvers<any>();
- w.onmessage = function (evt) {
- resolve(evt.data);
- };
-
- assertEquals(
- Object.keys(
- await promise as unknown as Record<string, number>,
- ),
- ["rss", "heapTotal", "heapUsed", "external"],
- );
- w.terminate();
- },
-});
diff --git a/cli/tests/unit/write_file_test.ts b/cli/tests/unit/write_file_test.ts
deleted file mode 100644
index 6cd08e2d1..000000000
--- a/cli/tests/unit/write_file_test.ts
+++ /dev/null
@@ -1,427 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
- unreachable,
-} from "./test_util.ts";
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeFileSyncSuccess() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- Deno.writeFileSync(filename, data);
- const dataRead = Deno.readFileSync(filename);
- const dec = new TextDecoder("utf-8");
- const actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeFileSyncUrl() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = Deno.makeTempDirSync();
- const fileUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/test.txt`,
- );
- Deno.writeFileSync(fileUrl, data);
- const dataRead = Deno.readFileSync(fileUrl);
- const dec = new TextDecoder("utf-8");
- const actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test({ permissions: { write: true } }, function writeFileSyncFail() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = "/baddir/test.txt";
- // The following should fail because /baddir doesn't exist (hopefully).
- assertThrows(() => {
- Deno.writeFileSync(filename, data);
- }, Deno.errors.NotFound);
-});
-
-Deno.test({ permissions: { write: false } }, function writeFileSyncPerm() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = "/baddir/test.txt";
- // The following should fail due to no write permission
- assertThrows(() => {
- Deno.writeFileSync(filename, data);
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeFileSyncUpdateMode() {
- if (Deno.build.os !== "windows") {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- Deno.writeFileSync(filename, data, { mode: 0o755 });
- assertEquals(Deno.statSync(filename).mode! & 0o777, 0o755);
- Deno.writeFileSync(filename, data, { mode: 0o666 });
- assertEquals(Deno.statSync(filename).mode! & 0o777, 0o666);
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeFileSyncCreate() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- // if create turned off, the file won't be created
- assertThrows(() => {
- Deno.writeFileSync(filename, data, { create: false });
- }, Deno.errors.NotFound);
-
- // Turn on create, should have no error
- Deno.writeFileSync(filename, data, { create: true });
- Deno.writeFileSync(filename, data, { create: false });
- const dataRead = Deno.readFileSync(filename);
- const dec = new TextDecoder("utf-8");
- const actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeFileSyncCreateNew() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- Deno.writeFileSync(filename, data, { createNew: true });
-
- assertThrows(() => {
- Deno.writeFileSync(filename, data, { createNew: true });
- }, Deno.errors.AlreadyExists);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeFileSyncAppend() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- Deno.writeFileSync(filename, data);
- Deno.writeFileSync(filename, data, { append: true });
- let dataRead = Deno.readFileSync(filename);
- const dec = new TextDecoder("utf-8");
- let actual = dec.decode(dataRead);
- assertEquals(actual, "HelloHello");
- // Now attempt overwrite
- Deno.writeFileSync(filename, data, { append: false });
- dataRead = Deno.readFileSync(filename);
- actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
- // append not set should also overwrite
- Deno.writeFileSync(filename, data);
- dataRead = Deno.readFileSync(filename);
- actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileSuccess() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeFile(filename, data);
- const dataRead = Deno.readFileSync(filename);
- const dec = new TextDecoder("utf-8");
- const actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileUrl() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const tempDir = await Deno.makeTempDir();
- const fileUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/test.txt`,
- );
- await Deno.writeFile(fileUrl, data);
- const dataRead = Deno.readFileSync(fileUrl);
- const dec = new TextDecoder("utf-8");
- const actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
-
- Deno.removeSync(tempDir, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileNotFound() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = "/baddir/test.txt";
- // The following should fail because /baddir doesn't exist (hopefully).
- await assertRejects(async () => {
- await Deno.writeFile(filename, data);
- }, Deno.errors.NotFound);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: false } },
- async function writeFilePerm() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = "/baddir/test.txt";
- // The following should fail due to no write permission
- await assertRejects(async () => {
- await Deno.writeFile(filename, data);
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileUpdateMode() {
- if (Deno.build.os !== "windows") {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeFile(filename, data, { mode: 0o755 });
- assertEquals(Deno.statSync(filename).mode! & 0o777, 0o755);
- await Deno.writeFile(filename, data, { mode: 0o666 });
- assertEquals(Deno.statSync(filename).mode! & 0o777, 0o666);
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileCreate() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- // if create turned off, the file won't be created
- await assertRejects(async () => {
- await Deno.writeFile(filename, data, { create: false });
- }, Deno.errors.NotFound);
-
- // Turn on create, should have no error
- await Deno.writeFile(filename, data, { create: true });
- await Deno.writeFile(filename, data, { create: false });
- const dataRead = Deno.readFileSync(filename);
- const dec = new TextDecoder("utf-8");
- const actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileCreateNew() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeFile(filename, data, { createNew: true });
- await assertRejects(async () => {
- await Deno.writeFile(filename, data, { createNew: true });
- }, Deno.errors.AlreadyExists);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileAppend() {
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeFile(filename, data);
- await Deno.writeFile(filename, data, { append: true });
- let dataRead = Deno.readFileSync(filename);
- const dec = new TextDecoder("utf-8");
- let actual = dec.decode(dataRead);
- assertEquals(actual, "HelloHello");
- // Now attempt overwrite
- await Deno.writeFile(filename, data, { append: false });
- dataRead = Deno.readFileSync(filename);
- actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
- // append not set should also overwrite
- await Deno.writeFile(filename, data);
- dataRead = Deno.readFileSync(filename);
- actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileAbortSignal(): Promise<void> {
- const ac = new AbortController();
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- queueMicrotask(() => ac.abort());
- try {
- await Deno.writeFile(filename, data, { signal: ac.signal });
- unreachable();
- } catch (e) {
- assert(e instanceof Error);
- assertEquals(e.name, "AbortError");
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileAbortSignalReason(): Promise<void> {
- const ac = new AbortController();
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- const abortReason = new Error();
- queueMicrotask(() => ac.abort(abortReason));
- try {
- await Deno.writeFile(filename, data, { signal: ac.signal });
- unreachable();
- } catch (e) {
- assertEquals(e, abortReason);
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileAbortSignalPrimitiveReason(): Promise<void> {
- const ac = new AbortController();
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- queueMicrotask(() => ac.abort("Some string"));
- try {
- await Deno.writeFile(filename, data, { signal: ac.signal });
- unreachable();
- } catch (e) {
- assertEquals(e, "Some string");
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileAbortSignalPreAborted(): Promise<void> {
- const ac = new AbortController();
- ac.abort();
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- try {
- await Deno.writeFile(filename, data, { signal: ac.signal });
- unreachable();
- } catch (e) {
- assert(e instanceof Error);
- assertEquals(e.name, "AbortError");
- }
- assertNotExists(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileAbortSignalReasonPreAborted(): Promise<void> {
- const ac = new AbortController();
- const abortReason = new Error();
- ac.abort(abortReason);
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- try {
- await Deno.writeFile(filename, data, { signal: ac.signal });
- unreachable();
- } catch (e) {
- assertEquals(e, abortReason);
- }
- assertNotExists(filename);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileAbortSignalPrimitiveReasonPreAborted(): Promise<
- void
- > {
- const ac = new AbortController();
- ac.abort("Some string");
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- try {
- await Deno.writeFile(filename, data, { signal: ac.signal });
- unreachable();
- } catch (e) {
- assertEquals(e, "Some string");
- }
- assertNotExists(filename);
- },
-);
-
-// Test that AbortController's cancel handle is cleaned-up correctly, and do not leak resources.
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileWithAbortSignalNotCalled() {
- const ac = new AbortController();
- const enc = new TextEncoder();
- const data = enc.encode("Hello");
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeFile(filename, data, { signal: ac.signal });
- const dataRead = Deno.readFileSync(filename);
- const dec = new TextDecoder("utf-8");
- const actual = dec.decode(dataRead);
- assertEquals(actual, "Hello");
- },
-);
-
-function assertNotExists(filename: string | URL) {
- if (pathExists(filename)) {
- throw new Error(`The file ${filename} exists.`);
- }
-}
-
-function pathExists(path: string | URL) {
- try {
- Deno.statSync(path);
- return true;
- } catch {
- return false;
- }
-}
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeFileStream() {
- const stream = new ReadableStream({
- pull(controller) {
- controller.enqueue(new Uint8Array([1]));
- controller.enqueue(new Uint8Array([2]));
- controller.close();
- },
- });
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeFile(filename, stream);
- assertEquals(Deno.readFileSync(filename), new Uint8Array([1, 2]));
- },
-);
diff --git a/cli/tests/unit/write_text_file_test.ts b/cli/tests/unit/write_text_file_test.ts
deleted file mode 100644
index a58d91997..000000000
--- a/cli/tests/unit/write_text_file_test.ts
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-
-import {
- assert,
- assertEquals,
- assertRejects,
- assertThrows,
-} from "./test_util.ts";
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeTextFileSyncSuccess() {
- const filename = Deno.makeTempDirSync() + "/test.txt";
- Deno.writeTextFileSync(filename, "Hello");
- const dataRead = Deno.readTextFileSync(filename);
- assertEquals(dataRead, "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeTextFileSyncByUrl() {
- const tempDir = Deno.makeTempDirSync();
- const fileUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/test.txt`,
- );
- Deno.writeTextFileSync(fileUrl, "Hello");
- const dataRead = Deno.readTextFileSync(fileUrl);
- assertEquals(dataRead, "Hello");
-
- Deno.removeSync(fileUrl, { recursive: true });
- },
-);
-
-Deno.test({ permissions: { write: true } }, function writeTextFileSyncFail() {
- const filename = "/baddir/test.txt";
- // The following should fail because /baddir doesn't exist (hopefully).
- assertThrows(() => {
- Deno.writeTextFileSync(filename, "hello");
- }, Deno.errors.NotFound);
-});
-
-Deno.test({ permissions: { write: false } }, function writeTextFileSyncPerm() {
- const filename = "/baddir/test.txt";
- // The following should fail due to no write permission
- assertThrows(() => {
- Deno.writeTextFileSync(filename, "Hello");
- }, Deno.errors.PermissionDenied);
-});
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeTextFileSyncUpdateMode() {
- if (Deno.build.os !== "windows") {
- const data = "Hello";
- const filename = Deno.makeTempDirSync() + "/test.txt";
- Deno.writeTextFileSync(filename, data, { mode: 0o755 });
- assertEquals(Deno.statSync(filename).mode! & 0o777, 0o755);
- Deno.writeTextFileSync(filename, data, { mode: 0o666 });
- assertEquals(Deno.statSync(filename).mode! & 0o777, 0o666);
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeTextFileSyncCreate() {
- const data = "Hello";
- const filename = Deno.makeTempDirSync() + "/test.txt";
- let caughtError = false;
- // if create turned off, the file won't be created
- try {
- Deno.writeTextFileSync(filename, data, { create: false });
- } catch (e) {
- caughtError = true;
- assert(e instanceof Deno.errors.NotFound);
- }
- assert(caughtError);
-
- // Turn on create, should have no error
- Deno.writeTextFileSync(filename, data, { create: true });
- Deno.writeTextFileSync(filename, data, { create: false });
- assertEquals(Deno.readTextFileSync(filename), "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- function writeTextFileSyncAppend() {
- const data = "Hello";
- const filename = Deno.makeTempDirSync() + "/test.txt";
- Deno.writeTextFileSync(filename, data);
- Deno.writeTextFileSync(filename, data, { append: true });
- assertEquals(Deno.readTextFileSync(filename), "HelloHello");
- // Now attempt overwrite
- Deno.writeTextFileSync(filename, data, { append: false });
- assertEquals(Deno.readTextFileSync(filename), "Hello");
- // append not set should also overwrite
- Deno.writeTextFileSync(filename, data);
- assertEquals(Deno.readTextFileSync(filename), "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeTextFileSuccess() {
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeTextFile(filename, "Hello");
- const dataRead = Deno.readTextFileSync(filename);
- assertEquals(dataRead, "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeTextFileByUrl() {
- const tempDir = Deno.makeTempDirSync();
- const fileUrl = new URL(
- `file://${Deno.build.os === "windows" ? "/" : ""}${tempDir}/test.txt`,
- );
- await Deno.writeTextFile(fileUrl, "Hello");
- const dataRead = Deno.readTextFileSync(fileUrl);
- assertEquals(dataRead, "Hello");
-
- Deno.removeSync(fileUrl, { recursive: true });
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeTextFileNotFound() {
- const filename = "/baddir/test.txt";
- // The following should fail because /baddir doesn't exist (hopefully).
- await assertRejects(async () => {
- await Deno.writeTextFile(filename, "Hello");
- }, Deno.errors.NotFound);
- },
-);
-
-Deno.test(
- { permissions: { write: false } },
- async function writeTextFilePerm() {
- const filename = "/baddir/test.txt";
- // The following should fail due to no write permission
- await assertRejects(async () => {
- await Deno.writeTextFile(filename, "Hello");
- }, Deno.errors.PermissionDenied);
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeTextFileUpdateMode() {
- if (Deno.build.os !== "windows") {
- const data = "Hello";
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeTextFile(filename, data, { mode: 0o755 });
- assertEquals(Deno.statSync(filename).mode! & 0o777, 0o755);
- await Deno.writeTextFile(filename, data, { mode: 0o666 });
- assertEquals(Deno.statSync(filename).mode! & 0o777, 0o666);
- }
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeTextFileCreate() {
- const data = "Hello";
- const filename = Deno.makeTempDirSync() + "/test.txt";
- let caughtError = false;
- // if create turned off, the file won't be created
- try {
- await Deno.writeTextFile(filename, data, { create: false });
- } catch (e) {
- caughtError = true;
- assert(e instanceof Deno.errors.NotFound);
- }
- assert(caughtError);
-
- // Turn on create, should have no error
- await Deno.writeTextFile(filename, data, { create: true });
- await Deno.writeTextFile(filename, data, { create: false });
- assertEquals(Deno.readTextFileSync(filename), "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeTextFileAppend() {
- const data = "Hello";
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeTextFile(filename, data);
- await Deno.writeTextFile(filename, data, { append: true });
- assertEquals(Deno.readTextFileSync(filename), "HelloHello");
- // Now attempt overwrite
- await Deno.writeTextFile(filename, data, { append: false });
- assertEquals(Deno.readTextFileSync(filename), "Hello");
- // append not set should also overwrite
- await Deno.writeTextFile(filename, data);
- assertEquals(Deno.readTextFileSync(filename), "Hello");
- },
-);
-
-Deno.test(
- { permissions: { read: true, write: true } },
- async function writeTextFileStream() {
- const stream = new ReadableStream({
- pull(controller) {
- controller.enqueue("Hello");
- controller.enqueue("World");
- controller.close();
- },
- });
- const filename = Deno.makeTempDirSync() + "/test.txt";
- await Deno.writeTextFile(filename, stream);
- assertEquals(Deno.readTextFileSync(filename), "HelloWorld");
- },
-);