From 68119e1d7ed23421ccdcba20532ebe9ae3df9f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 10 Mar 2020 01:06:47 +0100 Subject: reorg: move js runtime tests to cli/js/tests/ (#4250) All Deno runtime test files were moved to cli/js/tests/ directory. It makes a clear distinction that cli/js/tests/ contains code that is run under Deno runtime as opposed to code in cli/js/ which is used to create bundle and snapshot with "deno_typescript". --- cli/js/blob_test.ts | 62 --- cli/js/body_test.ts | 74 ---- cli/js/buffer_test.ts | 296 -------------- cli/js/build_test.ts | 10 - cli/js/chmod_test.ts | 159 -------- cli/js/chown_test.ts | 147 ------- cli/js/compiler_api_test.ts | 153 ------- cli/js/console_test.ts | 706 --------------------------------- cli/js/copy_file_test.ts | 176 -------- cli/js/custom_event_test.ts | 27 -- cli/js/dir_test.ts | 54 --- cli/js/dispatch_json_test.ts | 32 -- cli/js/dispatch_minimal_test.ts | 43 -- cli/js/error_stack_test.ts | 108 ----- cli/js/event_target_test.ts | 231 ----------- cli/js/event_test.ts | 96 ----- cli/js/fetch_test.ts | 497 ----------------------- cli/js/file_test.ts | 105 ----- cli/js/files_test.ts | 446 --------------------- cli/js/form_data_test.ts | 189 --------- cli/js/format_error_test.ts | 37 -- cli/js/fs_events_test.ts | 51 --- cli/js/get_random_values_test.ts | 51 --- cli/js/globals_test.ts | 112 ------ cli/js/headers_test.ts | 355 ----------------- cli/js/internals_test.ts | 10 - cli/js/link_test.ts | 147 ------- cli/js/location_test.ts | 7 - cli/js/make_temp_test.ts | 134 ------- cli/js/metrics_test.ts | 58 --- cli/js/mixins/dom_iterable_test.ts | 87 ---- cli/js/mkdir_test.ts | 76 ---- cli/js/net_test.ts | 307 -------------- cli/js/os_test.ts | 337 ---------------- cli/js/performance_test.ts | 15 - cli/js/permissions_test.ts | 27 -- cli/js/process_test.ts | 383 ------------------ cli/js/read_dir_test.ts | 86 ---- cli/js/read_file_test.ts | 59 --- cli/js/read_link_test.ts | 75 ---- cli/js/realpath_test.ts | 108 ----- cli/js/remove_test.ts | 481 ---------------------- cli/js/rename_test.ts | 84 ---- cli/js/request_test.ts | 49 --- cli/js/resources_test.ts | 51 --- cli/js/signal_test.ts | 201 ---------- cli/js/stat_test.ts | 229 ----------- cli/js/symbols_test.ts | 7 - cli/js/symlink_test.ts | 85 ---- cli/js/test_util.ts | 411 ------------------- cli/js/testing_test.ts | 37 -- cli/js/tests/README.md | 47 +++ cli/js/tests/blob_test.ts | 62 +++ cli/js/tests/body_test.ts | 74 ++++ cli/js/tests/buffer_test.ts | 296 ++++++++++++++ cli/js/tests/build_test.ts | 10 + cli/js/tests/chmod_test.ts | 159 ++++++++ cli/js/tests/chown_test.ts | 147 +++++++ cli/js/tests/compiler_api_test.ts | 153 +++++++ cli/js/tests/console_test.ts | 706 +++++++++++++++++++++++++++++++++ cli/js/tests/copy_file_test.ts | 176 ++++++++ cli/js/tests/custom_event_test.ts | 27 ++ cli/js/tests/dir_test.ts | 54 +++ cli/js/tests/dispatch_json_test.ts | 32 ++ cli/js/tests/dispatch_minimal_test.ts | 43 ++ cli/js/tests/dom_iterable_test.ts | 87 ++++ cli/js/tests/error_stack_test.ts | 108 +++++ cli/js/tests/event_target_test.ts | 231 +++++++++++ cli/js/tests/event_test.ts | 96 +++++ cli/js/tests/fetch_test.ts | 497 +++++++++++++++++++++++ cli/js/tests/file_test.ts | 105 +++++ cli/js/tests/files_test.ts | 446 +++++++++++++++++++++ cli/js/tests/form_data_test.ts | 189 +++++++++ cli/js/tests/format_error_test.ts | 37 ++ cli/js/tests/fs_events_test.ts | 51 +++ cli/js/tests/get_random_values_test.ts | 51 +++ cli/js/tests/globals_test.ts | 112 ++++++ cli/js/tests/headers_test.ts | 355 +++++++++++++++++ cli/js/tests/internals_test.ts | 10 + cli/js/tests/link_test.ts | 147 +++++++ cli/js/tests/location_test.ts | 7 + cli/js/tests/make_temp_test.ts | 134 +++++++ cli/js/tests/metrics_test.ts | 58 +++ cli/js/tests/mkdir_test.ts | 76 ++++ cli/js/tests/net_test.ts | 307 ++++++++++++++ cli/js/tests/os_test.ts | 337 ++++++++++++++++ cli/js/tests/performance_test.ts | 15 + cli/js/tests/permissions_test.ts | 27 ++ cli/js/tests/process_test.ts | 383 ++++++++++++++++++ cli/js/tests/read_dir_test.ts | 86 ++++ cli/js/tests/read_file_test.ts | 59 +++ cli/js/tests/read_link_test.ts | 75 ++++ cli/js/tests/realpath_test.ts | 108 +++++ cli/js/tests/remove_test.ts | 481 ++++++++++++++++++++++ cli/js/tests/rename_test.ts | 84 ++++ cli/js/tests/request_test.ts | 49 +++ cli/js/tests/resources_test.ts | 51 +++ cli/js/tests/signal_test.ts | 201 ++++++++++ cli/js/tests/stat_test.ts | 229 +++++++++++ cli/js/tests/symbols_test.ts | 7 + cli/js/tests/symlink_test.ts | 85 ++++ cli/js/tests/test_util.ts | 417 +++++++++++++++++++ cli/js/tests/testing_test.ts | 37 ++ cli/js/tests/text_encoding_test.ts | 193 +++++++++ cli/js/tests/timers_test.ts | 353 +++++++++++++++++ cli/js/tests/tls_test.ts | 214 ++++++++++ cli/js/tests/truncate_test.ts | 80 ++++ cli/js/tests/tty_test.ts | 23 ++ cli/js/tests/unit_test_runner.ts | 108 +++++ cli/js/tests/unit_tests.ts | 69 ++++ cli/js/tests/url_search_params_test.ts | 245 ++++++++++++ cli/js/tests/url_test.ts | 208 ++++++++++ cli/js/tests/utime_test.ts | 193 +++++++++ cli/js/tests/version_test.ts | 8 + cli/js/tests/write_file_test.ts | 228 +++++++++++ cli/js/text_encoding_test.ts | 193 --------- cli/js/timers_test.ts | 353 ----------------- cli/js/tls_test.ts | 214 ---------- cli/js/truncate_test.ts | 80 ---- cli/js/tty_test.ts | 23 -- cli/js/unit_test_runner.ts | 103 ----- cli/js/unit_tests.ts | 69 ---- cli/js/url_search_params_test.ts | 245 ------------ cli/js/url_test.ts | 208 ---------- cli/js/utime_test.ts | 193 --------- cli/js/version_test.ts | 8 - cli/js/write_file_test.ts | 228 ----------- 127 files changed, 9743 insertions(+), 9685 deletions(-) delete mode 100644 cli/js/blob_test.ts delete mode 100644 cli/js/body_test.ts delete mode 100644 cli/js/buffer_test.ts delete mode 100644 cli/js/build_test.ts delete mode 100644 cli/js/chmod_test.ts delete mode 100644 cli/js/chown_test.ts delete mode 100644 cli/js/compiler_api_test.ts delete mode 100644 cli/js/console_test.ts delete mode 100644 cli/js/copy_file_test.ts delete mode 100644 cli/js/custom_event_test.ts delete mode 100644 cli/js/dir_test.ts delete mode 100644 cli/js/dispatch_json_test.ts delete mode 100644 cli/js/dispatch_minimal_test.ts delete mode 100644 cli/js/error_stack_test.ts delete mode 100644 cli/js/event_target_test.ts delete mode 100644 cli/js/event_test.ts delete mode 100644 cli/js/fetch_test.ts delete mode 100644 cli/js/file_test.ts delete mode 100644 cli/js/files_test.ts delete mode 100644 cli/js/form_data_test.ts delete mode 100644 cli/js/format_error_test.ts delete mode 100644 cli/js/fs_events_test.ts delete mode 100644 cli/js/get_random_values_test.ts delete mode 100644 cli/js/globals_test.ts delete mode 100644 cli/js/headers_test.ts delete mode 100644 cli/js/internals_test.ts delete mode 100644 cli/js/link_test.ts delete mode 100644 cli/js/location_test.ts delete mode 100644 cli/js/make_temp_test.ts delete mode 100644 cli/js/metrics_test.ts delete mode 100644 cli/js/mixins/dom_iterable_test.ts delete mode 100644 cli/js/mkdir_test.ts delete mode 100644 cli/js/net_test.ts delete mode 100644 cli/js/os_test.ts delete mode 100644 cli/js/performance_test.ts delete mode 100644 cli/js/permissions_test.ts delete mode 100644 cli/js/process_test.ts delete mode 100644 cli/js/read_dir_test.ts delete mode 100644 cli/js/read_file_test.ts delete mode 100644 cli/js/read_link_test.ts delete mode 100644 cli/js/realpath_test.ts delete mode 100644 cli/js/remove_test.ts delete mode 100644 cli/js/rename_test.ts delete mode 100644 cli/js/request_test.ts delete mode 100644 cli/js/resources_test.ts delete mode 100644 cli/js/signal_test.ts delete mode 100644 cli/js/stat_test.ts delete mode 100644 cli/js/symbols_test.ts delete mode 100644 cli/js/symlink_test.ts delete mode 100644 cli/js/test_util.ts delete mode 100644 cli/js/testing_test.ts create mode 100644 cli/js/tests/README.md create mode 100644 cli/js/tests/blob_test.ts create mode 100644 cli/js/tests/body_test.ts create mode 100644 cli/js/tests/buffer_test.ts create mode 100644 cli/js/tests/build_test.ts create mode 100644 cli/js/tests/chmod_test.ts create mode 100644 cli/js/tests/chown_test.ts create mode 100644 cli/js/tests/compiler_api_test.ts create mode 100644 cli/js/tests/console_test.ts create mode 100644 cli/js/tests/copy_file_test.ts create mode 100644 cli/js/tests/custom_event_test.ts create mode 100644 cli/js/tests/dir_test.ts create mode 100644 cli/js/tests/dispatch_json_test.ts create mode 100644 cli/js/tests/dispatch_minimal_test.ts create mode 100644 cli/js/tests/dom_iterable_test.ts create mode 100644 cli/js/tests/error_stack_test.ts create mode 100644 cli/js/tests/event_target_test.ts create mode 100644 cli/js/tests/event_test.ts create mode 100644 cli/js/tests/fetch_test.ts create mode 100644 cli/js/tests/file_test.ts create mode 100644 cli/js/tests/files_test.ts create mode 100644 cli/js/tests/form_data_test.ts create mode 100644 cli/js/tests/format_error_test.ts create mode 100644 cli/js/tests/fs_events_test.ts create mode 100644 cli/js/tests/get_random_values_test.ts create mode 100644 cli/js/tests/globals_test.ts create mode 100644 cli/js/tests/headers_test.ts create mode 100644 cli/js/tests/internals_test.ts create mode 100644 cli/js/tests/link_test.ts create mode 100644 cli/js/tests/location_test.ts create mode 100644 cli/js/tests/make_temp_test.ts create mode 100644 cli/js/tests/metrics_test.ts create mode 100644 cli/js/tests/mkdir_test.ts create mode 100644 cli/js/tests/net_test.ts create mode 100644 cli/js/tests/os_test.ts create mode 100644 cli/js/tests/performance_test.ts create mode 100644 cli/js/tests/permissions_test.ts create mode 100644 cli/js/tests/process_test.ts create mode 100644 cli/js/tests/read_dir_test.ts create mode 100644 cli/js/tests/read_file_test.ts create mode 100644 cli/js/tests/read_link_test.ts create mode 100644 cli/js/tests/realpath_test.ts create mode 100644 cli/js/tests/remove_test.ts create mode 100644 cli/js/tests/rename_test.ts create mode 100644 cli/js/tests/request_test.ts create mode 100644 cli/js/tests/resources_test.ts create mode 100644 cli/js/tests/signal_test.ts create mode 100644 cli/js/tests/stat_test.ts create mode 100644 cli/js/tests/symbols_test.ts create mode 100644 cli/js/tests/symlink_test.ts create mode 100644 cli/js/tests/test_util.ts create mode 100644 cli/js/tests/testing_test.ts create mode 100644 cli/js/tests/text_encoding_test.ts create mode 100644 cli/js/tests/timers_test.ts create mode 100644 cli/js/tests/tls_test.ts create mode 100644 cli/js/tests/truncate_test.ts create mode 100644 cli/js/tests/tty_test.ts create mode 100755 cli/js/tests/unit_test_runner.ts create mode 100644 cli/js/tests/unit_tests.ts create mode 100644 cli/js/tests/url_search_params_test.ts create mode 100644 cli/js/tests/url_test.ts create mode 100644 cli/js/tests/utime_test.ts create mode 100644 cli/js/tests/version_test.ts create mode 100644 cli/js/tests/write_file_test.ts delete mode 100644 cli/js/text_encoding_test.ts delete mode 100644 cli/js/timers_test.ts delete mode 100644 cli/js/tls_test.ts delete mode 100644 cli/js/truncate_test.ts delete mode 100644 cli/js/tty_test.ts delete mode 100755 cli/js/unit_test_runner.ts delete mode 100644 cli/js/unit_tests.ts delete mode 100644 cli/js/url_search_params_test.ts delete mode 100644 cli/js/url_test.ts delete mode 100644 cli/js/utime_test.ts delete mode 100644 cli/js/version_test.ts delete mode 100644 cli/js/write_file_test.ts (limited to 'cli/js') diff --git a/cli/js/blob_test.ts b/cli/js/blob_test.ts deleted file mode 100644 index 54071a11e..000000000 --- a/cli/js/blob_test.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest(function blobString(): void { - const b1 = new Blob(["Hello World"]); - const str = "Test"; - const b2 = new Blob([b1, str]); - assertEquals(b2.size, b1.size + str.length); -}); - -unitTest(function blobBuffer(): void { - 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); -}); - -unitTest(function blobSlice(): void { - 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); -}); - -unitTest(function blobShouldNotThrowError(): void { - let hasThrown = false; - - try { - const options1: object = { - ending: "utf8", - hasOwnProperty: "hasOwnProperty" - }; - const options2: object = Object.create(null); - new Blob(["Hello World"], options1); - new Blob(["Hello World"], options2); - } catch { - hasThrown = true; - } - - assertEquals(hasThrown, false); -}); - -unitTest(function nativeEndLine(): void { - const options: object = { - ending: "native" - }; - const blob = new Blob(["Hello\nWorld"], options); - - assertEquals(blob.size, Deno.build.os === "win" ? 12 : 11); -}); - -// TODO(qti3e) Test the stored data in a Blob after implementing FileReader API. diff --git a/cli/js/body_test.ts b/cli/js/body_test.ts deleted file mode 100644 index 23f6d89e4..000000000 --- a/cli/js/body_test.ts +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assertEquals, assert } from "./test_util.ts"; - -// just a hack to get a body object -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function buildBody(body: any): Body { - const stub = new Request("", { - body: body - }); - return stub as Body; -} - -const intArrays = [ - Int8Array, - Int16Array, - Int32Array, - Uint8Array, - Uint16Array, - Uint32Array, - Uint8ClampedArray, - Float32Array, - Float64Array -]; -unitTest(async function arrayBufferFromByteArrays(): Promise { - 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 -unitTest( - { perms: { net: true } }, - async function bodyMultipartFormData(): Promise { - const response = await fetch( - "http://localhost:4545/cli/tests/subdir/multipart_form_data.txt" - ); - const text = await response.text(); - - const body = buildBody(text); - - // @ts-ignore - body.contentType = "multipart/form-data;boundary=boundary"; - - 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")); - } -); - -unitTest( - { perms: { net: true } }, - async function bodyURLEncodedFormData(): Promise { - const response = await fetch( - "http://localhost:4545/cli/tests/subdir/form_urlencoded.txt" - ); - const text = await response.text(); - - const body = buildBody(text); - - // @ts-ignore - body.contentType = "application/x-www-form-urlencoded"; - - 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(), ""); - } -); diff --git a/cli/js/buffer_test.ts b/cli/js/buffer_test.ts deleted file mode 100644 index 163ed0a30..000000000 --- a/cli/js/buffer_test.ts +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -// 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 { - assertEquals, - assert, - assertStrContains, - unitTest -} from "./test_util.ts"; - -const { Buffer, readAll, readAllSync, writeAll, writeAllSync } = Deno; -type Buffer = Deno.Buffer; - -// N controls how many iterations of certain checks are performed. -const N = 100; -let testBytes: Uint8Array | null; -let testString: string | null; - -function init(): void { - 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): void { - const bytes = buf.bytes(); - assertEquals(buf.length, bytes.byteLength); - const decoder = new TextDecoder(); - const bytesStr = decoder.decode(bytes); - assertEquals(bytesStr, s); - assertEquals(buf.length, buf.toString().length); - 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: Buffer, - s: string, - n: number, - fub: Uint8Array -): Promise { - 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: Buffer, s: string, fub: Uint8Array): Promise { - check(buf, s); - while (true) { - const r = await buf.read(fub); - if (r === Deno.EOF) { - 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; -} - -unitTest(function bufferNewBuffer(): void { - init(); - assert(testBytes); - assert(testString); - const buf = new Buffer(testBytes.buffer as ArrayBuffer); - check(buf, testString); -}); - -unitTest(async function bufferBasicOperations(): Promise { - init(); - assert(testBytes); - assert(testString); - const buf = new 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 buf.writeByte() - // TODO buf.readByte() - } -}); - -unitTest(async function bufferReadEmptyAtEOF(): Promise { - // 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 Buffer(); - const zeroLengthTmp = new Uint8Array(0); - const result = await buf.read(zeroLengthTmp); - assertEquals(result, 0); -}); - -unitTest(async function bufferLargeByteWrites(): Promise { - init(); - const buf = new 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, ""); -}); - -unitTest(async function bufferTooLargeByteWrites(): Promise { - init(); - const tmp = new Uint8Array(72); - const growLen = Number.MAX_VALUE; - const xBytes = repeat("x", 0); - const buf = new Buffer(xBytes.buffer as ArrayBuffer); - await buf.read(tmp); - - let err; - try { - buf.grow(growLen); - } catch (e) { - err = e; - } - - assert(err instanceof Error); - assertStrContains(err.message, "grown beyond the maximum size"); -}); - -unitTest(async function bufferLargeByteReads(): Promise { - init(); - assert(testBytes); - assert(testString); - const buf = new 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, ""); -}); - -unitTest(function bufferCapWithPreallocatedSlice(): void { - const buf = new Buffer(new ArrayBuffer(10)); - assertEquals(buf.capacity, 10); -}); - -unitTest(async function bufferReadFrom(): Promise { - init(); - assert(testBytes); - assert(testString); - const buf = new 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 Buffer(); - await b.readFrom(buf); - const fub = new Uint8Array(testString.length); - await empty(b, s, fub); - } -}); - -unitTest(async function bufferReadFromSync(): Promise { - init(); - assert(testBytes); - assert(testString); - const buf = new 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 Buffer(); - b.readFromSync(buf); - const fub = new Uint8Array(testString.length); - await empty(b, s, fub); - } -}); - -unitTest(async function bufferTestGrow(): Promise { - const tmp = new Uint8Array(72); - for (const startLen of [0, 100, 1000, 10000, 100000]) { - const xBytes = repeat("x", startLen); - for (const growLen of [0, 100, 1000, 10000, 100000]) { - const buf = new Buffer(xBytes.buffer as ArrayBuffer); - // If we read, this affects buf.off, which is good to test. - const result = await buf.read(tmp); - const nread = result === Deno.EOF ? 0 : result; - 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 - ); - } - } -}); - -unitTest(async function testReadAll(): Promise { - init(); - assert(testBytes); - const reader = new Buffer(testBytes.buffer as ArrayBuffer); - const actualBytes = await readAll(reader); - assertEquals(testBytes.byteLength, actualBytes.byteLength); - for (let i = 0; i < testBytes.length; ++i) { - assertEquals(testBytes[i], actualBytes[i]); - } -}); - -unitTest(function testReadAllSync(): void { - init(); - assert(testBytes); - const reader = new Buffer(testBytes.buffer as ArrayBuffer); - const actualBytes = readAllSync(reader); - assertEquals(testBytes.byteLength, actualBytes.byteLength); - for (let i = 0; i < testBytes.length; ++i) { - assertEquals(testBytes[i], actualBytes[i]); - } -}); - -unitTest(async function testWriteAll(): Promise { - init(); - assert(testBytes); - const writer = new Buffer(); - await 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]); - } -}); - -unitTest(function testWriteAllSync(): void { - init(); - assert(testBytes); - const writer = new Buffer(); - 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]); - } -}); diff --git a/cli/js/build_test.ts b/cli/js/build_test.ts deleted file mode 100644 index 50c7b519c..000000000 --- a/cli/js/build_test.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -unitTest(function buildInfo(): void { - // Deno.build is injected by rollup at compile time. Here - // we check it has been properly transformed. - const { arch, os } = Deno.build; - assert(arch === "x64"); - assert(os === "mac" || os === "win" || os === "linux"); -}); diff --git a/cli/js/chmod_test.ts b/cli/js/chmod_test.ts deleted file mode 100644 index 8731fad22..000000000 --- a/cli/js/chmod_test.ts +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -const isNotWindows = Deno.build.os !== "win"; - -unitTest( - { perms: { read: true, write: true } }, - function chmodSyncSuccess(): void { - const enc = new TextEncoder(); - const data = enc.encode("Hello"); - const tempDir = Deno.makeTempDirSync(); - const filename = tempDir + "/test.txt"; - Deno.writeFileSync(filename, data, { mode: 0o666 }); - - // On windows no effect, but should not crash - Deno.chmodSync(filename, 0o777); - - // Check success when not on windows - if (isNotWindows) { - const fileInfo = Deno.statSync(filename); - assert(fileInfo.mode); - assertEquals(fileInfo.mode & 0o777, 0o777); - } - } -); - -// Check symlink when not on windows -unitTest( - { - skip: Deno.build.os === "win", - perms: { read: true, write: true } - }, - function chmodSyncSymlinkSuccess(): void { - 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); - } -); - -unitTest({ perms: { write: true } }, function chmodSyncFailure(): void { - let err; - try { - const filename = "/badfile.txt"; - Deno.chmodSync(filename, 0o777); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); -}); - -unitTest({ perms: { write: false } }, function chmodSyncPerm(): void { - let err; - try { - Deno.chmodSync("/somefile.txt", 0o777); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest( - { perms: { read: true, write: true } }, - async function chmodSuccess(): Promise { - const enc = new TextEncoder(); - const data = enc.encode("Hello"); - const tempDir = Deno.makeTempDirSync(); - const filename = tempDir + "/test.txt"; - Deno.writeFileSync(filename, data, { mode: 0o666 }); - - // On windows no effect, but should not crash - await Deno.chmod(filename, 0o777); - - // Check success when not on windows - if (isNotWindows) { - const fileInfo = Deno.statSync(filename); - assert(fileInfo.mode); - assertEquals(fileInfo.mode & 0o777, 0o777); - } - } -); - -// Check symlink when not on windows - -unitTest( - { - skip: Deno.build.os === "win", - perms: { read: true, write: true } - }, - async function chmodSymlinkSuccess(): Promise { - 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); - } -); - -unitTest({ perms: { write: true } }, async function chmodFailure(): Promise< - void -> { - let err; - try { - const filename = "/badfile.txt"; - await Deno.chmod(filename, 0o777); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); -}); - -unitTest({ perms: { write: false } }, async function chmodPerm(): Promise< - void -> { - let err; - try { - await Deno.chmod("/somefile.txt", 0o777); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); diff --git a/cli/js/chown_test.ts b/cli/js/chown_test.ts deleted file mode 100644 index 50dcd6dc1..000000000 --- a/cli/js/chown_test.ts +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assertEquals, assert } from "./test_util.ts"; - -// chown on Windows is noop for now, so ignore its testing on Windows -if (Deno.build.os !== "win") { - async function getUidAndGid(): Promise<{ uid: number; gid: number }> { - // get the user ID and group ID of the current process - const uidProc = Deno.run({ - stdout: "piped", - args: ["python", "-c", "import os; print(os.getuid())"] - }); - const gidProc = Deno.run({ - stdout: "piped", - args: ["python", "-c", "import os; print(os.getgid())"] - }); - - assertEquals((await uidProc.status()).code, 0); - assertEquals((await gidProc.status()).code, 0); - const uid = parseInt( - new TextDecoder("utf-8").decode(await uidProc.output()) - ); - uidProc.close(); - const gid = parseInt( - new TextDecoder("utf-8").decode(await gidProc.output()) - ); - gidProc.close(); - - return { uid, gid }; - } - - unitTest(async function chownNoWritePermission(): Promise { - const filePath = "chown_test_file.txt"; - try { - await Deno.chown(filePath, 1000, 1000); - } catch (e) { - assert(e instanceof Deno.errors.PermissionDenied); - } - }); - - unitTest( - { perms: { run: true, write: true } }, - async function chownSyncFileNotExist(): Promise { - const { uid, gid } = await getUidAndGid(); - const filePath = Deno.makeTempDirSync() + "/chown_test_file.txt"; - - try { - Deno.chownSync(filePath, uid, gid); - } catch (e) { - assert(e instanceof Deno.errors.NotFound); - } - } - ); - - unitTest( - { perms: { run: true, write: true } }, - async function chownFileNotExist(): Promise { - const { uid, gid } = await getUidAndGid(); - const filePath = (await Deno.makeTempDir()) + "/chown_test_file.txt"; - - try { - await Deno.chown(filePath, uid, gid); - } catch (e) { - assert(e instanceof Deno.errors.NotFound); - } - } - ); - - unitTest( - { perms: { write: true } }, - function chownSyncPermissionDenied(): void { - const enc = new TextEncoder(); - const dirPath = Deno.makeTempDirSync(); - const filePath = dirPath + "/chown_test_file.txt"; - const fileData = enc.encode("Hello"); - Deno.writeFileSync(filePath, fileData); - - try { - // try changing the file's owner to root - Deno.chownSync(filePath, 0, 0); - } catch (e) { - assert(e instanceof Deno.errors.PermissionDenied); - } - Deno.removeSync(dirPath, { recursive: true }); - } - ); - - unitTest( - { perms: { write: true } }, - async function chownPermissionDenied(): Promise { - const enc = new TextEncoder(); - const dirPath = await Deno.makeTempDir(); - const filePath = dirPath + "/chown_test_file.txt"; - const fileData = enc.encode("Hello"); - await Deno.writeFile(filePath, fileData); - - try { - // try changing the file's owner to root - await Deno.chown(filePath, 0, 0); - } catch (e) { - assert(e instanceof Deno.errors.PermissionDenied); - } - await Deno.remove(dirPath, { recursive: true }); - } - ); - - unitTest( - { perms: { run: true, write: true } }, - async function chownSyncSucceed(): Promise { - // TODO: when a file's owner is actually being changed, - // chown only succeeds if run under priviledged user (root) - // The test script has no such priviledge, so need to find a better way to test this case - const { uid, gid } = await getUidAndGid(); - - const enc = new TextEncoder(); - const dirPath = Deno.makeTempDirSync(); - const filePath = dirPath + "/chown_test_file.txt"; - const fileData = enc.encode("Hello"); - Deno.writeFileSync(filePath, fileData); - - // the test script creates this file with the same uid and gid, - // here chown is a noop so it succeeds under non-priviledged user - Deno.chownSync(filePath, uid, gid); - - Deno.removeSync(dirPath, { recursive: true }); - } - ); - - unitTest( - { perms: { run: true, write: true } }, - async function chownSucceed(): Promise { - // TODO: same as chownSyncSucceed - const { uid, gid } = await getUidAndGid(); - - const enc = new TextEncoder(); - const dirPath = await Deno.makeTempDir(); - const filePath = dirPath + "/chown_test_file.txt"; - const fileData = enc.encode("Hello"); - await Deno.writeFile(filePath, fileData); - - // the test script creates this file with the same uid and gid, - // here chown is a noop so it succeeds under non-priviledged user - await Deno.chown(filePath, uid, gid); - - Deno.removeSync(dirPath, { recursive: true }); - } - ); -} diff --git a/cli/js/compiler_api_test.ts b/cli/js/compiler_api_test.ts deleted file mode 100644 index 3b0449f9a..000000000 --- a/cli/js/compiler_api_test.ts +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import { assert, assertEquals, unitTest } from "./test_util.ts"; - -const { compile, transpileOnly, bundle } = Deno; - -unitTest(async function compilerApiCompileSources() { - const [diagnostics, actual] = await compile("/foo.ts", { - "/foo.ts": `import * as bar from "./bar.ts";\n\nconsole.log(bar);\n`, - "/bar.ts": `export const bar = "bar";\n` - }); - assert(diagnostics == null); - assert(actual); - assertEquals(Object.keys(actual), [ - "/bar.js.map", - "/bar.js", - "/foo.js.map", - "/foo.js" - ]); -}); - -unitTest(async function compilerApiCompileNoSources() { - const [diagnostics, actual] = await compile("./cli/tests/subdir/mod1.ts"); - assert(diagnostics == null); - assert(actual); - const keys = Object.keys(actual); - assertEquals(keys.length, 6); - assert(keys[0].endsWith("print_hello.js.map")); - assert(keys[1].endsWith("print_hello.js")); -}); - -unitTest(async function compilerApiCompileOptions() { - const [diagnostics, actual] = await compile( - "/foo.ts", - { - "/foo.ts": `export const foo = "foo";` - }, - { - module: "amd", - sourceMap: false - } - ); - assert(diagnostics == null); - assert(actual); - assertEquals(Object.keys(actual), ["/foo.js"]); - assert(actual["/foo.js"].startsWith("define(")); -}); - -unitTest(async function compilerApiCompileLib() { - const [diagnostics, actual] = await compile( - "/foo.ts", - { - "/foo.ts": `console.log(document.getElementById("foo")); - console.log(Deno.args);` - }, - { - lib: ["dom", "es2018", "deno.ns"] - } - ); - assert(diagnostics == null); - assert(actual); - assertEquals(Object.keys(actual), ["/foo.js.map", "/foo.js"]); -}); - -unitTest(async function compilerApiCompileTypes() { - const [diagnostics, actual] = await compile( - "/foo.ts", - { - "/foo.ts": `console.log(Foo.bar);` - }, - { - types: ["./cli/tests/subdir/foo_types.d.ts"] - } - ); - assert(diagnostics == null); - assert(actual); - assertEquals(Object.keys(actual), ["/foo.js.map", "/foo.js"]); -}); - -unitTest(async function transpileOnlyApi() { - const actual = await transpileOnly({ - "foo.ts": `export enum Foo { Foo, Bar, Baz };\n` - }); - assert(actual); - assertEquals(Object.keys(actual), ["foo.ts"]); - assert(actual["foo.ts"].source.startsWith("export var Foo;")); - assert(actual["foo.ts"].map); -}); - -unitTest(async function transpileOnlyApiConfig() { - const actual = await transpileOnly( - { - "foo.ts": `export enum Foo { Foo, Bar, Baz };\n` - }, - { - sourceMap: false, - module: "amd" - } - ); - assert(actual); - assertEquals(Object.keys(actual), ["foo.ts"]); - assert(actual["foo.ts"].source.startsWith("define(")); - assert(actual["foo.ts"].map == null); -}); - -unitTest(async function bundleApiSources() { - const [diagnostics, actual] = await bundle("/foo.ts", { - "/foo.ts": `export * from "./bar.ts";\n`, - "/bar.ts": `export const bar = "bar";\n` - }); - assert(diagnostics == null); - assert(actual.includes(`__instantiate("foo")`)); - assert(actual.includes(`__exp["bar"]`)); -}); - -unitTest(async function bundleApiNoSources() { - const [diagnostics, actual] = await bundle("./cli/tests/subdir/mod1.ts"); - assert(diagnostics == null); - assert(actual.includes(`__instantiate("mod1")`)); - assert(actual.includes(`__exp["printHello3"]`)); -}); - -unitTest(async function bundleApiConfig() { - const [diagnostics, actual] = await bundle( - "/foo.ts", - { - "/foo.ts": `// random comment\nexport * from "./bar.ts";\n`, - "/bar.ts": `export const bar = "bar";\n` - }, - { - removeComments: true - } - ); - assert(diagnostics == null); - assert(!actual.includes(`random`)); -}); - -unitTest(async function bundleApiJsModules() { - const [diagnostics, actual] = await bundle("/foo.js", { - "/foo.js": `export * from "./bar.js";\n`, - "/bar.js": `export const bar = "bar";\n` - }); - assert(diagnostics == null); - assert(actual.includes(`System.register("bar",`)); -}); - -unitTest(async function diagnosticsTest() { - const [diagnostics] = await compile("/foo.ts", { - "/foo.ts": `document.getElementById("foo");` - }); - assert(Array.isArray(diagnostics)); - assert(diagnostics.length === 1); -}); diff --git a/cli/js/console_test.ts b/cli/js/console_test.ts deleted file mode 100644 index 34a61c25f..000000000 --- a/cli/js/console_test.ts +++ /dev/null @@ -1,706 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { assert, assertEquals, unitTest } from "./test_util.ts"; - -// Some of these APIs aren't exposed in the types and so we have to cast to any -// in order to "trick" TypeScript. -const { - inspect, - writeSync, - stdout - // eslint-disable-next-line @typescript-eslint/no-explicit-any -} = Deno as any; - -const customInspect = Deno.symbols.customInspect; -const { - Console, - stringifyArgs - // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol -} = Deno[Deno.symbols.internal]; - -function stringify(...args: unknown[]): string { - return stringifyArgs(args).replace(/\n$/, ""); -} - -// test cases from web-platform-tests -// via https://github.com/web-platform-tests/wpt/blob/master/console/console-is-a-namespace.any.js -unitTest(function consoleShouldBeANamespace(): void { - const prototype1 = Object.getPrototypeOf(console); - const prototype2 = Object.getPrototypeOf(prototype1); - - assertEquals(Object.getOwnPropertyNames(prototype1).length, 0); - assertEquals(prototype2, Object.prototype); -}); - -unitTest(function consoleHasRightInstance(): void { - assert(console instanceof Console); - assertEquals({} instanceof Console, false); -}); - -unitTest(function consoleTestAssertShouldNotThrowError(): void { - mockConsole(console => { - console.assert(true); - let hasThrown = undefined; - try { - console.assert(false); - hasThrown = false; - } catch { - hasThrown = true; - } - assertEquals(hasThrown, false); - }); -}); - -unitTest(function consoleTestStringifyComplexObjects(): void { - assertEquals(stringify("foo"), "foo"); - assertEquals(stringify(["foo", "bar"]), `[ "foo", "bar" ]`); - assertEquals(stringify({ foo: "bar" }), `{ foo: "bar" }`); -}); - -unitTest(function consoleTestStringifyLongStrings(): void { - 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); -}); - -/* eslint-disable @typescript-eslint/explicit-function-return-type */ -unitTest(function consoleTestStringifyCircular(): void { - class Base { - a = 1; - m1() {} - } - - class Extended extends Base { - b = 2; - m2() {} - } - - // eslint-disable-next-line @typescript-eslint/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 = `{ num, bool, str, method, asyncMethod, generatorMethod, un, nu, arrowFunc, extendedClass, nFunc, extendedCstr, o }`; - - 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 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 { 1, 2, 3 }"); - assertEquals( - stringify( - new Map([ - [1, "one"], - [2, "two"] - ]) - ), - `Map { 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(null), "null"); - assertEquals(stringify(undefined), "undefined"); - assertEquals(stringify(new Extended()), "Extended { a: 1, b: 2 }"); - assertEquals( - stringify(function f(): void {}), - "[Function: f]" - ); - assertEquals( - stringify(async function af(): Promise {}), - "[AsyncFunction: af]" - ); - assertEquals( - stringify(function* gf() {}), - "[GeneratorFunction: gf]" - ); - assertEquals( - stringify(async function* agf() {}), - "[AsyncGeneratorFunction: agf]" - ); - assertEquals(stringify(new Uint8Array([1, 2, 3])), "Uint8Array [ 1, 2, 3 ]"); - assertEquals(stringify(Uint8Array.prototype), "TypedArray []"); - assertEquals( - stringify({ a: { b: { c: { d: new Set([1]) } } } }), - "{ a: { b: { c: { d: [Set] } } } }" - ); - assertEquals(stringify(nestedObj), nestedObjExpected); - assertEquals(stringify(JSON), "{}"); - assertEquals( - stringify(console), - "{ printFunc, log, debug, info, dir, dirxml, warn, error, assert, count, countReset, table, time, timeLog, timeEnd, group, groupCollapsed, groupEnd, clear, trace, indentLevel }" - ); - // test inspect is working the same - assertEquals(inspect(nestedObj), nestedObjExpected); -}); -/* eslint-enable @typescript-eslint/explicit-function-return-type */ - -unitTest(function consoleTestStringifyWithDepth(): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const nestedObj: any = { a: { b: { c: { d: { e: { f: 42 } } } } } }; - assertEquals( - stringifyArgs([nestedObj], { depth: 3 }), - "{ a: { b: { c: [Object] } } }" - ); - assertEquals( - stringifyArgs([nestedObj], { depth: 4 }), - "{ a: { b: { c: { d: [Object] } } } }" - ); - assertEquals(stringifyArgs([nestedObj], { depth: 0 }), "[Object]"); - assertEquals( - stringifyArgs([nestedObj], { depth: null }), - "{ a: { b: { c: { d: [Object] } } } }" - ); - // test inspect is working the same way - assertEquals( - inspect(nestedObj, { depth: 4 }), - "{ a: { b: { c: { d: [Object] } } } }" - ); -}); - -unitTest(function consoleTestWithCustomInspector(): void { - class A { - [customInspect](): string { - return "b"; - } - } - - assertEquals(stringify(new A()), "b"); -}); - -unitTest(function consoleTestWithCustomInspectorError(): void { - class A { - [customInspect](): string { - throw new Error("BOOM"); - return "b"; - } - } - - assertEquals(stringify(new A()), "A {}"); - - class B { - constructor(public field: { a: string }) {} - [customInspect](): string { - return this.field.a; - } - } - - assertEquals(stringify(new B({ a: "a" })), "a"); - assertEquals(stringify(B.prototype), "{}"); -}); - -unitTest(function consoleTestWithIntegerFormatSpecifier(): void { - assertEquals(stringify("%i"), "%i"); - assertEquals(stringify("%i", 42.0), "42"); - assertEquals(stringify("%i", 42), "42"); - assertEquals(stringify("%i", "42"), "42"); - assertEquals(stringify("%i", "42.0"), "42"); - 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" - ); -}); - -unitTest(function consoleTestWithFloatFormatSpecifier(): void { - assertEquals(stringify("%f"), "%f"); - assertEquals(stringify("%f", 42.0), "42"); - assertEquals(stringify("%f", 42), "42"); - assertEquals(stringify("%f", "42"), "42"); - assertEquals(stringify("%f", "42.0"), "42"); - 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), "5"); - assertEquals(stringify("%f %f", 42, 43), "42 43"); - assertEquals(stringify("%f %f", 42), "42 %f"); -}); - -unitTest(function consoleTestWithStringFormatSpecifier(): void { - 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)"); -}); - -unitTest(function consoleTestWithObjectFormatSpecifier(): void { - 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]) } } } }), - "{ a: { b: { c: { d: [Set] } } } }" - ); -}); - -unitTest(function consoleTestWithVariousOrInvalidFormatSpecifier(): void { - 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"); -}); - -unitTest(function consoleTestCallToStringOnLabel(): void { - const methods = ["count", "countReset", "time", "timeLog", "timeEnd"]; - mockConsole(console => { - for (const method of methods) { - let hasCalled = false; - // @ts-ignore - console[method]({ - toString(): void { - hasCalled = true; - } - }); - assertEquals(hasCalled, true); - } - }); -}); - -unitTest(function consoleTestError(): void { - 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") - ); - } -}); - -unitTest(function consoleTestClear(): void { - const stdoutWriteSync = stdout.writeSync; - const uint8 = new TextEncoder().encode("\x1b[1;1H" + "\x1b[0J"); - let buffer = new Uint8Array(0); - - stdout.writeSync = (u8: Uint8Array): Promise => { - const tmp = new Uint8Array(buffer.length + u8.length); - tmp.set(buffer, 0); - tmp.set(u8, buffer.length); - buffer = tmp; - - return writeSync(stdout.rid, u8); - }; - console.clear(); - stdout.writeSync = stdoutWriteSync; - assertEquals(buffer, uint8); -}); - -// Test bound this issue -unitTest(function consoleDetachedLog(): void { - 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): void { - this.chunks.push(x); - } - toString(): string { - return this.chunks.join(""); - } -} - -type ConsoleExamineFunc = ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - csl: any, - out: StringBuffer, - err?: StringBuffer, - both?: StringBuffer -) => void; - -function mockConsole(f: ConsoleExamineFunc): void { - const out = new StringBuffer(); - const err = new StringBuffer(); - const both = new StringBuffer(); - const csl = new Console( - (x: string, isErr: boolean, printsNewLine: boolean): void => { - const content = x + (printsNewLine ? "\n" : ""); - const buf = isErr ? err : out; - buf.add(content); - both.add(content); - } - ); - f(csl, out, err, both); -} - -// console.group test -unitTest(function consoleGroup(): void { - mockConsole((console, out): void => { - 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 -unitTest(function consoleGroupWarn(): void { - mockConsole((console, _out, _err, both): void => { - 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 -unitTest(function consoleTable(): void { - mockConsole((console, out): void => { - console.table({ a: "test", b: 1 }); - assertEquals( - out.toString(), - `┌─────────┬────────┐ -│ (index) │ Values │ -├─────────┼────────┤ -│ a │ "test" │ -│ b │ 1 │ -└─────────┴────────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table({ a: { b: 10 }, b: { b: 20, c: 30 } }, ["c"]); - assertEquals( - out.toString(), - `┌─────────┬────┐ -│ (index) │ c │ -├─────────┼────┤ -│ a │ │ -│ b │ 30 │ -└─────────┴────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table([1, 2, [3, [4]], [5, 6], [[7], [8]]]); - assertEquals( - out.toString(), - `┌─────────┬───────┬───────┬────────┐ -│ (index) │ 0 │ 1 │ Values │ -├─────────┼───────┼───────┼────────┤ -│ 0 │ │ │ 1 │ -│ 1 │ │ │ 2 │ -│ 2 │ 3 │ [ 4 ] │ │ -│ 3 │ 5 │ 6 │ │ -│ 4 │ [ 7 ] │ [ 8 ] │ │ -└─────────┴───────┴───────┴────────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table(new Set([1, 2, 3, "test"])); - assertEquals( - out.toString(), - `┌───────────────────┬────────┐ -│ (iteration index) │ Values │ -├───────────────────┼────────┤ -│ 0 │ 1 │ -│ 1 │ 2 │ -│ 2 │ 3 │ -│ 3 │ "test" │ -└───────────────────┴────────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table( - new Map([ - [1, "one"], - [2, "two"] - ]) - ); - assertEquals( - out.toString(), - `┌───────────────────┬─────┬────────┐ -│ (iteration index) │ Key │ Values │ -├───────────────────┼─────┼────────┤ -│ 0 │ 1 │ "one" │ -│ 1 │ 2 │ "two" │ -└───────────────────┴─────┴────────┘ -` - ); - }); - mockConsole((console, out): void => { - 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( - out.toString(), - `┌─────────┬───────────┬───────────────────┬────────┐ -│ (index) │ c │ e │ Values │ -├─────────┼───────────┼───────────────────┼────────┤ -│ a │ │ │ true │ -│ b │ { d: 10 } │ [ 1, 2, [Array] ] │ │ -│ f │ │ │ "test" │ -│ g │ │ │ │ -│ h │ │ │ │ -└─────────┴───────────┴───────────────────┴────────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table([ - 1, - "test", - false, - { a: 10 }, - ["test", { b: 20, c: "test" }] - ]); - assertEquals( - out.toString(), - `┌─────────┬────────┬──────────────────────┬────┬────────┐ -│ (index) │ 0 │ 1 │ a │ Values │ -├─────────┼────────┼──────────────────────┼────┼────────┤ -│ 0 │ │ │ │ 1 │ -│ 1 │ │ │ │ "test" │ -│ 2 │ │ │ │ false │ -│ 3 │ │ │ 10 │ │ -│ 4 │ "test" │ { b: 20, c: "test" } │ │ │ -└─────────┴────────┴──────────────────────┴────┴────────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table([]); - assertEquals( - out.toString(), - `┌─────────┐ -│ (index) │ -├─────────┤ -└─────────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table({}); - assertEquals( - out.toString(), - `┌─────────┐ -│ (index) │ -├─────────┤ -└─────────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table(new Set()); - assertEquals( - out.toString(), - `┌───────────────────┐ -│ (iteration index) │ -├───────────────────┤ -└───────────────────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table(new Map()); - assertEquals( - out.toString(), - `┌───────────────────┐ -│ (iteration index) │ -├───────────────────┤ -└───────────────────┘ -` - ); - }); - mockConsole((console, out): void => { - console.table("test"); - assertEquals(out.toString(), "test\n"); - }); -}); - -// console.log(Error) test -unitTest(function consoleLogShouldNotThrowError(): void { - 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): void => { - console.log(new Error("foo")); - assertEquals(out.toString().includes("Uncaught"), false); - }); -}); - -// console.dir test -unitTest(function consoleDir(): void { - mockConsole((console, out): void => { - console.dir("DIR"); - assertEquals(out.toString(), "DIR\n"); - }); - mockConsole((console, out): void => { - console.dir("DIR", { indentLevel: 2 }); - assertEquals(out.toString(), " DIR\n"); - }); -}); - -// console.dir test -unitTest(function consoleDirXml(): void { - mockConsole((console, out): void => { - console.dirxml("DIRXML"); - assertEquals(out.toString(), "DIRXML\n"); - }); - mockConsole((console, out): void => { - console.dirxml("DIRXML", { indentLevel: 2 }); - assertEquals(out.toString(), " DIRXML\n"); - }); -}); - -// console.trace test -unitTest(function consoleTrace(): void { - mockConsole((console, _out, err): void => { - console.trace("%s", "custom message"); - assert(err); - assert(err.toString().includes("Trace: custom message")); - }); -}); diff --git a/cli/js/copy_file_test.ts b/cli/js/copy_file_test.ts deleted file mode 100644 index 986bab53b..000000000 --- a/cli/js/copy_file_test.ts +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -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): void { - const enc = new TextEncoder(); - const data = enc.encode(s); - Deno.writeFileSync(filename, data, { mode: 0o666 }); -} - -function assertSameContent(filename1: string, filename2: string): void { - const data1 = Deno.readFileSync(filename1); - const data2 = Deno.readFileSync(filename2); - assertEquals(data1, data2); -} - -unitTest( - { perms: { read: true, write: true } }, - function copyFileSyncSuccess(): void { - 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); - } -); - -unitTest( - { perms: { write: true, read: true } }, - function copyFileSyncFailure(): void { - const tempDir = Deno.makeTempDirSync(); - const fromFilename = tempDir + "/from.txt"; - const toFilename = tempDir + "/to.txt"; - // We skip initial writing here, from.txt does not exist - let err; - try { - Deno.copyFileSync(fromFilename, toFilename); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { write: true, read: false } }, - function copyFileSyncPerm1(): void { - let caughtError = false; - try { - Deno.copyFileSync("/from.txt", "/to.txt"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); - } -); - -unitTest( - { perms: { write: false, read: true } }, - function copyFileSyncPerm2(): void { - let caughtError = false; - try { - Deno.copyFileSync("/from.txt", "/to.txt"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); - } -); - -unitTest( - { perms: { read: true, write: true } }, - function copyFileSyncOverwrite(): void { - 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); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function copyFileSuccess(): Promise { - 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); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function copyFileFailure(): Promise { - const tempDir = Deno.makeTempDirSync(); - const fromFilename = tempDir + "/from.txt"; - const toFilename = tempDir + "/to.txt"; - // We skip initial writing here, from.txt does not exist - let err; - try { - await Deno.copyFile(fromFilename, toFilename); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function copyFileOverwrite(): Promise { - 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); - } -); - -unitTest( - { perms: { read: false, write: true } }, - async function copyFilePerm1(): Promise { - let caughtError = false; - try { - await Deno.copyFile("/from.txt", "/to.txt"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); - } -); - -unitTest( - { perms: { read: true, write: false } }, - async function copyFilePerm2(): Promise { - let caughtError = false; - try { - await Deno.copyFile("/from.txt", "/to.txt"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); - } -); diff --git a/cli/js/custom_event_test.ts b/cli/js/custom_event_test.ts deleted file mode 100644 index 7a5cc44ca..000000000 --- a/cli/js/custom_event_test.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assertEquals } from "./test_util.ts"; - -unitTest(function customEventInitializedWithDetail(): void { - 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); -}); - -unitTest(function toStringShouldBeWebCompatibility(): void { - const type = "touchstart"; - const event = new CustomEvent(type, {}); - assertEquals(event.toString(), "[object CustomEvent]"); -}); diff --git a/cli/js/dir_test.ts b/cli/js/dir_test.ts deleted file mode 100644 index 75184587b..000000000 --- a/cli/js/dir_test.ts +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest(function dirCwdNotNull(): void { - assert(Deno.cwd() != null); -}); - -unitTest({ perms: { write: true } }, function dirCwdChdirSuccess(): void { - const initialdir = Deno.cwd(); - const path = Deno.makeTempDirSync(); - Deno.chdir(path); - const current = Deno.cwd(); - if (Deno.build.os === "mac") { - assertEquals(current, "/private" + path); - } else { - assertEquals(current, path); - } - Deno.chdir(initialdir); -}); - -unitTest({ perms: { write: true } }, function dirCwdError(): void { - // excluding windows since it throws resource busy, while removeSync - if (["linux", "mac"].includes(Deno.build.os)) { - const initialdir = Deno.cwd(); - const path = Deno.makeTempDirSync(); - Deno.chdir(path); - Deno.removeSync(path); - try { - Deno.cwd(); - throw Error("current directory removed, should throw error"); - } catch (err) { - if (err instanceof Deno.errors.NotFound) { - assert(err.name === "NotFound"); - } else { - throw Error("raised different exception"); - } - } - Deno.chdir(initialdir); - } -}); - -unitTest({ perms: { write: true } }, function dirChdirError(): void { - const path = Deno.makeTempDirSync() + "test"; - try { - Deno.chdir(path); - throw Error("directory not available, should throw error"); - } catch (err) { - if (err instanceof Deno.errors.NotFound) { - assert(err.name === "NotFound"); - } else { - throw Error("raised different exception"); - } - } -}); diff --git a/cli/js/dispatch_json_test.ts b/cli/js/dispatch_json_test.ts deleted file mode 100644 index a2306dda8..000000000 --- a/cli/js/dispatch_json_test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { assert, unitTest, assertMatch, unreachable } from "./test_util.ts"; - -const openErrorStackPattern = new RegExp( - `^.* - at unwrapResponse \\(.*dispatch_json\\.ts:.*\\) - at Object.sendAsync \\(.*dispatch_json\\.ts:.*\\) - at async Object\\.open \\(.*files\\.ts:.*\\).*$`, - "ms" -); - -unitTest( - { perms: { read: true } }, - async function sendAsyncStackTrace(): Promise { - await Deno.open("nonexistent.txt") - .then(unreachable) - .catch((error): void => { - assertMatch(error.stack, openErrorStackPattern); - }); - } -); - -unitTest(async function malformedJsonControlBuffer(): Promise { - // @ts-ignore - const opId = Deno.core.ops()["op_open"]; - // @ts-ignore - const res = Deno.core.send(opId, new Uint8Array([1, 2, 3, 4, 5])); - const resText = new TextDecoder().decode(res); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const resJson = JSON.parse(resText) as any; - assert(!resJson.ok); - assert(resJson.err); -}); diff --git a/cli/js/dispatch_minimal_test.ts b/cli/js/dispatch_minimal_test.ts deleted file mode 100644 index 724a41698..000000000 --- a/cli/js/dispatch_minimal_test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - assert, - assertEquals, - assertMatch, - unitTest, - unreachable -} from "./test_util.ts"; - -const readErrorStackPattern = new RegExp( - `^.* - at unwrapResponse \\(.*dispatch_minimal\\.ts:.*\\) - at Object.sendAsyncMinimal \\(.*dispatch_minimal\\.ts:.*\\) - at async Object\\.read \\(.*io\\.ts:.*\\).*$`, - "ms" -); - -unitTest(async function sendAsyncStackTrace(): Promise { - const buf = new Uint8Array(10); - const rid = 10; - try { - await Deno.read(rid, buf); - unreachable(); - } catch (error) { - assertMatch(error.stack, readErrorStackPattern); - } -}); - -unitTest(async function malformedMinimalControlBuffer(): Promise { - // @ts-ignore - const readOpId = Deno.core.ops()["op_read"]; - // @ts-ignore - const res = Deno.core.send(readOpId, new Uint8Array([1, 2, 3, 4, 5])); - const header = res.slice(0, 12); - const buf32 = new Int32Array( - header.buffer, - header.byteOffset, - header.byteLength / 4 - ); - const arg = buf32[1]; - const message = new TextDecoder().decode(res.slice(12)).trim(); - assert(arg < 0); - assertEquals(message, "Unparsable control buffer"); -}); diff --git a/cli/js/error_stack_test.ts b/cli/js/error_stack_test.ts deleted file mode 100644 index 7acbd3a3d..000000000 --- a/cli/js/error_stack_test.ts +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -// @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol -const { setPrepareStackTrace } = Deno[Deno.symbols.internal]; - -interface CallSite { - getThis(): unknown; - getTypeName(): string; - getFunction(): Function; - getFunctionName(): string; - getMethodName(): string; - getFileName(): string; - getLineNumber(): number | null; - getColumnNumber(): number | null; - getEvalOrigin(): string | null; - isToplevel(): boolean; - isEval(): boolean; - isNative(): boolean; - isConstructor(): boolean; - isAsync(): boolean; - isPromiseAll(): boolean; - getPromiseIndex(): number | null; -} - -function getMockCallSite( - filename: string, - line: number | null, - column: number | null -): CallSite { - return { - getThis(): unknown { - return undefined; - }, - getTypeName(): string { - return ""; - }, - getFunction(): Function { - return (): void => {}; - }, - getFunctionName(): string { - return ""; - }, - getMethodName(): string { - return ""; - }, - getFileName(): string { - return filename; - }, - getLineNumber(): number | null { - return line; - }, - getColumnNumber(): number | null { - return column; - }, - getEvalOrigin(): null { - return null; - }, - isToplevel(): false { - return false; - }, - isEval(): false { - return false; - }, - isNative(): false { - return false; - }, - isConstructor(): false { - return false; - }, - isAsync(): false { - return false; - }, - isPromiseAll(): false { - return false; - }, - getPromiseIndex(): null { - return null; - } - }; -} - -unitTest(function prepareStackTrace(): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const MockError = {} as any; - setPrepareStackTrace(MockError); - assert(typeof MockError.prepareStackTrace === "function"); - const prepareStackTrace: ( - error: Error, - structuredStackTrace: CallSite[] - ) => string = MockError.prepareStackTrace; - const result = prepareStackTrace(new Error("foo"), [ - getMockCallSite("CLI_SNAPSHOT.js", 23, 0) - ]); - assert(result.startsWith("Error: foo\n")); - assert(result.includes(".ts:"), "should remap to something in 'js/'"); -}); - -unitTest(function applySourceMap(): void { - const result = Deno.applySourceMap({ - filename: "CLI_SNAPSHOT.js", - line: 23, - column: 0 - }); - assert(result.filename.endsWith(".ts")); - assert(result.line != null); - assert(result.column != null); -}); diff --git a/cli/js/event_target_test.ts b/cli/js/event_target_test.ts deleted file mode 100644 index 09d47f704..000000000 --- a/cli/js/event_target_test.ts +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assertEquals } from "./test_util.ts"; - -unitTest(function addEventListenerTest(): void { - const document = new EventTarget(); - - // @ts-ignore tests ignoring the type system for resilience - assertEquals(document.addEventListener("x", null, false), undefined); - // @ts-ignore - assertEquals(document.addEventListener("x", null, true), undefined); - // @ts-ignore - assertEquals(document.addEventListener("x", null), undefined); -}); - -unitTest(function constructedEventTargetCanBeUsedAsExpected(): void { - const target = new EventTarget(); - const event = new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = (e: Event): void => { - 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); -}); - -unitTest(function anEventTargetCanBeSubclassed(): void { - class NicerEventTarget extends EventTarget { - on( - type: string, - callback: ((e: Event) => void) | null, - options?: __domTypes.AddEventListenerOptions - ): void { - this.addEventListener(type, callback, options); - } - - off( - type: string, - callback: ((e: Event) => void) | null, - options?: __domTypes.EventListenerOptions - ): void { - this.removeEventListener(type, callback, options); - } - } - - const target = new NicerEventTarget(); - new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = (): void => { - ++callCount; - }; - - target.on("foo", listener); - assertEquals(callCount, 0); - - target.off("foo", listener); - assertEquals(callCount, 0); -}); - -unitTest(function removingNullEventListenerShouldSucceed(): void { - const document = new EventTarget(); - // @ts-ignore - assertEquals(document.removeEventListener("x", null, false), undefined); - // @ts-ignore - assertEquals(document.removeEventListener("x", null, true), undefined); - // @ts-ignore - assertEquals(document.removeEventListener("x", null), undefined); -}); - -unitTest(function constructedEventTargetUseObjectPrototype(): void { - const target = new EventTarget(); - const event = new Event("toString", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = (e: Event): void => { - 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); -}); - -unitTest(function toStringShouldBeWebCompatible(): void { - const target = new EventTarget(); - assertEquals(target.toString(), "[object EventTarget]"); -}); - -unitTest(function dispatchEventShouldNotThrowError(): void { - let hasThrown = false; - - try { - const target = new EventTarget(); - const event = new Event("hasOwnProperty", { - bubbles: true, - cancelable: false - }); - const listener = (): void => {}; - target.addEventListener("hasOwnProperty", listener); - target.dispatchEvent(event); - } catch { - hasThrown = true; - } - - assertEquals(hasThrown, false); -}); - -unitTest(function eventTargetThisShouldDefaultToWindow(): void { - const { - addEventListener, - dispatchEvent, - removeEventListener - } = EventTarget.prototype; - let n = 1; - const event = new Event("hello"); - const listener = (): void => { - 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); -}); - -unitTest(function eventTargetShouldAcceptEventListenerObject(): void { - const target = new EventTarget(); - const event = new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = { - handleEvent(e: Event): void { - 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); -}); - -unitTest(function eventTargetShouldAcceptAsyncFunction(): void { - const target = new EventTarget(); - const event = new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = async (e: Event): Promise => { - 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); -}); - -unitTest( - function eventTargetShouldAcceptAsyncFunctionForEventListenerObject(): void { - const target = new EventTarget(); - const event = new Event("foo", { bubbles: true, cancelable: false }); - let callCount = 0; - - const listener = { - async handleEvent(e: Event): Promise { - 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); - } -); diff --git a/cli/js/event_test.ts b/cli/js/event_test.ts deleted file mode 100644 index 05a9ed577..000000000 --- a/cli/js/event_test.ts +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assertEquals, assert } from "./test_util.ts"; - -unitTest(function eventInitializedWithType(): void { - 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); -}); - -unitTest(function eventInitializedWithTypeAndDict(): void { - 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); -}); - -unitTest(function eventComposedPathSuccess(): void { - const type = "click"; - const event = new Event(type); - const composedPath = event.composedPath(); - - assertEquals(composedPath, []); -}); - -unitTest(function eventStopPropagationSuccess(): void { - const type = "click"; - const event = new Event(type); - - assertEquals(event.cancelBubble, false); - event.stopPropagation(); - assertEquals(event.cancelBubble, true); -}); - -unitTest(function eventStopImmediatePropagationSuccess(): void { - const type = "click"; - const event = new Event(type); - - assertEquals(event.cancelBubble, false); - assertEquals(event.cancelBubbleImmediately, false); - event.stopImmediatePropagation(); - assertEquals(event.cancelBubble, true); - assertEquals(event.cancelBubbleImmediately, true); -}); - -unitTest(function eventPreventDefaultSuccess(): void { - 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); -}); - -unitTest(function eventInitializedWithNonStringType(): void { - // eslint-disable-next-line @typescript-eslint/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); -}); - -// ref https://github.com/web-platform-tests/wpt/blob/master/dom/events/Event-isTrusted.any.js -unitTest(function eventIsTrusted(): void { - const desc1 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted"); - assert(desc1); - assertEquals(typeof desc1.get, "function"); - - const desc2 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted"); - assert(desc2); - assertEquals(typeof desc2!.get, "function"); - - assertEquals(desc1!.get, desc2!.get); -}); diff --git a/cli/js/fetch_test.ts b/cli/js/fetch_test.ts deleted file mode 100644 index 5ebef92d9..000000000 --- a/cli/js/fetch_test.ts +++ /dev/null @@ -1,497 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { - unitTest, - assert, - assertEquals, - assertStrContains, - assertThrows, - fail -} from "./test_util.ts"; - -unitTest({ perms: { net: true } }, async function fetchProtocolError(): Promise< - void -> { - let err; - try { - await fetch("file:///"); - } catch (err_) { - err = err_; - } - assert(err instanceof TypeError); - assertStrContains(err.message, "not supported"); -}); - -unitTest( - { perms: { net: true } }, - async function fetchConnectionError(): Promise { - let err; - try { - await fetch("http://localhost:4000"); - } catch (err_) { - err = err_; - } - assert(err instanceof Deno.errors.Http); - assertStrContains(err.message, "error trying to connect"); - } -); - -unitTest({ perms: { net: true } }, async function fetchJsonSuccess(): Promise< - void -> { - const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); - const json = await response.json(); - assertEquals(json.name, "deno"); -}); - -unitTest(async function fetchPerm(): Promise { - let err; - try { - await fetch("http://localhost:4545/cli/tests/fixture.json"); - } catch (err_) { - err = err_; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest({ perms: { net: true } }, async function fetchUrl(): Promise { - const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); - assertEquals(response.url, "http://localhost:4545/cli/tests/fixture.json"); - response.body.close(); -}); - -unitTest({ perms: { net: true } }, async function fetchURL(): Promise { - const response = await fetch( - new URL("http://localhost:4545/cli/tests/fixture.json") - ); - assertEquals(response.url, "http://localhost:4545/cli/tests/fixture.json"); - response.body.close(); -}); - -unitTest({ perms: { net: true } }, async function fetchHeaders(): Promise< - void -> { - const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); - const headers = response.headers; - assertEquals(headers.get("Content-Type"), "application/json"); - assert(headers.get("Server")!.startsWith("SimpleHTTP")); - response.body.close(); -}); - -unitTest({ perms: { net: true } }, async function fetchBlob(): Promise { - const response = await fetch("http://localhost:4545/cli/tests/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"))); -}); - -unitTest({ perms: { net: true } }, async function fetchBodyUsed(): Promise< - void -> { - const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); - assertEquals(response.bodyUsed, false); - assertThrows((): void => { - // Assigning to read-only property throws in the strict mode. - response.bodyUsed = true; - }); - await response.blob(); - assertEquals(response.bodyUsed, true); -}); - -unitTest({ perms: { net: true } }, async function fetchAsyncIterator(): Promise< - void -> { - const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); - const headers = response.headers; - let total = 0; - for await (const chunk of response.body) { - total += chunk.length; - } - - assertEquals(total, Number(headers.get("Content-Length"))); - response.body.close(); -}); - -unitTest({ perms: { net: true } }, async function responseClone(): Promise< - void -> { - const response = await fetch("http://localhost:4545/cli/tests/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]); - } -}); - -unitTest({ perms: { net: true } }, async function fetchEmptyInvalid(): Promise< - void -> { - let err; - try { - await fetch(""); - } catch (err_) { - err = err_; - } - assert(err instanceof URIError); -}); - -unitTest( - { perms: { net: true } }, - async function fetchMultipartFormDataSuccess(): Promise { - const response = await fetch( - "http://localhost:4545/cli/tests/subdir/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")); - /* TODO(ry) Re-enable this test once we bring back the global File type. - const file = formData.get("field_2") as File; - assertEquals(file.name, "file.js"); - */ - // Currently we cannot read from file... - } -); - -unitTest( - { perms: { net: true } }, - async function fetchURLEncodedFormDataSuccess(): Promise { - const response = await fetch( - "http://localhost:4545/cli/tests/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(), ""); - } -); - -unitTest( - { - // TODO(bartlomieju): leaking resources - skip: true, - perms: { net: true } - }, - async function fetchWithRedirection(): Promise { - const response = await fetch("http://localhost:4546/"); // will redirect to http://localhost:4545/ - assertEquals(response.status, 200); - assertEquals(response.statusText, "OK"); - assertEquals(response.url, "http://localhost:4545/"); - const body = await response.text(); - assert(body.includes("Directory listing for /")); - } -); - -unitTest( - { - // TODO: leaking resources - skip: true, - perms: { net: true } - }, - async function fetchWithRelativeRedirection(): Promise { - const response = await fetch("http://localhost:4545/cli/tests"); // will redirect to /cli/tests/ - assertEquals(response.status, 200); - assertEquals(response.statusText, "OK"); - const body = await response.text(); - assert(body.includes("Directory listing for /cli/tests/")); - } -); - -// The feature below is not implemented, but the test should work after implementation -/* -unitTest({ perms: { net: true} }, async function fetchWithInfRedirection(): Promise< - void -> { - const response = await fetch("http://localhost:4549/cli/tests"); // will redirect to the same place - assertEquals(response.status, 0); // network error -}); -*/ - -unitTest( - { perms: { net: true } }, - async function fetchInitStringBody(): Promise { - 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")); - } -); - -unitTest( - { perms: { net: true } }, - async function fetchRequestInitStringBody(): Promise { - 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); - } -); - -unitTest( - { perms: { net: true } }, - async function fetchInitTypedArrayBody(): Promise { - 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); - } -); - -unitTest( - { perms: { net: true } }, - async function fetchInitURLSearchParamsBody(): Promise { - const data = "param1=value1¶m2=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") - ); - } -); - -unitTest({ perms: { net: true } }, async function fetchInitBlobBody(): Promise< - void -> { - 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")); -}); - -unitTest({ perms: { net: true } }, async function fetchUserAgent(): Promise< - void -> { - 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(); -}); - -// TODO(ry) The following tests work but are flaky. There's a race condition -// somewhere. Here is what one of these flaky failures looks like: -// -// unitTest fetchPostBodyString_permW0N1E0R0 -// assertEquals failed. actual = expected = POST /blah HTTP/1.1 -// hello: World -// foo: Bar -// host: 127.0.0.1:4502 -// content-length: 11 -// hello world -// Error: actual: expected: POST /blah HTTP/1.1 -// hello: World -// foo: Bar -// host: 127.0.0.1:4502 -// content-length: 11 -// hello world -// at Object.assertEquals (file:///C:/deno/js/testing/util.ts:29:11) -// at fetchPostBodyString (file - -/* -function bufferServer(addr: string): Deno.Buffer { - const listener = Deno.listen(addr); - const buf = new Deno.Buffer(); - listener.accept().then(async conn => { - 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; -} - -unitTest({ perms: { net: true} }, async function fetchRequest():Promise { - const addr = "127.0.0.1:4501"; - const buf = bufferServer(addr); - const response = await fetch(`http://${addr}/blah`, { - method: "POST", - headers: [["Hello", "World"], ["Foo", "Bar"]] - }); - assertEquals(response.status, 404); - assertEquals(response.headers.get("Content-Length"), "2"); - - const actual = new TextDecoder().decode(buf.bytes()); - const expected = [ - "POST /blah HTTP/1.1\r\n", - "hello: World\r\n", - "foo: Bar\r\n", - `host: ${addr}\r\n\r\n` - ].join(""); - assertEquals(actual, expected); -}); - -unitTest({ perms: { net: true} }, async function fetchPostBodyString():Promise { - const addr = "127.0.0.1:4502"; - const buf = bufferServer(addr); - const body = "hello world"; - const response = await fetch(`http://${addr}/blah`, { - method: "POST", - headers: [["Hello", "World"], ["Foo", "Bar"]], - body - }); - assertEquals(response.status, 404); - assertEquals(response.headers.get("Content-Length"), "2"); - - const actual = new TextDecoder().decode(buf.bytes()); - const expected = [ - "POST /blah HTTP/1.1\r\n", - "hello: World\r\n", - "foo: Bar\r\n", - `host: ${addr}\r\n`, - `content-length: ${body.length}\r\n\r\n`, - body - ].join(""); - assertEquals(actual, expected); -}); - -unitTest({ perms: { net: true} }, async function fetchPostBodyTypedArray():Promise { - const addr = "127.0.0.1:4503"; - const buf = 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 - }); - assertEquals(response.status, 404); - assertEquals(response.headers.get("Content-Length"), "2"); - - const actual = new TextDecoder().decode(buf.bytes()); - const expected = [ - "POST /blah HTTP/1.1\r\n", - "hello: World\r\n", - "foo: Bar\r\n", - `host: ${addr}\r\n`, - `content-length: ${body.byteLength}\r\n\r\n`, - bodyStr - ].join(""); - assertEquals(actual, expected); -}); -*/ - -unitTest( - { - // TODO: leaking resources - skip: true, - perms: { net: true } - }, - async function fetchWithManualRedirection(): Promise { - const response = await fetch("http://localhost:4546/", { - redirect: "manual" - }); // will redirect to http://localhost:4545/ - assertEquals(response.status, 0); - assertEquals(response.statusText, ""); - assertEquals(response.url, ""); - assertEquals(response.type, "opaqueredirect"); - try { - await response.text(); - fail( - "Reponse.text() didn't throw on a filtered response without a body (type opaqueredirect)" - ); - } catch (e) { - return; - } - } -); - -unitTest( - { - // TODO: leaking resources - skip: true, - perms: { net: true } - }, - async function fetchWithErrorRedirection(): Promise { - const response = await fetch("http://localhost:4546/", { - redirect: "error" - }); // will redirect to http://localhost:4545/ - assertEquals(response.status, 0); - assertEquals(response.statusText, ""); - assertEquals(response.url, ""); - assertEquals(response.type, "error"); - try { - await response.text(); - fail( - "Reponse.text() didn't throw on a filtered response without a body (type error)" - ); - } catch (e) { - return; - } - } -); - -unitTest(function responseRedirect(): void { - const response = new Response( - "example.com/beforeredirect", - 200, - "OK", - [["This-Should", "Disappear"]], - -1, - false, - null - ); - const redir = response.redirect("example.com/newLocation", 301); - assertEquals(redir.status, 301); - assertEquals(redir.statusText, ""); - assertEquals(redir.url, ""); - assertEquals(redir.headers.get("Location"), "example.com/newLocation"); - assertEquals(redir.type, "default"); -}); - -unitTest(function responseConstructionHeaderRemoval(): void { - const res = new Response( - "example.com", - 200, - "OK", - [["Set-Cookie", "mysessionid"]], - -1, - false, - "basic", - null - ); - assert(res.headers.get("Set-Cookie") != "mysessionid"); -}); diff --git a/cli/js/file_test.ts b/cli/js/file_test.ts deleted file mode 100644 index 1a7a5f88b..000000000 --- a/cli/js/file_test.ts +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function testFirstArgument(arg1: any[], expectedSize: number): void { - const file = new File(arg1, "name"); - assert(file instanceof File); - assertEquals(file.name, "name"); - assertEquals(file.size, expectedSize); - assertEquals(file.type, ""); -} - -unitTest(function fileEmptyFileBits(): void { - testFirstArgument([], 0); -}); - -unitTest(function fileStringFileBits(): void { - testFirstArgument(["bits"], 4); -}); - -unitTest(function fileUnicodeStringFileBits(): void { - testFirstArgument(["𝓽𝓮𝔁𝓽"], 16); -}); - -unitTest(function fileStringObjectFileBits(): void { - testFirstArgument([new String("string object")], 13); -}); - -unitTest(function fileEmptyBlobFileBits(): void { - testFirstArgument([new Blob()], 0); -}); - -unitTest(function fileBlobFileBits(): void { - testFirstArgument([new Blob(["bits"])], 4); -}); - -unitTest(function fileEmptyFileFileBits(): void { - testFirstArgument([new File([], "world.txt")], 0); -}); - -unitTest(function fileFileFileBits(): void { - testFirstArgument([new File(["bits"], "world.txt")], 4); -}); - -unitTest(function fileArrayBufferFileBits(): void { - testFirstArgument([new ArrayBuffer(8)], 8); -}); - -unitTest(function fileTypedArrayFileBits(): void { - testFirstArgument([new Uint8Array([0x50, 0x41, 0x53, 0x53])], 4); -}); - -unitTest(function fileVariousFileBits(): void { - testFirstArgument( - [ - "bits", - new Blob(["bits"]), - new Blob(), - new Uint8Array([0x50, 0x41]), - new Uint16Array([0x5353]), - new Uint32Array([0x53534150]) - ], - 16 - ); -}); - -unitTest(function fileNumberInFileBits(): void { - testFirstArgument([12], 2); -}); - -unitTest(function fileArrayInFileBits(): void { - testFirstArgument([[1, 2, 3]], 5); -}); - -unitTest(function fileObjectInFileBits(): void { - // "[object Object]" - testFirstArgument([{}], 15); -}); - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function testSecondArgument(arg2: any, expectedFileName: string): void { - const file = new File(["bits"], arg2); - assert(file instanceof File); - assertEquals(file.name, expectedFileName); -} - -unitTest(function fileUsingFileName(): void { - testSecondArgument("dummy", "dummy"); -}); - -unitTest(function fileUsingSpecialCharacterInFileName(): void { - testSecondArgument("dummy/foo", "dummy:foo"); -}); - -unitTest(function fileUsingNullFileName(): void { - testSecondArgument(null, "null"); -}); - -unitTest(function fileUsingNumberFileName(): void { - testSecondArgument(1, "1"); -}); - -unitTest(function fileUsingEmptyStringFileName(): void { - testSecondArgument("", ""); -}); diff --git a/cli/js/files_test.ts b/cli/js/files_test.ts deleted file mode 100644 index 49fecabe0..000000000 --- a/cli/js/files_test.ts +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { - unitTest, - assert, - assertEquals, - assertStrContains -} from "./test_util.ts"; - -unitTest(function filesStdioFileDescriptors(): void { - assertEquals(Deno.stdin.rid, 0); - assertEquals(Deno.stdout.rid, 1); - assertEquals(Deno.stderr.rid, 2); -}); - -unitTest({ perms: { read: true } }, async function filesCopyToStdout(): Promise< - void -> { - const filename = "cli/tests/fixture.json"; - const file = await Deno.open(filename); - assert(file.rid > 2); - const bytesWritten = await Deno.copy(Deno.stdout, file); - const fileSize = Deno.statSync(filename).len; - assertEquals(bytesWritten, fileSize); - console.log("bytes written", bytesWritten); - file.close(); -}); - -unitTest( - { perms: { read: true } }, - async function filesToAsyncIterator(): Promise { - const filename = "cli/tests/hello.txt"; - const file = await Deno.open(filename); - - let totalSize = 0; - for await (const buf of Deno.toAsyncIterator(file)) { - totalSize += buf.byteLength; - } - - assertEquals(totalSize, 12); - file.close(); - } -); - -unitTest(async function readerToAsyncIterator(): Promise { - // ref: https://github.com/denoland/deno/issues/2330 - const encoder = new TextEncoder(); - - class TestReader implements Deno.Reader { - private offset = 0; - private buf = new Uint8Array(encoder.encode(this.s)); - - constructor(private readonly s: string) {} - - async read(p: Uint8Array): Promise { - 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 Deno.EOF; - } - - return n; - } - } - - const reader = new TestReader("hello world!"); - - let totalSize = 0; - for await (const buf of Deno.toAsyncIterator(reader)) { - totalSize += buf.byteLength; - } - - assertEquals(totalSize, 12); -}); - -unitTest( - { perms: { write: false } }, - async function writePermFailure(): Promise { - const filename = "tests/hello.txt"; - const writeModes: Deno.OpenMode[] = ["w", "a", "x"]; - for (const mode of writeModes) { - let err; - try { - await Deno.open(filename, mode); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } - } -); - -unitTest(async function openOptions(): Promise { - const filename = "cli/tests/fixture.json"; - let err; - try { - await Deno.open(filename, { write: false }); - } catch (e) { - err = e; - } - assert(!!err); - assertStrContains( - err.message, - "OpenOptions requires at least one option to be true" - ); - - try { - await Deno.open(filename, { truncate: true, write: false }); - } catch (e) { - err = e; - } - assert(!!err); - assertStrContains(err.message, "'truncate' option requires 'write' option"); - - try { - await Deno.open(filename, { create: true, write: false }); - } catch (e) { - err = e; - } - assert(!!err); - assertStrContains( - err.message, - "'create' or 'createNew' options require 'write' or 'append' option" - ); - - try { - await Deno.open(filename, { createNew: true, append: false }); - } catch (e) { - err = e; - } - assert(!!err); - assertStrContains( - err.message, - "'create' or 'createNew' options require 'write' or 'append' option" - ); -}); - -unitTest({ perms: { read: false } }, async function readPermFailure(): Promise< - void -> { - let caughtError = false; - try { - await Deno.open("package.json", "r"); - await Deno.open("cli/tests/fixture.json", "r"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest( - { perms: { write: true } }, - async function writeNullBufferFailure(): Promise { - const tempDir = Deno.makeTempDirSync(); - const filename = tempDir + "hello.txt"; - const w = { - write: true, - truncate: true, - create: true - }; - const file = await Deno.open(filename, w); - - // writing null should throw an error - let err; - try { - // @ts-ignore - await file.write(null); - } catch (e) { - err = e; - } - // TODO: Check error kind when dispatch_minimal pipes errors properly - assert(!!err); - - file.close(); - await Deno.remove(tempDir, { recursive: true }); - } -); - -unitTest( - { perms: { write: true, read: true } }, - async function readNullBufferFailure(): Promise { - const tempDir = Deno.makeTempDirSync(); - const filename = tempDir + "hello.txt"; - const file = await Deno.open(filename, "w+"); - - // 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 - let err; - try { - // @ts-ignore - await file.read(null); - } catch (e) { - err = e; - } - // TODO: Check error kind when dispatch_minimal pipes errors properly - assert(!!err); - - file.close(); - await Deno.remove(tempDir, { recursive: true }); - } -); - -unitTest( - { perms: { write: false, read: false } }, - async function readWritePermFailure(): Promise { - const filename = "tests/hello.txt"; - const writeModes: Deno.OpenMode[] = ["r+", "w+", "a+", "x+"]; - for (const mode of writeModes) { - let err; - try { - await Deno.open(filename, mode); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function createFile(): Promise { - 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.len === 0); - const enc = new TextEncoder(); - const data = enc.encode("Hello"); - await f.write(data); - fileInfo = Deno.statSync(filename); - assert(fileInfo.len === 5); - f.close(); - - // TODO: test different modes - await Deno.remove(tempDir, { recursive: true }); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function openModeWrite(): Promise { - 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, "w"); - // assert file was created - let fileInfo = Deno.statSync(filename); - assert(fileInfo.isFile()); - assertEquals(fileInfo.len, 0); - // write some data - await file.write(data); - fileInfo = Deno.statSync(filename); - assertEquals(fileInfo.len, 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, "w"); - file.close(); - const fileSize = Deno.statSync(filename).len; - assertEquals(fileSize, 0); - await Deno.remove(tempDir, { recursive: true }); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function openModeWriteRead(): Promise { - const tempDir = Deno.makeTempDirSync(); - const encoder = new TextEncoder(); - const filename = tempDir + "hello.txt"; - const data = encoder.encode("Hello world!\n"); - - const file = await Deno.open(filename, "w+"); - const seekPosition = 0; - // assert file was created - let fileInfo = Deno.statSync(filename); - assert(fileInfo.isFile()); - assertEquals(fileInfo.len, 0); - // write some data - await file.write(data); - fileInfo = Deno.statSync(filename); - assertEquals(fileInfo.len, 13); - - const buf = new Uint8Array(20); - // seeking from beginning of a file - const cursorPosition = await file.seek( - seekPosition, - Deno.SeekMode.SEEK_START - ); - assertEquals(seekPosition, cursorPosition); - const result = await file.read(buf); - assertEquals(result, 13); - file.close(); - - await Deno.remove(tempDir, { recursive: true }); - } -); - -unitTest({ perms: { read: true } }, async function seekStart(): Promise { - const filename = "cli/tests/hello.txt"; - const 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.SEEK_START - ); - assertEquals(seekPosition, cursorPosition); - const buf = new Uint8Array(6); - await file.read(buf); - const decoded = new TextDecoder().decode(buf); - assertEquals(decoded, "world!"); - file.close(); -}); - -unitTest({ perms: { read: true } }, function seekSyncStart(): void { - const filename = "cli/tests/hello.txt"; - const 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.SEEK_START); - assertEquals(seekPosition, cursorPosition); - const buf = new Uint8Array(6); - file.readSync(buf); - const decoded = new TextDecoder().decode(buf); - assertEquals(decoded, "world!"); - file.close(); -}); - -unitTest({ perms: { read: true } }, async function seekCurrent(): Promise< - void -> { - const filename = "cli/tests/hello.txt"; - const 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.SEEK_CURRENT - ); - assertEquals(seekPosition + 1, cursorPosition); - const buf = new Uint8Array(6); - await file.read(buf); - const decoded = new TextDecoder().decode(buf); - assertEquals(decoded, "world!"); - file.close(); -}); - -unitTest({ perms: { read: true } }, function seekSyncCurrent(): void { - const filename = "cli/tests/hello.txt"; - const 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.SEEK_CURRENT - ); - assertEquals(seekPosition + 1, cursorPosition); - const buf = new Uint8Array(6); - file.readSync(buf); - const decoded = new TextDecoder().decode(buf); - assertEquals(decoded, "world!"); - file.close(); -}); - -unitTest({ perms: { read: true } }, async function seekEnd(): Promise { - const filename = "cli/tests/hello.txt"; - const 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.SEEK_END); - assertEquals(6, cursorPosition); - const buf = new Uint8Array(6); - await file.read(buf); - const decoded = new TextDecoder().decode(buf); - assertEquals(decoded, "world!"); - file.close(); -}); - -unitTest({ perms: { read: true } }, function seekSyncEnd(): void { - const filename = "cli/tests/hello.txt"; - const 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.SEEK_END); - assertEquals(6, cursorPosition); - const buf = new Uint8Array(6); - file.readSync(buf); - const decoded = new TextDecoder().decode(buf); - assertEquals(decoded, "world!"); - file.close(); -}); - -unitTest({ perms: { read: true } }, async function seekMode(): Promise { - const filename = "cli/tests/hello.txt"; - const file = await Deno.open(filename); - let err; - try { - await file.seek(1, -1); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof TypeError); - assertStrContains(err.message, "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"); - file.close(); -}); diff --git a/cli/js/form_data_test.ts b/cli/js/form_data_test.ts deleted file mode 100644 index 9b218547c..000000000 --- a/cli/js/form_data_test.ts +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest(function formDataHasCorrectNameProp(): void { - assertEquals(FormData.name, "FormData"); -}); - -unitTest(function formDataParamsAppendSuccess(): void { - const formData = new FormData(); - formData.append("a", "true"); - assertEquals(formData.get("a"), "true"); -}); - -unitTest(function formDataParamsDeleteSuccess(): void { - const formData = new FormData(); - formData.append("a", "true"); - formData.append("b", "false"); - assertEquals(formData.get("b"), "false"); - formData.delete("b"); - assertEquals(formData.get("a"), "true"); - assertEquals(formData.get("b"), null); -}); - -unitTest(function formDataParamsGetAllSuccess(): void { - const formData = new FormData(); - formData.append("a", "true"); - formData.append("b", "false"); - formData.append("a", "null"); - assertEquals(formData.getAll("a"), ["true", "null"]); - assertEquals(formData.getAll("b"), ["false"]); - assertEquals(formData.getAll("c"), []); -}); - -unitTest(function formDataParamsGetSuccess(): void { - const formData = new FormData(); - formData.append("a", "true"); - formData.append("b", "false"); - formData.append("a", "null"); - // @ts-ignore - formData.append("d", undefined); - // @ts-ignore - formData.append("e", null); - assertEquals(formData.get("a"), "true"); - assertEquals(formData.get("b"), "false"); - assertEquals(formData.get("c"), null); - assertEquals(formData.get("d"), "undefined"); - assertEquals(formData.get("e"), "null"); -}); - -unitTest(function formDataParamsHasSuccess(): void { - const formData = new FormData(); - formData.append("a", "true"); - formData.append("b", "false"); - assert(formData.has("a")); - assert(formData.has("b")); - assert(!formData.has("c")); -}); - -unitTest(function formDataParamsSetSuccess(): void { - const formData = new FormData(); - formData.append("a", "true"); - formData.append("b", "false"); - formData.append("a", "null"); - assertEquals(formData.getAll("a"), ["true", "null"]); - assertEquals(formData.getAll("b"), ["false"]); - formData.set("a", "false"); - assertEquals(formData.getAll("a"), ["false"]); - // @ts-ignore - formData.set("d", undefined); - assertEquals(formData.get("d"), "undefined"); - // @ts-ignore - formData.set("e", null); - assertEquals(formData.get("e"), "null"); -}); - -unitTest(function formDataSetEmptyBlobSuccess(): void { - const formData = new FormData(); - formData.set("a", new Blob([]), "blank.txt"); - formData.get("a"); - /* TODO Fix this test. - assert(file instanceof File); - if (typeof file !== "string") { - assertEquals(file.name, "blank.txt"); - } - */ -}); - -unitTest(function formDataParamsForEachSuccess(): void { - const init = [ - ["a", "54"], - ["b", "true"] - ]; - const formData = new FormData(); - for (const [name, value] of init) { - formData.append(name, value); - } - let callNum = 0; - formData.forEach((value, key, parent): void => { - assertEquals(formData, parent); - assertEquals(value, init[callNum][1]); - assertEquals(key, init[callNum][0]); - callNum++; - }); - assertEquals(callNum, init.length); -}); - -unitTest(function formDataParamsArgumentsCheck(): void { - const methodRequireOneParam = [ - "delete", - "getAll", - "get", - "has", - "forEach" - ] as const; - - const methodRequireTwoParams = ["append", "set"] as const; - - methodRequireOneParam.forEach((method): void => { - const formData = new FormData(); - let hasThrown = 0; - let errMsg = ""; - try { - // @ts-ignore - formData[method](); - hasThrown = 1; - } catch (err) { - errMsg = err.message; - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); - assertEquals( - errMsg, - `FormData.${method} requires at least 1 argument, but only 0 present` - ); - }); - - methodRequireTwoParams.forEach((method: string): void => { - const formData = new FormData(); - let hasThrown = 0; - let errMsg = ""; - - try { - // @ts-ignore - formData[method](); - hasThrown = 1; - } catch (err) { - errMsg = err.message; - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); - assertEquals( - errMsg, - `FormData.${method} requires at least 2 arguments, but only 0 present` - ); - - hasThrown = 0; - errMsg = ""; - try { - // @ts-ignore - formData[method]("foo"); - hasThrown = 1; - } catch (err) { - errMsg = err.message; - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); - assertEquals( - errMsg, - `FormData.${method} requires at least 2 arguments, but only 1 present` - ); - }); -}); - -unitTest(function toStringShouldBeWebCompatibility(): void { - const formData = new FormData(); - assertEquals(formData.toString(), "[object FormData]"); -}); diff --git a/cli/js/format_error_test.ts b/cli/js/format_error_test.ts deleted file mode 100644 index 9831ef160..000000000 --- a/cli/js/format_error_test.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { assert, unitTest } from "./test_util.ts"; - -unitTest(function formatDiagnosticBasic() { - const fixture: Deno.DiagnosticItem[] = [ - { - message: "Example error", - category: Deno.DiagnosticCategory.Error, - sourceLine: "abcdefghijklmnopqrstuv", - lineNumber: 1000, - scriptResourceName: "foo.ts", - startColumn: 1, - endColumn: 2, - code: 4000 - } - ]; - const out = Deno.formatDiagnostics(fixture); - assert(out.includes("Example error")); - assert(out.includes("foo.ts")); -}); - -unitTest(function formatDiagnosticError() { - let thrown = false; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const bad = ([{ hello: 123 }] as any) as Deno.DiagnosticItem[]; - try { - Deno.formatDiagnostics(bad); - } catch (e) { - assert(e instanceof TypeError); - thrown = true; - } - assert(thrown); -}); - -if (import.meta.main) { - Deno.runTests(); -} diff --git a/cli/js/fs_events_test.ts b/cli/js/fs_events_test.ts deleted file mode 100644 index b1697971a..000000000 --- a/cli/js/fs_events_test.ts +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -// TODO(ry) Add more tests to specify format. - -unitTest({ perms: { read: false } }, function fsEventsPermissions() { - let thrown = false; - try { - Deno.fsEvents("."); - } catch (err) { - assert(err instanceof Deno.errors.PermissionDenied); - thrown = true; - } - assert(thrown); -}); - -async function getTwoEvents( - iter: AsyncIterableIterator -): Promise { - const events = []; - for await (const event of iter) { - events.push(event); - if (events.length > 2) break; - } - return events; -} - -unitTest( - { perms: { read: true, write: true } }, - async function fsEventsBasic(): Promise { - const testDir = await Deno.makeTempDir(); - const iter = Deno.fsEvents(testDir); - - // Asynchornously 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)); - } -); diff --git a/cli/js/get_random_values_test.ts b/cli/js/get_random_values_test.ts deleted file mode 100644 index 76fa732ea..000000000 --- a/cli/js/get_random_values_test.ts +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assertNotEquals, assertStrictEq } from "./test_util.ts"; - -unitTest(function getRandomValuesInt8Array(): void { - const arr = new Int8Array(32); - crypto.getRandomValues(arr); - assertNotEquals(arr, new Int8Array(32)); -}); - -unitTest(function getRandomValuesUint8Array(): void { - const arr = new Uint8Array(32); - crypto.getRandomValues(arr); - assertNotEquals(arr, new Uint8Array(32)); -}); - -unitTest(function getRandomValuesUint8ClampedArray(): void { - const arr = new Uint8ClampedArray(32); - crypto.getRandomValues(arr); - assertNotEquals(arr, new Uint8ClampedArray(32)); -}); - -unitTest(function getRandomValuesInt16Array(): void { - const arr = new Int16Array(4); - crypto.getRandomValues(arr); - assertNotEquals(arr, new Int16Array(4)); -}); - -unitTest(function getRandomValuesUint16Array(): void { - const arr = new Uint16Array(4); - crypto.getRandomValues(arr); - assertNotEquals(arr, new Uint16Array(4)); -}); - -unitTest(function getRandomValuesInt32Array(): void { - const arr = new Int32Array(8); - crypto.getRandomValues(arr); - assertNotEquals(arr, new Int32Array(8)); -}); - -unitTest(function getRandomValuesUint32Array(): void { - const arr = new Uint32Array(8); - crypto.getRandomValues(arr); - assertNotEquals(arr, new Uint32Array(8)); -}); - -unitTest(function getRandomValuesReturnValue(): void { - const arr = new Uint32Array(8); - const rtn = crypto.getRandomValues(arr); - assertNotEquals(arr, new Uint32Array(8)); - assertStrictEq(rtn, arr); -}); diff --git a/cli/js/globals_test.ts b/cli/js/globals_test.ts deleted file mode 100644 index aa8b4f46e..000000000 --- a/cli/js/globals_test.ts +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -unitTest(function globalThisExists(): void { - assert(globalThis != null); -}); - -unitTest(function windowExists(): void { - assert(window != null); -}); - -unitTest(function selfExists(): void { - assert(self != null); -}); - -unitTest(function windowWindowExists(): void { - assert(window.window === window); -}); - -unitTest(function windowSelfExists(): void { - assert(window.self === window); -}); - -unitTest(function globalThisEqualsWindow(): void { - assert(globalThis === window); -}); - -unitTest(function globalThisEqualsSelf(): void { - assert(globalThis === self); -}); - -unitTest(function DenoNamespaceExists(): void { - assert(Deno != null); -}); - -unitTest(function DenoNamespaceEqualsWindowDeno(): void { - assert(Deno === window.Deno); -}); - -unitTest(function DenoNamespaceIsFrozen(): void { - assert(Object.isFrozen(Deno)); -}); - -unitTest(function webAssemblyExists(): void { - assert(typeof WebAssembly.compile === "function"); -}); - -unitTest(function DenoNamespaceImmutable(): void { - const denoCopy = window.Deno; - try { - // @ts-ignore - Deno = 1; - } catch {} - assert(denoCopy === Deno); - try { - // @ts-ignore - window.Deno = 1; - } catch {} - assert(denoCopy === Deno); - try { - delete window.Deno; - } catch {} - assert(denoCopy === Deno); - - const { readFile } = Deno; - try { - // @ts-ignore - Deno.readFile = 1; - } catch {} - assert(readFile === Deno.readFile); - try { - delete window.Deno.readFile; - } catch {} - assert(readFile === Deno.readFile); - - // @ts-ignore - const { print } = Deno.core; - try { - // @ts-ignore - Deno.core.print = 1; - } catch {} - // @ts-ignore - assert(print === Deno.core.print); - try { - // @ts-ignore - delete Deno.core.print; - } catch {} - // @ts-ignore - assert(print === Deno.core.print); -}); - -unitTest(async function windowQueueMicrotask(): Promise { - let resolve1: () => void | undefined; - let resolve2: () => void | undefined; - let microtaskDone = false; - const p1 = new Promise((res): void => { - resolve1 = (): void => { - microtaskDone = true; - res(); - }; - }); - const p2 = new Promise((res): void => { - resolve2 = (): void => { - assert(microtaskDone); - res(); - }; - }); - window.queueMicrotask(resolve1!); - setTimeout(resolve2!, 0); - await p1; - await p2; -}); diff --git a/cli/js/headers_test.ts b/cli/js/headers_test.ts deleted file mode 100644 index fcb5385a5..000000000 --- a/cli/js/headers_test.ts +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; -const { - stringifyArgs - // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol -} = Deno[Deno.symbols.internal]; - -// 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 -unitTest(function newHeaderTest(): void { - new Headers(); - new Headers(undefined); - new Headers({}); - try { - // @ts-ignore - new Headers(null); - } catch (e) { - assertEquals( - e.message, - "Failed to construct 'Headers'; The provided value was not valid" - ); - } -}); - -const headerDict: Record = { - name1: "value1", - name2: "value2", - name3: "value3", - // @ts-ignore - name4: undefined, - "Content-Type": "value4" -}; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const headerSeq: any[] = []; -for (const name in headerDict) { - headerSeq.push([name, headerDict[name]]); -} - -unitTest(function newHeaderWithSequence(): void { - const headers = new Headers(headerSeq); - for (const name in headerDict) { - assertEquals(headers.get(name), String(headerDict[name])); - } - assertEquals(headers.get("length"), null); -}); - -unitTest(function newHeaderWithRecord(): void { - const headers = new Headers(headerDict); - for (const name in headerDict) { - assertEquals(headers.get(name), String(headerDict[name])); - } -}); - -unitTest(function newHeaderWithHeadersInstance(): void { - const headers = new Headers(headerDict); - const headers2 = new Headers(headers); - for (const name in headerDict) { - assertEquals(headers2.get(name), String(headerDict[name])); - } -}); - -unitTest(function headerAppendSuccess(): void { - const headers = new Headers(); - for (const name in headerDict) { - headers.append(name, headerDict[name]); - assertEquals(headers.get(name), String(headerDict[name])); - } -}); - -unitTest(function headerSetSuccess(): void { - const headers = new Headers(); - for (const name in headerDict) { - headers.set(name, headerDict[name]); - assertEquals(headers.get(name), String(headerDict[name])); - } -}); - -unitTest(function headerHasSuccess(): void { - const headers = new Headers(headerDict); - for (const name in headerDict) { - assert(headers.has(name), "headers has name " + name); - assert( - !headers.has("nameNotInHeaders"), - "headers do not have header: nameNotInHeaders" - ); - } -}); - -unitTest(function headerDeleteSuccess(): void { - const headers = new Headers(headerDict); - for (const name in 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); - } -}); - -unitTest(function headerGetSuccess(): void { - const headers = new Headers(headerDict); - for (const name in headerDict) { - assertEquals(headers.get(name), String(headerDict[name])); - assertEquals(headers.get("nameNotInHeaders"), null); - } -}); - -unitTest(function headerEntriesSuccess(): void { - 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)); - } -}); - -unitTest(function headerKeysSuccess(): void { - const headers = new Headers(headerDict); - const iterators = headers.keys(); - for (const it of iterators) { - assert(headers.has(it)); - } -}); - -unitTest(function headerValuesSuccess(): void { - 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 = { - name1: "value1", - Name2: "value2", - name: "value3", - "content-Type": "value4", - "Content-Typ": "value5", - "Content-Types": "value6" -}; - -unitTest(function headerForEachSuccess(): void { - const headers = new Headers(headerEntriesDict); - const keys = Object.keys(headerEntriesDict); - keys.forEach((key): void => { - const value = headerEntriesDict[key]; - const newkey = key.toLowerCase(); - headerEntriesDict[newkey] = value; - }); - let callNum = 0; - headers.forEach((value, key, container): void => { - assertEquals(headers, container); - assertEquals(value, headerEntriesDict[key]); - callNum++; - }); - assertEquals(callNum, keys.length); -}); - -unitTest(function headerSymbolIteratorSuccess(): void { - 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)); - } -}); - -unitTest(function headerTypesAvailable(): void { - 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. -unitTest(function headerIllegalReject(): void { - 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. -unitTest(function headerParamsShouldThrowTypeError(): void { - 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); -}); - -unitTest(function headerParamsArgumentsCheck(): void { - const methodRequireOneParam = ["delete", "get", "has", "forEach"]; - - const methodRequireTwoParams = ["append", "set"]; - - methodRequireOneParam.forEach((method): void => { - const headers = new Headers(); - let hasThrown = 0; - let errMsg = ""; - try { - // @ts-ignore - headers[method](); - hasThrown = 1; - } catch (err) { - errMsg = err.message; - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); - assertEquals( - errMsg, - `Headers.${method} requires at least 1 argument, but only 0 present` - ); - }); - - methodRequireTwoParams.forEach((method): void => { - const headers = new Headers(); - let hasThrown = 0; - let errMsg = ""; - - try { - // @ts-ignore - headers[method](); - hasThrown = 1; - } catch (err) { - errMsg = err.message; - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); - assertEquals( - errMsg, - `Headers.${method} requires at least 2 arguments, but only 0 present` - ); - - hasThrown = 0; - errMsg = ""; - try { - // @ts-ignore - headers[method]("foo"); - hasThrown = 1; - } catch (err) { - errMsg = err.message; - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); - assertEquals( - errMsg, - `Headers.${method} requires at least 2 arguments, but only 1 present` - ); - }); -}); - -unitTest(function toStringShouldBeWebCompatibility(): void { - const headers = new Headers(); - assertEquals(headers.toString(), "[object Headers]"); -}); - -function stringify(...args: unknown[]): string { - return stringifyArgs(args).replace(/\n$/, ""); -} - -unitTest(function customInspectReturnsCorrectHeadersFormat(): void { - 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-type: application/json, content-length: 1337 }" - ); -}); diff --git a/cli/js/internals_test.ts b/cli/js/internals_test.ts deleted file mode 100644 index fb712707c..000000000 --- a/cli/js/internals_test.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -unitTest(function internalsExists(): void { - const { - stringifyArgs - // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol - } = Deno[Deno.symbols.internal]; - assert(!!stringifyArgs); -}); diff --git a/cli/js/link_test.ts b/cli/js/link_test.ts deleted file mode 100644 index e9f72ebef..000000000 --- a/cli/js/link_test.ts +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest( - { perms: { read: true, write: true } }, - function linkSyncSuccess(): void { - 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 = new TextDecoder().decode(Deno.readFileSync(newName)); - assertEquals(oldData, newData); - // Writing to newname also affects oldname. - const newData2 = "Modified"; - Deno.writeFileSync(newName, new TextEncoder().encode(newData2)); - assertEquals( - newData2, - new TextDecoder().decode(Deno.readFileSync(oldName)) - ); - // Writing to oldname also affects newname. - const newData3 = "ModifiedAgain"; - Deno.writeFileSync(oldName, new TextEncoder().encode(newData3)); - assertEquals( - newData3, - new TextDecoder().decode(Deno.readFileSync(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, - new TextDecoder().decode(Deno.readFileSync(newName)) - ); - } -); - -unitTest( - { perms: { read: true, write: true } }, - function linkSyncExists(): void { - 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")); - - let err; - try { - Deno.linkSync(oldName, newName); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Deno.errors.AlreadyExists); - } -); - -unitTest( - { perms: { read: true, write: true } }, - function linkSyncNotFound(): void { - const testDir = Deno.makeTempDirSync(); - const oldName = testDir + "/oldname"; - const newName = testDir + "/newname"; - - let err; - try { - Deno.linkSync(oldName, newName); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { read: false, write: true } }, - function linkSyncReadPerm(): void { - let err; - try { - Deno.linkSync("oldbaddir", "newbaddir"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } -); - -unitTest( - { perms: { read: true, write: false } }, - function linkSyncWritePerm(): void { - let err; - try { - Deno.linkSync("oldbaddir", "newbaddir"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function linkSuccess(): Promise { - 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 = new TextDecoder().decode(Deno.readFileSync(newName)); - assertEquals(oldData, newData); - // Writing to newname also affects oldname. - const newData2 = "Modified"; - Deno.writeFileSync(newName, new TextEncoder().encode(newData2)); - assertEquals( - newData2, - new TextDecoder().decode(Deno.readFileSync(oldName)) - ); - // Writing to oldname also affects newname. - const newData3 = "ModifiedAgain"; - Deno.writeFileSync(oldName, new TextEncoder().encode(newData3)); - assertEquals( - newData3, - new TextDecoder().decode(Deno.readFileSync(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, - new TextDecoder().decode(Deno.readFileSync(newName)) - ); - } -); diff --git a/cli/js/location_test.ts b/cli/js/location_test.ts deleted file mode 100644 index 78ecb55b3..000000000 --- a/cli/js/location_test.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -unitTest(function locationBasic(): void { - // location example: file:///Users/rld/src/deno/js/unit_tests.ts - assert(window.location.toString().endsWith("unit_tests.ts")); -}); diff --git a/cli/js/make_temp_test.ts b/cli/js/make_temp_test.ts deleted file mode 100644 index 9804a7043..000000000 --- a/cli/js/make_temp_test.ts +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest({ perms: { write: true } }, function makeTempDirSyncSuccess(): void { - 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. - let err; - try { - Deno.makeTempDirSync({ dir: "/baddir" }); - } catch (err_) { - err = err_; - } - assert(err instanceof Deno.errors.NotFound); -}); - -unitTest(function makeTempDirSyncPerm(): void { - // makeTempDirSync should require write permissions (for now). - let err; - try { - Deno.makeTempDirSync({ dir: "/baddir" }); - } catch (err_) { - err = err_; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest( - { perms: { write: true } }, - async function makeTempDirSuccess(): Promise { - 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. - let err; - try { - await Deno.makeTempDir({ dir: "/baddir" }); - } catch (err_) { - err = err_; - } - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest({ perms: { write: true } }, function makeTempFileSyncSuccess(): void { - 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. - let err; - try { - Deno.makeTempFileSync({ dir: "/baddir" }); - } catch (err_) { - err = err_; - } - assert(err instanceof Deno.errors.NotFound); -}); - -unitTest(function makeTempFileSyncPerm(): void { - // makeTempFileSync should require write permissions (for now). - let err; - try { - Deno.makeTempFileSync({ dir: "/baddir" }); - } catch (err_) { - err = err_; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest( - { perms: { write: true } }, - async function makeTempFileSuccess(): Promise { - 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. - let err; - try { - await Deno.makeTempFile({ dir: "/baddir" }); - } catch (err_) { - err = err_; - } - assert(err instanceof Deno.errors.NotFound); - } -); diff --git a/cli/js/metrics_test.ts b/cli/js/metrics_test.ts deleted file mode 100644 index 9b7d83887..000000000 --- a/cli/js/metrics_test.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -unitTest(async function metrics(): Promise { - const m1 = Deno.metrics(); - assert(m1.opsDispatched > 0); - assert(m1.opsDispatchedSync > 0); - assert(m1.opsCompleted > 0); - assert(m1.opsCompletedSync > 0); - assert(m1.bytesSentControl > 0); - assert(m1.bytesSentData >= 0); - assert(m1.bytesReceived > 0); - - // Write to stdout to ensure a "data" message gets sent instead of just - // control messages. - const dataMsg = new Uint8Array([13, 13, 13]); // "\r\r\r", - await Deno.stdout.write(dataMsg); - - const m2 = Deno.metrics(); - assert(m2.opsDispatched > m1.opsDispatched); - assert(m2.opsDispatchedSync > m1.opsDispatchedSync); - assert(m2.opsDispatchedAsync > m1.opsDispatchedAsync); - assert(m2.opsCompleted > m1.opsCompleted); - assert(m2.opsCompletedSync > m1.opsCompletedSync); - assert(m2.opsCompletedAsync > m1.opsCompletedAsync); - assert(m2.bytesSentControl > m1.bytesSentControl); - assert(m2.bytesSentData >= m1.bytesSentData + dataMsg.byteLength); - assert(m2.bytesReceived > m1.bytesReceived); -}); - -unitTest( - { perms: { write: true } }, - function metricsUpdatedIfNoResponseSync(): void { - const filename = Deno.makeTempDirSync() + "/test.txt"; - - const data = new Uint8Array([41, 42, 43]); - Deno.writeFileSync(filename, data, { mode: 0o666 }); - - const metrics = Deno.metrics(); - assert(metrics.opsDispatched === metrics.opsCompleted); - assert(metrics.opsDispatchedSync === metrics.opsCompletedSync); - } -); - -unitTest( - { perms: { write: true } }, - async function metricsUpdatedIfNoResponseAsync(): Promise { - const filename = Deno.makeTempDirSync() + "/test.txt"; - - const data = new Uint8Array([41, 42, 43]); - await Deno.writeFile(filename, data, { mode: 0o666 }); - - const metrics = Deno.metrics(); - assert(metrics.opsDispatched === metrics.opsCompleted); - assert(metrics.opsDispatchedSync === metrics.opsCompletedSync); - assert(metrics.opsDispatchedAsync === metrics.opsCompletedAsync); - } -); diff --git a/cli/js/mixins/dom_iterable_test.ts b/cli/js/mixins/dom_iterable_test.ts deleted file mode 100644 index a1b8b5699..000000000 --- a/cli/js/mixins/dom_iterable_test.ts +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "../test_util.ts"; - -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -function setup() { - const dataSymbol = Symbol("data symbol"); - class Base { - private [dataSymbol] = new Map(); - - constructor( - data: Array<[string, number]> | IterableIterator<[string, number]> - ) { - for (const [key, value] of data) { - this[dataSymbol].set(key, value); - } - } - } - - return { - Base, - // This is using an internal API we don't want published as types, so having - // to cast to any to "trick" TypeScript - // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol - DomIterable: Deno[Deno.symbols.internal].DomIterableMixin(Base, dataSymbol) - }; -} - -unitTest(function testDomIterable(): void { - const { DomIterable, Base } = setup(); - - const fixture: Array<[string, number]> = [ - ["foo", 1], - ["bar", 2] - ]; - - const domIterable = new DomIterable(fixture); - - assertEquals(Array.from(domIterable.entries()), fixture); - assertEquals(Array.from(domIterable.values()), [1, 2]); - assertEquals(Array.from(domIterable.keys()), ["foo", "bar"]); - - let result: Array<[string, number]> = []; - for (const [key, value] of domIterable) { - assert(key != null); - assert(value != null); - result.push([key, value]); - } - assertEquals(fixture, result); - - result = []; - const scope = {}; - function callback( - this: typeof scope, - value: number, - key: string, - parent: typeof domIterable - ): void { - assertEquals(parent, domIterable); - assert(key != null); - assert(value != null); - assert(this === scope); - result.push([key, value]); - } - domIterable.forEach(callback, scope); - assertEquals(fixture, result); - - assertEquals(DomIterable.name, Base.name); -}); - -unitTest(function testDomIterableScope(): void { - const { DomIterable } = setup(); - - const domIterable = new DomIterable([["foo", 1]]); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function checkScope(thisArg: any, expected: any): void { - function callback(this: typeof thisArg): void { - assertEquals(this, expected); - } - domIterable.forEach(callback, thisArg); - } - - checkScope(0, Object(0)); - checkScope("", Object("")); - checkScope(null, window); - checkScope(undefined, window); -}); diff --git a/cli/js/mkdir_test.ts b/cli/js/mkdir_test.ts deleted file mode 100644 index 2921177eb..000000000 --- a/cli/js/mkdir_test.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest( - { perms: { read: true, write: true } }, - function mkdirSyncSuccess(): void { - const path = Deno.makeTempDirSync() + "/dir"; - Deno.mkdirSync(path); - const pathInfo = Deno.statSync(path); - assert(pathInfo.isDirectory()); - } -); - -unitTest( - { perms: { read: true, write: true } }, - function mkdirSyncMode(): void { - const path = Deno.makeTempDirSync() + "/dir"; - Deno.mkdirSync(path, { mode: 0o755 }); // no perm for x - const pathInfo = Deno.statSync(path); - if (pathInfo.mode !== null) { - // Skip windows - assertEquals(pathInfo.mode & 0o777, 0o755); - } - } -); - -unitTest({ perms: { write: false } }, function mkdirSyncPerm(): void { - let err; - try { - Deno.mkdirSync("/baddir"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest( - { perms: { read: true, write: true } }, - async function mkdirSuccess(): Promise { - const path = Deno.makeTempDirSync() + "/dir"; - await Deno.mkdir(path); - const pathInfo = Deno.statSync(path); - assert(pathInfo.isDirectory()); - } -); - -unitTest({ perms: { write: true } }, function mkdirErrIfExists(): void { - let err; - try { - Deno.mkdirSync("."); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.AlreadyExists); -}); - -unitTest( - { perms: { read: true, write: true } }, - function mkdirSyncRecursive(): void { - const path = Deno.makeTempDirSync() + "/nested/directory"; - Deno.mkdirSync(path, { recursive: true }); - const pathInfo = Deno.statSync(path); - assert(pathInfo.isDirectory()); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function mkdirRecursive(): Promise { - const path = Deno.makeTempDirSync() + "/nested/directory"; - await Deno.mkdir(path, { recursive: true }); - const pathInfo = Deno.statSync(path); - assert(pathInfo.isDirectory()); - } -); diff --git a/cli/js/net_test.ts b/cli/js/net_test.ts deleted file mode 100644 index 46543acdf..000000000 --- a/cli/js/net_test.ts +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest({ perms: { net: true } }, function netTcpListenClose(): void { - const listener = Deno.listen({ hostname: "127.0.0.1", port: 4500 }); - assertEquals(listener.addr.transport, "tcp"); - assertEquals(listener.addr.hostname, "127.0.0.1"); - assertEquals(listener.addr.port, 4500); - listener.close(); -}); - -unitTest( - { - perms: { net: true }, - // TODO: - skip: Deno.build.os === "win" - }, - function netUdpListenClose(): void { - const socket = Deno.listen({ - hostname: "127.0.0.1", - port: 4500, - transport: "udp" - }); - assertEquals(socket.addr.transport, "udp"); - assertEquals(socket.addr.hostname, "127.0.0.1"); - assertEquals(socket.addr.port, 4500); - socket.close(); - } -); - -unitTest( - { - perms: { net: true } - }, - async function netTcpCloseWhileAccept(): Promise { - const listener = Deno.listen({ port: 4501 }); - const p = listener.accept(); - listener.close(); - let err; - try { - await p; - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Error); - assertEquals(err.message, "Listener has been closed"); - } -); - -unitTest( - { perms: { net: true } }, - async function netTcpConcurrentAccept(): Promise { - const listener = Deno.listen({ port: 4502 }); - let acceptErrCount = 0; - const checkErr = (e: Error): void => { - 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); - } -); - -unitTest({ perms: { net: true } }, async function netTcpDialListen(): Promise< - void -> { - const listener = Deno.listen({ port: 4500 }); - listener.accept().then( - async (conn): Promise => { - assert(conn.remoteAddr != null); - assertEquals(conn.localAddr.hostname, "127.0.0.1"); - assertEquals(conn.localAddr.port, 4500); - await conn.write(new Uint8Array([1, 2, 3])); - conn.close(); - } - ); - const conn = await Deno.connect({ hostname: "127.0.0.1", port: 4500 }); - assertEquals(conn.remoteAddr.hostname, "127.0.0.1"); - assertEquals(conn.remoteAddr.port, 4500); - 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 !== Deno.EOF); - - const readResult2 = await conn.read(buf); - assertEquals(Deno.EOF, readResult2); - - listener.close(); - conn.close(); -}); - -unitTest( - { skip: Deno.build.os === "win", perms: { net: true } }, - async function netUdpSendReceive(): Promise { - const alice = Deno.listen({ port: 4500, transport: "udp" }); - assertEquals(alice.addr.port, 4500); - assertEquals(alice.addr.hostname, "0.0.0.0"); - assertEquals(alice.addr.transport, "udp"); - - const bob = Deno.listen({ port: 4501, transport: "udp" }); - assertEquals(bob.addr.port, 4501); - assertEquals(bob.addr.hostname, "0.0.0.0"); - assertEquals(bob.addr.transport, "udp"); - - const sent = new Uint8Array([1, 2, 3]); - await alice.send(sent, bob.addr); - - const [recvd, remote] = await bob.receive(); - assertEquals(remote.port, 4500); - assertEquals(recvd.length, 3); - assertEquals(1, recvd[0]); - assertEquals(2, recvd[1]); - assertEquals(3, recvd[2]); - alice.close(); - bob.close(); - } -); - -unitTest( - { perms: { net: true } }, - async function netTcpListenCloseWhileIterating(): Promise { - const listener = Deno.listen({ port: 8000 }); - 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 }); - } -); - -unitTest( - { skip: Deno.build.os === "win", perms: { net: true } }, - async function netUdpListenCloseWhileIterating(): Promise { - const socket = Deno.listen({ 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 }); - } -); - -/* TODO(ry) Re-enable this test. -unitTest({ perms: { net: true } }, async function netListenAsyncIterator(): Promise { - const listener = Deno.listen(":4500"); - const runAsyncIterator = async (): Promise => { - for await (let conn of listener) { - await conn.write(new Uint8Array([1, 2, 3])); - conn.close(); - } - }; - runAsyncIterator(); - const conn = await Deno.connect("127.0.0.1:4500"); - 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 !== Deno.EOF); - - const readResult2 = await conn.read(buf); - assertEquals(Deno.EOF, readResult2); - - listener.close(); - conn.close(); -}); - */ - -/* TODO Fix broken test. -unitTest({ perms: { net: true } }, async function netCloseReadSuccess() { - const addr = "127.0.0.1:4500"; - const listener = Deno.listen(addr); - const closeDeferred = deferred(); - const closeReadDeferred = deferred(); - listener.accept().then(async conn => { - await closeReadDeferred.promise; - await conn.write(new Uint8Array([1, 2, 3])); - const buf = new Uint8Array(1024); - const readResult = await conn.read(buf); - assertEquals(3, readResult); - assertEquals(4, buf[0]); - assertEquals(5, buf[1]); - assertEquals(6, buf[2]); - conn.close(); - closeDeferred.resolve(); - }); - const conn = await Deno.connect(addr); - conn.closeRead(); // closing read - closeReadDeferred.resolve(); - const buf = new Uint8Array(1024); - const readResult = await conn.read(buf); - assertEquals(Deno.EOF, readResult); // with immediate EOF - // Ensure closeRead does not impact write - await conn.write(new Uint8Array([4, 5, 6])); - await closeDeferred.promise; - listener.close(); - conn.close(); -}); -*/ - -/* TODO Fix broken test. -unitTest({ perms: { net: true } }, async function netDoubleCloseRead() { - const addr = "127.0.0.1:4500"; - const listener = Deno.listen(addr); - const closeDeferred = deferred(); - listener.accept().then(async conn => { - await conn.write(new Uint8Array([1, 2, 3])); - await closeDeferred.promise; - conn.close(); - }); - const conn = await Deno.connect(addr); - conn.closeRead(); // closing read - let err; - try { - // Duplicated close should throw error - conn.closeRead(); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Deno.errors.NotConnected); - closeDeferred.resolve(); - listener.close(); - conn.close(); -}); -*/ - -/* TODO Fix broken test. -unitTest({ perms: { net: true } }, async function netCloseWriteSuccess() { - const addr = "127.0.0.1:4500"; - const listener = Deno.listen(addr); - const closeDeferred = deferred(); - listener.accept().then(async conn => { - await conn.write(new Uint8Array([1, 2, 3])); - await closeDeferred.promise; - 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]); - // Check write should be closed - let err; - try { - await conn.write(new Uint8Array([1, 2, 3])); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Deno.errors.BrokenPipe); - closeDeferred.resolve(); - listener.close(); - conn.close(); -}); -*/ - -/* TODO Fix broken test. -unitTest({ perms: { net: true } }, async function netDoubleCloseWrite() { - const addr = "127.0.0.1:4500"; - const listener = Deno.listen(addr); - const closeDeferred = deferred(); - listener.accept().then(async conn => { - await closeDeferred.promise; - conn.close(); - }); - const conn = await Deno.connect(addr); - conn.closeWrite(); // closing write - let err; - try { - // Duplicated close should throw error - conn.closeWrite(); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof Deno.errors.NotConnected); - closeDeferred.resolve(); - listener.close(); - conn.close(); -}); -*/ diff --git a/cli/js/os_test.ts b/cli/js/os_test.ts deleted file mode 100644 index 0c851be51..000000000 --- a/cli/js/os_test.ts +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertEquals, - assertNotEquals, - assertThrows, - unitTest -} from "./test_util.ts"; - -unitTest({ perms: { env: true } }, function envSuccess(): void { - const env = Deno.env(); - assert(env !== null); - // eslint-disable-next-line @typescript-eslint/camelcase - env.test_var = "Hello World"; - const newEnv = Deno.env(); - assertEquals(env.test_var, newEnv.test_var); - assertEquals(Deno.env("test_var"), env.test_var); -}); - -unitTest({ perms: { env: true } }, function envNotFound(): void { - const r = Deno.env("env_var_does_not_exist!"); - assertEquals(r, undefined); -}); - -unitTest(function envPermissionDenied1(): void { - let err; - try { - Deno.env(); - } catch (e) { - err = e; - } - assertNotEquals(err, undefined); - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest(function envPermissionDenied2(): void { - let err; - try { - Deno.env("PATH"); - } catch (e) { - err = e; - } - assertNotEquals(err, undefined); - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "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(). -unitTest( - { skip: Deno.build.os !== "win", perms: { 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, - expectedEnv: Record - ): Promise => { - const src = ` - console.log( - ${JSON.stringify(Object.keys(expectedEnv))}.map(k => Deno.env(k)) - )`; - const proc = Deno.run({ - args: [Deno.execPath(), "eval", src], - env: inputEnv, - stdout: "piped" - }); - const status = await proc.status(); - assertEquals(status.success, true); - const expectedValues = Object.values(expectedEnv); - const actualValues = JSON.parse( - new TextDecoder().decode(await proc.output()) - ); - assertEquals(actualValues, expectedValues); - proc.close(); - }; - - assertEquals(Deno.env("path"), Deno.env("PATH")); - assertEquals(Deno.env("Path"), Deno.env("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" } - ); - } -); - -unitTest(function osPid(): void { - assert(Deno.pid > 0); -}); - -unitTest({ perms: { env: true } }, function getDir(): void { - type supportOS = "mac" | "win" | "linux"; - - interface Runtime { - os: supportOS; - shouldHaveValue: boolean; - } - - interface Scenes { - kind: Deno.DirKind; - runtime: Runtime[]; - } - - const scenes: Scenes[] = [ - { - kind: "config", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] - }, - { - kind: "cache", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] - }, - { - kind: "executable", - runtime: [ - { os: "mac", shouldHaveValue: false }, - { os: "win", shouldHaveValue: false }, - { os: "linux", shouldHaveValue: true } - ] - }, - { - kind: "data", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] - }, - { - kind: "data_local", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] - }, - { - kind: "audio", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] - }, - { - kind: "desktop", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] - }, - { - kind: "document", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] - }, - { - kind: "download", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] - }, - { - kind: "font", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: false }, - { os: "linux", shouldHaveValue: true } - ] - }, - { - kind: "picture", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] - }, - { - kind: "public", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] - }, - { - kind: "template", - runtime: [ - { os: "mac", shouldHaveValue: false }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] - }, - { - kind: "tmp", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: true } - ] - }, - { - kind: "video", - runtime: [ - { os: "mac", shouldHaveValue: true }, - { os: "win", shouldHaveValue: true }, - { os: "linux", shouldHaveValue: false } - ] - } - ]; - - for (const s of scenes) { - for (const r of s.runtime) { - if (Deno.build.os !== r.os) continue; - if (r.shouldHaveValue) { - const d = Deno.dir(s.kind); - assert(d); - assert(d.length > 0); - } - } - } -}); - -unitTest(function getDirWithoutPermission(): void { - assertThrows( - () => Deno.dir("home"), - Deno.errors.PermissionDenied, - `run again with the --allow-env flag` - ); -}); - -unitTest({ perms: { env: true } }, function execPath(): void { - assertNotEquals(Deno.execPath(), ""); -}); - -unitTest({ perms: { env: false } }, function execPathPerm(): void { - let caughtError = false; - try { - Deno.execPath(); - } catch (err) { - caughtError = true; - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } - assert(caughtError); -}); - -unitTest({ perms: { env: true } }, function loadavgSuccess(): void { - const load = Deno.loadavg(); - assertEquals(load.length, 3); -}); - -unitTest({ perms: { env: false } }, function loadavgPerm(): void { - let caughtError = false; - try { - Deno.loadavg(); - } catch (err) { - caughtError = true; - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } - assert(caughtError); -}); - -unitTest({ perms: { env: true } }, function hostnameDir(): void { - assertNotEquals(Deno.hostname(), ""); -}); - -unitTest({ perms: { env: false } }, function hostnamePerm(): void { - let caughtError = false; - try { - Deno.hostname(); - } catch (err) { - caughtError = true; - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } - assert(caughtError); -}); - -unitTest({ perms: { env: true } }, function releaseDir(): void { - assertNotEquals(Deno.osRelease(), ""); -}); - -unitTest({ perms: { env: false } }, function releasePerm(): void { - let caughtError = false; - try { - Deno.osRelease(); - } catch (err) { - caughtError = true; - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } - assert(caughtError); -}); diff --git a/cli/js/performance_test.ts b/cli/js/performance_test.ts deleted file mode 100644 index 89b7cad8b..000000000 --- a/cli/js/performance_test.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, createResolvable } from "./test_util.ts"; - -unitTest({ perms: { hrtime: false } }, async function performanceNow(): Promise< - void -> { - const resolvable = createResolvable(); - const start = performance.now(); - setTimeout((): void => { - const end = performance.now(); - assert(end - start >= 10); - resolvable.resolve(); - }, 10); - await resolvable; -}); diff --git a/cli/js/permissions_test.ts b/cli/js/permissions_test.ts deleted file mode 100644 index 7528768a1..000000000 --- a/cli/js/permissions_test.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -unitTest(async function permissionInvalidName(): Promise { - let thrown = false; - try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - await Deno.permissions.query({ name: "foo" as any }); - } catch (e) { - thrown = true; - assert(e instanceof Error); - } finally { - assert(thrown); - } -}); - -unitTest(async function permissionNetInvalidUrl(): Promise { - let thrown = false; - try { - await Deno.permissions.query({ name: "net", url: ":" }); - } catch (e) { - thrown = true; - assert(e instanceof URIError); - } finally { - assert(thrown); - } -}); diff --git a/cli/js/process_test.ts b/cli/js/process_test.ts deleted file mode 100644 index 2411b5134..000000000 --- a/cli/js/process_test.ts +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertEquals, - assertStrContains, - unitTest -} from "./test_util.ts"; -const { kill, run, readFile, open, makeTempDir, writeFile } = Deno; - -unitTest(function runPermissions(): void { - let caughtError = false; - try { - Deno.run({ args: ["python", "-c", "print('hello world')"] }); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { run: true } }, async function runSuccess(): Promise { - const p = run({ - args: ["python", "-c", "print('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(); -}); - -unitTest( - { perms: { run: true } }, - async function runCommandFailedWithCode(): Promise { - const p = run({ - args: ["python", "-c", "import sys;sys.exit(41 + 1)"] - }); - const status = await p.status(); - assertEquals(status.success, false); - assertEquals(status.code, 42); - assertEquals(status.signal, undefined); - p.close(); - } -); - -unitTest( - { - // No signals on windows. - skip: Deno.build.os === "win", - perms: { run: true } - }, - async function runCommandFailedWithSignal(): Promise { - const p = run({ - args: ["python", "-c", "import os;os.kill(os.getpid(), 9)"] - }); - const status = await p.status(); - assertEquals(status.success, false); - assertEquals(status.code, undefined); - assertEquals(status.signal, 9); - p.close(); - } -); - -unitTest({ perms: { run: true } }, function runNotFound(): void { - let error; - try { - run({ args: ["this file hopefully doesn't exist"] }); - } catch (e) { - error = e; - } - assert(error !== undefined); - assert(error instanceof Deno.errors.NotFound); -}); - -unitTest( - { perms: { write: true, run: true } }, - async function runWithCwdIsAsync(): Promise { - const enc = new TextEncoder(); - const cwd = await makeTempDir({ prefix: "deno_command_test" }); - - const exitCodeFile = "deno_was_here"; - const pyProgramFile = "poll_exit.py"; - const pyProgram = ` -from sys import exit -from time import sleep - -while True: - try: - with open("${exitCodeFile}", "r") as f: - line = f.readline() - code = int(line) - exit(code) - except IOError: - # Retry if we got here before deno wrote the file. - sleep(0.01) - pass -`; - - Deno.writeFileSync(`${cwd}/${pyProgramFile}.py`, enc.encode(pyProgram)); - const p = run({ - cwd, - args: ["python", `${pyProgramFile}.py`] - }); - - // Write the expected exit code *after* starting python. - // 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(); - } -); - -unitTest({ perms: { run: true } }, async function runStdinPiped(): Promise< - void -> { - const p = run({ - args: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"], - 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(); -}); - -unitTest({ perms: { run: true } }, async function runStdoutPiped(): Promise< - void -> { - const p = run({ - args: ["python", "-c", "import sys; sys.stdout.write('hello')"], - stdout: "piped" - }); - assert(!p.stdin); - assert(!p.stderr); - - const data = new Uint8Array(10); - let r = await p.stdout!.read(data); - if (r === Deno.EOF) { - throw new Error("p.stdout.read(...) should not be EOF"); - } - assertEquals(r, 5); - const s = new TextDecoder().decode(data.subarray(0, r)); - assertEquals(s, "hello"); - r = await p.stdout!.read(data); - assertEquals(r, Deno.EOF); - p.stdout!.close(); - - const status = await p.status(); - assertEquals(status.success, true); - assertEquals(status.code, 0); - assertEquals(status.signal, undefined); - p.close(); -}); - -unitTest({ perms: { run: true } }, async function runStderrPiped(): Promise< - void -> { - const p = run({ - args: ["python", "-c", "import sys; sys.stderr.write('hello')"], - stderr: "piped" - }); - assert(!p.stdin); - assert(!p.stdout); - - const data = new Uint8Array(10); - let r = await p.stderr!.read(data); - if (r === Deno.EOF) { - throw new Error("p.stderr.read should not return EOF here"); - } - assertEquals(r, 5); - const s = new TextDecoder().decode(data.subarray(0, r)); - assertEquals(s, "hello"); - r = await p.stderr!.read(data); - assertEquals(r, Deno.EOF); - p.stderr!.close(); - - const status = await p.status(); - assertEquals(status.success, true); - assertEquals(status.code, 0); - assertEquals(status.signal, undefined); - p.close(); -}); - -unitTest({ perms: { run: true } }, async function runOutput(): Promise { - const p = run({ - args: ["python", "-c", "import sys; sys.stdout.write('hello')"], - stdout: "piped" - }); - const output = await p.output(); - const s = new TextDecoder().decode(output); - assertEquals(s, "hello"); - p.close(); -}); - -unitTest({ perms: { run: true } }, async function runStderrOutput(): Promise< - void -> { - const p = run({ - args: ["python", "-c", "import sys; sys.stderr.write('error')"], - stderr: "piped" - }); - const error = await p.stderrOutput(); - const s = new TextDecoder().decode(error); - assertEquals(s, "error"); - p.close(); -}); - -unitTest( - { perms: { run: true, write: true, read: true } }, - async function runRedirectStdoutStderr(): Promise { - const tempDir = await makeTempDir(); - const fileName = tempDir + "/redirected_stdio.txt"; - const file = await open(fileName, "w"); - - const p = run({ - args: [ - "python", - "-c", - "import sys; sys.stderr.write('error\\n'); sys.stdout.write('output\\n');" - ], - stdout: file.rid, - stderr: file.rid - }); - - await p.status(); - p.close(); - file.close(); - - const fileContents = await readFile(fileName); - const decoder = new TextDecoder(); - const text = decoder.decode(fileContents); - - assertStrContains(text, "error"); - assertStrContains(text, "output"); - } -); - -unitTest( - { perms: { run: true, write: true, read: true } }, - async function runRedirectStdin(): Promise { - const tempDir = await makeTempDir(); - const fileName = tempDir + "/redirected_stdio.txt"; - const encoder = new TextEncoder(); - await writeFile(fileName, encoder.encode("hello")); - const file = await open(fileName, "r"); - - const p = run({ - args: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"], - stdin: file.rid - }); - - const status = await p.status(); - assertEquals(status.code, 0); - p.close(); - file.close(); - } -); - -unitTest({ perms: { run: true } }, async function runEnv(): Promise { - const p = run({ - args: [ - "python", - "-c", - "import os, sys; sys.stdout.write(os.environ.get('FOO', '') + os.environ.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(); -}); - -unitTest({ perms: { run: true } }, async function runClose(): Promise { - const p = run({ - args: [ - "python", - "-c", - "from time import sleep; import sys; sleep(10000); sys.stderr.write('error')" - ], - stderr: "piped" - }); - assert(!p.stdin); - assert(!p.stdout); - - p.close(); - - const data = new Uint8Array(10); - const r = await p.stderr!.read(data); - assertEquals(r, Deno.EOF); - p.stderr!.close(); -}); - -unitTest(function signalNumbers(): void { - if (Deno.build.os === "mac") { - assertEquals(Deno.Signal.SIGSTOP, 17); - } else if (Deno.build.os === "linux") { - assertEquals(Deno.Signal.SIGSTOP, 19); - } -}); - -// Ignore signal tests on windows for now... -if (Deno.build.os !== "win") { - unitTest(function killPermissions(): void { - let caughtError = false; - try { - // 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, Deno.Signal.SIGCONT); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); - }); - - unitTest({ perms: { run: true } }, async function killSuccess(): Promise< - void - > { - const p = run({ - args: ["python", "-c", "from time import sleep; sleep(10000)"] - }); - - assertEquals(Deno.Signal.SIGINT, 2); - kill(p.pid, Deno.Signal.SIGINT); - const status = await p.status(); - - assertEquals(status.success, false); - // TODO(ry) On Linux, status.code is sometimes undefined and sometimes 1. - // The following assert is causing this test to be flaky. Investigate and - // re-enable when it can be made deterministic. - // assertEquals(status.code, 1); - // assertEquals(status.signal, Deno.Signal.SIGINT); - p.close(); - }); - - unitTest({ perms: { run: true } }, async function killFailed(): Promise< - void - > { - const p = run({ - args: ["python", "-c", "from time import sleep; sleep(10000)"] - }); - assert(!p.stdin); - assert(!p.stdout); - - let err; - try { - kill(p.pid, 12345); - } catch (e) { - err = e; - } - - assert(!!err); - assert(err instanceof TypeError); - - p.close(); - }); -} diff --git a/cli/js/read_dir_test.ts b/cli/js/read_dir_test.ts deleted file mode 100644 index 95936c645..000000000 --- a/cli/js/read_dir_test.ts +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -type FileInfo = Deno.FileInfo; - -function assertSameContent(files: FileInfo[]): void { - let counter = 0; - - for (const file of files) { - if (file.name === "subdir") { - assert(file.isDirectory()); - counter++; - } - - if (file.name === "002_hello.ts") { - assertEquals(file.mode!, Deno.statSync(`cli/tests/${file.name}`).mode!); - counter++; - } - } - - assertEquals(counter, 2); -} - -unitTest({ perms: { read: true } }, function readdirSyncSuccess(): void { - const files = Deno.readdirSync("cli/tests/"); - assertSameContent(files); -}); - -unitTest({ perms: { read: false } }, function readdirSyncPerm(): void { - let caughtError = false; - try { - Deno.readdirSync("tests/"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, function readdirSyncNotDir(): void { - let caughtError = false; - let src; - - try { - src = Deno.readdirSync("cli/tests/fixture.json"); - } catch (err) { - caughtError = true; - assert(err instanceof Error); - } - assert(caughtError); - assertEquals(src, undefined); -}); - -unitTest({ perms: { read: true } }, function readdirSyncNotFound(): void { - let caughtError = false; - let src; - - try { - src = Deno.readdirSync("bad_dir_name"); - } catch (err) { - caughtError = true; - assert(err instanceof Deno.errors.NotFound); - } - assert(caughtError); - assertEquals(src, undefined); -}); - -unitTest({ perms: { read: true } }, async function readdirSuccess(): Promise< - void -> { - const files = await Deno.readdir("cli/tests/"); - assertSameContent(files); -}); - -unitTest({ perms: { read: false } }, async function readdirPerm(): Promise< - void -> { - let caughtError = false; - try { - await Deno.readdir("tests/"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); diff --git a/cli/js/read_file_test.ts b/cli/js/read_file_test.ts deleted file mode 100644 index 1b709b1f4..000000000 --- a/cli/js/read_file_test.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest({ perms: { read: true } }, function readFileSyncSuccess(): void { - const data = Deno.readFileSync("cli/tests/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"); -}); - -unitTest({ perms: { read: false } }, function readFileSyncPerm(): void { - let caughtError = false; - try { - Deno.readFileSync("cli/tests/fixture.json"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, function readFileSyncNotFound(): void { - let caughtError = false; - let data; - try { - data = Deno.readFileSync("bad_filename"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtError); - assert(data === undefined); -}); - -unitTest({ perms: { read: true } }, async function readFileSuccess(): Promise< - void -> { - const data = await Deno.readFile("cli/tests/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"); -}); - -unitTest({ perms: { read: false } }, async function readFilePerm(): Promise< - void -> { - let caughtError = false; - try { - await Deno.readFile("cli/tests/fixture.json"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); diff --git a/cli/js/read_link_test.ts b/cli/js/read_link_test.ts deleted file mode 100644 index 409f37110..000000000 --- a/cli/js/read_link_test.ts +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest( - { perms: { write: true, read: true } }, - function readlinkSyncSuccess(): void { - const testDir = Deno.makeTempDirSync(); - const target = testDir + "/target"; - const symlink = testDir + "/symln"; - Deno.mkdirSync(target); - // TODO Add test for Windows once symlink is implemented for Windows. - // See https://github.com/denoland/deno/issues/815. - if (Deno.build.os !== "win") { - Deno.symlinkSync(target, symlink); - const targetPath = Deno.readlinkSync(symlink); - assertEquals(targetPath, target); - } - } -); - -unitTest({ perms: { read: false } }, async function readlinkSyncPerm(): Promise< - void -> { - let caughtError = false; - try { - Deno.readlinkSync("/symlink"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, function readlinkSyncNotFound(): void { - let caughtError = false; - let data; - try { - data = Deno.readlinkSync("bad_filename"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtError); - assertEquals(data, undefined); -}); - -unitTest( - { perms: { write: true, read: true } }, - async function readlinkSuccess(): Promise { - const testDir = Deno.makeTempDirSync(); - const target = testDir + "/target"; - const symlink = testDir + "/symln"; - Deno.mkdirSync(target); - // TODO Add test for Windows once symlink is implemented for Windows. - // See https://github.com/denoland/deno/issues/815. - if (Deno.build.os !== "win") { - Deno.symlinkSync(target, symlink); - const targetPath = await Deno.readlink(symlink); - assertEquals(targetPath, target); - } - } -); - -unitTest({ perms: { read: false } }, async function readlinkPerm(): Promise< - void -> { - let caughtError = false; - try { - await Deno.readlink("/symlink"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); diff --git a/cli/js/realpath_test.ts b/cli/js/realpath_test.ts deleted file mode 100644 index cda7ddaf1..000000000 --- a/cli/js/realpath_test.ts +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -unitTest({ perms: { read: true } }, function realpathSyncSuccess(): void { - const incompletePath = "cli/tests/fixture.json"; - const realPath = Deno.realpathSync(incompletePath); - if (Deno.build.os !== "win") { - assert(realPath.startsWith("/")); - } else { - assert(/^[A-Z]/.test(realPath)); - } - assert(realPath.endsWith(incompletePath)); -}); - -unitTest( - { - skip: Deno.build.os === "win", - perms: { read: true, write: true } - }, - function realpathSyncSymlink(): void { - const testDir = Deno.makeTempDirSync(); - const target = testDir + "/target"; - const symlink = testDir + "/symln"; - Deno.mkdirSync(target); - Deno.symlinkSync(target, symlink); - const targetPath = Deno.realpathSync(symlink); - assert(targetPath.startsWith("/")); - assert(targetPath.endsWith("/target")); - } -); - -unitTest({ perms: { read: false } }, function realpathSyncPerm(): void { - let caughtError = false; - try { - Deno.realpathSync("some_file"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, function realpathSyncNotFound(): void { - let caughtError = false; - try { - Deno.realpathSync("bad_filename"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, async function realpathSuccess(): Promise< - void -> { - const incompletePath = "cli/tests/fixture.json"; - const realPath = await Deno.realpath(incompletePath); - if (Deno.build.os !== "win") { - assert(realPath.startsWith("/")); - } else { - assert(/^[A-Z]/.test(realPath)); - } - assert(realPath.endsWith(incompletePath)); -}); - -unitTest( - { - skip: Deno.build.os === "win", - perms: { read: true, write: true } - }, - async function realpathSymlink(): Promise { - const testDir = Deno.makeTempDirSync(); - const target = testDir + "/target"; - const symlink = testDir + "/symln"; - Deno.mkdirSync(target); - Deno.symlinkSync(target, symlink); - const targetPath = await Deno.realpath(symlink); - assert(targetPath.startsWith("/")); - assert(targetPath.endsWith("/target")); - } -); - -unitTest({ perms: { read: false } }, async function realpathPerm(): Promise< - void -> { - let caughtError = false; - try { - await Deno.realpath("some_file"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, async function realpathNotFound(): Promise< - void -> { - let caughtError = false; - try { - await Deno.realpath("bad_filename"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtError); -}); diff --git a/cli/js/remove_test.ts b/cli/js/remove_test.ts deleted file mode 100644 index fac5ba303..000000000 --- a/cli/js/remove_test.ts +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -// SYNC - -unitTest( - { perms: { write: true, read: true } }, - function removeSyncDirSuccess(): void { - // REMOVE EMPTY DIRECTORY - const path = Deno.makeTempDirSync() + "/subdir"; - Deno.mkdirSync(path); - const pathInfo = Deno.statSync(path); - assert(pathInfo.isDirectory()); // check exist first - Deno.removeSync(path); // remove - // We then check again after remove - let err; - try { - Deno.statSync(path); - } catch (e) { - err = e; - } - // Directory is gone - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { write: true, read: true } }, - function removeSyncFileSuccess(): void { - // 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 - Deno.removeSync(filename); // remove - // We then check again after remove - let err; - try { - Deno.statSync(filename); - } catch (e) { - err = e; - } - // File is gone - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { write: true, read: true } }, - function removeSyncFail(): void { - // 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 - let err; - try { - // Should not be able to recursively remove - Deno.removeSync(path); - } catch (e) { - err = e; - } - // TODO(ry) Is Other really the error we should get here? What would Go do? - assert(err instanceof Error); - // NON-EXISTENT DIRECTORY/FILE - try { - // Non-existent - Deno.removeSync("/baddir"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { write: true, read: true } }, - function removeSyncDanglingSymlinkSuccess(): void { - const danglingSymlinkPath = Deno.makeTempDirSync() + "/dangling_symlink"; - // TODO(#3832): Remove "Not Implemented" error checking when symlink creation is implemented for Windows - let errOnWindows; - try { - Deno.symlinkSync("unexistent_file", danglingSymlinkPath); - } catch (err) { - errOnWindows = err; - } - if (Deno.build.os === "win") { - assertEquals(errOnWindows.message, "Not implemented"); - } else { - const pathInfo = Deno.lstatSync(danglingSymlinkPath); - assert(pathInfo.isSymlink()); - Deno.removeSync(danglingSymlinkPath); - let err; - try { - Deno.lstatSync(danglingSymlinkPath); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); - } - } -); - -unitTest( - { perms: { write: true, read: true } }, - function removeSyncValidSymlinkSuccess(): void { - 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 }); - // TODO(#3832): Remove "Not Implemented" error checking when symlink creation is implemented for Windows - let errOnWindows; - try { - Deno.symlinkSync(filePath, validSymlinkPath); - } catch (err) { - errOnWindows = err; - } - if (Deno.build.os === "win") { - assertEquals(errOnWindows.message, "Not implemented"); - } else { - const symlinkPathInfo = Deno.statSync(validSymlinkPath); - assert(symlinkPathInfo.isFile()); - Deno.removeSync(validSymlinkPath); - let err; - try { - Deno.statSync(validSymlinkPath); - } catch (e) { - err = e; - } - Deno.removeSync(filePath); - assert(err instanceof Deno.errors.NotFound); - } - } -); - -unitTest({ perms: { write: false } }, function removeSyncPerm(): void { - let err; - try { - Deno.removeSync("/baddir"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest( - { perms: { write: true, read: true } }, - function removeAllSyncDirSuccess(): void { - // 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 - Deno.removeSync(path, { recursive: true }); // remove - // We then check again after remove - let err; - try { - Deno.statSync(path); - } catch (e) { - err = e; - } - // Directory is gone - assert(err instanceof 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 - Deno.removeSync(path, { recursive: true }); // remove - // We then check parent directory again after remove - try { - Deno.statSync(path); - } catch (e) { - err = e; - } - // Directory is gone - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { write: true, read: true } }, - function removeAllSyncFileSuccess(): void { - // 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 - Deno.removeSync(filename, { recursive: true }); // remove - // We then check again after remove - let err; - try { - Deno.statSync(filename); - } catch (e) { - err = e; - } - // File is gone - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest({ perms: { write: true } }, function removeAllSyncFail(): void { - // NON-EXISTENT DIRECTORY/FILE - let err; - try { - // Non-existent - Deno.removeSync("/baddir", { recursive: true }); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); -}); - -unitTest({ perms: { write: false } }, function removeAllSyncPerm(): void { - let err; - try { - Deno.removeSync("/baddir", { recursive: true }); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -// ASYNC - -unitTest( - { perms: { write: true, read: true } }, - async function removeDirSuccess(): Promise { - // REMOVE EMPTY DIRECTORY - const path = Deno.makeTempDirSync() + "/dir/subdir"; - Deno.mkdirSync(path, { recursive: true }); - const pathInfo = Deno.statSync(path); - assert(pathInfo.isDirectory()); // check exist first - await Deno.remove(path); // remove - // We then check again after remove - let err; - try { - Deno.statSync(path); - } catch (e) { - err = e; - } - // Directory is gone - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { write: true, read: true } }, - async function removeFileSuccess(): Promise { - // 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.remove(filename); // remove - // We then check again after remove - let err; - try { - Deno.statSync(filename); - } catch (e) { - err = e; - } - // File is gone - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { write: true, read: true } }, - async function removeFail(): Promise { - // 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 - let err; - try { - // Should not be able to recursively remove - await Deno.remove(path); - } catch (e) { - err = e; - } - assert(err instanceof Error); - // NON-EXISTENT DIRECTORY/FILE - try { - // Non-existent - await Deno.remove("/baddir"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { write: true, read: true } }, - async function removeDanglingSymlinkSuccess(): Promise { - const danglingSymlinkPath = Deno.makeTempDirSync() + "/dangling_symlink"; - // TODO(#3832): Remove "Not Implemented" error checking when symlink creation is implemented for Windows - let errOnWindows; - try { - Deno.symlinkSync("unexistent_file", danglingSymlinkPath); - } catch (e) { - errOnWindows = e; - } - if (Deno.build.os === "win") { - assertEquals(errOnWindows.message, "Not implemented"); - } else { - const pathInfo = Deno.lstatSync(danglingSymlinkPath); - assert(pathInfo.isSymlink()); - await Deno.remove(danglingSymlinkPath); - let err; - try { - Deno.lstatSync(danglingSymlinkPath); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); - } - } -); - -unitTest( - { perms: { write: true, read: true } }, - async function removeValidSymlinkSuccess(): Promise { - 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 }); - // TODO(#3832): Remove "Not Implemented" error checking when symlink creation is implemented for Windows - let errOnWindows; - try { - Deno.symlinkSync(filePath, validSymlinkPath); - } catch (e) { - errOnWindows = e; - } - if (Deno.build.os === "win") { - assertEquals(errOnWindows.message, "Not implemented"); - } else { - const symlinkPathInfo = Deno.statSync(validSymlinkPath); - assert(symlinkPathInfo.isFile()); - await Deno.remove(validSymlinkPath); - let err; - try { - Deno.statSync(validSymlinkPath); - } catch (e) { - err = e; - } - Deno.removeSync(filePath); - assert(err instanceof Deno.errors.NotFound); - } - } -); - -unitTest({ perms: { write: false } }, async function removePerm(): Promise< - void -> { - let err; - try { - await Deno.remove("/baddir"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest( - { perms: { write: true, read: true } }, - async function removeAllDirSuccess(): Promise { - // 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.remove(path, { recursive: true }); // remove - // We then check again after remove - let err; - try { - Deno.statSync(path); - } catch (e) { - err = e; - } - // Directory is gone - assert(err instanceof 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.remove(path, { recursive: true }); // remove - // We then check parent directory again after remove - try { - Deno.statSync(path); - } catch (e) { - err = e; - } - // Directory is gone - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { write: true, read: true } }, - async function removeAllFileSuccess(): Promise { - // 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.remove(filename, { recursive: true }); // remove - // We then check again after remove - let err; - try { - Deno.statSync(filename); - } catch (e) { - err = e; - } - // File is gone - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest({ perms: { write: true } }, async function removeAllFail(): Promise< - void -> { - // NON-EXISTENT DIRECTORY/FILE - let err; - try { - // Non-existent - await Deno.remove("/baddir", { recursive: true }); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); -}); - -unitTest({ perms: { write: false } }, async function removeAllPerm(): Promise< - void -> { - let err; - try { - await Deno.remove("/baddir", { recursive: true }); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); diff --git a/cli/js/rename_test.ts b/cli/js/rename_test.ts deleted file mode 100644 index 288f24bd7..000000000 --- a/cli/js/rename_test.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest( - { perms: { read: true, write: true } }, - function renameSyncSuccess(): void { - const testDir = Deno.makeTempDirSync(); - const oldpath = testDir + "/oldpath"; - const newpath = testDir + "/newpath"; - Deno.mkdirSync(oldpath); - Deno.renameSync(oldpath, newpath); - const newPathInfo = Deno.statSync(newpath); - assert(newPathInfo.isDirectory()); - - let caughtErr = false; - let oldPathInfo; - - try { - oldPathInfo = Deno.statSync(oldpath); - } catch (e) { - caughtErr = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtErr); - assertEquals(oldPathInfo, undefined); - } -); - -unitTest( - { perms: { read: false, write: true } }, - function renameSyncReadPerm(): void { - let err; - try { - const oldpath = "/oldbaddir"; - const newpath = "/newbaddir"; - Deno.renameSync(oldpath, newpath); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } -); - -unitTest( - { perms: { read: true, write: false } }, - function renameSyncWritePerm(): void { - let err; - try { - const oldpath = "/oldbaddir"; - const newpath = "/newbaddir"; - Deno.renameSync(oldpath, newpath); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function renameSuccess(): Promise { - const testDir = Deno.makeTempDirSync(); - const oldpath = testDir + "/oldpath"; - const newpath = testDir + "/newpath"; - Deno.mkdirSync(oldpath); - await Deno.rename(oldpath, newpath); - const newPathInfo = Deno.statSync(newpath); - assert(newPathInfo.isDirectory()); - - let caughtErr = false; - let oldPathInfo; - - try { - oldPathInfo = Deno.statSync(oldpath); - } catch (e) { - caughtErr = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtErr); - assertEquals(oldPathInfo, undefined); - } -); diff --git a/cli/js/request_test.ts b/cli/js/request_test.ts deleted file mode 100644 index 15e19e285..000000000 --- a/cli/js/request_test.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest(function fromInit(): void { - const req = new Request("https://example.com", { - body: "ahoyhoy", - method: "POST", - headers: { - "test-header": "value" - } - }); - - // @ts-ignore - assertEquals("ahoyhoy", req._bodySource); - assertEquals(req.url, "https://example.com"); - assertEquals(req.headers.get("test-header"), "value"); -}); - -unitTest(function fromRequest(): void { - const r = new Request("https://example.com"); - // @ts-ignore - r._bodySource = "ahoyhoy"; - r.headers.set("test-header", "value"); - - const req = new Request(r); - - // @ts-ignore - assertEquals(req._bodySource, r._bodySource); - assertEquals(req.url, r.url); - assertEquals(req.headers.get("test-header"), r.headers.get("test-header")); -}); - -unitTest(async function cloneRequestBodyStream(): Promise { - // hack to get a stream - const stream = new Request("", { body: "a test body" }).body; - const r1 = new Request("https://example.com", { - body: stream - }); - - const r2 = r1.clone(); - - const b1 = await r1.text(); - const b2 = await r2.text(); - - assertEquals(b1, b2); - - // @ts-ignore - assert(r1._bodySource !== r2._bodySource); -}); diff --git a/cli/js/resources_test.ts b/cli/js/resources_test.ts deleted file mode 100644 index 84b713a6d..000000000 --- a/cli/js/resources_test.ts +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assertEquals } from "./test_util.ts"; - -unitTest(function resourcesStdio(): void { - const res = Deno.resources(); - - assertEquals(res[0], "stdin"); - assertEquals(res[1], "stdout"); - assertEquals(res[2], "stderr"); -}); - -unitTest({ perms: { net: true } }, async function resourcesNet(): Promise< - void -> { - const listener = Deno.listen({ port: 4501 }); - const dialerConn = await Deno.connect({ port: 4501 }); - const listenerConn = await listener.accept(); - - const res = Deno.resources(); - assertEquals( - Object.values(res).filter((r): boolean => r === "tcpListener").length, - 1 - ); - assertEquals( - Object.values(res).filter((r): boolean => r === "tcpStream").length, - 2 - ); - - listenerConn.close(); - dialerConn.close(); - listener.close(); -}); - -unitTest({ perms: { read: true } }, async function resourcesFile(): Promise< - void -> { - const resourcesBefore = Deno.resources(); - const f = await Deno.open("cli/tests/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 !resourcesBefore.hasOwnProperty(rid); - })!; - assertEquals(resourcesAfter[newRid], "fsFile"); -}); diff --git a/cli/js/signal_test.ts b/cli/js/signal_test.ts deleted file mode 100644 index e1d00c669..000000000 --- a/cli/js/signal_test.ts +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { - unitTest, - assert, - assertEquals, - assertThrows, - createResolvable -} from "./test_util.ts"; - -function defer(n: number): Promise { - return new Promise((resolve: () => void, _) => { - setTimeout(resolve, n); - }); -} - -unitTest( - { skip: Deno.build.os !== "win" }, - async function signalsNotImplemented(): Promise { - assertThrows( - () => { - Deno.signal(1); - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.alarm(); // for SIGALRM - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.child(); // for SIGCHLD - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.hungup(); // for SIGHUP - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.interrupt(); // for SIGINT - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.io(); // for SIGIO - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.pipe(); // for SIGPIPE - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.quit(); // for SIGQUIT - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.terminate(); // for SIGTERM - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.userDefined1(); // for SIGUSR1 - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.userDefined2(); // for SIGURS2 - }, - Error, - "not implemented" - ); - assertThrows( - () => { - Deno.signals.windowChange(); // for SIGWINCH - }, - Error, - "not implemented" - ); - } -); - -unitTest( - { skip: Deno.build.os === "win", perms: { run: true, net: true } }, - async function signalStreamTest(): Promise { - const resolvable = createResolvable(); - // This prevents the program from exiting. - const t = setInterval(() => {}, 1000); - - let c = 0; - const sig = Deno.signal(Deno.Signal.SIGUSR1); - setTimeout(async () => { - await defer(20); - for (const _ of Array(3)) { - // Sends SIGUSR1 3 times. - Deno.kill(Deno.pid, Deno.Signal.SIGUSR1); - await defer(20); - } - sig.dispose(); - resolvable.resolve(); - }); - - for await (const _ of sig) { - c += 1; - } - - assertEquals(c, 3); - - clearInterval(t); - // Defer for a moment to allow async op from `setInterval` to resolve; - // for more explanation see `FIXME` in `cli/js/timers.ts::setGlobalTimeout` - await defer(20); - await resolvable; - } -); - -unitTest( - { skip: Deno.build.os === "win", perms: { run: true } }, - async function signalPromiseTest(): Promise { - const resolvable = createResolvable(); - // This prevents the program from exiting. - const t = setInterval(() => {}, 1000); - - const sig = Deno.signal(Deno.Signal.SIGUSR1); - setTimeout(() => { - Deno.kill(Deno.pid, Deno.Signal.SIGUSR1); - resolvable.resolve(); - }, 20); - await sig; - sig.dispose(); - - clearInterval(t); - // Defer for a moment to allow async op from `setInterval` to resolve; - // for more explanation see `FIXME` in `cli/js/timers.ts::setGlobalTimeout` - await defer(20); - await resolvable; - } -); - -unitTest( - { skip: Deno.build.os === "win", perms: { run: true } }, - async function signalShorthandsTest(): Promise { - let s: Deno.SignalStream; - s = Deno.signals.alarm(); // for SIGALRM - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.child(); // for SIGCHLD - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.hungup(); // for SIGHUP - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.interrupt(); // for SIGINT - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.io(); // for SIGIO - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.pipe(); // for SIGPIPE - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.quit(); // for SIGQUIT - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.terminate(); // for SIGTERM - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.userDefined1(); // for SIGUSR1 - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.userDefined2(); // for SIGURS2 - assert(s instanceof Deno.SignalStream); - s.dispose(); - s = Deno.signals.windowChange(); // for SIGWINCH - assert(s instanceof Deno.SignalStream); - s.dispose(); - } -); diff --git a/cli/js/stat_test.ts b/cli/js/stat_test.ts deleted file mode 100644 index 0a33901b7..000000000 --- a/cli/js/stat_test.ts +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -// TODO Add tests for modified, accessed, and created fields once there is a way -// to create temp files. -unitTest({ perms: { read: true } }, async function statSyncSuccess(): Promise< - void -> { - const packageInfo = Deno.statSync("README.md"); - assert(packageInfo.isFile()); - assert(!packageInfo.isSymlink()); - - const modulesInfo = Deno.statSync("cli/tests/symlink_to_subdir"); - assert(modulesInfo.isDirectory()); - assert(!modulesInfo.isSymlink()); - - const testsInfo = Deno.statSync("cli/tests"); - assert(testsInfo.isDirectory()); - assert(!testsInfo.isSymlink()); -}); - -unitTest({ perms: { read: false } }, async function statSyncPerm(): Promise< - void -> { - let caughtError = false; - try { - Deno.statSync("README.md"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, async function statSyncNotFound(): Promise< - void -> { - let caughtError = false; - let badInfo; - - try { - badInfo = Deno.statSync("bad_file_name"); - } catch (err) { - caughtError = true; - assert(err instanceof Deno.errors.NotFound); - } - - assert(caughtError); - assertEquals(badInfo, undefined); -}); - -unitTest({ perms: { read: true } }, async function lstatSyncSuccess(): Promise< - void -> { - const packageInfo = Deno.lstatSync("README.md"); - assert(packageInfo.isFile()); - assert(!packageInfo.isSymlink()); - - const modulesInfo = Deno.lstatSync("cli/tests/symlink_to_subdir"); - assert(!modulesInfo.isDirectory()); - assert(modulesInfo.isSymlink()); - - const coreInfo = Deno.lstatSync("core"); - assert(coreInfo.isDirectory()); - assert(!coreInfo.isSymlink()); -}); - -unitTest({ perms: { read: false } }, async function lstatSyncPerm(): Promise< - void -> { - let caughtError = false; - try { - Deno.lstatSync("README.md"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, async function lstatSyncNotFound(): Promise< - void -> { - let caughtError = false; - let badInfo; - - try { - badInfo = Deno.lstatSync("bad_file_name"); - } catch (err) { - caughtError = true; - assert(err instanceof Deno.errors.NotFound); - } - - assert(caughtError); - assertEquals(badInfo, undefined); -}); - -unitTest({ perms: { read: true } }, async function statSuccess(): Promise< - void -> { - const packageInfo = await Deno.stat("README.md"); - assert(packageInfo.isFile()); - assert(!packageInfo.isSymlink()); - - const modulesInfo = await Deno.stat("cli/tests/symlink_to_subdir"); - assert(modulesInfo.isDirectory()); - assert(!modulesInfo.isSymlink()); - - const testsInfo = await Deno.stat("cli/tests"); - assert(testsInfo.isDirectory()); - assert(!testsInfo.isSymlink()); -}); - -unitTest({ perms: { read: false } }, async function statPerm(): Promise { - let caughtError = false; - try { - await Deno.stat("README.md"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, async function statNotFound(): Promise< - void -> { - let caughtError = false; - let badInfo; - - try { - badInfo = await Deno.stat("bad_file_name"); - } catch (err) { - caughtError = true; - assert(err instanceof Deno.errors.NotFound); - } - - assert(caughtError); - assertEquals(badInfo, undefined); -}); - -unitTest({ perms: { read: true } }, async function lstatSuccess(): Promise< - void -> { - const packageInfo = await Deno.lstat("README.md"); - assert(packageInfo.isFile()); - assert(!packageInfo.isSymlink()); - - const modulesInfo = await Deno.lstat("cli/tests/symlink_to_subdir"); - assert(!modulesInfo.isDirectory()); - assert(modulesInfo.isSymlink()); - - const coreInfo = await Deno.lstat("core"); - assert(coreInfo.isDirectory()); - assert(!coreInfo.isSymlink()); -}); - -unitTest({ perms: { read: false } }, async function lstatPerm(): Promise { - let caughtError = false; - try { - await Deno.lstat("README.md"); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest({ perms: { read: true } }, async function lstatNotFound(): Promise< - void -> { - let caughtError = false; - let badInfo; - - try { - badInfo = await Deno.lstat("bad_file_name"); - } catch (err) { - caughtError = true; - assert(err instanceof Deno.errors.NotFound); - } - - assert(caughtError); - assertEquals(badInfo, undefined); -}); - -unitTest( - { skip: Deno.build.os !== "win", perms: { read: true, write: true } }, - async function statNoUnixFields(): Promise { - 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 === null); - 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); - } -); - -unitTest( - { skip: Deno.build.os === "win", perms: { read: true, write: true } }, - async function statUnixFields(): Promise { - 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); - } -); diff --git a/cli/js/symbols_test.ts b/cli/js/symbols_test.ts deleted file mode 100644 index ad05e9a70..000000000 --- a/cli/js/symbols_test.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -unitTest(function symbolsExists(): void { - assert("internal" in Deno.symbols); - assert("customInspect" in Deno.symbols); -}); diff --git a/cli/js/symlink_test.ts b/cli/js/symlink_test.ts deleted file mode 100644 index 221960bb0..000000000 --- a/cli/js/symlink_test.ts +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest( - { perms: { read: true, write: true } }, - function symlinkSyncSuccess(): void { - const testDir = Deno.makeTempDirSync(); - const oldname = testDir + "/oldname"; - const newname = testDir + "/newname"; - Deno.mkdirSync(oldname); - let errOnWindows; - // Just for now, until we implement symlink for Windows. - try { - Deno.symlinkSync(oldname, newname); - } catch (e) { - errOnWindows = e; - } - if (errOnWindows) { - assertEquals(Deno.build.os, "win"); - assertEquals(errOnWindows.message, "Not implemented"); - } else { - const newNameInfoLStat = Deno.lstatSync(newname); - const newNameInfoStat = Deno.statSync(newname); - assert(newNameInfoLStat.isSymlink()); - assert(newNameInfoStat.isDirectory()); - } - } -); - -unitTest(function symlinkSyncPerm(): void { - let err; - try { - Deno.symlinkSync("oldbaddir", "newbaddir"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -// Just for now, until we implement symlink for Windows. -// Symlink with type should succeed on other platforms with type ignored -unitTest( - { perms: { write: true } }, - function symlinkSyncNotImplemented(): void { - const testDir = Deno.makeTempDirSync(); - const oldname = testDir + "/oldname"; - const newname = testDir + "/newname"; - let err; - try { - Deno.symlinkSync(oldname, newname, "dir"); - } catch (e) { - err = e; - } - if (err) { - assertEquals(Deno.build.os, "win"); - assertEquals(err.message, "Not implemented"); - } - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function symlinkSuccess(): Promise { - const testDir = Deno.makeTempDirSync(); - const oldname = testDir + "/oldname"; - const newname = testDir + "/newname"; - Deno.mkdirSync(oldname); - let errOnWindows; - // Just for now, until we implement symlink for Windows. - try { - await Deno.symlink(oldname, newname); - } catch (e) { - errOnWindows = e; - } - if (errOnWindows) { - assertEquals(errOnWindows.message, "Not implemented"); - } else { - const newNameInfoLStat = Deno.lstatSync(newname); - const newNameInfoStat = Deno.statSync(newname); - assert(newNameInfoLStat.isSymlink()); - assert(newNameInfoStat.isDirectory()); - } - } -); diff --git a/cli/js/test_util.ts b/cli/js/test_util.ts deleted file mode 100644 index fa17a2f87..000000000 --- a/cli/js/test_util.ts +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -// -// We want to test many ops in deno which have different behavior depending on -// the permissions set. These tests can specify which permissions they expect, -// which appends a special string like "permW1N0" to the end of the test name. -// Here we run several copies of deno with different permissions, filtering the -// tests by the special string. permW1N0 means allow-write but not allow-net. -// See tools/unit_tests.py for more details. - -import { readLines } from "../../std/io/bufio.ts"; -import { assert, assertEquals } from "../../std/testing/asserts.ts"; -export { - assert, - assertThrows, - assertEquals, - assertMatch, - assertNotEquals, - assertStrictEq, - assertStrContains, - unreachable, - fail -} from "../../std/testing/asserts.ts"; - -interface TestPermissions { - read?: boolean; - write?: boolean; - net?: boolean; - env?: boolean; - run?: boolean; - plugin?: boolean; - hrtime?: boolean; -} - -export interface Permissions { - read: boolean; - write: boolean; - net: boolean; - env: boolean; - run: boolean; - plugin: boolean; - hrtime: boolean; -} - -const isGranted = async (name: Deno.PermissionName): Promise => - (await Deno.permissions.query({ name })).state === "granted"; - -async function getProcessPermissions(): Promise { - return { - run: await isGranted("run"), - read: await isGranted("read"), - write: await isGranted("write"), - net: await isGranted("net"), - env: await isGranted("env"), - plugin: await isGranted("plugin"), - hrtime: await isGranted("hrtime") - }; -} - -const processPerms = await getProcessPermissions(); - -function permissionsMatch( - processPerms: Permissions, - requiredPerms: Permissions -): boolean { - for (const permName in processPerms) { - if ( - processPerms[permName as keyof Permissions] !== - requiredPerms[permName as keyof Permissions] - ) { - return false; - } - } - - return true; -} - -export const permissionCombinations: Map = new Map(); - -function permToString(perms: Permissions): string { - const r = perms.read ? 1 : 0; - const w = perms.write ? 1 : 0; - const n = perms.net ? 1 : 0; - const e = perms.env ? 1 : 0; - const u = perms.run ? 1 : 0; - const p = perms.plugin ? 1 : 0; - const h = perms.hrtime ? 1 : 0; - return `permR${r}W${w}N${n}E${e}U${u}P${p}H${h}`; -} - -function registerPermCombination(perms: Permissions): void { - const key = permToString(perms); - if (!permissionCombinations.has(key)) { - permissionCombinations.set(key, perms); - } -} - -function normalizeTestPermissions(perms: TestPermissions): Permissions { - return { - read: !!perms.read, - write: !!perms.write, - net: !!perms.net, - run: !!perms.run, - env: !!perms.env, - plugin: !!perms.plugin, - hrtime: !!perms.hrtime - }; -} - -// Wrap `TestFunction` in additional assertion that makes sure -// the test case does not leak async "ops" - ie. number of async -// completed ops after the test is the same as number of dispatched -// ops. Note that "unref" ops are ignored since in nature that are -// optional. -function assertOps(fn: Deno.TestFunction): Deno.TestFunction { - return async function asyncOpSanitizer(): Promise { - const pre = Deno.metrics(); - await fn(); - const post = Deno.metrics(); - // We're checking diff because one might spawn HTTP server in the background - // that will be a pending async op before test starts. - assertEquals( - post.opsDispatchedAsync - pre.opsDispatchedAsync, - post.opsCompletedAsync - pre.opsCompletedAsync, - `Test case is leaking async ops. - Before: - - dispatched: ${pre.opsDispatchedAsync} - - completed: ${pre.opsCompletedAsync} - After: - - dispatched: ${post.opsDispatchedAsync} - - completed: ${post.opsCompletedAsync}` - ); - }; -} - -// Wrap `TestFunction` in additional assertion that makes sure -// the test case does not "leak" resources - ie. resource table after -// the test has exactly the same contents as before the test. -function assertResources(fn: Deno.TestFunction): Deno.TestFunction { - return async function resourceSanitizer(): Promise { - const pre = Deno.resources(); - await fn(); - const post = Deno.resources(); - const msg = `Test case is leaking resources. - Before: ${JSON.stringify(pre, null, 2)} - After: ${JSON.stringify(post, null, 2)}`; - assertEquals(pre, post, msg); - }; -} - -interface UnitTestOptions { - skip?: boolean; - perms?: TestPermissions; -} - -export function unitTest(fn: Deno.TestFunction): void; -export function unitTest(options: UnitTestOptions, fn: Deno.TestFunction): void; -export function unitTest( - optionsOrFn: UnitTestOptions | Deno.TestFunction, - maybeFn?: Deno.TestFunction -): void { - assert(optionsOrFn, "At least one argument is required"); - - let options: UnitTestOptions; - let name: string; - let fn: Deno.TestFunction; - - if (typeof optionsOrFn === "function") { - options = {}; - fn = optionsOrFn; - name = fn.name; - assert(name, "Missing test function name"); - } else { - options = optionsOrFn; - assert(maybeFn, "Missing test function definition"); - assert( - typeof maybeFn === "function", - "Second argument should be test function definition" - ); - fn = maybeFn; - name = fn.name; - assert(name, "Missing test function name"); - } - - if (options.skip) { - return; - } - - const normalizedPerms = normalizeTestPermissions(options.perms || {}); - registerPermCombination(normalizedPerms); - if (!permissionsMatch(processPerms, normalizedPerms)) { - return; - } - - const testDefinition: Deno.TestDefinition = { - name, - fn: assertResources(assertOps(fn)) - }; - Deno.test(testDefinition); -} - -function extractNumber(re: RegExp, str: string): number | undefined { - const match = str.match(re); - - if (match) { - return Number.parseInt(match[1]); - } -} - -export async function parseUnitTestOutput( - reader: Deno.Reader, - print: boolean -): Promise<{ actual?: number; expected?: number; resultOutput?: string }> { - let expected, actual, result; - - for await (const line of readLines(reader)) { - if (!expected) { - // expect "running 30 tests" - expected = extractNumber(/running (\d+) tests/, line); - } else if (line.indexOf("test result:") !== -1) { - result = line; - } - - if (print) { - console.log(line); - } - } - - // Check that the number of expected tests equals what was reported at the - // bottom. - if (result) { - // result should be a string like this: - // "test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; ..." - actual = extractNumber(/(\d+) passed/, result); - } - - return { actual, expected, resultOutput: result }; -} - -export interface ResolvableMethods { - resolve: (value?: T | PromiseLike) => void; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - reject: (reason?: any) => void; -} - -export type Resolvable = Promise & ResolvableMethods; - -export function createResolvable(): Resolvable { - let methods: ResolvableMethods; - const promise = new Promise((resolve, reject): void => { - methods = { resolve, reject }; - }); - // TypeScript doesn't know that the Promise callback occurs synchronously - // therefore use of not null assertion (`!`) - return Object.assign(promise, methods!) as Resolvable; -} - -unitTest(function permissionsMatches(): void { - assert( - permissionsMatch( - { - read: true, - write: false, - net: false, - env: false, - run: false, - plugin: false, - hrtime: false - }, - normalizeTestPermissions({ read: true }) - ) - ); - - assert( - permissionsMatch( - { - read: false, - write: false, - net: false, - env: false, - run: false, - plugin: false, - hrtime: false - }, - normalizeTestPermissions({}) - ) - ); - - assertEquals( - permissionsMatch( - { - read: false, - write: true, - net: true, - env: true, - run: true, - plugin: true, - hrtime: true - }, - normalizeTestPermissions({ read: true }) - ), - false - ); - - assertEquals( - permissionsMatch( - { - read: true, - write: false, - net: true, - env: false, - run: false, - plugin: false, - hrtime: false - }, - normalizeTestPermissions({ read: true }) - ), - false - ); - - assert( - permissionsMatch( - { - read: true, - write: true, - net: true, - env: true, - run: true, - plugin: true, - hrtime: true - }, - { - read: true, - write: true, - net: true, - env: true, - run: true, - plugin: true, - hrtime: true - } - ) - ); -}); - -unitTest( - { perms: { read: true } }, - async function parsingUnitTestOutput(): Promise { - const cwd = Deno.cwd(); - const testDataPath = `${cwd}/tools/testdata/`; - - let result; - - // This is an example of a successful unit test output. - const f1 = await Deno.open(`${testDataPath}/unit_test_output1.txt`); - result = await parseUnitTestOutput(f1, false); - assertEquals(result.actual, 96); - assertEquals(result.expected, 96); - f1.close(); - - // This is an example of a silently dying unit test. - const f2 = await Deno.open(`${testDataPath}/unit_test_output2.txt`); - result = await parseUnitTestOutput(f2, false); - assertEquals(result.actual, undefined); - assertEquals(result.expected, 96); - f2.close(); - - // This is an example of compiling before successful unit tests. - const f3 = await Deno.open(`${testDataPath}/unit_test_output3.txt`); - result = await parseUnitTestOutput(f3, false); - assertEquals(result.actual, 96); - assertEquals(result.expected, 96); - f3.close(); - - // Check what happens on empty output. - const f = new Deno.Buffer(new TextEncoder().encode("\n\n\n")); - result = await parseUnitTestOutput(f, false); - assertEquals(result.actual, undefined); - assertEquals(result.expected, undefined); - } -); - -/* - * Ensure all unit test files (e.g. xxx_test.ts) are present as imports in - * cli/js/unit_tests.ts as it is easy to miss this out - */ -unitTest( - { perms: { read: true } }, - async function assertAllUnitTestFilesImported(): Promise { - const directoryTestFiles = Deno.readdirSync("./cli/js") - .map(k => k.name) - .filter(file => file!.endsWith("_test.ts")); - const unitTestsFile: Uint8Array = Deno.readFileSync( - "./cli/js/unit_tests.ts" - ); - const importLines = new TextDecoder("utf-8") - .decode(unitTestsFile) - .split("\n") - .filter(line => line.startsWith("import") && line.includes("_test.ts")); - const importedTestFiles = importLines.map( - relativeFilePath => relativeFilePath.match(/\/([^\/]+)";/)![1] - ); - - directoryTestFiles.forEach(dirFile => { - if (!importedTestFiles.includes(dirFile!)) { - throw new Error( - "cil/js/unit_tests.ts is missing import of test file: cli/js/" + - dirFile - ); - } - }); - } -); diff --git a/cli/js/testing_test.ts b/cli/js/testing_test.ts deleted file mode 100644 index b47eb03e2..000000000 --- a/cli/js/testing_test.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { assertThrows, unitTest } from "./test_util.ts"; - -unitTest(function testFnOverloading(): void { - // just verifying that you can use this test definition syntax - Deno.test("test fn overloading", (): void => {}); -}); - -unitTest(function nameOfTestCaseCantBeEmpty(): void { - assertThrows( - () => { - Deno.test("", () => {}); - }, - Error, - "The name of test case can't be empty" - ); - assertThrows( - () => { - Deno.test({ - name: "", - fn: () => {} - }); - }, - Error, - "The name of test case can't be empty" - ); -}); - -unitTest(function testFnCantBeAnonymous(): void { - assertThrows( - () => { - Deno.test(function() {}); - }, - Error, - "Test function can't be anonymous" - ); -}); diff --git a/cli/js/tests/README.md b/cli/js/tests/README.md new file mode 100644 index 000000000..5809224f7 --- /dev/null +++ b/cli/js/tests/README.md @@ -0,0 +1,47 @@ +# Deno runtime tests + +Files in this directory are unit tests for Deno runtime. + +They are run under compiled Deno binary as opposed to files in `cli/js/` which +are bundled and snapshotted using `deno_typescript` crate. + +Testing Deno runtime code requires checking API under different runtime +permissions (ie. running with different `--allow-*` flags). To accomplish this +all tests exercised are created using `unitTest()` function. + +``` +import { unitTest } from "./test_util.ts"; + +unitTest(function simpleTestFn(): void { + // test code here +}); + +unitTest({ + skip: Deno.build.os === "win", + perms: { read: true, write: true }, + }, + function complexTestFn(): void { + // test code here + } +); +``` + +`unitTest` is is a wrapper function that enhances `Deno.test()` API in several +ways: + +- ability to conditionally skip tests using `UnitTestOptions.skip` +- ability to register required set of permissions for given test case using + `UnitTestOptions.perms` +- sanitization of resources - ensuring that tests close all opened resources + preventing interference between tests +- sanitization of async ops - ensuring that tests don't leak async ops by + ensuring that all started async ops are done before test finishes + +`unit_test_runner.ts` is main script used to run unit tests. + +Runner discoveres required permissions combinations by loading +`cli/js/tests/unit_tests.ts` and going through all registered instances of +`unitTest`. For each discovered permission combination a new Deno process is +created with respective `--allow-*` flags which loads +`cli/js/tests/unit_tests.ts` and executes all `unitTest` that match runtime +permissions. diff --git a/cli/js/tests/blob_test.ts b/cli/js/tests/blob_test.ts new file mode 100644 index 000000000..54071a11e --- /dev/null +++ b/cli/js/tests/blob_test.ts @@ -0,0 +1,62 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest(function blobString(): void { + const b1 = new Blob(["Hello World"]); + const str = "Test"; + const b2 = new Blob([b1, str]); + assertEquals(b2.size, b1.size + str.length); +}); + +unitTest(function blobBuffer(): void { + 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); +}); + +unitTest(function blobSlice(): void { + 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); +}); + +unitTest(function blobShouldNotThrowError(): void { + let hasThrown = false; + + try { + const options1: object = { + ending: "utf8", + hasOwnProperty: "hasOwnProperty" + }; + const options2: object = Object.create(null); + new Blob(["Hello World"], options1); + new Blob(["Hello World"], options2); + } catch { + hasThrown = true; + } + + assertEquals(hasThrown, false); +}); + +unitTest(function nativeEndLine(): void { + const options: object = { + ending: "native" + }; + const blob = new Blob(["Hello\nWorld"], options); + + assertEquals(blob.size, Deno.build.os === "win" ? 12 : 11); +}); + +// TODO(qti3e) Test the stored data in a Blob after implementing FileReader API. diff --git a/cli/js/tests/body_test.ts b/cli/js/tests/body_test.ts new file mode 100644 index 000000000..23f6d89e4 --- /dev/null +++ b/cli/js/tests/body_test.ts @@ -0,0 +1,74 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assertEquals, assert } from "./test_util.ts"; + +// just a hack to get a body object +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function buildBody(body: any): Body { + const stub = new Request("", { + body: body + }); + return stub as Body; +} + +const intArrays = [ + Int8Array, + Int16Array, + Int32Array, + Uint8Array, + Uint16Array, + Uint32Array, + Uint8ClampedArray, + Float32Array, + Float64Array +]; +unitTest(async function arrayBufferFromByteArrays(): Promise { + 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 +unitTest( + { perms: { net: true } }, + async function bodyMultipartFormData(): Promise { + const response = await fetch( + "http://localhost:4545/cli/tests/subdir/multipart_form_data.txt" + ); + const text = await response.text(); + + const body = buildBody(text); + + // @ts-ignore + body.contentType = "multipart/form-data;boundary=boundary"; + + 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")); + } +); + +unitTest( + { perms: { net: true } }, + async function bodyURLEncodedFormData(): Promise { + const response = await fetch( + "http://localhost:4545/cli/tests/subdir/form_urlencoded.txt" + ); + const text = await response.text(); + + const body = buildBody(text); + + // @ts-ignore + body.contentType = "application/x-www-form-urlencoded"; + + 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(), ""); + } +); diff --git a/cli/js/tests/buffer_test.ts b/cli/js/tests/buffer_test.ts new file mode 100644 index 000000000..163ed0a30 --- /dev/null +++ b/cli/js/tests/buffer_test.ts @@ -0,0 +1,296 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +// 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 { + assertEquals, + assert, + assertStrContains, + unitTest +} from "./test_util.ts"; + +const { Buffer, readAll, readAllSync, writeAll, writeAllSync } = Deno; +type Buffer = Deno.Buffer; + +// N controls how many iterations of certain checks are performed. +const N = 100; +let testBytes: Uint8Array | null; +let testString: string | null; + +function init(): void { + 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): void { + const bytes = buf.bytes(); + assertEquals(buf.length, bytes.byteLength); + const decoder = new TextDecoder(); + const bytesStr = decoder.decode(bytes); + assertEquals(bytesStr, s); + assertEquals(buf.length, buf.toString().length); + 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: Buffer, + s: string, + n: number, + fub: Uint8Array +): Promise { + 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: Buffer, s: string, fub: Uint8Array): Promise { + check(buf, s); + while (true) { + const r = await buf.read(fub); + if (r === Deno.EOF) { + 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; +} + +unitTest(function bufferNewBuffer(): void { + init(); + assert(testBytes); + assert(testString); + const buf = new Buffer(testBytes.buffer as ArrayBuffer); + check(buf, testString); +}); + +unitTest(async function bufferBasicOperations(): Promise { + init(); + assert(testBytes); + assert(testString); + const buf = new 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 buf.writeByte() + // TODO buf.readByte() + } +}); + +unitTest(async function bufferReadEmptyAtEOF(): Promise { + // 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 Buffer(); + const zeroLengthTmp = new Uint8Array(0); + const result = await buf.read(zeroLengthTmp); + assertEquals(result, 0); +}); + +unitTest(async function bufferLargeByteWrites(): Promise { + init(); + const buf = new 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, ""); +}); + +unitTest(async function bufferTooLargeByteWrites(): Promise { + init(); + const tmp = new Uint8Array(72); + const growLen = Number.MAX_VALUE; + const xBytes = repeat("x", 0); + const buf = new Buffer(xBytes.buffer as ArrayBuffer); + await buf.read(tmp); + + let err; + try { + buf.grow(growLen); + } catch (e) { + err = e; + } + + assert(err instanceof Error); + assertStrContains(err.message, "grown beyond the maximum size"); +}); + +unitTest(async function bufferLargeByteReads(): Promise { + init(); + assert(testBytes); + assert(testString); + const buf = new 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, ""); +}); + +unitTest(function bufferCapWithPreallocatedSlice(): void { + const buf = new Buffer(new ArrayBuffer(10)); + assertEquals(buf.capacity, 10); +}); + +unitTest(async function bufferReadFrom(): Promise { + init(); + assert(testBytes); + assert(testString); + const buf = new 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 Buffer(); + await b.readFrom(buf); + const fub = new Uint8Array(testString.length); + await empty(b, s, fub); + } +}); + +unitTest(async function bufferReadFromSync(): Promise { + init(); + assert(testBytes); + assert(testString); + const buf = new 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 Buffer(); + b.readFromSync(buf); + const fub = new Uint8Array(testString.length); + await empty(b, s, fub); + } +}); + +unitTest(async function bufferTestGrow(): Promise { + const tmp = new Uint8Array(72); + for (const startLen of [0, 100, 1000, 10000, 100000]) { + const xBytes = repeat("x", startLen); + for (const growLen of [0, 100, 1000, 10000, 100000]) { + const buf = new Buffer(xBytes.buffer as ArrayBuffer); + // If we read, this affects buf.off, which is good to test. + const result = await buf.read(tmp); + const nread = result === Deno.EOF ? 0 : result; + 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 + ); + } + } +}); + +unitTest(async function testReadAll(): Promise { + init(); + assert(testBytes); + const reader = new Buffer(testBytes.buffer as ArrayBuffer); + const actualBytes = await readAll(reader); + assertEquals(testBytes.byteLength, actualBytes.byteLength); + for (let i = 0; i < testBytes.length; ++i) { + assertEquals(testBytes[i], actualBytes[i]); + } +}); + +unitTest(function testReadAllSync(): void { + init(); + assert(testBytes); + const reader = new Buffer(testBytes.buffer as ArrayBuffer); + const actualBytes = readAllSync(reader); + assertEquals(testBytes.byteLength, actualBytes.byteLength); + for (let i = 0; i < testBytes.length; ++i) { + assertEquals(testBytes[i], actualBytes[i]); + } +}); + +unitTest(async function testWriteAll(): Promise { + init(); + assert(testBytes); + const writer = new Buffer(); + await 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]); + } +}); + +unitTest(function testWriteAllSync(): void { + init(); + assert(testBytes); + const writer = new Buffer(); + 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]); + } +}); diff --git a/cli/js/tests/build_test.ts b/cli/js/tests/build_test.ts new file mode 100644 index 000000000..50c7b519c --- /dev/null +++ b/cli/js/tests/build_test.ts @@ -0,0 +1,10 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +unitTest(function buildInfo(): void { + // Deno.build is injected by rollup at compile time. Here + // we check it has been properly transformed. + const { arch, os } = Deno.build; + assert(arch === "x64"); + assert(os === "mac" || os === "win" || os === "linux"); +}); diff --git a/cli/js/tests/chmod_test.ts b/cli/js/tests/chmod_test.ts new file mode 100644 index 000000000..8731fad22 --- /dev/null +++ b/cli/js/tests/chmod_test.ts @@ -0,0 +1,159 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +const isNotWindows = Deno.build.os !== "win"; + +unitTest( + { perms: { read: true, write: true } }, + function chmodSyncSuccess(): void { + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + const tempDir = Deno.makeTempDirSync(); + const filename = tempDir + "/test.txt"; + Deno.writeFileSync(filename, data, { mode: 0o666 }); + + // On windows no effect, but should not crash + Deno.chmodSync(filename, 0o777); + + // Check success when not on windows + if (isNotWindows) { + const fileInfo = Deno.statSync(filename); + assert(fileInfo.mode); + assertEquals(fileInfo.mode & 0o777, 0o777); + } + } +); + +// Check symlink when not on windows +unitTest( + { + skip: Deno.build.os === "win", + perms: { read: true, write: true } + }, + function chmodSyncSymlinkSuccess(): void { + 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); + } +); + +unitTest({ perms: { write: true } }, function chmodSyncFailure(): void { + let err; + try { + const filename = "/badfile.txt"; + Deno.chmodSync(filename, 0o777); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); +}); + +unitTest({ perms: { write: false } }, function chmodSyncPerm(): void { + let err; + try { + Deno.chmodSync("/somefile.txt", 0o777); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest( + { perms: { read: true, write: true } }, + async function chmodSuccess(): Promise { + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + const tempDir = Deno.makeTempDirSync(); + const filename = tempDir + "/test.txt"; + Deno.writeFileSync(filename, data, { mode: 0o666 }); + + // On windows no effect, but should not crash + await Deno.chmod(filename, 0o777); + + // Check success when not on windows + if (isNotWindows) { + const fileInfo = Deno.statSync(filename); + assert(fileInfo.mode); + assertEquals(fileInfo.mode & 0o777, 0o777); + } + } +); + +// Check symlink when not on windows + +unitTest( + { + skip: Deno.build.os === "win", + perms: { read: true, write: true } + }, + async function chmodSymlinkSuccess(): Promise { + 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); + } +); + +unitTest({ perms: { write: true } }, async function chmodFailure(): Promise< + void +> { + let err; + try { + const filename = "/badfile.txt"; + await Deno.chmod(filename, 0o777); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); +}); + +unitTest({ perms: { write: false } }, async function chmodPerm(): Promise< + void +> { + let err; + try { + await Deno.chmod("/somefile.txt", 0o777); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); diff --git a/cli/js/tests/chown_test.ts b/cli/js/tests/chown_test.ts new file mode 100644 index 000000000..50dcd6dc1 --- /dev/null +++ b/cli/js/tests/chown_test.ts @@ -0,0 +1,147 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assertEquals, assert } from "./test_util.ts"; + +// chown on Windows is noop for now, so ignore its testing on Windows +if (Deno.build.os !== "win") { + async function getUidAndGid(): Promise<{ uid: number; gid: number }> { + // get the user ID and group ID of the current process + const uidProc = Deno.run({ + stdout: "piped", + args: ["python", "-c", "import os; print(os.getuid())"] + }); + const gidProc = Deno.run({ + stdout: "piped", + args: ["python", "-c", "import os; print(os.getgid())"] + }); + + assertEquals((await uidProc.status()).code, 0); + assertEquals((await gidProc.status()).code, 0); + const uid = parseInt( + new TextDecoder("utf-8").decode(await uidProc.output()) + ); + uidProc.close(); + const gid = parseInt( + new TextDecoder("utf-8").decode(await gidProc.output()) + ); + gidProc.close(); + + return { uid, gid }; + } + + unitTest(async function chownNoWritePermission(): Promise { + const filePath = "chown_test_file.txt"; + try { + await Deno.chown(filePath, 1000, 1000); + } catch (e) { + assert(e instanceof Deno.errors.PermissionDenied); + } + }); + + unitTest( + { perms: { run: true, write: true } }, + async function chownSyncFileNotExist(): Promise { + const { uid, gid } = await getUidAndGid(); + const filePath = Deno.makeTempDirSync() + "/chown_test_file.txt"; + + try { + Deno.chownSync(filePath, uid, gid); + } catch (e) { + assert(e instanceof Deno.errors.NotFound); + } + } + ); + + unitTest( + { perms: { run: true, write: true } }, + async function chownFileNotExist(): Promise { + const { uid, gid } = await getUidAndGid(); + const filePath = (await Deno.makeTempDir()) + "/chown_test_file.txt"; + + try { + await Deno.chown(filePath, uid, gid); + } catch (e) { + assert(e instanceof Deno.errors.NotFound); + } + } + ); + + unitTest( + { perms: { write: true } }, + function chownSyncPermissionDenied(): void { + const enc = new TextEncoder(); + const dirPath = Deno.makeTempDirSync(); + const filePath = dirPath + "/chown_test_file.txt"; + const fileData = enc.encode("Hello"); + Deno.writeFileSync(filePath, fileData); + + try { + // try changing the file's owner to root + Deno.chownSync(filePath, 0, 0); + } catch (e) { + assert(e instanceof Deno.errors.PermissionDenied); + } + Deno.removeSync(dirPath, { recursive: true }); + } + ); + + unitTest( + { perms: { write: true } }, + async function chownPermissionDenied(): Promise { + const enc = new TextEncoder(); + const dirPath = await Deno.makeTempDir(); + const filePath = dirPath + "/chown_test_file.txt"; + const fileData = enc.encode("Hello"); + await Deno.writeFile(filePath, fileData); + + try { + // try changing the file's owner to root + await Deno.chown(filePath, 0, 0); + } catch (e) { + assert(e instanceof Deno.errors.PermissionDenied); + } + await Deno.remove(dirPath, { recursive: true }); + } + ); + + unitTest( + { perms: { run: true, write: true } }, + async function chownSyncSucceed(): Promise { + // TODO: when a file's owner is actually being changed, + // chown only succeeds if run under priviledged user (root) + // The test script has no such priviledge, so need to find a better way to test this case + const { uid, gid } = await getUidAndGid(); + + const enc = new TextEncoder(); + const dirPath = Deno.makeTempDirSync(); + const filePath = dirPath + "/chown_test_file.txt"; + const fileData = enc.encode("Hello"); + Deno.writeFileSync(filePath, fileData); + + // the test script creates this file with the same uid and gid, + // here chown is a noop so it succeeds under non-priviledged user + Deno.chownSync(filePath, uid, gid); + + Deno.removeSync(dirPath, { recursive: true }); + } + ); + + unitTest( + { perms: { run: true, write: true } }, + async function chownSucceed(): Promise { + // TODO: same as chownSyncSucceed + const { uid, gid } = await getUidAndGid(); + + const enc = new TextEncoder(); + const dirPath = await Deno.makeTempDir(); + const filePath = dirPath + "/chown_test_file.txt"; + const fileData = enc.encode("Hello"); + await Deno.writeFile(filePath, fileData); + + // the test script creates this file with the same uid and gid, + // here chown is a noop so it succeeds under non-priviledged user + await Deno.chown(filePath, uid, gid); + + Deno.removeSync(dirPath, { recursive: true }); + } + ); +} diff --git a/cli/js/tests/compiler_api_test.ts b/cli/js/tests/compiler_api_test.ts new file mode 100644 index 000000000..3b0449f9a --- /dev/null +++ b/cli/js/tests/compiler_api_test.ts @@ -0,0 +1,153 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +import { assert, assertEquals, unitTest } from "./test_util.ts"; + +const { compile, transpileOnly, bundle } = Deno; + +unitTest(async function compilerApiCompileSources() { + const [diagnostics, actual] = await compile("/foo.ts", { + "/foo.ts": `import * as bar from "./bar.ts";\n\nconsole.log(bar);\n`, + "/bar.ts": `export const bar = "bar";\n` + }); + assert(diagnostics == null); + assert(actual); + assertEquals(Object.keys(actual), [ + "/bar.js.map", + "/bar.js", + "/foo.js.map", + "/foo.js" + ]); +}); + +unitTest(async function compilerApiCompileNoSources() { + const [diagnostics, actual] = await compile("./cli/tests/subdir/mod1.ts"); + assert(diagnostics == null); + assert(actual); + const keys = Object.keys(actual); + assertEquals(keys.length, 6); + assert(keys[0].endsWith("print_hello.js.map")); + assert(keys[1].endsWith("print_hello.js")); +}); + +unitTest(async function compilerApiCompileOptions() { + const [diagnostics, actual] = await compile( + "/foo.ts", + { + "/foo.ts": `export const foo = "foo";` + }, + { + module: "amd", + sourceMap: false + } + ); + assert(diagnostics == null); + assert(actual); + assertEquals(Object.keys(actual), ["/foo.js"]); + assert(actual["/foo.js"].startsWith("define(")); +}); + +unitTest(async function compilerApiCompileLib() { + const [diagnostics, actual] = await compile( + "/foo.ts", + { + "/foo.ts": `console.log(document.getElementById("foo")); + console.log(Deno.args);` + }, + { + lib: ["dom", "es2018", "deno.ns"] + } + ); + assert(diagnostics == null); + assert(actual); + assertEquals(Object.keys(actual), ["/foo.js.map", "/foo.js"]); +}); + +unitTest(async function compilerApiCompileTypes() { + const [diagnostics, actual] = await compile( + "/foo.ts", + { + "/foo.ts": `console.log(Foo.bar);` + }, + { + types: ["./cli/tests/subdir/foo_types.d.ts"] + } + ); + assert(diagnostics == null); + assert(actual); + assertEquals(Object.keys(actual), ["/foo.js.map", "/foo.js"]); +}); + +unitTest(async function transpileOnlyApi() { + const actual = await transpileOnly({ + "foo.ts": `export enum Foo { Foo, Bar, Baz };\n` + }); + assert(actual); + assertEquals(Object.keys(actual), ["foo.ts"]); + assert(actual["foo.ts"].source.startsWith("export var Foo;")); + assert(actual["foo.ts"].map); +}); + +unitTest(async function transpileOnlyApiConfig() { + const actual = await transpileOnly( + { + "foo.ts": `export enum Foo { Foo, Bar, Baz };\n` + }, + { + sourceMap: false, + module: "amd" + } + ); + assert(actual); + assertEquals(Object.keys(actual), ["foo.ts"]); + assert(actual["foo.ts"].source.startsWith("define(")); + assert(actual["foo.ts"].map == null); +}); + +unitTest(async function bundleApiSources() { + const [diagnostics, actual] = await bundle("/foo.ts", { + "/foo.ts": `export * from "./bar.ts";\n`, + "/bar.ts": `export const bar = "bar";\n` + }); + assert(diagnostics == null); + assert(actual.includes(`__instantiate("foo")`)); + assert(actual.includes(`__exp["bar"]`)); +}); + +unitTest(async function bundleApiNoSources() { + const [diagnostics, actual] = await bundle("./cli/tests/subdir/mod1.ts"); + assert(diagnostics == null); + assert(actual.includes(`__instantiate("mod1")`)); + assert(actual.includes(`__exp["printHello3"]`)); +}); + +unitTest(async function bundleApiConfig() { + const [diagnostics, actual] = await bundle( + "/foo.ts", + { + "/foo.ts": `// random comment\nexport * from "./bar.ts";\n`, + "/bar.ts": `export const bar = "bar";\n` + }, + { + removeComments: true + } + ); + assert(diagnostics == null); + assert(!actual.includes(`random`)); +}); + +unitTest(async function bundleApiJsModules() { + const [diagnostics, actual] = await bundle("/foo.js", { + "/foo.js": `export * from "./bar.js";\n`, + "/bar.js": `export const bar = "bar";\n` + }); + assert(diagnostics == null); + assert(actual.includes(`System.register("bar",`)); +}); + +unitTest(async function diagnosticsTest() { + const [diagnostics] = await compile("/foo.ts", { + "/foo.ts": `document.getElementById("foo");` + }); + assert(Array.isArray(diagnostics)); + assert(diagnostics.length === 1); +}); diff --git a/cli/js/tests/console_test.ts b/cli/js/tests/console_test.ts new file mode 100644 index 000000000..34a61c25f --- /dev/null +++ b/cli/js/tests/console_test.ts @@ -0,0 +1,706 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { assert, assertEquals, unitTest } from "./test_util.ts"; + +// Some of these APIs aren't exposed in the types and so we have to cast to any +// in order to "trick" TypeScript. +const { + inspect, + writeSync, + stdout + // eslint-disable-next-line @typescript-eslint/no-explicit-any +} = Deno as any; + +const customInspect = Deno.symbols.customInspect; +const { + Console, + stringifyArgs + // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol +} = Deno[Deno.symbols.internal]; + +function stringify(...args: unknown[]): string { + return stringifyArgs(args).replace(/\n$/, ""); +} + +// test cases from web-platform-tests +// via https://github.com/web-platform-tests/wpt/blob/master/console/console-is-a-namespace.any.js +unitTest(function consoleShouldBeANamespace(): void { + const prototype1 = Object.getPrototypeOf(console); + const prototype2 = Object.getPrototypeOf(prototype1); + + assertEquals(Object.getOwnPropertyNames(prototype1).length, 0); + assertEquals(prototype2, Object.prototype); +}); + +unitTest(function consoleHasRightInstance(): void { + assert(console instanceof Console); + assertEquals({} instanceof Console, false); +}); + +unitTest(function consoleTestAssertShouldNotThrowError(): void { + mockConsole(console => { + console.assert(true); + let hasThrown = undefined; + try { + console.assert(false); + hasThrown = false; + } catch { + hasThrown = true; + } + assertEquals(hasThrown, false); + }); +}); + +unitTest(function consoleTestStringifyComplexObjects(): void { + assertEquals(stringify("foo"), "foo"); + assertEquals(stringify(["foo", "bar"]), `[ "foo", "bar" ]`); + assertEquals(stringify({ foo: "bar" }), `{ foo: "bar" }`); +}); + +unitTest(function consoleTestStringifyLongStrings(): void { + 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); +}); + +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +unitTest(function consoleTestStringifyCircular(): void { + class Base { + a = 1; + m1() {} + } + + class Extended extends Base { + b = 2; + m2() {} + } + + // eslint-disable-next-line @typescript-eslint/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 = `{ num, bool, str, method, asyncMethod, generatorMethod, un, nu, arrowFunc, extendedClass, nFunc, extendedCstr, o }`; + + 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 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 { 1, 2, 3 }"); + assertEquals( + stringify( + new Map([ + [1, "one"], + [2, "two"] + ]) + ), + `Map { 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(null), "null"); + assertEquals(stringify(undefined), "undefined"); + assertEquals(stringify(new Extended()), "Extended { a: 1, b: 2 }"); + assertEquals( + stringify(function f(): void {}), + "[Function: f]" + ); + assertEquals( + stringify(async function af(): Promise {}), + "[AsyncFunction: af]" + ); + assertEquals( + stringify(function* gf() {}), + "[GeneratorFunction: gf]" + ); + assertEquals( + stringify(async function* agf() {}), + "[AsyncGeneratorFunction: agf]" + ); + assertEquals(stringify(new Uint8Array([1, 2, 3])), "Uint8Array [ 1, 2, 3 ]"); + assertEquals(stringify(Uint8Array.prototype), "TypedArray []"); + assertEquals( + stringify({ a: { b: { c: { d: new Set([1]) } } } }), + "{ a: { b: { c: { d: [Set] } } } }" + ); + assertEquals(stringify(nestedObj), nestedObjExpected); + assertEquals(stringify(JSON), "{}"); + assertEquals( + stringify(console), + "{ printFunc, log, debug, info, dir, dirxml, warn, error, assert, count, countReset, table, time, timeLog, timeEnd, group, groupCollapsed, groupEnd, clear, trace, indentLevel }" + ); + // test inspect is working the same + assertEquals(inspect(nestedObj), nestedObjExpected); +}); +/* eslint-enable @typescript-eslint/explicit-function-return-type */ + +unitTest(function consoleTestStringifyWithDepth(): void { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const nestedObj: any = { a: { b: { c: { d: { e: { f: 42 } } } } } }; + assertEquals( + stringifyArgs([nestedObj], { depth: 3 }), + "{ a: { b: { c: [Object] } } }" + ); + assertEquals( + stringifyArgs([nestedObj], { depth: 4 }), + "{ a: { b: { c: { d: [Object] } } } }" + ); + assertEquals(stringifyArgs([nestedObj], { depth: 0 }), "[Object]"); + assertEquals( + stringifyArgs([nestedObj], { depth: null }), + "{ a: { b: { c: { d: [Object] } } } }" + ); + // test inspect is working the same way + assertEquals( + inspect(nestedObj, { depth: 4 }), + "{ a: { b: { c: { d: [Object] } } } }" + ); +}); + +unitTest(function consoleTestWithCustomInspector(): void { + class A { + [customInspect](): string { + return "b"; + } + } + + assertEquals(stringify(new A()), "b"); +}); + +unitTest(function consoleTestWithCustomInspectorError(): void { + class A { + [customInspect](): string { + throw new Error("BOOM"); + return "b"; + } + } + + assertEquals(stringify(new A()), "A {}"); + + class B { + constructor(public field: { a: string }) {} + [customInspect](): string { + return this.field.a; + } + } + + assertEquals(stringify(new B({ a: "a" })), "a"); + assertEquals(stringify(B.prototype), "{}"); +}); + +unitTest(function consoleTestWithIntegerFormatSpecifier(): void { + assertEquals(stringify("%i"), "%i"); + assertEquals(stringify("%i", 42.0), "42"); + assertEquals(stringify("%i", 42), "42"); + assertEquals(stringify("%i", "42"), "42"); + assertEquals(stringify("%i", "42.0"), "42"); + 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" + ); +}); + +unitTest(function consoleTestWithFloatFormatSpecifier(): void { + assertEquals(stringify("%f"), "%f"); + assertEquals(stringify("%f", 42.0), "42"); + assertEquals(stringify("%f", 42), "42"); + assertEquals(stringify("%f", "42"), "42"); + assertEquals(stringify("%f", "42.0"), "42"); + 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), "5"); + assertEquals(stringify("%f %f", 42, 43), "42 43"); + assertEquals(stringify("%f %f", 42), "42 %f"); +}); + +unitTest(function consoleTestWithStringFormatSpecifier(): void { + 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)"); +}); + +unitTest(function consoleTestWithObjectFormatSpecifier(): void { + 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]) } } } }), + "{ a: { b: { c: { d: [Set] } } } }" + ); +}); + +unitTest(function consoleTestWithVariousOrInvalidFormatSpecifier(): void { + 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"); +}); + +unitTest(function consoleTestCallToStringOnLabel(): void { + const methods = ["count", "countReset", "time", "timeLog", "timeEnd"]; + mockConsole(console => { + for (const method of methods) { + let hasCalled = false; + // @ts-ignore + console[method]({ + toString(): void { + hasCalled = true; + } + }); + assertEquals(hasCalled, true); + } + }); +}); + +unitTest(function consoleTestError(): void { + 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") + ); + } +}); + +unitTest(function consoleTestClear(): void { + const stdoutWriteSync = stdout.writeSync; + const uint8 = new TextEncoder().encode("\x1b[1;1H" + "\x1b[0J"); + let buffer = new Uint8Array(0); + + stdout.writeSync = (u8: Uint8Array): Promise => { + const tmp = new Uint8Array(buffer.length + u8.length); + tmp.set(buffer, 0); + tmp.set(u8, buffer.length); + buffer = tmp; + + return writeSync(stdout.rid, u8); + }; + console.clear(); + stdout.writeSync = stdoutWriteSync; + assertEquals(buffer, uint8); +}); + +// Test bound this issue +unitTest(function consoleDetachedLog(): void { + 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): void { + this.chunks.push(x); + } + toString(): string { + return this.chunks.join(""); + } +} + +type ConsoleExamineFunc = ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + csl: any, + out: StringBuffer, + err?: StringBuffer, + both?: StringBuffer +) => void; + +function mockConsole(f: ConsoleExamineFunc): void { + const out = new StringBuffer(); + const err = new StringBuffer(); + const both = new StringBuffer(); + const csl = new Console( + (x: string, isErr: boolean, printsNewLine: boolean): void => { + const content = x + (printsNewLine ? "\n" : ""); + const buf = isErr ? err : out; + buf.add(content); + both.add(content); + } + ); + f(csl, out, err, both); +} + +// console.group test +unitTest(function consoleGroup(): void { + mockConsole((console, out): void => { + 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 +unitTest(function consoleGroupWarn(): void { + mockConsole((console, _out, _err, both): void => { + 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 +unitTest(function consoleTable(): void { + mockConsole((console, out): void => { + console.table({ a: "test", b: 1 }); + assertEquals( + out.toString(), + `┌─────────┬────────┐ +│ (index) │ Values │ +├─────────┼────────┤ +│ a │ "test" │ +│ b │ 1 │ +└─────────┴────────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table({ a: { b: 10 }, b: { b: 20, c: 30 } }, ["c"]); + assertEquals( + out.toString(), + `┌─────────┬────┐ +│ (index) │ c │ +├─────────┼────┤ +│ a │ │ +│ b │ 30 │ +└─────────┴────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table([1, 2, [3, [4]], [5, 6], [[7], [8]]]); + assertEquals( + out.toString(), + `┌─────────┬───────┬───────┬────────┐ +│ (index) │ 0 │ 1 │ Values │ +├─────────┼───────┼───────┼────────┤ +│ 0 │ │ │ 1 │ +│ 1 │ │ │ 2 │ +│ 2 │ 3 │ [ 4 ] │ │ +│ 3 │ 5 │ 6 │ │ +│ 4 │ [ 7 ] │ [ 8 ] │ │ +└─────────┴───────┴───────┴────────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table(new Set([1, 2, 3, "test"])); + assertEquals( + out.toString(), + `┌───────────────────┬────────┐ +│ (iteration index) │ Values │ +├───────────────────┼────────┤ +│ 0 │ 1 │ +│ 1 │ 2 │ +│ 2 │ 3 │ +│ 3 │ "test" │ +└───────────────────┴────────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table( + new Map([ + [1, "one"], + [2, "two"] + ]) + ); + assertEquals( + out.toString(), + `┌───────────────────┬─────┬────────┐ +│ (iteration index) │ Key │ Values │ +├───────────────────┼─────┼────────┤ +│ 0 │ 1 │ "one" │ +│ 1 │ 2 │ "two" │ +└───────────────────┴─────┴────────┘ +` + ); + }); + mockConsole((console, out): void => { + 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( + out.toString(), + `┌─────────┬───────────┬───────────────────┬────────┐ +│ (index) │ c │ e │ Values │ +├─────────┼───────────┼───────────────────┼────────┤ +│ a │ │ │ true │ +│ b │ { d: 10 } │ [ 1, 2, [Array] ] │ │ +│ f │ │ │ "test" │ +│ g │ │ │ │ +│ h │ │ │ │ +└─────────┴───────────┴───────────────────┴────────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table([ + 1, + "test", + false, + { a: 10 }, + ["test", { b: 20, c: "test" }] + ]); + assertEquals( + out.toString(), + `┌─────────┬────────┬──────────────────────┬────┬────────┐ +│ (index) │ 0 │ 1 │ a │ Values │ +├─────────┼────────┼──────────────────────┼────┼────────┤ +│ 0 │ │ │ │ 1 │ +│ 1 │ │ │ │ "test" │ +│ 2 │ │ │ │ false │ +│ 3 │ │ │ 10 │ │ +│ 4 │ "test" │ { b: 20, c: "test" } │ │ │ +└─────────┴────────┴──────────────────────┴────┴────────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table([]); + assertEquals( + out.toString(), + `┌─────────┐ +│ (index) │ +├─────────┤ +└─────────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table({}); + assertEquals( + out.toString(), + `┌─────────┐ +│ (index) │ +├─────────┤ +└─────────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table(new Set()); + assertEquals( + out.toString(), + `┌───────────────────┐ +│ (iteration index) │ +├───────────────────┤ +└───────────────────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table(new Map()); + assertEquals( + out.toString(), + `┌───────────────────┐ +│ (iteration index) │ +├───────────────────┤ +└───────────────────┘ +` + ); + }); + mockConsole((console, out): void => { + console.table("test"); + assertEquals(out.toString(), "test\n"); + }); +}); + +// console.log(Error) test +unitTest(function consoleLogShouldNotThrowError(): void { + 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): void => { + console.log(new Error("foo")); + assertEquals(out.toString().includes("Uncaught"), false); + }); +}); + +// console.dir test +unitTest(function consoleDir(): void { + mockConsole((console, out): void => { + console.dir("DIR"); + assertEquals(out.toString(), "DIR\n"); + }); + mockConsole((console, out): void => { + console.dir("DIR", { indentLevel: 2 }); + assertEquals(out.toString(), " DIR\n"); + }); +}); + +// console.dir test +unitTest(function consoleDirXml(): void { + mockConsole((console, out): void => { + console.dirxml("DIRXML"); + assertEquals(out.toString(), "DIRXML\n"); + }); + mockConsole((console, out): void => { + console.dirxml("DIRXML", { indentLevel: 2 }); + assertEquals(out.toString(), " DIRXML\n"); + }); +}); + +// console.trace test +unitTest(function consoleTrace(): void { + mockConsole((console, _out, err): void => { + console.trace("%s", "custom message"); + assert(err); + assert(err.toString().includes("Trace: custom message")); + }); +}); diff --git a/cli/js/tests/copy_file_test.ts b/cli/js/tests/copy_file_test.ts new file mode 100644 index 000000000..986bab53b --- /dev/null +++ b/cli/js/tests/copy_file_test.ts @@ -0,0 +1,176 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +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): void { + const enc = new TextEncoder(); + const data = enc.encode(s); + Deno.writeFileSync(filename, data, { mode: 0o666 }); +} + +function assertSameContent(filename1: string, filename2: string): void { + const data1 = Deno.readFileSync(filename1); + const data2 = Deno.readFileSync(filename2); + assertEquals(data1, data2); +} + +unitTest( + { perms: { read: true, write: true } }, + function copyFileSyncSuccess(): void { + 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); + } +); + +unitTest( + { perms: { write: true, read: true } }, + function copyFileSyncFailure(): void { + const tempDir = Deno.makeTempDirSync(); + const fromFilename = tempDir + "/from.txt"; + const toFilename = tempDir + "/to.txt"; + // We skip initial writing here, from.txt does not exist + let err; + try { + Deno.copyFileSync(fromFilename, toFilename); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { write: true, read: false } }, + function copyFileSyncPerm1(): void { + let caughtError = false; + try { + Deno.copyFileSync("/from.txt", "/to.txt"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); + } +); + +unitTest( + { perms: { write: false, read: true } }, + function copyFileSyncPerm2(): void { + let caughtError = false; + try { + Deno.copyFileSync("/from.txt", "/to.txt"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); + } +); + +unitTest( + { perms: { read: true, write: true } }, + function copyFileSyncOverwrite(): void { + 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); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function copyFileSuccess(): Promise { + 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); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function copyFileFailure(): Promise { + const tempDir = Deno.makeTempDirSync(); + const fromFilename = tempDir + "/from.txt"; + const toFilename = tempDir + "/to.txt"; + // We skip initial writing here, from.txt does not exist + let err; + try { + await Deno.copyFile(fromFilename, toFilename); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function copyFileOverwrite(): Promise { + 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); + } +); + +unitTest( + { perms: { read: false, write: true } }, + async function copyFilePerm1(): Promise { + let caughtError = false; + try { + await Deno.copyFile("/from.txt", "/to.txt"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); + } +); + +unitTest( + { perms: { read: true, write: false } }, + async function copyFilePerm2(): Promise { + let caughtError = false; + try { + await Deno.copyFile("/from.txt", "/to.txt"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); + } +); diff --git a/cli/js/tests/custom_event_test.ts b/cli/js/tests/custom_event_test.ts new file mode 100644 index 000000000..7a5cc44ca --- /dev/null +++ b/cli/js/tests/custom_event_test.ts @@ -0,0 +1,27 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assertEquals } from "./test_util.ts"; + +unitTest(function customEventInitializedWithDetail(): void { + 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); +}); + +unitTest(function toStringShouldBeWebCompatibility(): void { + const type = "touchstart"; + const event = new CustomEvent(type, {}); + assertEquals(event.toString(), "[object CustomEvent]"); +}); diff --git a/cli/js/tests/dir_test.ts b/cli/js/tests/dir_test.ts new file mode 100644 index 000000000..75184587b --- /dev/null +++ b/cli/js/tests/dir_test.ts @@ -0,0 +1,54 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest(function dirCwdNotNull(): void { + assert(Deno.cwd() != null); +}); + +unitTest({ perms: { write: true } }, function dirCwdChdirSuccess(): void { + const initialdir = Deno.cwd(); + const path = Deno.makeTempDirSync(); + Deno.chdir(path); + const current = Deno.cwd(); + if (Deno.build.os === "mac") { + assertEquals(current, "/private" + path); + } else { + assertEquals(current, path); + } + Deno.chdir(initialdir); +}); + +unitTest({ perms: { write: true } }, function dirCwdError(): void { + // excluding windows since it throws resource busy, while removeSync + if (["linux", "mac"].includes(Deno.build.os)) { + const initialdir = Deno.cwd(); + const path = Deno.makeTempDirSync(); + Deno.chdir(path); + Deno.removeSync(path); + try { + Deno.cwd(); + throw Error("current directory removed, should throw error"); + } catch (err) { + if (err instanceof Deno.errors.NotFound) { + assert(err.name === "NotFound"); + } else { + throw Error("raised different exception"); + } + } + Deno.chdir(initialdir); + } +}); + +unitTest({ perms: { write: true } }, function dirChdirError(): void { + const path = Deno.makeTempDirSync() + "test"; + try { + Deno.chdir(path); + throw Error("directory not available, should throw error"); + } catch (err) { + if (err instanceof Deno.errors.NotFound) { + assert(err.name === "NotFound"); + } else { + throw Error("raised different exception"); + } + } +}); diff --git a/cli/js/tests/dispatch_json_test.ts b/cli/js/tests/dispatch_json_test.ts new file mode 100644 index 000000000..a2306dda8 --- /dev/null +++ b/cli/js/tests/dispatch_json_test.ts @@ -0,0 +1,32 @@ +import { assert, unitTest, assertMatch, unreachable } from "./test_util.ts"; + +const openErrorStackPattern = new RegExp( + `^.* + at unwrapResponse \\(.*dispatch_json\\.ts:.*\\) + at Object.sendAsync \\(.*dispatch_json\\.ts:.*\\) + at async Object\\.open \\(.*files\\.ts:.*\\).*$`, + "ms" +); + +unitTest( + { perms: { read: true } }, + async function sendAsyncStackTrace(): Promise { + await Deno.open("nonexistent.txt") + .then(unreachable) + .catch((error): void => { + assertMatch(error.stack, openErrorStackPattern); + }); + } +); + +unitTest(async function malformedJsonControlBuffer(): Promise { + // @ts-ignore + const opId = Deno.core.ops()["op_open"]; + // @ts-ignore + const res = Deno.core.send(opId, new Uint8Array([1, 2, 3, 4, 5])); + const resText = new TextDecoder().decode(res); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const resJson = JSON.parse(resText) as any; + assert(!resJson.ok); + assert(resJson.err); +}); diff --git a/cli/js/tests/dispatch_minimal_test.ts b/cli/js/tests/dispatch_minimal_test.ts new file mode 100644 index 000000000..724a41698 --- /dev/null +++ b/cli/js/tests/dispatch_minimal_test.ts @@ -0,0 +1,43 @@ +import { + assert, + assertEquals, + assertMatch, + unitTest, + unreachable +} from "./test_util.ts"; + +const readErrorStackPattern = new RegExp( + `^.* + at unwrapResponse \\(.*dispatch_minimal\\.ts:.*\\) + at Object.sendAsyncMinimal \\(.*dispatch_minimal\\.ts:.*\\) + at async Object\\.read \\(.*io\\.ts:.*\\).*$`, + "ms" +); + +unitTest(async function sendAsyncStackTrace(): Promise { + const buf = new Uint8Array(10); + const rid = 10; + try { + await Deno.read(rid, buf); + unreachable(); + } catch (error) { + assertMatch(error.stack, readErrorStackPattern); + } +}); + +unitTest(async function malformedMinimalControlBuffer(): Promise { + // @ts-ignore + const readOpId = Deno.core.ops()["op_read"]; + // @ts-ignore + const res = Deno.core.send(readOpId, new Uint8Array([1, 2, 3, 4, 5])); + const header = res.slice(0, 12); + const buf32 = new Int32Array( + header.buffer, + header.byteOffset, + header.byteLength / 4 + ); + const arg = buf32[1]; + const message = new TextDecoder().decode(res.slice(12)).trim(); + assert(arg < 0); + assertEquals(message, "Unparsable control buffer"); +}); diff --git a/cli/js/tests/dom_iterable_test.ts b/cli/js/tests/dom_iterable_test.ts new file mode 100644 index 000000000..e16378945 --- /dev/null +++ b/cli/js/tests/dom_iterable_test.ts @@ -0,0 +1,87 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +function setup() { + const dataSymbol = Symbol("data symbol"); + class Base { + private [dataSymbol] = new Map(); + + constructor( + data: Array<[string, number]> | IterableIterator<[string, number]> + ) { + for (const [key, value] of data) { + this[dataSymbol].set(key, value); + } + } + } + + return { + Base, + // This is using an internal API we don't want published as types, so having + // to cast to any to "trick" TypeScript + // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol + DomIterable: Deno[Deno.symbols.internal].DomIterableMixin(Base, dataSymbol) + }; +} + +unitTest(function testDomIterable(): void { + const { DomIterable, Base } = setup(); + + const fixture: Array<[string, number]> = [ + ["foo", 1], + ["bar", 2] + ]; + + const domIterable = new DomIterable(fixture); + + assertEquals(Array.from(domIterable.entries()), fixture); + assertEquals(Array.from(domIterable.values()), [1, 2]); + assertEquals(Array.from(domIterable.keys()), ["foo", "bar"]); + + let result: Array<[string, number]> = []; + for (const [key, value] of domIterable) { + assert(key != null); + assert(value != null); + result.push([key, value]); + } + assertEquals(fixture, result); + + result = []; + const scope = {}; + function callback( + this: typeof scope, + value: number, + key: string, + parent: typeof domIterable + ): void { + assertEquals(parent, domIterable); + assert(key != null); + assert(value != null); + assert(this === scope); + result.push([key, value]); + } + domIterable.forEach(callback, scope); + assertEquals(fixture, result); + + assertEquals(DomIterable.name, Base.name); +}); + +unitTest(function testDomIterableScope(): void { + const { DomIterable } = setup(); + + const domIterable = new DomIterable([["foo", 1]]); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function checkScope(thisArg: any, expected: any): void { + function callback(this: typeof thisArg): void { + assertEquals(this, expected); + } + domIterable.forEach(callback, thisArg); + } + + checkScope(0, Object(0)); + checkScope("", Object("")); + checkScope(null, window); + checkScope(undefined, window); +}); diff --git a/cli/js/tests/error_stack_test.ts b/cli/js/tests/error_stack_test.ts new file mode 100644 index 000000000..7acbd3a3d --- /dev/null +++ b/cli/js/tests/error_stack_test.ts @@ -0,0 +1,108 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +// @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol +const { setPrepareStackTrace } = Deno[Deno.symbols.internal]; + +interface CallSite { + getThis(): unknown; + getTypeName(): string; + getFunction(): Function; + getFunctionName(): string; + getMethodName(): string; + getFileName(): string; + getLineNumber(): number | null; + getColumnNumber(): number | null; + getEvalOrigin(): string | null; + isToplevel(): boolean; + isEval(): boolean; + isNative(): boolean; + isConstructor(): boolean; + isAsync(): boolean; + isPromiseAll(): boolean; + getPromiseIndex(): number | null; +} + +function getMockCallSite( + filename: string, + line: number | null, + column: number | null +): CallSite { + return { + getThis(): unknown { + return undefined; + }, + getTypeName(): string { + return ""; + }, + getFunction(): Function { + return (): void => {}; + }, + getFunctionName(): string { + return ""; + }, + getMethodName(): string { + return ""; + }, + getFileName(): string { + return filename; + }, + getLineNumber(): number | null { + return line; + }, + getColumnNumber(): number | null { + return column; + }, + getEvalOrigin(): null { + return null; + }, + isToplevel(): false { + return false; + }, + isEval(): false { + return false; + }, + isNative(): false { + return false; + }, + isConstructor(): false { + return false; + }, + isAsync(): false { + return false; + }, + isPromiseAll(): false { + return false; + }, + getPromiseIndex(): null { + return null; + } + }; +} + +unitTest(function prepareStackTrace(): void { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const MockError = {} as any; + setPrepareStackTrace(MockError); + assert(typeof MockError.prepareStackTrace === "function"); + const prepareStackTrace: ( + error: Error, + structuredStackTrace: CallSite[] + ) => string = MockError.prepareStackTrace; + const result = prepareStackTrace(new Error("foo"), [ + getMockCallSite("CLI_SNAPSHOT.js", 23, 0) + ]); + assert(result.startsWith("Error: foo\n")); + assert(result.includes(".ts:"), "should remap to something in 'js/'"); +}); + +unitTest(function applySourceMap(): void { + const result = Deno.applySourceMap({ + filename: "CLI_SNAPSHOT.js", + line: 23, + column: 0 + }); + assert(result.filename.endsWith(".ts")); + assert(result.line != null); + assert(result.column != null); +}); diff --git a/cli/js/tests/event_target_test.ts b/cli/js/tests/event_target_test.ts new file mode 100644 index 000000000..09d47f704 --- /dev/null +++ b/cli/js/tests/event_target_test.ts @@ -0,0 +1,231 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assertEquals } from "./test_util.ts"; + +unitTest(function addEventListenerTest(): void { + const document = new EventTarget(); + + // @ts-ignore tests ignoring the type system for resilience + assertEquals(document.addEventListener("x", null, false), undefined); + // @ts-ignore + assertEquals(document.addEventListener("x", null, true), undefined); + // @ts-ignore + assertEquals(document.addEventListener("x", null), undefined); +}); + +unitTest(function constructedEventTargetCanBeUsedAsExpected(): void { + const target = new EventTarget(); + const event = new Event("foo", { bubbles: true, cancelable: false }); + let callCount = 0; + + const listener = (e: Event): void => { + 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); +}); + +unitTest(function anEventTargetCanBeSubclassed(): void { + class NicerEventTarget extends EventTarget { + on( + type: string, + callback: ((e: Event) => void) | null, + options?: __domTypes.AddEventListenerOptions + ): void { + this.addEventListener(type, callback, options); + } + + off( + type: string, + callback: ((e: Event) => void) | null, + options?: __domTypes.EventListenerOptions + ): void { + this.removeEventListener(type, callback, options); + } + } + + const target = new NicerEventTarget(); + new Event("foo", { bubbles: true, cancelable: false }); + let callCount = 0; + + const listener = (): void => { + ++callCount; + }; + + target.on("foo", listener); + assertEquals(callCount, 0); + + target.off("foo", listener); + assertEquals(callCount, 0); +}); + +unitTest(function removingNullEventListenerShouldSucceed(): void { + const document = new EventTarget(); + // @ts-ignore + assertEquals(document.removeEventListener("x", null, false), undefined); + // @ts-ignore + assertEquals(document.removeEventListener("x", null, true), undefined); + // @ts-ignore + assertEquals(document.removeEventListener("x", null), undefined); +}); + +unitTest(function constructedEventTargetUseObjectPrototype(): void { + const target = new EventTarget(); + const event = new Event("toString", { bubbles: true, cancelable: false }); + let callCount = 0; + + const listener = (e: Event): void => { + 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); +}); + +unitTest(function toStringShouldBeWebCompatible(): void { + const target = new EventTarget(); + assertEquals(target.toString(), "[object EventTarget]"); +}); + +unitTest(function dispatchEventShouldNotThrowError(): void { + let hasThrown = false; + + try { + const target = new EventTarget(); + const event = new Event("hasOwnProperty", { + bubbles: true, + cancelable: false + }); + const listener = (): void => {}; + target.addEventListener("hasOwnProperty", listener); + target.dispatchEvent(event); + } catch { + hasThrown = true; + } + + assertEquals(hasThrown, false); +}); + +unitTest(function eventTargetThisShouldDefaultToWindow(): void { + const { + addEventListener, + dispatchEvent, + removeEventListener + } = EventTarget.prototype; + let n = 1; + const event = new Event("hello"); + const listener = (): void => { + 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); +}); + +unitTest(function eventTargetShouldAcceptEventListenerObject(): void { + const target = new EventTarget(); + const event = new Event("foo", { bubbles: true, cancelable: false }); + let callCount = 0; + + const listener = { + handleEvent(e: Event): void { + 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); +}); + +unitTest(function eventTargetShouldAcceptAsyncFunction(): void { + const target = new EventTarget(); + const event = new Event("foo", { bubbles: true, cancelable: false }); + let callCount = 0; + + const listener = async (e: Event): Promise => { + 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); +}); + +unitTest( + function eventTargetShouldAcceptAsyncFunctionForEventListenerObject(): void { + const target = new EventTarget(); + const event = new Event("foo", { bubbles: true, cancelable: false }); + let callCount = 0; + + const listener = { + async handleEvent(e: Event): Promise { + 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); + } +); diff --git a/cli/js/tests/event_test.ts b/cli/js/tests/event_test.ts new file mode 100644 index 000000000..05a9ed577 --- /dev/null +++ b/cli/js/tests/event_test.ts @@ -0,0 +1,96 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assertEquals, assert } from "./test_util.ts"; + +unitTest(function eventInitializedWithType(): void { + 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); +}); + +unitTest(function eventInitializedWithTypeAndDict(): void { + 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); +}); + +unitTest(function eventComposedPathSuccess(): void { + const type = "click"; + const event = new Event(type); + const composedPath = event.composedPath(); + + assertEquals(composedPath, []); +}); + +unitTest(function eventStopPropagationSuccess(): void { + const type = "click"; + const event = new Event(type); + + assertEquals(event.cancelBubble, false); + event.stopPropagation(); + assertEquals(event.cancelBubble, true); +}); + +unitTest(function eventStopImmediatePropagationSuccess(): void { + const type = "click"; + const event = new Event(type); + + assertEquals(event.cancelBubble, false); + assertEquals(event.cancelBubbleImmediately, false); + event.stopImmediatePropagation(); + assertEquals(event.cancelBubble, true); + assertEquals(event.cancelBubbleImmediately, true); +}); + +unitTest(function eventPreventDefaultSuccess(): void { + 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); +}); + +unitTest(function eventInitializedWithNonStringType(): void { + // eslint-disable-next-line @typescript-eslint/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); +}); + +// ref https://github.com/web-platform-tests/wpt/blob/master/dom/events/Event-isTrusted.any.js +unitTest(function eventIsTrusted(): void { + const desc1 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted"); + assert(desc1); + assertEquals(typeof desc1.get, "function"); + + const desc2 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted"); + assert(desc2); + assertEquals(typeof desc2!.get, "function"); + + assertEquals(desc1!.get, desc2!.get); +}); diff --git a/cli/js/tests/fetch_test.ts b/cli/js/tests/fetch_test.ts new file mode 100644 index 000000000..5ebef92d9 --- /dev/null +++ b/cli/js/tests/fetch_test.ts @@ -0,0 +1,497 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { + unitTest, + assert, + assertEquals, + assertStrContains, + assertThrows, + fail +} from "./test_util.ts"; + +unitTest({ perms: { net: true } }, async function fetchProtocolError(): Promise< + void +> { + let err; + try { + await fetch("file:///"); + } catch (err_) { + err = err_; + } + assert(err instanceof TypeError); + assertStrContains(err.message, "not supported"); +}); + +unitTest( + { perms: { net: true } }, + async function fetchConnectionError(): Promise { + let err; + try { + await fetch("http://localhost:4000"); + } catch (err_) { + err = err_; + } + assert(err instanceof Deno.errors.Http); + assertStrContains(err.message, "error trying to connect"); + } +); + +unitTest({ perms: { net: true } }, async function fetchJsonSuccess(): Promise< + void +> { + const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); + const json = await response.json(); + assertEquals(json.name, "deno"); +}); + +unitTest(async function fetchPerm(): Promise { + let err; + try { + await fetch("http://localhost:4545/cli/tests/fixture.json"); + } catch (err_) { + err = err_; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest({ perms: { net: true } }, async function fetchUrl(): Promise { + const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); + assertEquals(response.url, "http://localhost:4545/cli/tests/fixture.json"); + response.body.close(); +}); + +unitTest({ perms: { net: true } }, async function fetchURL(): Promise { + const response = await fetch( + new URL("http://localhost:4545/cli/tests/fixture.json") + ); + assertEquals(response.url, "http://localhost:4545/cli/tests/fixture.json"); + response.body.close(); +}); + +unitTest({ perms: { net: true } }, async function fetchHeaders(): Promise< + void +> { + const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); + const headers = response.headers; + assertEquals(headers.get("Content-Type"), "application/json"); + assert(headers.get("Server")!.startsWith("SimpleHTTP")); + response.body.close(); +}); + +unitTest({ perms: { net: true } }, async function fetchBlob(): Promise { + const response = await fetch("http://localhost:4545/cli/tests/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"))); +}); + +unitTest({ perms: { net: true } }, async function fetchBodyUsed(): Promise< + void +> { + const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); + assertEquals(response.bodyUsed, false); + assertThrows((): void => { + // Assigning to read-only property throws in the strict mode. + response.bodyUsed = true; + }); + await response.blob(); + assertEquals(response.bodyUsed, true); +}); + +unitTest({ perms: { net: true } }, async function fetchAsyncIterator(): Promise< + void +> { + const response = await fetch("http://localhost:4545/cli/tests/fixture.json"); + const headers = response.headers; + let total = 0; + for await (const chunk of response.body) { + total += chunk.length; + } + + assertEquals(total, Number(headers.get("Content-Length"))); + response.body.close(); +}); + +unitTest({ perms: { net: true } }, async function responseClone(): Promise< + void +> { + const response = await fetch("http://localhost:4545/cli/tests/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]); + } +}); + +unitTest({ perms: { net: true } }, async function fetchEmptyInvalid(): Promise< + void +> { + let err; + try { + await fetch(""); + } catch (err_) { + err = err_; + } + assert(err instanceof URIError); +}); + +unitTest( + { perms: { net: true } }, + async function fetchMultipartFormDataSuccess(): Promise { + const response = await fetch( + "http://localhost:4545/cli/tests/subdir/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")); + /* TODO(ry) Re-enable this test once we bring back the global File type. + const file = formData.get("field_2") as File; + assertEquals(file.name, "file.js"); + */ + // Currently we cannot read from file... + } +); + +unitTest( + { perms: { net: true } }, + async function fetchURLEncodedFormDataSuccess(): Promise { + const response = await fetch( + "http://localhost:4545/cli/tests/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(), ""); + } +); + +unitTest( + { + // TODO(bartlomieju): leaking resources + skip: true, + perms: { net: true } + }, + async function fetchWithRedirection(): Promise { + const response = await fetch("http://localhost:4546/"); // will redirect to http://localhost:4545/ + assertEquals(response.status, 200); + assertEquals(response.statusText, "OK"); + assertEquals(response.url, "http://localhost:4545/"); + const body = await response.text(); + assert(body.includes("Directory listing for /")); + } +); + +unitTest( + { + // TODO: leaking resources + skip: true, + perms: { net: true } + }, + async function fetchWithRelativeRedirection(): Promise { + const response = await fetch("http://localhost:4545/cli/tests"); // will redirect to /cli/tests/ + assertEquals(response.status, 200); + assertEquals(response.statusText, "OK"); + const body = await response.text(); + assert(body.includes("Directory listing for /cli/tests/")); + } +); + +// The feature below is not implemented, but the test should work after implementation +/* +unitTest({ perms: { net: true} }, async function fetchWithInfRedirection(): Promise< + void +> { + const response = await fetch("http://localhost:4549/cli/tests"); // will redirect to the same place + assertEquals(response.status, 0); // network error +}); +*/ + +unitTest( + { perms: { net: true } }, + async function fetchInitStringBody(): Promise { + 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")); + } +); + +unitTest( + { perms: { net: true } }, + async function fetchRequestInitStringBody(): Promise { + 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); + } +); + +unitTest( + { perms: { net: true } }, + async function fetchInitTypedArrayBody(): Promise { + 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); + } +); + +unitTest( + { perms: { net: true } }, + async function fetchInitURLSearchParamsBody(): Promise { + const data = "param1=value1¶m2=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") + ); + } +); + +unitTest({ perms: { net: true } }, async function fetchInitBlobBody(): Promise< + void +> { + 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")); +}); + +unitTest({ perms: { net: true } }, async function fetchUserAgent(): Promise< + void +> { + 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(); +}); + +// TODO(ry) The following tests work but are flaky. There's a race condition +// somewhere. Here is what one of these flaky failures looks like: +// +// unitTest fetchPostBodyString_permW0N1E0R0 +// assertEquals failed. actual = expected = POST /blah HTTP/1.1 +// hello: World +// foo: Bar +// host: 127.0.0.1:4502 +// content-length: 11 +// hello world +// Error: actual: expected: POST /blah HTTP/1.1 +// hello: World +// foo: Bar +// host: 127.0.0.1:4502 +// content-length: 11 +// hello world +// at Object.assertEquals (file:///C:/deno/js/testing/util.ts:29:11) +// at fetchPostBodyString (file + +/* +function bufferServer(addr: string): Deno.Buffer { + const listener = Deno.listen(addr); + const buf = new Deno.Buffer(); + listener.accept().then(async conn => { + 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; +} + +unitTest({ perms: { net: true} }, async function fetchRequest():Promise { + const addr = "127.0.0.1:4501"; + const buf = bufferServer(addr); + const response = await fetch(`http://${addr}/blah`, { + method: "POST", + headers: [["Hello", "World"], ["Foo", "Bar"]] + }); + assertEquals(response.status, 404); + assertEquals(response.headers.get("Content-Length"), "2"); + + const actual = new TextDecoder().decode(buf.bytes()); + const expected = [ + "POST /blah HTTP/1.1\r\n", + "hello: World\r\n", + "foo: Bar\r\n", + `host: ${addr}\r\n\r\n` + ].join(""); + assertEquals(actual, expected); +}); + +unitTest({ perms: { net: true} }, async function fetchPostBodyString():Promise { + const addr = "127.0.0.1:4502"; + const buf = bufferServer(addr); + const body = "hello world"; + const response = await fetch(`http://${addr}/blah`, { + method: "POST", + headers: [["Hello", "World"], ["Foo", "Bar"]], + body + }); + assertEquals(response.status, 404); + assertEquals(response.headers.get("Content-Length"), "2"); + + const actual = new TextDecoder().decode(buf.bytes()); + const expected = [ + "POST /blah HTTP/1.1\r\n", + "hello: World\r\n", + "foo: Bar\r\n", + `host: ${addr}\r\n`, + `content-length: ${body.length}\r\n\r\n`, + body + ].join(""); + assertEquals(actual, expected); +}); + +unitTest({ perms: { net: true} }, async function fetchPostBodyTypedArray():Promise { + const addr = "127.0.0.1:4503"; + const buf = 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 + }); + assertEquals(response.status, 404); + assertEquals(response.headers.get("Content-Length"), "2"); + + const actual = new TextDecoder().decode(buf.bytes()); + const expected = [ + "POST /blah HTTP/1.1\r\n", + "hello: World\r\n", + "foo: Bar\r\n", + `host: ${addr}\r\n`, + `content-length: ${body.byteLength}\r\n\r\n`, + bodyStr + ].join(""); + assertEquals(actual, expected); +}); +*/ + +unitTest( + { + // TODO: leaking resources + skip: true, + perms: { net: true } + }, + async function fetchWithManualRedirection(): Promise { + const response = await fetch("http://localhost:4546/", { + redirect: "manual" + }); // will redirect to http://localhost:4545/ + assertEquals(response.status, 0); + assertEquals(response.statusText, ""); + assertEquals(response.url, ""); + assertEquals(response.type, "opaqueredirect"); + try { + await response.text(); + fail( + "Reponse.text() didn't throw on a filtered response without a body (type opaqueredirect)" + ); + } catch (e) { + return; + } + } +); + +unitTest( + { + // TODO: leaking resources + skip: true, + perms: { net: true } + }, + async function fetchWithErrorRedirection(): Promise { + const response = await fetch("http://localhost:4546/", { + redirect: "error" + }); // will redirect to http://localhost:4545/ + assertEquals(response.status, 0); + assertEquals(response.statusText, ""); + assertEquals(response.url, ""); + assertEquals(response.type, "error"); + try { + await response.text(); + fail( + "Reponse.text() didn't throw on a filtered response without a body (type error)" + ); + } catch (e) { + return; + } + } +); + +unitTest(function responseRedirect(): void { + const response = new Response( + "example.com/beforeredirect", + 200, + "OK", + [["This-Should", "Disappear"]], + -1, + false, + null + ); + const redir = response.redirect("example.com/newLocation", 301); + assertEquals(redir.status, 301); + assertEquals(redir.statusText, ""); + assertEquals(redir.url, ""); + assertEquals(redir.headers.get("Location"), "example.com/newLocation"); + assertEquals(redir.type, "default"); +}); + +unitTest(function responseConstructionHeaderRemoval(): void { + const res = new Response( + "example.com", + 200, + "OK", + [["Set-Cookie", "mysessionid"]], + -1, + false, + "basic", + null + ); + assert(res.headers.get("Set-Cookie") != "mysessionid"); +}); diff --git a/cli/js/tests/file_test.ts b/cli/js/tests/file_test.ts new file mode 100644 index 000000000..1a7a5f88b --- /dev/null +++ b/cli/js/tests/file_test.ts @@ -0,0 +1,105 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function testFirstArgument(arg1: any[], expectedSize: number): void { + const file = new File(arg1, "name"); + assert(file instanceof File); + assertEquals(file.name, "name"); + assertEquals(file.size, expectedSize); + assertEquals(file.type, ""); +} + +unitTest(function fileEmptyFileBits(): void { + testFirstArgument([], 0); +}); + +unitTest(function fileStringFileBits(): void { + testFirstArgument(["bits"], 4); +}); + +unitTest(function fileUnicodeStringFileBits(): void { + testFirstArgument(["𝓽𝓮𝔁𝓽"], 16); +}); + +unitTest(function fileStringObjectFileBits(): void { + testFirstArgument([new String("string object")], 13); +}); + +unitTest(function fileEmptyBlobFileBits(): void { + testFirstArgument([new Blob()], 0); +}); + +unitTest(function fileBlobFileBits(): void { + testFirstArgument([new Blob(["bits"])], 4); +}); + +unitTest(function fileEmptyFileFileBits(): void { + testFirstArgument([new File([], "world.txt")], 0); +}); + +unitTest(function fileFileFileBits(): void { + testFirstArgument([new File(["bits"], "world.txt")], 4); +}); + +unitTest(function fileArrayBufferFileBits(): void { + testFirstArgument([new ArrayBuffer(8)], 8); +}); + +unitTest(function fileTypedArrayFileBits(): void { + testFirstArgument([new Uint8Array([0x50, 0x41, 0x53, 0x53])], 4); +}); + +unitTest(function fileVariousFileBits(): void { + testFirstArgument( + [ + "bits", + new Blob(["bits"]), + new Blob(), + new Uint8Array([0x50, 0x41]), + new Uint16Array([0x5353]), + new Uint32Array([0x53534150]) + ], + 16 + ); +}); + +unitTest(function fileNumberInFileBits(): void { + testFirstArgument([12], 2); +}); + +unitTest(function fileArrayInFileBits(): void { + testFirstArgument([[1, 2, 3]], 5); +}); + +unitTest(function fileObjectInFileBits(): void { + // "[object Object]" + testFirstArgument([{}], 15); +}); + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function testSecondArgument(arg2: any, expectedFileName: string): void { + const file = new File(["bits"], arg2); + assert(file instanceof File); + assertEquals(file.name, expectedFileName); +} + +unitTest(function fileUsingFileName(): void { + testSecondArgument("dummy", "dummy"); +}); + +unitTest(function fileUsingSpecialCharacterInFileName(): void { + testSecondArgument("dummy/foo", "dummy:foo"); +}); + +unitTest(function fileUsingNullFileName(): void { + testSecondArgument(null, "null"); +}); + +unitTest(function fileUsingNumberFileName(): void { + testSecondArgument(1, "1"); +}); + +unitTest(function fileUsingEmptyStringFileName(): void { + testSecondArgument("", ""); +}); diff --git a/cli/js/tests/files_test.ts b/cli/js/tests/files_test.ts new file mode 100644 index 000000000..49fecabe0 --- /dev/null +++ b/cli/js/tests/files_test.ts @@ -0,0 +1,446 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { + unitTest, + assert, + assertEquals, + assertStrContains +} from "./test_util.ts"; + +unitTest(function filesStdioFileDescriptors(): void { + assertEquals(Deno.stdin.rid, 0); + assertEquals(Deno.stdout.rid, 1); + assertEquals(Deno.stderr.rid, 2); +}); + +unitTest({ perms: { read: true } }, async function filesCopyToStdout(): Promise< + void +> { + const filename = "cli/tests/fixture.json"; + const file = await Deno.open(filename); + assert(file.rid > 2); + const bytesWritten = await Deno.copy(Deno.stdout, file); + const fileSize = Deno.statSync(filename).len; + assertEquals(bytesWritten, fileSize); + console.log("bytes written", bytesWritten); + file.close(); +}); + +unitTest( + { perms: { read: true } }, + async function filesToAsyncIterator(): Promise { + const filename = "cli/tests/hello.txt"; + const file = await Deno.open(filename); + + let totalSize = 0; + for await (const buf of Deno.toAsyncIterator(file)) { + totalSize += buf.byteLength; + } + + assertEquals(totalSize, 12); + file.close(); + } +); + +unitTest(async function readerToAsyncIterator(): Promise { + // ref: https://github.com/denoland/deno/issues/2330 + const encoder = new TextEncoder(); + + class TestReader implements Deno.Reader { + private offset = 0; + private buf = new Uint8Array(encoder.encode(this.s)); + + constructor(private readonly s: string) {} + + async read(p: Uint8Array): Promise { + 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 Deno.EOF; + } + + return n; + } + } + + const reader = new TestReader("hello world!"); + + let totalSize = 0; + for await (const buf of Deno.toAsyncIterator(reader)) { + totalSize += buf.byteLength; + } + + assertEquals(totalSize, 12); +}); + +unitTest( + { perms: { write: false } }, + async function writePermFailure(): Promise { + const filename = "tests/hello.txt"; + const writeModes: Deno.OpenMode[] = ["w", "a", "x"]; + for (const mode of writeModes) { + let err; + try { + await Deno.open(filename, mode); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } + } +); + +unitTest(async function openOptions(): Promise { + const filename = "cli/tests/fixture.json"; + let err; + try { + await Deno.open(filename, { write: false }); + } catch (e) { + err = e; + } + assert(!!err); + assertStrContains( + err.message, + "OpenOptions requires at least one option to be true" + ); + + try { + await Deno.open(filename, { truncate: true, write: false }); + } catch (e) { + err = e; + } + assert(!!err); + assertStrContains(err.message, "'truncate' option requires 'write' option"); + + try { + await Deno.open(filename, { create: true, write: false }); + } catch (e) { + err = e; + } + assert(!!err); + assertStrContains( + err.message, + "'create' or 'createNew' options require 'write' or 'append' option" + ); + + try { + await Deno.open(filename, { createNew: true, append: false }); + } catch (e) { + err = e; + } + assert(!!err); + assertStrContains( + err.message, + "'create' or 'createNew' options require 'write' or 'append' option" + ); +}); + +unitTest({ perms: { read: false } }, async function readPermFailure(): Promise< + void +> { + let caughtError = false; + try { + await Deno.open("package.json", "r"); + await Deno.open("cli/tests/fixture.json", "r"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest( + { perms: { write: true } }, + async function writeNullBufferFailure(): Promise { + const tempDir = Deno.makeTempDirSync(); + const filename = tempDir + "hello.txt"; + const w = { + write: true, + truncate: true, + create: true + }; + const file = await Deno.open(filename, w); + + // writing null should throw an error + let err; + try { + // @ts-ignore + await file.write(null); + } catch (e) { + err = e; + } + // TODO: Check error kind when dispatch_minimal pipes errors properly + assert(!!err); + + file.close(); + await Deno.remove(tempDir, { recursive: true }); + } +); + +unitTest( + { perms: { write: true, read: true } }, + async function readNullBufferFailure(): Promise { + const tempDir = Deno.makeTempDirSync(); + const filename = tempDir + "hello.txt"; + const file = await Deno.open(filename, "w+"); + + // 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 + let err; + try { + // @ts-ignore + await file.read(null); + } catch (e) { + err = e; + } + // TODO: Check error kind when dispatch_minimal pipes errors properly + assert(!!err); + + file.close(); + await Deno.remove(tempDir, { recursive: true }); + } +); + +unitTest( + { perms: { write: false, read: false } }, + async function readWritePermFailure(): Promise { + const filename = "tests/hello.txt"; + const writeModes: Deno.OpenMode[] = ["r+", "w+", "a+", "x+"]; + for (const mode of writeModes) { + let err; + try { + await Deno.open(filename, mode); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function createFile(): Promise { + 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.len === 0); + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + await f.write(data); + fileInfo = Deno.statSync(filename); + assert(fileInfo.len === 5); + f.close(); + + // TODO: test different modes + await Deno.remove(tempDir, { recursive: true }); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function openModeWrite(): Promise { + 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, "w"); + // assert file was created + let fileInfo = Deno.statSync(filename); + assert(fileInfo.isFile()); + assertEquals(fileInfo.len, 0); + // write some data + await file.write(data); + fileInfo = Deno.statSync(filename); + assertEquals(fileInfo.len, 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, "w"); + file.close(); + const fileSize = Deno.statSync(filename).len; + assertEquals(fileSize, 0); + await Deno.remove(tempDir, { recursive: true }); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function openModeWriteRead(): Promise { + const tempDir = Deno.makeTempDirSync(); + const encoder = new TextEncoder(); + const filename = tempDir + "hello.txt"; + const data = encoder.encode("Hello world!\n"); + + const file = await Deno.open(filename, "w+"); + const seekPosition = 0; + // assert file was created + let fileInfo = Deno.statSync(filename); + assert(fileInfo.isFile()); + assertEquals(fileInfo.len, 0); + // write some data + await file.write(data); + fileInfo = Deno.statSync(filename); + assertEquals(fileInfo.len, 13); + + const buf = new Uint8Array(20); + // seeking from beginning of a file + const cursorPosition = await file.seek( + seekPosition, + Deno.SeekMode.SEEK_START + ); + assertEquals(seekPosition, cursorPosition); + const result = await file.read(buf); + assertEquals(result, 13); + file.close(); + + await Deno.remove(tempDir, { recursive: true }); + } +); + +unitTest({ perms: { read: true } }, async function seekStart(): Promise { + const filename = "cli/tests/hello.txt"; + const 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.SEEK_START + ); + assertEquals(seekPosition, cursorPosition); + const buf = new Uint8Array(6); + await file.read(buf); + const decoded = new TextDecoder().decode(buf); + assertEquals(decoded, "world!"); + file.close(); +}); + +unitTest({ perms: { read: true } }, function seekSyncStart(): void { + const filename = "cli/tests/hello.txt"; + const 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.SEEK_START); + assertEquals(seekPosition, cursorPosition); + const buf = new Uint8Array(6); + file.readSync(buf); + const decoded = new TextDecoder().decode(buf); + assertEquals(decoded, "world!"); + file.close(); +}); + +unitTest({ perms: { read: true } }, async function seekCurrent(): Promise< + void +> { + const filename = "cli/tests/hello.txt"; + const 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.SEEK_CURRENT + ); + assertEquals(seekPosition + 1, cursorPosition); + const buf = new Uint8Array(6); + await file.read(buf); + const decoded = new TextDecoder().decode(buf); + assertEquals(decoded, "world!"); + file.close(); +}); + +unitTest({ perms: { read: true } }, function seekSyncCurrent(): void { + const filename = "cli/tests/hello.txt"; + const 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.SEEK_CURRENT + ); + assertEquals(seekPosition + 1, cursorPosition); + const buf = new Uint8Array(6); + file.readSync(buf); + const decoded = new TextDecoder().decode(buf); + assertEquals(decoded, "world!"); + file.close(); +}); + +unitTest({ perms: { read: true } }, async function seekEnd(): Promise { + const filename = "cli/tests/hello.txt"; + const 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.SEEK_END); + assertEquals(6, cursorPosition); + const buf = new Uint8Array(6); + await file.read(buf); + const decoded = new TextDecoder().decode(buf); + assertEquals(decoded, "world!"); + file.close(); +}); + +unitTest({ perms: { read: true } }, function seekSyncEnd(): void { + const filename = "cli/tests/hello.txt"; + const 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.SEEK_END); + assertEquals(6, cursorPosition); + const buf = new Uint8Array(6); + file.readSync(buf); + const decoded = new TextDecoder().decode(buf); + assertEquals(decoded, "world!"); + file.close(); +}); + +unitTest({ perms: { read: true } }, async function seekMode(): Promise { + const filename = "cli/tests/hello.txt"; + const file = await Deno.open(filename); + let err; + try { + await file.seek(1, -1); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof TypeError); + assertStrContains(err.message, "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"); + file.close(); +}); diff --git a/cli/js/tests/form_data_test.ts b/cli/js/tests/form_data_test.ts new file mode 100644 index 000000000..9b218547c --- /dev/null +++ b/cli/js/tests/form_data_test.ts @@ -0,0 +1,189 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest(function formDataHasCorrectNameProp(): void { + assertEquals(FormData.name, "FormData"); +}); + +unitTest(function formDataParamsAppendSuccess(): void { + const formData = new FormData(); + formData.append("a", "true"); + assertEquals(formData.get("a"), "true"); +}); + +unitTest(function formDataParamsDeleteSuccess(): void { + const formData = new FormData(); + formData.append("a", "true"); + formData.append("b", "false"); + assertEquals(formData.get("b"), "false"); + formData.delete("b"); + assertEquals(formData.get("a"), "true"); + assertEquals(formData.get("b"), null); +}); + +unitTest(function formDataParamsGetAllSuccess(): void { + const formData = new FormData(); + formData.append("a", "true"); + formData.append("b", "false"); + formData.append("a", "null"); + assertEquals(formData.getAll("a"), ["true", "null"]); + assertEquals(formData.getAll("b"), ["false"]); + assertEquals(formData.getAll("c"), []); +}); + +unitTest(function formDataParamsGetSuccess(): void { + const formData = new FormData(); + formData.append("a", "true"); + formData.append("b", "false"); + formData.append("a", "null"); + // @ts-ignore + formData.append("d", undefined); + // @ts-ignore + formData.append("e", null); + assertEquals(formData.get("a"), "true"); + assertEquals(formData.get("b"), "false"); + assertEquals(formData.get("c"), null); + assertEquals(formData.get("d"), "undefined"); + assertEquals(formData.get("e"), "null"); +}); + +unitTest(function formDataParamsHasSuccess(): void { + const formData = new FormData(); + formData.append("a", "true"); + formData.append("b", "false"); + assert(formData.has("a")); + assert(formData.has("b")); + assert(!formData.has("c")); +}); + +unitTest(function formDataParamsSetSuccess(): void { + const formData = new FormData(); + formData.append("a", "true"); + formData.append("b", "false"); + formData.append("a", "null"); + assertEquals(formData.getAll("a"), ["true", "null"]); + assertEquals(formData.getAll("b"), ["false"]); + formData.set("a", "false"); + assertEquals(formData.getAll("a"), ["false"]); + // @ts-ignore + formData.set("d", undefined); + assertEquals(formData.get("d"), "undefined"); + // @ts-ignore + formData.set("e", null); + assertEquals(formData.get("e"), "null"); +}); + +unitTest(function formDataSetEmptyBlobSuccess(): void { + const formData = new FormData(); + formData.set("a", new Blob([]), "blank.txt"); + formData.get("a"); + /* TODO Fix this test. + assert(file instanceof File); + if (typeof file !== "string") { + assertEquals(file.name, "blank.txt"); + } + */ +}); + +unitTest(function formDataParamsForEachSuccess(): void { + const init = [ + ["a", "54"], + ["b", "true"] + ]; + const formData = new FormData(); + for (const [name, value] of init) { + formData.append(name, value); + } + let callNum = 0; + formData.forEach((value, key, parent): void => { + assertEquals(formData, parent); + assertEquals(value, init[callNum][1]); + assertEquals(key, init[callNum][0]); + callNum++; + }); + assertEquals(callNum, init.length); +}); + +unitTest(function formDataParamsArgumentsCheck(): void { + const methodRequireOneParam = [ + "delete", + "getAll", + "get", + "has", + "forEach" + ] as const; + + const methodRequireTwoParams = ["append", "set"] as const; + + methodRequireOneParam.forEach((method): void => { + const formData = new FormData(); + let hasThrown = 0; + let errMsg = ""; + try { + // @ts-ignore + formData[method](); + hasThrown = 1; + } catch (err) { + errMsg = err.message; + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEquals(hasThrown, 2); + assertEquals( + errMsg, + `FormData.${method} requires at least 1 argument, but only 0 present` + ); + }); + + methodRequireTwoParams.forEach((method: string): void => { + const formData = new FormData(); + let hasThrown = 0; + let errMsg = ""; + + try { + // @ts-ignore + formData[method](); + hasThrown = 1; + } catch (err) { + errMsg = err.message; + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEquals(hasThrown, 2); + assertEquals( + errMsg, + `FormData.${method} requires at least 2 arguments, but only 0 present` + ); + + hasThrown = 0; + errMsg = ""; + try { + // @ts-ignore + formData[method]("foo"); + hasThrown = 1; + } catch (err) { + errMsg = err.message; + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEquals(hasThrown, 2); + assertEquals( + errMsg, + `FormData.${method} requires at least 2 arguments, but only 1 present` + ); + }); +}); + +unitTest(function toStringShouldBeWebCompatibility(): void { + const formData = new FormData(); + assertEquals(formData.toString(), "[object FormData]"); +}); diff --git a/cli/js/tests/format_error_test.ts b/cli/js/tests/format_error_test.ts new file mode 100644 index 000000000..9831ef160 --- /dev/null +++ b/cli/js/tests/format_error_test.ts @@ -0,0 +1,37 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { assert, unitTest } from "./test_util.ts"; + +unitTest(function formatDiagnosticBasic() { + const fixture: Deno.DiagnosticItem[] = [ + { + message: "Example error", + category: Deno.DiagnosticCategory.Error, + sourceLine: "abcdefghijklmnopqrstuv", + lineNumber: 1000, + scriptResourceName: "foo.ts", + startColumn: 1, + endColumn: 2, + code: 4000 + } + ]; + const out = Deno.formatDiagnostics(fixture); + assert(out.includes("Example error")); + assert(out.includes("foo.ts")); +}); + +unitTest(function formatDiagnosticError() { + let thrown = false; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const bad = ([{ hello: 123 }] as any) as Deno.DiagnosticItem[]; + try { + Deno.formatDiagnostics(bad); + } catch (e) { + assert(e instanceof TypeError); + thrown = true; + } + assert(thrown); +}); + +if (import.meta.main) { + Deno.runTests(); +} diff --git a/cli/js/tests/fs_events_test.ts b/cli/js/tests/fs_events_test.ts new file mode 100644 index 000000000..b1697971a --- /dev/null +++ b/cli/js/tests/fs_events_test.ts @@ -0,0 +1,51 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +// TODO(ry) Add more tests to specify format. + +unitTest({ perms: { read: false } }, function fsEventsPermissions() { + let thrown = false; + try { + Deno.fsEvents("."); + } catch (err) { + assert(err instanceof Deno.errors.PermissionDenied); + thrown = true; + } + assert(thrown); +}); + +async function getTwoEvents( + iter: AsyncIterableIterator +): Promise { + const events = []; + for await (const event of iter) { + events.push(event); + if (events.length > 2) break; + } + return events; +} + +unitTest( + { perms: { read: true, write: true } }, + async function fsEventsBasic(): Promise { + const testDir = await Deno.makeTempDir(); + const iter = Deno.fsEvents(testDir); + + // Asynchornously 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)); + } +); diff --git a/cli/js/tests/get_random_values_test.ts b/cli/js/tests/get_random_values_test.ts new file mode 100644 index 000000000..76fa732ea --- /dev/null +++ b/cli/js/tests/get_random_values_test.ts @@ -0,0 +1,51 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assertNotEquals, assertStrictEq } from "./test_util.ts"; + +unitTest(function getRandomValuesInt8Array(): void { + const arr = new Int8Array(32); + crypto.getRandomValues(arr); + assertNotEquals(arr, new Int8Array(32)); +}); + +unitTest(function getRandomValuesUint8Array(): void { + const arr = new Uint8Array(32); + crypto.getRandomValues(arr); + assertNotEquals(arr, new Uint8Array(32)); +}); + +unitTest(function getRandomValuesUint8ClampedArray(): void { + const arr = new Uint8ClampedArray(32); + crypto.getRandomValues(arr); + assertNotEquals(arr, new Uint8ClampedArray(32)); +}); + +unitTest(function getRandomValuesInt16Array(): void { + const arr = new Int16Array(4); + crypto.getRandomValues(arr); + assertNotEquals(arr, new Int16Array(4)); +}); + +unitTest(function getRandomValuesUint16Array(): void { + const arr = new Uint16Array(4); + crypto.getRandomValues(arr); + assertNotEquals(arr, new Uint16Array(4)); +}); + +unitTest(function getRandomValuesInt32Array(): void { + const arr = new Int32Array(8); + crypto.getRandomValues(arr); + assertNotEquals(arr, new Int32Array(8)); +}); + +unitTest(function getRandomValuesUint32Array(): void { + const arr = new Uint32Array(8); + crypto.getRandomValues(arr); + assertNotEquals(arr, new Uint32Array(8)); +}); + +unitTest(function getRandomValuesReturnValue(): void { + const arr = new Uint32Array(8); + const rtn = crypto.getRandomValues(arr); + assertNotEquals(arr, new Uint32Array(8)); + assertStrictEq(rtn, arr); +}); diff --git a/cli/js/tests/globals_test.ts b/cli/js/tests/globals_test.ts new file mode 100644 index 000000000..aa8b4f46e --- /dev/null +++ b/cli/js/tests/globals_test.ts @@ -0,0 +1,112 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +unitTest(function globalThisExists(): void { + assert(globalThis != null); +}); + +unitTest(function windowExists(): void { + assert(window != null); +}); + +unitTest(function selfExists(): void { + assert(self != null); +}); + +unitTest(function windowWindowExists(): void { + assert(window.window === window); +}); + +unitTest(function windowSelfExists(): void { + assert(window.self === window); +}); + +unitTest(function globalThisEqualsWindow(): void { + assert(globalThis === window); +}); + +unitTest(function globalThisEqualsSelf(): void { + assert(globalThis === self); +}); + +unitTest(function DenoNamespaceExists(): void { + assert(Deno != null); +}); + +unitTest(function DenoNamespaceEqualsWindowDeno(): void { + assert(Deno === window.Deno); +}); + +unitTest(function DenoNamespaceIsFrozen(): void { + assert(Object.isFrozen(Deno)); +}); + +unitTest(function webAssemblyExists(): void { + assert(typeof WebAssembly.compile === "function"); +}); + +unitTest(function DenoNamespaceImmutable(): void { + const denoCopy = window.Deno; + try { + // @ts-ignore + Deno = 1; + } catch {} + assert(denoCopy === Deno); + try { + // @ts-ignore + window.Deno = 1; + } catch {} + assert(denoCopy === Deno); + try { + delete window.Deno; + } catch {} + assert(denoCopy === Deno); + + const { readFile } = Deno; + try { + // @ts-ignore + Deno.readFile = 1; + } catch {} + assert(readFile === Deno.readFile); + try { + delete window.Deno.readFile; + } catch {} + assert(readFile === Deno.readFile); + + // @ts-ignore + const { print } = Deno.core; + try { + // @ts-ignore + Deno.core.print = 1; + } catch {} + // @ts-ignore + assert(print === Deno.core.print); + try { + // @ts-ignore + delete Deno.core.print; + } catch {} + // @ts-ignore + assert(print === Deno.core.print); +}); + +unitTest(async function windowQueueMicrotask(): Promise { + let resolve1: () => void | undefined; + let resolve2: () => void | undefined; + let microtaskDone = false; + const p1 = new Promise((res): void => { + resolve1 = (): void => { + microtaskDone = true; + res(); + }; + }); + const p2 = new Promise((res): void => { + resolve2 = (): void => { + assert(microtaskDone); + res(); + }; + }); + window.queueMicrotask(resolve1!); + setTimeout(resolve2!, 0); + await p1; + await p2; +}); diff --git a/cli/js/tests/headers_test.ts b/cli/js/tests/headers_test.ts new file mode 100644 index 000000000..fcb5385a5 --- /dev/null +++ b/cli/js/tests/headers_test.ts @@ -0,0 +1,355 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; +const { + stringifyArgs + // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol +} = Deno[Deno.symbols.internal]; + +// 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 +unitTest(function newHeaderTest(): void { + new Headers(); + new Headers(undefined); + new Headers({}); + try { + // @ts-ignore + new Headers(null); + } catch (e) { + assertEquals( + e.message, + "Failed to construct 'Headers'; The provided value was not valid" + ); + } +}); + +const headerDict: Record = { + name1: "value1", + name2: "value2", + name3: "value3", + // @ts-ignore + name4: undefined, + "Content-Type": "value4" +}; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const headerSeq: any[] = []; +for (const name in headerDict) { + headerSeq.push([name, headerDict[name]]); +} + +unitTest(function newHeaderWithSequence(): void { + const headers = new Headers(headerSeq); + for (const name in headerDict) { + assertEquals(headers.get(name), String(headerDict[name])); + } + assertEquals(headers.get("length"), null); +}); + +unitTest(function newHeaderWithRecord(): void { + const headers = new Headers(headerDict); + for (const name in headerDict) { + assertEquals(headers.get(name), String(headerDict[name])); + } +}); + +unitTest(function newHeaderWithHeadersInstance(): void { + const headers = new Headers(headerDict); + const headers2 = new Headers(headers); + for (const name in headerDict) { + assertEquals(headers2.get(name), String(headerDict[name])); + } +}); + +unitTest(function headerAppendSuccess(): void { + const headers = new Headers(); + for (const name in headerDict) { + headers.append(name, headerDict[name]); + assertEquals(headers.get(name), String(headerDict[name])); + } +}); + +unitTest(function headerSetSuccess(): void { + const headers = new Headers(); + for (const name in headerDict) { + headers.set(name, headerDict[name]); + assertEquals(headers.get(name), String(headerDict[name])); + } +}); + +unitTest(function headerHasSuccess(): void { + const headers = new Headers(headerDict); + for (const name in headerDict) { + assert(headers.has(name), "headers has name " + name); + assert( + !headers.has("nameNotInHeaders"), + "headers do not have header: nameNotInHeaders" + ); + } +}); + +unitTest(function headerDeleteSuccess(): void { + const headers = new Headers(headerDict); + for (const name in 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); + } +}); + +unitTest(function headerGetSuccess(): void { + const headers = new Headers(headerDict); + for (const name in headerDict) { + assertEquals(headers.get(name), String(headerDict[name])); + assertEquals(headers.get("nameNotInHeaders"), null); + } +}); + +unitTest(function headerEntriesSuccess(): void { + 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)); + } +}); + +unitTest(function headerKeysSuccess(): void { + const headers = new Headers(headerDict); + const iterators = headers.keys(); + for (const it of iterators) { + assert(headers.has(it)); + } +}); + +unitTest(function headerValuesSuccess(): void { + 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 = { + name1: "value1", + Name2: "value2", + name: "value3", + "content-Type": "value4", + "Content-Typ": "value5", + "Content-Types": "value6" +}; + +unitTest(function headerForEachSuccess(): void { + const headers = new Headers(headerEntriesDict); + const keys = Object.keys(headerEntriesDict); + keys.forEach((key): void => { + const value = headerEntriesDict[key]; + const newkey = key.toLowerCase(); + headerEntriesDict[newkey] = value; + }); + let callNum = 0; + headers.forEach((value, key, container): void => { + assertEquals(headers, container); + assertEquals(value, headerEntriesDict[key]); + callNum++; + }); + assertEquals(callNum, keys.length); +}); + +unitTest(function headerSymbolIteratorSuccess(): void { + 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)); + } +}); + +unitTest(function headerTypesAvailable(): void { + 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. +unitTest(function headerIllegalReject(): void { + 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. +unitTest(function headerParamsShouldThrowTypeError(): void { + 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); +}); + +unitTest(function headerParamsArgumentsCheck(): void { + const methodRequireOneParam = ["delete", "get", "has", "forEach"]; + + const methodRequireTwoParams = ["append", "set"]; + + methodRequireOneParam.forEach((method): void => { + const headers = new Headers(); + let hasThrown = 0; + let errMsg = ""; + try { + // @ts-ignore + headers[method](); + hasThrown = 1; + } catch (err) { + errMsg = err.message; + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEquals(hasThrown, 2); + assertEquals( + errMsg, + `Headers.${method} requires at least 1 argument, but only 0 present` + ); + }); + + methodRequireTwoParams.forEach((method): void => { + const headers = new Headers(); + let hasThrown = 0; + let errMsg = ""; + + try { + // @ts-ignore + headers[method](); + hasThrown = 1; + } catch (err) { + errMsg = err.message; + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEquals(hasThrown, 2); + assertEquals( + errMsg, + `Headers.${method} requires at least 2 arguments, but only 0 present` + ); + + hasThrown = 0; + errMsg = ""; + try { + // @ts-ignore + headers[method]("foo"); + hasThrown = 1; + } catch (err) { + errMsg = err.message; + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEquals(hasThrown, 2); + assertEquals( + errMsg, + `Headers.${method} requires at least 2 arguments, but only 1 present` + ); + }); +}); + +unitTest(function toStringShouldBeWebCompatibility(): void { + const headers = new Headers(); + assertEquals(headers.toString(), "[object Headers]"); +}); + +function stringify(...args: unknown[]): string { + return stringifyArgs(args).replace(/\n$/, ""); +} + +unitTest(function customInspectReturnsCorrectHeadersFormat(): void { + 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-type: application/json, content-length: 1337 }" + ); +}); diff --git a/cli/js/tests/internals_test.ts b/cli/js/tests/internals_test.ts new file mode 100644 index 000000000..fb712707c --- /dev/null +++ b/cli/js/tests/internals_test.ts @@ -0,0 +1,10 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +unitTest(function internalsExists(): void { + const { + stringifyArgs + // @ts-ignore TypeScript (as of 3.7) does not support indexing namespaces by symbol + } = Deno[Deno.symbols.internal]; + assert(!!stringifyArgs); +}); diff --git a/cli/js/tests/link_test.ts b/cli/js/tests/link_test.ts new file mode 100644 index 000000000..e9f72ebef --- /dev/null +++ b/cli/js/tests/link_test.ts @@ -0,0 +1,147 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest( + { perms: { read: true, write: true } }, + function linkSyncSuccess(): void { + 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 = new TextDecoder().decode(Deno.readFileSync(newName)); + assertEquals(oldData, newData); + // Writing to newname also affects oldname. + const newData2 = "Modified"; + Deno.writeFileSync(newName, new TextEncoder().encode(newData2)); + assertEquals( + newData2, + new TextDecoder().decode(Deno.readFileSync(oldName)) + ); + // Writing to oldname also affects newname. + const newData3 = "ModifiedAgain"; + Deno.writeFileSync(oldName, new TextEncoder().encode(newData3)); + assertEquals( + newData3, + new TextDecoder().decode(Deno.readFileSync(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, + new TextDecoder().decode(Deno.readFileSync(newName)) + ); + } +); + +unitTest( + { perms: { read: true, write: true } }, + function linkSyncExists(): void { + 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")); + + let err; + try { + Deno.linkSync(oldName, newName); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Deno.errors.AlreadyExists); + } +); + +unitTest( + { perms: { read: true, write: true } }, + function linkSyncNotFound(): void { + const testDir = Deno.makeTempDirSync(); + const oldName = testDir + "/oldname"; + const newName = testDir + "/newname"; + + let err; + try { + Deno.linkSync(oldName, newName); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { read: false, write: true } }, + function linkSyncReadPerm(): void { + let err; + try { + Deno.linkSync("oldbaddir", "newbaddir"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } +); + +unitTest( + { perms: { read: true, write: false } }, + function linkSyncWritePerm(): void { + let err; + try { + Deno.linkSync("oldbaddir", "newbaddir"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function linkSuccess(): Promise { + 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 = new TextDecoder().decode(Deno.readFileSync(newName)); + assertEquals(oldData, newData); + // Writing to newname also affects oldname. + const newData2 = "Modified"; + Deno.writeFileSync(newName, new TextEncoder().encode(newData2)); + assertEquals( + newData2, + new TextDecoder().decode(Deno.readFileSync(oldName)) + ); + // Writing to oldname also affects newname. + const newData3 = "ModifiedAgain"; + Deno.writeFileSync(oldName, new TextEncoder().encode(newData3)); + assertEquals( + newData3, + new TextDecoder().decode(Deno.readFileSync(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, + new TextDecoder().decode(Deno.readFileSync(newName)) + ); + } +); diff --git a/cli/js/tests/location_test.ts b/cli/js/tests/location_test.ts new file mode 100644 index 000000000..78ecb55b3 --- /dev/null +++ b/cli/js/tests/location_test.ts @@ -0,0 +1,7 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +unitTest(function locationBasic(): void { + // location example: file:///Users/rld/src/deno/js/unit_tests.ts + assert(window.location.toString().endsWith("unit_tests.ts")); +}); diff --git a/cli/js/tests/make_temp_test.ts b/cli/js/tests/make_temp_test.ts new file mode 100644 index 000000000..9804a7043 --- /dev/null +++ b/cli/js/tests/make_temp_test.ts @@ -0,0 +1,134 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest({ perms: { write: true } }, function makeTempDirSyncSuccess(): void { + 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. + let err; + try { + Deno.makeTempDirSync({ dir: "/baddir" }); + } catch (err_) { + err = err_; + } + assert(err instanceof Deno.errors.NotFound); +}); + +unitTest(function makeTempDirSyncPerm(): void { + // makeTempDirSync should require write permissions (for now). + let err; + try { + Deno.makeTempDirSync({ dir: "/baddir" }); + } catch (err_) { + err = err_; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest( + { perms: { write: true } }, + async function makeTempDirSuccess(): Promise { + 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. + let err; + try { + await Deno.makeTempDir({ dir: "/baddir" }); + } catch (err_) { + err = err_; + } + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest({ perms: { write: true } }, function makeTempFileSyncSuccess(): void { + 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. + let err; + try { + Deno.makeTempFileSync({ dir: "/baddir" }); + } catch (err_) { + err = err_; + } + assert(err instanceof Deno.errors.NotFound); +}); + +unitTest(function makeTempFileSyncPerm(): void { + // makeTempFileSync should require write permissions (for now). + let err; + try { + Deno.makeTempFileSync({ dir: "/baddir" }); + } catch (err_) { + err = err_; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest( + { perms: { write: true } }, + async function makeTempFileSuccess(): Promise { + 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. + let err; + try { + await Deno.makeTempFile({ dir: "/baddir" }); + } catch (err_) { + err = err_; + } + assert(err instanceof Deno.errors.NotFound); + } +); diff --git a/cli/js/tests/metrics_test.ts b/cli/js/tests/metrics_test.ts new file mode 100644 index 000000000..9b7d83887 --- /dev/null +++ b/cli/js/tests/metrics_test.ts @@ -0,0 +1,58 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +unitTest(async function metrics(): Promise { + const m1 = Deno.metrics(); + assert(m1.opsDispatched > 0); + assert(m1.opsDispatchedSync > 0); + assert(m1.opsCompleted > 0); + assert(m1.opsCompletedSync > 0); + assert(m1.bytesSentControl > 0); + assert(m1.bytesSentData >= 0); + assert(m1.bytesReceived > 0); + + // Write to stdout to ensure a "data" message gets sent instead of just + // control messages. + const dataMsg = new Uint8Array([13, 13, 13]); // "\r\r\r", + await Deno.stdout.write(dataMsg); + + const m2 = Deno.metrics(); + assert(m2.opsDispatched > m1.opsDispatched); + assert(m2.opsDispatchedSync > m1.opsDispatchedSync); + assert(m2.opsDispatchedAsync > m1.opsDispatchedAsync); + assert(m2.opsCompleted > m1.opsCompleted); + assert(m2.opsCompletedSync > m1.opsCompletedSync); + assert(m2.opsCompletedAsync > m1.opsCompletedAsync); + assert(m2.bytesSentControl > m1.bytesSentControl); + assert(m2.bytesSentData >= m1.bytesSentData + dataMsg.byteLength); + assert(m2.bytesReceived > m1.bytesReceived); +}); + +unitTest( + { perms: { write: true } }, + function metricsUpdatedIfNoResponseSync(): void { + const filename = Deno.makeTempDirSync() + "/test.txt"; + + const data = new Uint8Array([41, 42, 43]); + Deno.writeFileSync(filename, data, { mode: 0o666 }); + + const metrics = Deno.metrics(); + assert(metrics.opsDispatched === metrics.opsCompleted); + assert(metrics.opsDispatchedSync === metrics.opsCompletedSync); + } +); + +unitTest( + { perms: { write: true } }, + async function metricsUpdatedIfNoResponseAsync(): Promise { + const filename = Deno.makeTempDirSync() + "/test.txt"; + + const data = new Uint8Array([41, 42, 43]); + await Deno.writeFile(filename, data, { mode: 0o666 }); + + const metrics = Deno.metrics(); + assert(metrics.opsDispatched === metrics.opsCompleted); + assert(metrics.opsDispatchedSync === metrics.opsCompletedSync); + assert(metrics.opsDispatchedAsync === metrics.opsCompletedAsync); + } +); diff --git a/cli/js/tests/mkdir_test.ts b/cli/js/tests/mkdir_test.ts new file mode 100644 index 000000000..2921177eb --- /dev/null +++ b/cli/js/tests/mkdir_test.ts @@ -0,0 +1,76 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest( + { perms: { read: true, write: true } }, + function mkdirSyncSuccess(): void { + const path = Deno.makeTempDirSync() + "/dir"; + Deno.mkdirSync(path); + const pathInfo = Deno.statSync(path); + assert(pathInfo.isDirectory()); + } +); + +unitTest( + { perms: { read: true, write: true } }, + function mkdirSyncMode(): void { + const path = Deno.makeTempDirSync() + "/dir"; + Deno.mkdirSync(path, { mode: 0o755 }); // no perm for x + const pathInfo = Deno.statSync(path); + if (pathInfo.mode !== null) { + // Skip windows + assertEquals(pathInfo.mode & 0o777, 0o755); + } + } +); + +unitTest({ perms: { write: false } }, function mkdirSyncPerm(): void { + let err; + try { + Deno.mkdirSync("/baddir"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest( + { perms: { read: true, write: true } }, + async function mkdirSuccess(): Promise { + const path = Deno.makeTempDirSync() + "/dir"; + await Deno.mkdir(path); + const pathInfo = Deno.statSync(path); + assert(pathInfo.isDirectory()); + } +); + +unitTest({ perms: { write: true } }, function mkdirErrIfExists(): void { + let err; + try { + Deno.mkdirSync("."); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.AlreadyExists); +}); + +unitTest( + { perms: { read: true, write: true } }, + function mkdirSyncRecursive(): void { + const path = Deno.makeTempDirSync() + "/nested/directory"; + Deno.mkdirSync(path, { recursive: true }); + const pathInfo = Deno.statSync(path); + assert(pathInfo.isDirectory()); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function mkdirRecursive(): Promise { + const path = Deno.makeTempDirSync() + "/nested/directory"; + await Deno.mkdir(path, { recursive: true }); + const pathInfo = Deno.statSync(path); + assert(pathInfo.isDirectory()); + } +); diff --git a/cli/js/tests/net_test.ts b/cli/js/tests/net_test.ts new file mode 100644 index 000000000..46543acdf --- /dev/null +++ b/cli/js/tests/net_test.ts @@ -0,0 +1,307 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest({ perms: { net: true } }, function netTcpListenClose(): void { + const listener = Deno.listen({ hostname: "127.0.0.1", port: 4500 }); + assertEquals(listener.addr.transport, "tcp"); + assertEquals(listener.addr.hostname, "127.0.0.1"); + assertEquals(listener.addr.port, 4500); + listener.close(); +}); + +unitTest( + { + perms: { net: true }, + // TODO: + skip: Deno.build.os === "win" + }, + function netUdpListenClose(): void { + const socket = Deno.listen({ + hostname: "127.0.0.1", + port: 4500, + transport: "udp" + }); + assertEquals(socket.addr.transport, "udp"); + assertEquals(socket.addr.hostname, "127.0.0.1"); + assertEquals(socket.addr.port, 4500); + socket.close(); + } +); + +unitTest( + { + perms: { net: true } + }, + async function netTcpCloseWhileAccept(): Promise { + const listener = Deno.listen({ port: 4501 }); + const p = listener.accept(); + listener.close(); + let err; + try { + await p; + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Error); + assertEquals(err.message, "Listener has been closed"); + } +); + +unitTest( + { perms: { net: true } }, + async function netTcpConcurrentAccept(): Promise { + const listener = Deno.listen({ port: 4502 }); + let acceptErrCount = 0; + const checkErr = (e: Error): void => { + 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); + } +); + +unitTest({ perms: { net: true } }, async function netTcpDialListen(): Promise< + void +> { + const listener = Deno.listen({ port: 4500 }); + listener.accept().then( + async (conn): Promise => { + assert(conn.remoteAddr != null); + assertEquals(conn.localAddr.hostname, "127.0.0.1"); + assertEquals(conn.localAddr.port, 4500); + await conn.write(new Uint8Array([1, 2, 3])); + conn.close(); + } + ); + const conn = await Deno.connect({ hostname: "127.0.0.1", port: 4500 }); + assertEquals(conn.remoteAddr.hostname, "127.0.0.1"); + assertEquals(conn.remoteAddr.port, 4500); + 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 !== Deno.EOF); + + const readResult2 = await conn.read(buf); + assertEquals(Deno.EOF, readResult2); + + listener.close(); + conn.close(); +}); + +unitTest( + { skip: Deno.build.os === "win", perms: { net: true } }, + async function netUdpSendReceive(): Promise { + const alice = Deno.listen({ port: 4500, transport: "udp" }); + assertEquals(alice.addr.port, 4500); + assertEquals(alice.addr.hostname, "0.0.0.0"); + assertEquals(alice.addr.transport, "udp"); + + const bob = Deno.listen({ port: 4501, transport: "udp" }); + assertEquals(bob.addr.port, 4501); + assertEquals(bob.addr.hostname, "0.0.0.0"); + assertEquals(bob.addr.transport, "udp"); + + const sent = new Uint8Array([1, 2, 3]); + await alice.send(sent, bob.addr); + + const [recvd, remote] = await bob.receive(); + assertEquals(remote.port, 4500); + assertEquals(recvd.length, 3); + assertEquals(1, recvd[0]); + assertEquals(2, recvd[1]); + assertEquals(3, recvd[2]); + alice.close(); + bob.close(); + } +); + +unitTest( + { perms: { net: true } }, + async function netTcpListenCloseWhileIterating(): Promise { + const listener = Deno.listen({ port: 8000 }); + 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 }); + } +); + +unitTest( + { skip: Deno.build.os === "win", perms: { net: true } }, + async function netUdpListenCloseWhileIterating(): Promise { + const socket = Deno.listen({ 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 }); + } +); + +/* TODO(ry) Re-enable this test. +unitTest({ perms: { net: true } }, async function netListenAsyncIterator(): Promise { + const listener = Deno.listen(":4500"); + const runAsyncIterator = async (): Promise => { + for await (let conn of listener) { + await conn.write(new Uint8Array([1, 2, 3])); + conn.close(); + } + }; + runAsyncIterator(); + const conn = await Deno.connect("127.0.0.1:4500"); + 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 !== Deno.EOF); + + const readResult2 = await conn.read(buf); + assertEquals(Deno.EOF, readResult2); + + listener.close(); + conn.close(); +}); + */ + +/* TODO Fix broken test. +unitTest({ perms: { net: true } }, async function netCloseReadSuccess() { + const addr = "127.0.0.1:4500"; + const listener = Deno.listen(addr); + const closeDeferred = deferred(); + const closeReadDeferred = deferred(); + listener.accept().then(async conn => { + await closeReadDeferred.promise; + await conn.write(new Uint8Array([1, 2, 3])); + const buf = new Uint8Array(1024); + const readResult = await conn.read(buf); + assertEquals(3, readResult); + assertEquals(4, buf[0]); + assertEquals(5, buf[1]); + assertEquals(6, buf[2]); + conn.close(); + closeDeferred.resolve(); + }); + const conn = await Deno.connect(addr); + conn.closeRead(); // closing read + closeReadDeferred.resolve(); + const buf = new Uint8Array(1024); + const readResult = await conn.read(buf); + assertEquals(Deno.EOF, readResult); // with immediate EOF + // Ensure closeRead does not impact write + await conn.write(new Uint8Array([4, 5, 6])); + await closeDeferred.promise; + listener.close(); + conn.close(); +}); +*/ + +/* TODO Fix broken test. +unitTest({ perms: { net: true } }, async function netDoubleCloseRead() { + const addr = "127.0.0.1:4500"; + const listener = Deno.listen(addr); + const closeDeferred = deferred(); + listener.accept().then(async conn => { + await conn.write(new Uint8Array([1, 2, 3])); + await closeDeferred.promise; + conn.close(); + }); + const conn = await Deno.connect(addr); + conn.closeRead(); // closing read + let err; + try { + // Duplicated close should throw error + conn.closeRead(); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Deno.errors.NotConnected); + closeDeferred.resolve(); + listener.close(); + conn.close(); +}); +*/ + +/* TODO Fix broken test. +unitTest({ perms: { net: true } }, async function netCloseWriteSuccess() { + const addr = "127.0.0.1:4500"; + const listener = Deno.listen(addr); + const closeDeferred = deferred(); + listener.accept().then(async conn => { + await conn.write(new Uint8Array([1, 2, 3])); + await closeDeferred.promise; + 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]); + // Check write should be closed + let err; + try { + await conn.write(new Uint8Array([1, 2, 3])); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Deno.errors.BrokenPipe); + closeDeferred.resolve(); + listener.close(); + conn.close(); +}); +*/ + +/* TODO Fix broken test. +unitTest({ perms: { net: true } }, async function netDoubleCloseWrite() { + const addr = "127.0.0.1:4500"; + const listener = Deno.listen(addr); + const closeDeferred = deferred(); + listener.accept().then(async conn => { + await closeDeferred.promise; + conn.close(); + }); + const conn = await Deno.connect(addr); + conn.closeWrite(); // closing write + let err; + try { + // Duplicated close should throw error + conn.closeWrite(); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof Deno.errors.NotConnected); + closeDeferred.resolve(); + listener.close(); + conn.close(); +}); +*/ diff --git a/cli/js/tests/os_test.ts b/cli/js/tests/os_test.ts new file mode 100644 index 000000000..0c851be51 --- /dev/null +++ b/cli/js/tests/os_test.ts @@ -0,0 +1,337 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { + assert, + assertEquals, + assertNotEquals, + assertThrows, + unitTest +} from "./test_util.ts"; + +unitTest({ perms: { env: true } }, function envSuccess(): void { + const env = Deno.env(); + assert(env !== null); + // eslint-disable-next-line @typescript-eslint/camelcase + env.test_var = "Hello World"; + const newEnv = Deno.env(); + assertEquals(env.test_var, newEnv.test_var); + assertEquals(Deno.env("test_var"), env.test_var); +}); + +unitTest({ perms: { env: true } }, function envNotFound(): void { + const r = Deno.env("env_var_does_not_exist!"); + assertEquals(r, undefined); +}); + +unitTest(function envPermissionDenied1(): void { + let err; + try { + Deno.env(); + } catch (e) { + err = e; + } + assertNotEquals(err, undefined); + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest(function envPermissionDenied2(): void { + let err; + try { + Deno.env("PATH"); + } catch (e) { + err = e; + } + assertNotEquals(err, undefined); + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "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(). +unitTest( + { skip: Deno.build.os !== "win", perms: { 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, + expectedEnv: Record + ): Promise => { + const src = ` + console.log( + ${JSON.stringify(Object.keys(expectedEnv))}.map(k => Deno.env(k)) + )`; + const proc = Deno.run({ + args: [Deno.execPath(), "eval", src], + env: inputEnv, + stdout: "piped" + }); + const status = await proc.status(); + assertEquals(status.success, true); + const expectedValues = Object.values(expectedEnv); + const actualValues = JSON.parse( + new TextDecoder().decode(await proc.output()) + ); + assertEquals(actualValues, expectedValues); + proc.close(); + }; + + assertEquals(Deno.env("path"), Deno.env("PATH")); + assertEquals(Deno.env("Path"), Deno.env("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" } + ); + } +); + +unitTest(function osPid(): void { + assert(Deno.pid > 0); +}); + +unitTest({ perms: { env: true } }, function getDir(): void { + type supportOS = "mac" | "win" | "linux"; + + interface Runtime { + os: supportOS; + shouldHaveValue: boolean; + } + + interface Scenes { + kind: Deno.DirKind; + runtime: Runtime[]; + } + + const scenes: Scenes[] = [ + { + kind: "config", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: true } + ] + }, + { + kind: "cache", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: true } + ] + }, + { + kind: "executable", + runtime: [ + { os: "mac", shouldHaveValue: false }, + { os: "win", shouldHaveValue: false }, + { os: "linux", shouldHaveValue: true } + ] + }, + { + kind: "data", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: true } + ] + }, + { + kind: "data_local", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: true } + ] + }, + { + kind: "audio", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: false } + ] + }, + { + kind: "desktop", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: false } + ] + }, + { + kind: "document", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: false } + ] + }, + { + kind: "download", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: false } + ] + }, + { + kind: "font", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: false }, + { os: "linux", shouldHaveValue: true } + ] + }, + { + kind: "picture", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: false } + ] + }, + { + kind: "public", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: false } + ] + }, + { + kind: "template", + runtime: [ + { os: "mac", shouldHaveValue: false }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: false } + ] + }, + { + kind: "tmp", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: true } + ] + }, + { + kind: "video", + runtime: [ + { os: "mac", shouldHaveValue: true }, + { os: "win", shouldHaveValue: true }, + { os: "linux", shouldHaveValue: false } + ] + } + ]; + + for (const s of scenes) { + for (const r of s.runtime) { + if (Deno.build.os !== r.os) continue; + if (r.shouldHaveValue) { + const d = Deno.dir(s.kind); + assert(d); + assert(d.length > 0); + } + } + } +}); + +unitTest(function getDirWithoutPermission(): void { + assertThrows( + () => Deno.dir("home"), + Deno.errors.PermissionDenied, + `run again with the --allow-env flag` + ); +}); + +unitTest({ perms: { env: true } }, function execPath(): void { + assertNotEquals(Deno.execPath(), ""); +}); + +unitTest({ perms: { env: false } }, function execPathPerm(): void { + let caughtError = false; + try { + Deno.execPath(); + } catch (err) { + caughtError = true; + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } + assert(caughtError); +}); + +unitTest({ perms: { env: true } }, function loadavgSuccess(): void { + const load = Deno.loadavg(); + assertEquals(load.length, 3); +}); + +unitTest({ perms: { env: false } }, function loadavgPerm(): void { + let caughtError = false; + try { + Deno.loadavg(); + } catch (err) { + caughtError = true; + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } + assert(caughtError); +}); + +unitTest({ perms: { env: true } }, function hostnameDir(): void { + assertNotEquals(Deno.hostname(), ""); +}); + +unitTest({ perms: { env: false } }, function hostnamePerm(): void { + let caughtError = false; + try { + Deno.hostname(); + } catch (err) { + caughtError = true; + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } + assert(caughtError); +}); + +unitTest({ perms: { env: true } }, function releaseDir(): void { + assertNotEquals(Deno.osRelease(), ""); +}); + +unitTest({ perms: { env: false } }, function releasePerm(): void { + let caughtError = false; + try { + Deno.osRelease(); + } catch (err) { + caughtError = true; + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } + assert(caughtError); +}); diff --git a/cli/js/tests/performance_test.ts b/cli/js/tests/performance_test.ts new file mode 100644 index 000000000..89b7cad8b --- /dev/null +++ b/cli/js/tests/performance_test.ts @@ -0,0 +1,15 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, createResolvable } from "./test_util.ts"; + +unitTest({ perms: { hrtime: false } }, async function performanceNow(): Promise< + void +> { + const resolvable = createResolvable(); + const start = performance.now(); + setTimeout((): void => { + const end = performance.now(); + assert(end - start >= 10); + resolvable.resolve(); + }, 10); + await resolvable; +}); diff --git a/cli/js/tests/permissions_test.ts b/cli/js/tests/permissions_test.ts new file mode 100644 index 000000000..7528768a1 --- /dev/null +++ b/cli/js/tests/permissions_test.ts @@ -0,0 +1,27 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +unitTest(async function permissionInvalidName(): Promise { + let thrown = false; + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + await Deno.permissions.query({ name: "foo" as any }); + } catch (e) { + thrown = true; + assert(e instanceof Error); + } finally { + assert(thrown); + } +}); + +unitTest(async function permissionNetInvalidUrl(): Promise { + let thrown = false; + try { + await Deno.permissions.query({ name: "net", url: ":" }); + } catch (e) { + thrown = true; + assert(e instanceof URIError); + } finally { + assert(thrown); + } +}); diff --git a/cli/js/tests/process_test.ts b/cli/js/tests/process_test.ts new file mode 100644 index 000000000..2411b5134 --- /dev/null +++ b/cli/js/tests/process_test.ts @@ -0,0 +1,383 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { + assert, + assertEquals, + assertStrContains, + unitTest +} from "./test_util.ts"; +const { kill, run, readFile, open, makeTempDir, writeFile } = Deno; + +unitTest(function runPermissions(): void { + let caughtError = false; + try { + Deno.run({ args: ["python", "-c", "print('hello world')"] }); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { run: true } }, async function runSuccess(): Promise { + const p = run({ + args: ["python", "-c", "print('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(); +}); + +unitTest( + { perms: { run: true } }, + async function runCommandFailedWithCode(): Promise { + const p = run({ + args: ["python", "-c", "import sys;sys.exit(41 + 1)"] + }); + const status = await p.status(); + assertEquals(status.success, false); + assertEquals(status.code, 42); + assertEquals(status.signal, undefined); + p.close(); + } +); + +unitTest( + { + // No signals on windows. + skip: Deno.build.os === "win", + perms: { run: true } + }, + async function runCommandFailedWithSignal(): Promise { + const p = run({ + args: ["python", "-c", "import os;os.kill(os.getpid(), 9)"] + }); + const status = await p.status(); + assertEquals(status.success, false); + assertEquals(status.code, undefined); + assertEquals(status.signal, 9); + p.close(); + } +); + +unitTest({ perms: { run: true } }, function runNotFound(): void { + let error; + try { + run({ args: ["this file hopefully doesn't exist"] }); + } catch (e) { + error = e; + } + assert(error !== undefined); + assert(error instanceof Deno.errors.NotFound); +}); + +unitTest( + { perms: { write: true, run: true } }, + async function runWithCwdIsAsync(): Promise { + const enc = new TextEncoder(); + const cwd = await makeTempDir({ prefix: "deno_command_test" }); + + const exitCodeFile = "deno_was_here"; + const pyProgramFile = "poll_exit.py"; + const pyProgram = ` +from sys import exit +from time import sleep + +while True: + try: + with open("${exitCodeFile}", "r") as f: + line = f.readline() + code = int(line) + exit(code) + except IOError: + # Retry if we got here before deno wrote the file. + sleep(0.01) + pass +`; + + Deno.writeFileSync(`${cwd}/${pyProgramFile}.py`, enc.encode(pyProgram)); + const p = run({ + cwd, + args: ["python", `${pyProgramFile}.py`] + }); + + // Write the expected exit code *after* starting python. + // 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(); + } +); + +unitTest({ perms: { run: true } }, async function runStdinPiped(): Promise< + void +> { + const p = run({ + args: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"], + 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(); +}); + +unitTest({ perms: { run: true } }, async function runStdoutPiped(): Promise< + void +> { + const p = run({ + args: ["python", "-c", "import sys; sys.stdout.write('hello')"], + stdout: "piped" + }); + assert(!p.stdin); + assert(!p.stderr); + + const data = new Uint8Array(10); + let r = await p.stdout!.read(data); + if (r === Deno.EOF) { + throw new Error("p.stdout.read(...) should not be EOF"); + } + assertEquals(r, 5); + const s = new TextDecoder().decode(data.subarray(0, r)); + assertEquals(s, "hello"); + r = await p.stdout!.read(data); + assertEquals(r, Deno.EOF); + p.stdout!.close(); + + const status = await p.status(); + assertEquals(status.success, true); + assertEquals(status.code, 0); + assertEquals(status.signal, undefined); + p.close(); +}); + +unitTest({ perms: { run: true } }, async function runStderrPiped(): Promise< + void +> { + const p = run({ + args: ["python", "-c", "import sys; sys.stderr.write('hello')"], + stderr: "piped" + }); + assert(!p.stdin); + assert(!p.stdout); + + const data = new Uint8Array(10); + let r = await p.stderr!.read(data); + if (r === Deno.EOF) { + throw new Error("p.stderr.read should not return EOF here"); + } + assertEquals(r, 5); + const s = new TextDecoder().decode(data.subarray(0, r)); + assertEquals(s, "hello"); + r = await p.stderr!.read(data); + assertEquals(r, Deno.EOF); + p.stderr!.close(); + + const status = await p.status(); + assertEquals(status.success, true); + assertEquals(status.code, 0); + assertEquals(status.signal, undefined); + p.close(); +}); + +unitTest({ perms: { run: true } }, async function runOutput(): Promise { + const p = run({ + args: ["python", "-c", "import sys; sys.stdout.write('hello')"], + stdout: "piped" + }); + const output = await p.output(); + const s = new TextDecoder().decode(output); + assertEquals(s, "hello"); + p.close(); +}); + +unitTest({ perms: { run: true } }, async function runStderrOutput(): Promise< + void +> { + const p = run({ + args: ["python", "-c", "import sys; sys.stderr.write('error')"], + stderr: "piped" + }); + const error = await p.stderrOutput(); + const s = new TextDecoder().decode(error); + assertEquals(s, "error"); + p.close(); +}); + +unitTest( + { perms: { run: true, write: true, read: true } }, + async function runRedirectStdoutStderr(): Promise { + const tempDir = await makeTempDir(); + const fileName = tempDir + "/redirected_stdio.txt"; + const file = await open(fileName, "w"); + + const p = run({ + args: [ + "python", + "-c", + "import sys; sys.stderr.write('error\\n'); sys.stdout.write('output\\n');" + ], + stdout: file.rid, + stderr: file.rid + }); + + await p.status(); + p.close(); + file.close(); + + const fileContents = await readFile(fileName); + const decoder = new TextDecoder(); + const text = decoder.decode(fileContents); + + assertStrContains(text, "error"); + assertStrContains(text, "output"); + } +); + +unitTest( + { perms: { run: true, write: true, read: true } }, + async function runRedirectStdin(): Promise { + const tempDir = await makeTempDir(); + const fileName = tempDir + "/redirected_stdio.txt"; + const encoder = new TextEncoder(); + await writeFile(fileName, encoder.encode("hello")); + const file = await open(fileName, "r"); + + const p = run({ + args: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"], + stdin: file.rid + }); + + const status = await p.status(); + assertEquals(status.code, 0); + p.close(); + file.close(); + } +); + +unitTest({ perms: { run: true } }, async function runEnv(): Promise { + const p = run({ + args: [ + "python", + "-c", + "import os, sys; sys.stdout.write(os.environ.get('FOO', '') + os.environ.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(); +}); + +unitTest({ perms: { run: true } }, async function runClose(): Promise { + const p = run({ + args: [ + "python", + "-c", + "from time import sleep; import sys; sleep(10000); sys.stderr.write('error')" + ], + stderr: "piped" + }); + assert(!p.stdin); + assert(!p.stdout); + + p.close(); + + const data = new Uint8Array(10); + const r = await p.stderr!.read(data); + assertEquals(r, Deno.EOF); + p.stderr!.close(); +}); + +unitTest(function signalNumbers(): void { + if (Deno.build.os === "mac") { + assertEquals(Deno.Signal.SIGSTOP, 17); + } else if (Deno.build.os === "linux") { + assertEquals(Deno.Signal.SIGSTOP, 19); + } +}); + +// Ignore signal tests on windows for now... +if (Deno.build.os !== "win") { + unitTest(function killPermissions(): void { + let caughtError = false; + try { + // 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, Deno.Signal.SIGCONT); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); + }); + + unitTest({ perms: { run: true } }, async function killSuccess(): Promise< + void + > { + const p = run({ + args: ["python", "-c", "from time import sleep; sleep(10000)"] + }); + + assertEquals(Deno.Signal.SIGINT, 2); + kill(p.pid, Deno.Signal.SIGINT); + const status = await p.status(); + + assertEquals(status.success, false); + // TODO(ry) On Linux, status.code is sometimes undefined and sometimes 1. + // The following assert is causing this test to be flaky. Investigate and + // re-enable when it can be made deterministic. + // assertEquals(status.code, 1); + // assertEquals(status.signal, Deno.Signal.SIGINT); + p.close(); + }); + + unitTest({ perms: { run: true } }, async function killFailed(): Promise< + void + > { + const p = run({ + args: ["python", "-c", "from time import sleep; sleep(10000)"] + }); + assert(!p.stdin); + assert(!p.stdout); + + let err; + try { + kill(p.pid, 12345); + } catch (e) { + err = e; + } + + assert(!!err); + assert(err instanceof TypeError); + + p.close(); + }); +} diff --git a/cli/js/tests/read_dir_test.ts b/cli/js/tests/read_dir_test.ts new file mode 100644 index 000000000..95936c645 --- /dev/null +++ b/cli/js/tests/read_dir_test.ts @@ -0,0 +1,86 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +type FileInfo = Deno.FileInfo; + +function assertSameContent(files: FileInfo[]): void { + let counter = 0; + + for (const file of files) { + if (file.name === "subdir") { + assert(file.isDirectory()); + counter++; + } + + if (file.name === "002_hello.ts") { + assertEquals(file.mode!, Deno.statSync(`cli/tests/${file.name}`).mode!); + counter++; + } + } + + assertEquals(counter, 2); +} + +unitTest({ perms: { read: true } }, function readdirSyncSuccess(): void { + const files = Deno.readdirSync("cli/tests/"); + assertSameContent(files); +}); + +unitTest({ perms: { read: false } }, function readdirSyncPerm(): void { + let caughtError = false; + try { + Deno.readdirSync("tests/"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, function readdirSyncNotDir(): void { + let caughtError = false; + let src; + + try { + src = Deno.readdirSync("cli/tests/fixture.json"); + } catch (err) { + caughtError = true; + assert(err instanceof Error); + } + assert(caughtError); + assertEquals(src, undefined); +}); + +unitTest({ perms: { read: true } }, function readdirSyncNotFound(): void { + let caughtError = false; + let src; + + try { + src = Deno.readdirSync("bad_dir_name"); + } catch (err) { + caughtError = true; + assert(err instanceof Deno.errors.NotFound); + } + assert(caughtError); + assertEquals(src, undefined); +}); + +unitTest({ perms: { read: true } }, async function readdirSuccess(): Promise< + void +> { + const files = await Deno.readdir("cli/tests/"); + assertSameContent(files); +}); + +unitTest({ perms: { read: false } }, async function readdirPerm(): Promise< + void +> { + let caughtError = false; + try { + await Deno.readdir("tests/"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); diff --git a/cli/js/tests/read_file_test.ts b/cli/js/tests/read_file_test.ts new file mode 100644 index 000000000..1b709b1f4 --- /dev/null +++ b/cli/js/tests/read_file_test.ts @@ -0,0 +1,59 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest({ perms: { read: true } }, function readFileSyncSuccess(): void { + const data = Deno.readFileSync("cli/tests/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"); +}); + +unitTest({ perms: { read: false } }, function readFileSyncPerm(): void { + let caughtError = false; + try { + Deno.readFileSync("cli/tests/fixture.json"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, function readFileSyncNotFound(): void { + let caughtError = false; + let data; + try { + data = Deno.readFileSync("bad_filename"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtError); + assert(data === undefined); +}); + +unitTest({ perms: { read: true } }, async function readFileSuccess(): Promise< + void +> { + const data = await Deno.readFile("cli/tests/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"); +}); + +unitTest({ perms: { read: false } }, async function readFilePerm(): Promise< + void +> { + let caughtError = false; + try { + await Deno.readFile("cli/tests/fixture.json"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); diff --git a/cli/js/tests/read_link_test.ts b/cli/js/tests/read_link_test.ts new file mode 100644 index 000000000..409f37110 --- /dev/null +++ b/cli/js/tests/read_link_test.ts @@ -0,0 +1,75 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest( + { perms: { write: true, read: true } }, + function readlinkSyncSuccess(): void { + const testDir = Deno.makeTempDirSync(); + const target = testDir + "/target"; + const symlink = testDir + "/symln"; + Deno.mkdirSync(target); + // TODO Add test for Windows once symlink is implemented for Windows. + // See https://github.com/denoland/deno/issues/815. + if (Deno.build.os !== "win") { + Deno.symlinkSync(target, symlink); + const targetPath = Deno.readlinkSync(symlink); + assertEquals(targetPath, target); + } + } +); + +unitTest({ perms: { read: false } }, async function readlinkSyncPerm(): Promise< + void +> { + let caughtError = false; + try { + Deno.readlinkSync("/symlink"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, function readlinkSyncNotFound(): void { + let caughtError = false; + let data; + try { + data = Deno.readlinkSync("bad_filename"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtError); + assertEquals(data, undefined); +}); + +unitTest( + { perms: { write: true, read: true } }, + async function readlinkSuccess(): Promise { + const testDir = Deno.makeTempDirSync(); + const target = testDir + "/target"; + const symlink = testDir + "/symln"; + Deno.mkdirSync(target); + // TODO Add test for Windows once symlink is implemented for Windows. + // See https://github.com/denoland/deno/issues/815. + if (Deno.build.os !== "win") { + Deno.symlinkSync(target, symlink); + const targetPath = await Deno.readlink(symlink); + assertEquals(targetPath, target); + } + } +); + +unitTest({ perms: { read: false } }, async function readlinkPerm(): Promise< + void +> { + let caughtError = false; + try { + await Deno.readlink("/symlink"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); diff --git a/cli/js/tests/realpath_test.ts b/cli/js/tests/realpath_test.ts new file mode 100644 index 000000000..cda7ddaf1 --- /dev/null +++ b/cli/js/tests/realpath_test.ts @@ -0,0 +1,108 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +unitTest({ perms: { read: true } }, function realpathSyncSuccess(): void { + const incompletePath = "cli/tests/fixture.json"; + const realPath = Deno.realpathSync(incompletePath); + if (Deno.build.os !== "win") { + assert(realPath.startsWith("/")); + } else { + assert(/^[A-Z]/.test(realPath)); + } + assert(realPath.endsWith(incompletePath)); +}); + +unitTest( + { + skip: Deno.build.os === "win", + perms: { read: true, write: true } + }, + function realpathSyncSymlink(): void { + const testDir = Deno.makeTempDirSync(); + const target = testDir + "/target"; + const symlink = testDir + "/symln"; + Deno.mkdirSync(target); + Deno.symlinkSync(target, symlink); + const targetPath = Deno.realpathSync(symlink); + assert(targetPath.startsWith("/")); + assert(targetPath.endsWith("/target")); + } +); + +unitTest({ perms: { read: false } }, function realpathSyncPerm(): void { + let caughtError = false; + try { + Deno.realpathSync("some_file"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, function realpathSyncNotFound(): void { + let caughtError = false; + try { + Deno.realpathSync("bad_filename"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, async function realpathSuccess(): Promise< + void +> { + const incompletePath = "cli/tests/fixture.json"; + const realPath = await Deno.realpath(incompletePath); + if (Deno.build.os !== "win") { + assert(realPath.startsWith("/")); + } else { + assert(/^[A-Z]/.test(realPath)); + } + assert(realPath.endsWith(incompletePath)); +}); + +unitTest( + { + skip: Deno.build.os === "win", + perms: { read: true, write: true } + }, + async function realpathSymlink(): Promise { + const testDir = Deno.makeTempDirSync(); + const target = testDir + "/target"; + const symlink = testDir + "/symln"; + Deno.mkdirSync(target); + Deno.symlinkSync(target, symlink); + const targetPath = await Deno.realpath(symlink); + assert(targetPath.startsWith("/")); + assert(targetPath.endsWith("/target")); + } +); + +unitTest({ perms: { read: false } }, async function realpathPerm(): Promise< + void +> { + let caughtError = false; + try { + await Deno.realpath("some_file"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, async function realpathNotFound(): Promise< + void +> { + let caughtError = false; + try { + await Deno.realpath("bad_filename"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtError); +}); diff --git a/cli/js/tests/remove_test.ts b/cli/js/tests/remove_test.ts new file mode 100644 index 000000000..fac5ba303 --- /dev/null +++ b/cli/js/tests/remove_test.ts @@ -0,0 +1,481 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +// SYNC + +unitTest( + { perms: { write: true, read: true } }, + function removeSyncDirSuccess(): void { + // REMOVE EMPTY DIRECTORY + const path = Deno.makeTempDirSync() + "/subdir"; + Deno.mkdirSync(path); + const pathInfo = Deno.statSync(path); + assert(pathInfo.isDirectory()); // check exist first + Deno.removeSync(path); // remove + // We then check again after remove + let err; + try { + Deno.statSync(path); + } catch (e) { + err = e; + } + // Directory is gone + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { write: true, read: true } }, + function removeSyncFileSuccess(): void { + // 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 + Deno.removeSync(filename); // remove + // We then check again after remove + let err; + try { + Deno.statSync(filename); + } catch (e) { + err = e; + } + // File is gone + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { write: true, read: true } }, + function removeSyncFail(): void { + // 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 + let err; + try { + // Should not be able to recursively remove + Deno.removeSync(path); + } catch (e) { + err = e; + } + // TODO(ry) Is Other really the error we should get here? What would Go do? + assert(err instanceof Error); + // NON-EXISTENT DIRECTORY/FILE + try { + // Non-existent + Deno.removeSync("/baddir"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { write: true, read: true } }, + function removeSyncDanglingSymlinkSuccess(): void { + const danglingSymlinkPath = Deno.makeTempDirSync() + "/dangling_symlink"; + // TODO(#3832): Remove "Not Implemented" error checking when symlink creation is implemented for Windows + let errOnWindows; + try { + Deno.symlinkSync("unexistent_file", danglingSymlinkPath); + } catch (err) { + errOnWindows = err; + } + if (Deno.build.os === "win") { + assertEquals(errOnWindows.message, "Not implemented"); + } else { + const pathInfo = Deno.lstatSync(danglingSymlinkPath); + assert(pathInfo.isSymlink()); + Deno.removeSync(danglingSymlinkPath); + let err; + try { + Deno.lstatSync(danglingSymlinkPath); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); + } + } +); + +unitTest( + { perms: { write: true, read: true } }, + function removeSyncValidSymlinkSuccess(): void { + 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 }); + // TODO(#3832): Remove "Not Implemented" error checking when symlink creation is implemented for Windows + let errOnWindows; + try { + Deno.symlinkSync(filePath, validSymlinkPath); + } catch (err) { + errOnWindows = err; + } + if (Deno.build.os === "win") { + assertEquals(errOnWindows.message, "Not implemented"); + } else { + const symlinkPathInfo = Deno.statSync(validSymlinkPath); + assert(symlinkPathInfo.isFile()); + Deno.removeSync(validSymlinkPath); + let err; + try { + Deno.statSync(validSymlinkPath); + } catch (e) { + err = e; + } + Deno.removeSync(filePath); + assert(err instanceof Deno.errors.NotFound); + } + } +); + +unitTest({ perms: { write: false } }, function removeSyncPerm(): void { + let err; + try { + Deno.removeSync("/baddir"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest( + { perms: { write: true, read: true } }, + function removeAllSyncDirSuccess(): void { + // 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 + Deno.removeSync(path, { recursive: true }); // remove + // We then check again after remove + let err; + try { + Deno.statSync(path); + } catch (e) { + err = e; + } + // Directory is gone + assert(err instanceof 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 + Deno.removeSync(path, { recursive: true }); // remove + // We then check parent directory again after remove + try { + Deno.statSync(path); + } catch (e) { + err = e; + } + // Directory is gone + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { write: true, read: true } }, + function removeAllSyncFileSuccess(): void { + // 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 + Deno.removeSync(filename, { recursive: true }); // remove + // We then check again after remove + let err; + try { + Deno.statSync(filename); + } catch (e) { + err = e; + } + // File is gone + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest({ perms: { write: true } }, function removeAllSyncFail(): void { + // NON-EXISTENT DIRECTORY/FILE + let err; + try { + // Non-existent + Deno.removeSync("/baddir", { recursive: true }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); +}); + +unitTest({ perms: { write: false } }, function removeAllSyncPerm(): void { + let err; + try { + Deno.removeSync("/baddir", { recursive: true }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +// ASYNC + +unitTest( + { perms: { write: true, read: true } }, + async function removeDirSuccess(): Promise { + // REMOVE EMPTY DIRECTORY + const path = Deno.makeTempDirSync() + "/dir/subdir"; + Deno.mkdirSync(path, { recursive: true }); + const pathInfo = Deno.statSync(path); + assert(pathInfo.isDirectory()); // check exist first + await Deno.remove(path); // remove + // We then check again after remove + let err; + try { + Deno.statSync(path); + } catch (e) { + err = e; + } + // Directory is gone + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { write: true, read: true } }, + async function removeFileSuccess(): Promise { + // 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.remove(filename); // remove + // We then check again after remove + let err; + try { + Deno.statSync(filename); + } catch (e) { + err = e; + } + // File is gone + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { write: true, read: true } }, + async function removeFail(): Promise { + // 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 + let err; + try { + // Should not be able to recursively remove + await Deno.remove(path); + } catch (e) { + err = e; + } + assert(err instanceof Error); + // NON-EXISTENT DIRECTORY/FILE + try { + // Non-existent + await Deno.remove("/baddir"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { write: true, read: true } }, + async function removeDanglingSymlinkSuccess(): Promise { + const danglingSymlinkPath = Deno.makeTempDirSync() + "/dangling_symlink"; + // TODO(#3832): Remove "Not Implemented" error checking when symlink creation is implemented for Windows + let errOnWindows; + try { + Deno.symlinkSync("unexistent_file", danglingSymlinkPath); + } catch (e) { + errOnWindows = e; + } + if (Deno.build.os === "win") { + assertEquals(errOnWindows.message, "Not implemented"); + } else { + const pathInfo = Deno.lstatSync(danglingSymlinkPath); + assert(pathInfo.isSymlink()); + await Deno.remove(danglingSymlinkPath); + let err; + try { + Deno.lstatSync(danglingSymlinkPath); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); + } + } +); + +unitTest( + { perms: { write: true, read: true } }, + async function removeValidSymlinkSuccess(): Promise { + 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 }); + // TODO(#3832): Remove "Not Implemented" error checking when symlink creation is implemented for Windows + let errOnWindows; + try { + Deno.symlinkSync(filePath, validSymlinkPath); + } catch (e) { + errOnWindows = e; + } + if (Deno.build.os === "win") { + assertEquals(errOnWindows.message, "Not implemented"); + } else { + const symlinkPathInfo = Deno.statSync(validSymlinkPath); + assert(symlinkPathInfo.isFile()); + await Deno.remove(validSymlinkPath); + let err; + try { + Deno.statSync(validSymlinkPath); + } catch (e) { + err = e; + } + Deno.removeSync(filePath); + assert(err instanceof Deno.errors.NotFound); + } + } +); + +unitTest({ perms: { write: false } }, async function removePerm(): Promise< + void +> { + let err; + try { + await Deno.remove("/baddir"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest( + { perms: { write: true, read: true } }, + async function removeAllDirSuccess(): Promise { + // 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.remove(path, { recursive: true }); // remove + // We then check again after remove + let err; + try { + Deno.statSync(path); + } catch (e) { + err = e; + } + // Directory is gone + assert(err instanceof 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.remove(path, { recursive: true }); // remove + // We then check parent directory again after remove + try { + Deno.statSync(path); + } catch (e) { + err = e; + } + // Directory is gone + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { write: true, read: true } }, + async function removeAllFileSuccess(): Promise { + // 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.remove(filename, { recursive: true }); // remove + // We then check again after remove + let err; + try { + Deno.statSync(filename); + } catch (e) { + err = e; + } + // File is gone + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest({ perms: { write: true } }, async function removeAllFail(): Promise< + void +> { + // NON-EXISTENT DIRECTORY/FILE + let err; + try { + // Non-existent + await Deno.remove("/baddir", { recursive: true }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); +}); + +unitTest({ perms: { write: false } }, async function removeAllPerm(): Promise< + void +> { + let err; + try { + await Deno.remove("/baddir", { recursive: true }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); diff --git a/cli/js/tests/rename_test.ts b/cli/js/tests/rename_test.ts new file mode 100644 index 000000000..288f24bd7 --- /dev/null +++ b/cli/js/tests/rename_test.ts @@ -0,0 +1,84 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest( + { perms: { read: true, write: true } }, + function renameSyncSuccess(): void { + const testDir = Deno.makeTempDirSync(); + const oldpath = testDir + "/oldpath"; + const newpath = testDir + "/newpath"; + Deno.mkdirSync(oldpath); + Deno.renameSync(oldpath, newpath); + const newPathInfo = Deno.statSync(newpath); + assert(newPathInfo.isDirectory()); + + let caughtErr = false; + let oldPathInfo; + + try { + oldPathInfo = Deno.statSync(oldpath); + } catch (e) { + caughtErr = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtErr); + assertEquals(oldPathInfo, undefined); + } +); + +unitTest( + { perms: { read: false, write: true } }, + function renameSyncReadPerm(): void { + let err; + try { + const oldpath = "/oldbaddir"; + const newpath = "/newbaddir"; + Deno.renameSync(oldpath, newpath); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } +); + +unitTest( + { perms: { read: true, write: false } }, + function renameSyncWritePerm(): void { + let err; + try { + const oldpath = "/oldbaddir"; + const newpath = "/newbaddir"; + Deno.renameSync(oldpath, newpath); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function renameSuccess(): Promise { + const testDir = Deno.makeTempDirSync(); + const oldpath = testDir + "/oldpath"; + const newpath = testDir + "/newpath"; + Deno.mkdirSync(oldpath); + await Deno.rename(oldpath, newpath); + const newPathInfo = Deno.statSync(newpath); + assert(newPathInfo.isDirectory()); + + let caughtErr = false; + let oldPathInfo; + + try { + oldPathInfo = Deno.statSync(oldpath); + } catch (e) { + caughtErr = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtErr); + assertEquals(oldPathInfo, undefined); + } +); diff --git a/cli/js/tests/request_test.ts b/cli/js/tests/request_test.ts new file mode 100644 index 000000000..15e19e285 --- /dev/null +++ b/cli/js/tests/request_test.ts @@ -0,0 +1,49 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest(function fromInit(): void { + const req = new Request("https://example.com", { + body: "ahoyhoy", + method: "POST", + headers: { + "test-header": "value" + } + }); + + // @ts-ignore + assertEquals("ahoyhoy", req._bodySource); + assertEquals(req.url, "https://example.com"); + assertEquals(req.headers.get("test-header"), "value"); +}); + +unitTest(function fromRequest(): void { + const r = new Request("https://example.com"); + // @ts-ignore + r._bodySource = "ahoyhoy"; + r.headers.set("test-header", "value"); + + const req = new Request(r); + + // @ts-ignore + assertEquals(req._bodySource, r._bodySource); + assertEquals(req.url, r.url); + assertEquals(req.headers.get("test-header"), r.headers.get("test-header")); +}); + +unitTest(async function cloneRequestBodyStream(): Promise { + // hack to get a stream + const stream = new Request("", { body: "a test body" }).body; + const r1 = new Request("https://example.com", { + body: stream + }); + + const r2 = r1.clone(); + + const b1 = await r1.text(); + const b2 = await r2.text(); + + assertEquals(b1, b2); + + // @ts-ignore + assert(r1._bodySource !== r2._bodySource); +}); diff --git a/cli/js/tests/resources_test.ts b/cli/js/tests/resources_test.ts new file mode 100644 index 000000000..84b713a6d --- /dev/null +++ b/cli/js/tests/resources_test.ts @@ -0,0 +1,51 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assertEquals } from "./test_util.ts"; + +unitTest(function resourcesStdio(): void { + const res = Deno.resources(); + + assertEquals(res[0], "stdin"); + assertEquals(res[1], "stdout"); + assertEquals(res[2], "stderr"); +}); + +unitTest({ perms: { net: true } }, async function resourcesNet(): Promise< + void +> { + const listener = Deno.listen({ port: 4501 }); + const dialerConn = await Deno.connect({ port: 4501 }); + const listenerConn = await listener.accept(); + + const res = Deno.resources(); + assertEquals( + Object.values(res).filter((r): boolean => r === "tcpListener").length, + 1 + ); + assertEquals( + Object.values(res).filter((r): boolean => r === "tcpStream").length, + 2 + ); + + listenerConn.close(); + dialerConn.close(); + listener.close(); +}); + +unitTest({ perms: { read: true } }, async function resourcesFile(): Promise< + void +> { + const resourcesBefore = Deno.resources(); + const f = await Deno.open("cli/tests/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 !resourcesBefore.hasOwnProperty(rid); + })!; + assertEquals(resourcesAfter[newRid], "fsFile"); +}); diff --git a/cli/js/tests/signal_test.ts b/cli/js/tests/signal_test.ts new file mode 100644 index 000000000..e1d00c669 --- /dev/null +++ b/cli/js/tests/signal_test.ts @@ -0,0 +1,201 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { + unitTest, + assert, + assertEquals, + assertThrows, + createResolvable +} from "./test_util.ts"; + +function defer(n: number): Promise { + return new Promise((resolve: () => void, _) => { + setTimeout(resolve, n); + }); +} + +unitTest( + { skip: Deno.build.os !== "win" }, + async function signalsNotImplemented(): Promise { + assertThrows( + () => { + Deno.signal(1); + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.alarm(); // for SIGALRM + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.child(); // for SIGCHLD + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.hungup(); // for SIGHUP + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.interrupt(); // for SIGINT + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.io(); // for SIGIO + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.pipe(); // for SIGPIPE + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.quit(); // for SIGQUIT + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.terminate(); // for SIGTERM + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.userDefined1(); // for SIGUSR1 + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.userDefined2(); // for SIGURS2 + }, + Error, + "not implemented" + ); + assertThrows( + () => { + Deno.signals.windowChange(); // for SIGWINCH + }, + Error, + "not implemented" + ); + } +); + +unitTest( + { skip: Deno.build.os === "win", perms: { run: true, net: true } }, + async function signalStreamTest(): Promise { + const resolvable = createResolvable(); + // This prevents the program from exiting. + const t = setInterval(() => {}, 1000); + + let c = 0; + const sig = Deno.signal(Deno.Signal.SIGUSR1); + setTimeout(async () => { + await defer(20); + for (const _ of Array(3)) { + // Sends SIGUSR1 3 times. + Deno.kill(Deno.pid, Deno.Signal.SIGUSR1); + await defer(20); + } + sig.dispose(); + resolvable.resolve(); + }); + + for await (const _ of sig) { + c += 1; + } + + assertEquals(c, 3); + + clearInterval(t); + // Defer for a moment to allow async op from `setInterval` to resolve; + // for more explanation see `FIXME` in `cli/js/timers.ts::setGlobalTimeout` + await defer(20); + await resolvable; + } +); + +unitTest( + { skip: Deno.build.os === "win", perms: { run: true } }, + async function signalPromiseTest(): Promise { + const resolvable = createResolvable(); + // This prevents the program from exiting. + const t = setInterval(() => {}, 1000); + + const sig = Deno.signal(Deno.Signal.SIGUSR1); + setTimeout(() => { + Deno.kill(Deno.pid, Deno.Signal.SIGUSR1); + resolvable.resolve(); + }, 20); + await sig; + sig.dispose(); + + clearInterval(t); + // Defer for a moment to allow async op from `setInterval` to resolve; + // for more explanation see `FIXME` in `cli/js/timers.ts::setGlobalTimeout` + await defer(20); + await resolvable; + } +); + +unitTest( + { skip: Deno.build.os === "win", perms: { run: true } }, + async function signalShorthandsTest(): Promise { + let s: Deno.SignalStream; + s = Deno.signals.alarm(); // for SIGALRM + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.child(); // for SIGCHLD + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.hungup(); // for SIGHUP + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.interrupt(); // for SIGINT + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.io(); // for SIGIO + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.pipe(); // for SIGPIPE + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.quit(); // for SIGQUIT + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.terminate(); // for SIGTERM + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.userDefined1(); // for SIGUSR1 + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.userDefined2(); // for SIGURS2 + assert(s instanceof Deno.SignalStream); + s.dispose(); + s = Deno.signals.windowChange(); // for SIGWINCH + assert(s instanceof Deno.SignalStream); + s.dispose(); + } +); diff --git a/cli/js/tests/stat_test.ts b/cli/js/tests/stat_test.ts new file mode 100644 index 000000000..0a33901b7 --- /dev/null +++ b/cli/js/tests/stat_test.ts @@ -0,0 +1,229 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +// TODO Add tests for modified, accessed, and created fields once there is a way +// to create temp files. +unitTest({ perms: { read: true } }, async function statSyncSuccess(): Promise< + void +> { + const packageInfo = Deno.statSync("README.md"); + assert(packageInfo.isFile()); + assert(!packageInfo.isSymlink()); + + const modulesInfo = Deno.statSync("cli/tests/symlink_to_subdir"); + assert(modulesInfo.isDirectory()); + assert(!modulesInfo.isSymlink()); + + const testsInfo = Deno.statSync("cli/tests"); + assert(testsInfo.isDirectory()); + assert(!testsInfo.isSymlink()); +}); + +unitTest({ perms: { read: false } }, async function statSyncPerm(): Promise< + void +> { + let caughtError = false; + try { + Deno.statSync("README.md"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, async function statSyncNotFound(): Promise< + void +> { + let caughtError = false; + let badInfo; + + try { + badInfo = Deno.statSync("bad_file_name"); + } catch (err) { + caughtError = true; + assert(err instanceof Deno.errors.NotFound); + } + + assert(caughtError); + assertEquals(badInfo, undefined); +}); + +unitTest({ perms: { read: true } }, async function lstatSyncSuccess(): Promise< + void +> { + const packageInfo = Deno.lstatSync("README.md"); + assert(packageInfo.isFile()); + assert(!packageInfo.isSymlink()); + + const modulesInfo = Deno.lstatSync("cli/tests/symlink_to_subdir"); + assert(!modulesInfo.isDirectory()); + assert(modulesInfo.isSymlink()); + + const coreInfo = Deno.lstatSync("core"); + assert(coreInfo.isDirectory()); + assert(!coreInfo.isSymlink()); +}); + +unitTest({ perms: { read: false } }, async function lstatSyncPerm(): Promise< + void +> { + let caughtError = false; + try { + Deno.lstatSync("README.md"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, async function lstatSyncNotFound(): Promise< + void +> { + let caughtError = false; + let badInfo; + + try { + badInfo = Deno.lstatSync("bad_file_name"); + } catch (err) { + caughtError = true; + assert(err instanceof Deno.errors.NotFound); + } + + assert(caughtError); + assertEquals(badInfo, undefined); +}); + +unitTest({ perms: { read: true } }, async function statSuccess(): Promise< + void +> { + const packageInfo = await Deno.stat("README.md"); + assert(packageInfo.isFile()); + assert(!packageInfo.isSymlink()); + + const modulesInfo = await Deno.stat("cli/tests/symlink_to_subdir"); + assert(modulesInfo.isDirectory()); + assert(!modulesInfo.isSymlink()); + + const testsInfo = await Deno.stat("cli/tests"); + assert(testsInfo.isDirectory()); + assert(!testsInfo.isSymlink()); +}); + +unitTest({ perms: { read: false } }, async function statPerm(): Promise { + let caughtError = false; + try { + await Deno.stat("README.md"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, async function statNotFound(): Promise< + void +> { + let caughtError = false; + let badInfo; + + try { + badInfo = await Deno.stat("bad_file_name"); + } catch (err) { + caughtError = true; + assert(err instanceof Deno.errors.NotFound); + } + + assert(caughtError); + assertEquals(badInfo, undefined); +}); + +unitTest({ perms: { read: true } }, async function lstatSuccess(): Promise< + void +> { + const packageInfo = await Deno.lstat("README.md"); + assert(packageInfo.isFile()); + assert(!packageInfo.isSymlink()); + + const modulesInfo = await Deno.lstat("cli/tests/symlink_to_subdir"); + assert(!modulesInfo.isDirectory()); + assert(modulesInfo.isSymlink()); + + const coreInfo = await Deno.lstat("core"); + assert(coreInfo.isDirectory()); + assert(!coreInfo.isSymlink()); +}); + +unitTest({ perms: { read: false } }, async function lstatPerm(): Promise { + let caughtError = false; + try { + await Deno.lstat("README.md"); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest({ perms: { read: true } }, async function lstatNotFound(): Promise< + void +> { + let caughtError = false; + let badInfo; + + try { + badInfo = await Deno.lstat("bad_file_name"); + } catch (err) { + caughtError = true; + assert(err instanceof Deno.errors.NotFound); + } + + assert(caughtError); + assertEquals(badInfo, undefined); +}); + +unitTest( + { skip: Deno.build.os !== "win", perms: { read: true, write: true } }, + async function statNoUnixFields(): Promise { + 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 === null); + 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); + } +); + +unitTest( + { skip: Deno.build.os === "win", perms: { read: true, write: true } }, + async function statUnixFields(): Promise { + 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); + } +); diff --git a/cli/js/tests/symbols_test.ts b/cli/js/tests/symbols_test.ts new file mode 100644 index 000000000..ad05e9a70 --- /dev/null +++ b/cli/js/tests/symbols_test.ts @@ -0,0 +1,7 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +unitTest(function symbolsExists(): void { + assert("internal" in Deno.symbols); + assert("customInspect" in Deno.symbols); +}); diff --git a/cli/js/tests/symlink_test.ts b/cli/js/tests/symlink_test.ts new file mode 100644 index 000000000..221960bb0 --- /dev/null +++ b/cli/js/tests/symlink_test.ts @@ -0,0 +1,85 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest( + { perms: { read: true, write: true } }, + function symlinkSyncSuccess(): void { + const testDir = Deno.makeTempDirSync(); + const oldname = testDir + "/oldname"; + const newname = testDir + "/newname"; + Deno.mkdirSync(oldname); + let errOnWindows; + // Just for now, until we implement symlink for Windows. + try { + Deno.symlinkSync(oldname, newname); + } catch (e) { + errOnWindows = e; + } + if (errOnWindows) { + assertEquals(Deno.build.os, "win"); + assertEquals(errOnWindows.message, "Not implemented"); + } else { + const newNameInfoLStat = Deno.lstatSync(newname); + const newNameInfoStat = Deno.statSync(newname); + assert(newNameInfoLStat.isSymlink()); + assert(newNameInfoStat.isDirectory()); + } + } +); + +unitTest(function symlinkSyncPerm(): void { + let err; + try { + Deno.symlinkSync("oldbaddir", "newbaddir"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +// Just for now, until we implement symlink for Windows. +// Symlink with type should succeed on other platforms with type ignored +unitTest( + { perms: { write: true } }, + function symlinkSyncNotImplemented(): void { + const testDir = Deno.makeTempDirSync(); + const oldname = testDir + "/oldname"; + const newname = testDir + "/newname"; + let err; + try { + Deno.symlinkSync(oldname, newname, "dir"); + } catch (e) { + err = e; + } + if (err) { + assertEquals(Deno.build.os, "win"); + assertEquals(err.message, "Not implemented"); + } + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function symlinkSuccess(): Promise { + const testDir = Deno.makeTempDirSync(); + const oldname = testDir + "/oldname"; + const newname = testDir + "/newname"; + Deno.mkdirSync(oldname); + let errOnWindows; + // Just for now, until we implement symlink for Windows. + try { + await Deno.symlink(oldname, newname); + } catch (e) { + errOnWindows = e; + } + if (errOnWindows) { + assertEquals(errOnWindows.message, "Not implemented"); + } else { + const newNameInfoLStat = Deno.lstatSync(newname); + const newNameInfoStat = Deno.statSync(newname); + assert(newNameInfoLStat.isSymlink()); + assert(newNameInfoStat.isDirectory()); + } + } +); diff --git a/cli/js/tests/test_util.ts b/cli/js/tests/test_util.ts new file mode 100644 index 000000000..c8f28437d --- /dev/null +++ b/cli/js/tests/test_util.ts @@ -0,0 +1,417 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +// +// We want to test many ops in deno which have different behavior depending on +// the permissions set. These tests can specify which permissions they expect, +// which appends a special string like "permW1N0" to the end of the test name. +// Here we run several copies of deno with different permissions, filtering the +// tests by the special string. permW1N0 means allow-write but not allow-net. +// See tools/unit_tests.py for more details. + +import { readLines } from "../../../std/io/bufio.ts"; +import { assert, assertEquals } from "../../../std/testing/asserts.ts"; +export { + assert, + assertThrows, + assertEquals, + assertMatch, + assertNotEquals, + assertStrictEq, + assertStrContains, + unreachable, + fail +} from "../../../std/testing/asserts.ts"; + +interface TestPermissions { + read?: boolean; + write?: boolean; + net?: boolean; + env?: boolean; + run?: boolean; + plugin?: boolean; + hrtime?: boolean; +} + +export interface Permissions { + read: boolean; + write: boolean; + net: boolean; + env: boolean; + run: boolean; + plugin: boolean; + hrtime: boolean; +} + +const isGranted = async (name: Deno.PermissionName): Promise => + (await Deno.permissions.query({ name })).state === "granted"; + +async function getProcessPermissions(): Promise { + return { + run: await isGranted("run"), + read: await isGranted("read"), + write: await isGranted("write"), + net: await isGranted("net"), + env: await isGranted("env"), + plugin: await isGranted("plugin"), + hrtime: await isGranted("hrtime") + }; +} + +const processPerms = await getProcessPermissions(); + +function permissionsMatch( + processPerms: Permissions, + requiredPerms: Permissions +): boolean { + for (const permName in processPerms) { + if ( + processPerms[permName as keyof Permissions] !== + requiredPerms[permName as keyof Permissions] + ) { + return false; + } + } + + return true; +} + +export const permissionCombinations: Map = new Map(); + +function permToString(perms: Permissions): string { + const r = perms.read ? 1 : 0; + const w = perms.write ? 1 : 0; + const n = perms.net ? 1 : 0; + const e = perms.env ? 1 : 0; + const u = perms.run ? 1 : 0; + const p = perms.plugin ? 1 : 0; + const h = perms.hrtime ? 1 : 0; + return `permR${r}W${w}N${n}E${e}U${u}P${p}H${h}`; +} + +function registerPermCombination(perms: Permissions): void { + const key = permToString(perms); + if (!permissionCombinations.has(key)) { + permissionCombinations.set(key, perms); + } +} + +function normalizeTestPermissions(perms: TestPermissions): Permissions { + return { + read: !!perms.read, + write: !!perms.write, + net: !!perms.net, + run: !!perms.run, + env: !!perms.env, + plugin: !!perms.plugin, + hrtime: !!perms.hrtime + }; +} + +// Wrap `TestFunction` in additional assertion that makes sure +// the test case does not leak async "ops" - ie. number of async +// completed ops after the test is the same as number of dispatched +// ops. Note that "unref" ops are ignored since in nature that are +// optional. +function assertOps(fn: Deno.TestFunction): Deno.TestFunction { + return async function asyncOpSanitizer(): Promise { + const pre = Deno.metrics(); + await fn(); + const post = Deno.metrics(); + // We're checking diff because one might spawn HTTP server in the background + // that will be a pending async op before test starts. + assertEquals( + post.opsDispatchedAsync - pre.opsDispatchedAsync, + post.opsCompletedAsync - pre.opsCompletedAsync, + `Test case is leaking async ops. + Before: + - dispatched: ${pre.opsDispatchedAsync} + - completed: ${pre.opsCompletedAsync} + After: + - dispatched: ${post.opsDispatchedAsync} + - completed: ${post.opsCompletedAsync}` + ); + }; +} + +// Wrap `TestFunction` in additional assertion that makes sure +// the test case does not "leak" resources - ie. resource table after +// the test has exactly the same contents as before the test. +function assertResources(fn: Deno.TestFunction): Deno.TestFunction { + return async function resourceSanitizer(): Promise { + const pre = Deno.resources(); + await fn(); + const post = Deno.resources(); + const msg = `Test case is leaking resources. + Before: ${JSON.stringify(pre, null, 2)} + After: ${JSON.stringify(post, null, 2)}`; + assertEquals(pre, post, msg); + }; +} + +interface UnitTestOptions { + skip?: boolean; + perms?: TestPermissions; +} + +export function unitTest(fn: Deno.TestFunction): void; +export function unitTest(options: UnitTestOptions, fn: Deno.TestFunction): void; +export function unitTest( + optionsOrFn: UnitTestOptions | Deno.TestFunction, + maybeFn?: Deno.TestFunction +): void { + assert(optionsOrFn, "At least one argument is required"); + + let options: UnitTestOptions; + let name: string; + let fn: Deno.TestFunction; + + if (typeof optionsOrFn === "function") { + options = {}; + fn = optionsOrFn; + name = fn.name; + assert(name, "Missing test function name"); + } else { + options = optionsOrFn; + assert(maybeFn, "Missing test function definition"); + assert( + typeof maybeFn === "function", + "Second argument should be test function definition" + ); + fn = maybeFn; + name = fn.name; + assert(name, "Missing test function name"); + } + + if (options.skip) { + return; + } + + const normalizedPerms = normalizeTestPermissions(options.perms || {}); + registerPermCombination(normalizedPerms); + if (!permissionsMatch(processPerms, normalizedPerms)) { + return; + } + + const testDefinition: Deno.TestDefinition = { + name, + fn: assertResources(assertOps(fn)) + }; + Deno.test(testDefinition); +} + +function extractNumber(re: RegExp, str: string): number | undefined { + const match = str.match(re); + + if (match) { + return Number.parseInt(match[1]); + } +} + +export async function parseUnitTestOutput( + reader: Deno.Reader, + print: boolean +): Promise<{ actual?: number; expected?: number; resultOutput?: string }> { + let expected, actual, result; + + for await (const line of readLines(reader)) { + if (!expected) { + // expect "running 30 tests" + expected = extractNumber(/running (\d+) tests/, line); + } else if (line.indexOf("test result:") !== -1) { + result = line; + } + + if (print) { + console.log(line); + } + } + + // Check that the number of expected tests equals what was reported at the + // bottom. + if (result) { + // result should be a string like this: + // "test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; ..." + actual = extractNumber(/(\d+) passed/, result); + } + + return { actual, expected, resultOutput: result }; +} + +export interface ResolvableMethods { + resolve: (value?: T | PromiseLike) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + reject: (reason?: any) => void; +} + +export type Resolvable = Promise & ResolvableMethods; + +export function createResolvable(): Resolvable { + let methods: ResolvableMethods; + const promise = new Promise((resolve, reject): void => { + methods = { resolve, reject }; + }); + // TypeScript doesn't know that the Promise callback occurs synchronously + // therefore use of not null assertion (`!`) + return Object.assign(promise, methods!) as Resolvable; +} + +unitTest(function permissionsMatches(): void { + assert( + permissionsMatch( + { + read: true, + write: false, + net: false, + env: false, + run: false, + plugin: false, + hrtime: false + }, + normalizeTestPermissions({ read: true }) + ) + ); + + assert( + permissionsMatch( + { + read: false, + write: false, + net: false, + env: false, + run: false, + plugin: false, + hrtime: false + }, + normalizeTestPermissions({}) + ) + ); + + assertEquals( + permissionsMatch( + { + read: false, + write: true, + net: true, + env: true, + run: true, + plugin: true, + hrtime: true + }, + normalizeTestPermissions({ read: true }) + ), + false + ); + + assertEquals( + permissionsMatch( + { + read: true, + write: false, + net: true, + env: false, + run: false, + plugin: false, + hrtime: false + }, + normalizeTestPermissions({ read: true }) + ), + false + ); + + assert( + permissionsMatch( + { + read: true, + write: true, + net: true, + env: true, + run: true, + plugin: true, + hrtime: true + }, + { + read: true, + write: true, + net: true, + env: true, + run: true, + plugin: true, + hrtime: true + } + ) + ); +}); + +unitTest( + { perms: { read: true } }, + async function parsingUnitTestOutput(): Promise { + const cwd = Deno.cwd(); + const testDataPath = `${cwd}/tools/testdata/`; + + let result; + + // This is an example of a successful unit test output. + const f1 = await Deno.open(`${testDataPath}/unit_test_output1.txt`); + result = await parseUnitTestOutput(f1, false); + assertEquals(result.actual, 96); + assertEquals(result.expected, 96); + f1.close(); + + // This is an example of a silently dying unit test. + const f2 = await Deno.open(`${testDataPath}/unit_test_output2.txt`); + result = await parseUnitTestOutput(f2, false); + assertEquals(result.actual, undefined); + assertEquals(result.expected, 96); + f2.close(); + + // This is an example of compiling before successful unit tests. + const f3 = await Deno.open(`${testDataPath}/unit_test_output3.txt`); + result = await parseUnitTestOutput(f3, false); + assertEquals(result.actual, 96); + assertEquals(result.expected, 96); + f3.close(); + + // Check what happens on empty output. + const f = new Deno.Buffer(new TextEncoder().encode("\n\n\n")); + result = await parseUnitTestOutput(f, false); + assertEquals(result.actual, undefined); + assertEquals(result.expected, undefined); + } +); + +/* + * Ensure all unit test files (e.g. xxx_test.ts) are present as imports in + * cli/js/tests/unit_tests.ts as it is easy to miss this out + */ +unitTest( + { perms: { read: true } }, + async function assertAllUnitTestFilesImported(): Promise { + const directoryTestFiles = Deno.readdirSync("./cli/js/tests/") + .map(k => k.name) + .filter( + file => + file!.endsWith(".ts") && + !file!.endsWith("unit_tests.ts") && + !file!.endsWith("test_util.ts") && + !file!.endsWith("unit_test_runner.ts") + ); + const unitTestsFile: Uint8Array = Deno.readFileSync( + "./cli/js/tests/unit_tests.ts" + ); + const importLines = new TextDecoder("utf-8") + .decode(unitTestsFile) + .split("\n") + .filter(line => line.startsWith("import")); + const importedTestFiles = importLines.map( + relativeFilePath => relativeFilePath.match(/\/([^\/]+)";/)![1] + ); + + directoryTestFiles.forEach(dirFile => { + if (!importedTestFiles.includes(dirFile!)) { + throw new Error( + "cil/js/tests/unit_tests.ts is missing import of test file: cli/js/" + + dirFile + ); + } + }); + } +); diff --git a/cli/js/tests/testing_test.ts b/cli/js/tests/testing_test.ts new file mode 100644 index 000000000..b47eb03e2 --- /dev/null +++ b/cli/js/tests/testing_test.ts @@ -0,0 +1,37 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { assertThrows, unitTest } from "./test_util.ts"; + +unitTest(function testFnOverloading(): void { + // just verifying that you can use this test definition syntax + Deno.test("test fn overloading", (): void => {}); +}); + +unitTest(function nameOfTestCaseCantBeEmpty(): void { + assertThrows( + () => { + Deno.test("", () => {}); + }, + Error, + "The name of test case can't be empty" + ); + assertThrows( + () => { + Deno.test({ + name: "", + fn: () => {} + }); + }, + Error, + "The name of test case can't be empty" + ); +}); + +unitTest(function testFnCantBeAnonymous(): void { + assertThrows( + () => { + Deno.test(function() {}); + }, + Error, + "Test function can't be anonymous" + ); +}); diff --git a/cli/js/tests/text_encoding_test.ts b/cli/js/tests/text_encoding_test.ts new file mode 100644 index 000000000..e85655feb --- /dev/null +++ b/cli/js/tests/text_encoding_test.ts @@ -0,0 +1,193 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest(function btoaSuccess(): void { + const text = "hello world"; + const encoded = btoa(text); + assertEquals(encoded, "aGVsbG8gd29ybGQ="); +}); + +unitTest(function atobSuccess(): void { + const encoded = "aGVsbG8gd29ybGQ="; + const decoded = atob(encoded); + assertEquals(decoded, "hello world"); +}); + +unitTest(function atobWithAsciiWhitespace(): void { + 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"); + } +}); + +unitTest(function atobThrows(): void { + let threw = false; + try { + atob("aGVsbG8gd29ybGQ=="); + } catch (e) { + threw = true; + } + assert(threw); +}); + +unitTest(function atobThrows2(): void { + let threw = false; + try { + atob("aGVsbG8gd29ybGQ==="); + } catch (e) { + threw = true; + } + assert(threw); +}); + +unitTest(function btoaFailed(): void { + const text = "你好"; + let err; + try { + btoa(text); + } catch (e) { + err = e; + } + assert(!!err); + assert(err instanceof TypeError); +}); + +unitTest(function textDecoder2(): void { + // prettier-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), "𝓽𝓮𝔁𝓽"); +}); + +unitTest(function textDecoderIgnoreBOM(): void { + // prettier-ignore + const fixture = new Uint8Array([ + 0xef, 0xbb, 0xbf, + 0xf0, 0x9d, 0x93, 0xbd, + 0xf0, 0x9d, 0x93, 0xae, + 0xf0, 0x9d, 0x94, 0x81, + 0xf0, 0x9d, 0x93, 0xbd + ]); + const decoder = new TextDecoder("utf-8", { ignoreBOM: true }); + assertEquals(decoder.decode(fixture), "𝓽𝓮𝔁𝓽"); +}); + +unitTest(function textDecoderNotBOM(): void { + // prettier-ignore + const fixture = new Uint8Array([ + 0xef, 0xbb, 0x89, + 0xf0, 0x9d, 0x93, 0xbd, + 0xf0, 0x9d, 0x93, 0xae, + 0xf0, 0x9d, 0x94, 0x81, + 0xf0, 0x9d, 0x93, 0xbd + ]); + const decoder = new TextDecoder("utf-8", { ignoreBOM: true }); + assertEquals(decoder.decode(fixture), "ﻉ𝓽𝓮𝔁𝓽"); +}); + +unitTest(function textDecoderASCII(): void { + const fixture = new Uint8Array([0x89, 0x95, 0x9f, 0xbf]); + const decoder = new TextDecoder("ascii"); + assertEquals(decoder.decode(fixture), "‰•Ÿ¿"); +}); + +unitTest(function textDecoderErrorEncoding(): void { + let didThrow = false; + try { + new TextDecoder("foo"); + } catch (e) { + didThrow = true; + assertEquals(e.message, "The encoding label provided ('foo') is invalid."); + } + assert(didThrow); +}); + +unitTest(function textEncoder(): void { + const fixture = "𝓽𝓮𝔁𝓽"; + const encoder = new TextEncoder(); + // prettier-ignore + assertEquals(Array.from(encoder.encode(fixture)), [ + 0xf0, 0x9d, 0x93, 0xbd, + 0xf0, 0x9d, 0x93, 0xae, + 0xf0, 0x9d, 0x94, 0x81, + 0xf0, 0x9d, 0x93, 0xbd + ]); +}); + +unitTest(function textEncodeInto(): void { + 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); + // prettier-ignore + assertEquals(Array.from(bytes), [ + 0x74, 0x65, 0x78, 0x74, 0x00, + ]); +}); + +unitTest(function textEncodeInto2(): void { + 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); + // prettier-ignore + assertEquals(Array.from(bytes), [ + 0xf0, 0x9d, 0x93, 0xbd, + 0xf0, 0x9d, 0x93, 0xae, + 0xf0, 0x9d, 0x94, 0x81, + 0xf0, 0x9d, 0x93, 0xbd, 0x00, + ]); +}); + +unitTest(function textDecoderSharedUint8Array(): void { + 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"); +}); + +unitTest(function textDecoderSharedInt32Array(): void { + 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"); +}); + +unitTest(function toStringShouldBeWebCompatibility(): void { + const encoder = new TextEncoder(); + assertEquals(encoder.toString(), "[object TextEncoder]"); + + const decoder = new TextDecoder(); + assertEquals(decoder.toString(), "[object TextDecoder]"); +}); diff --git a/cli/js/tests/timers_test.ts b/cli/js/tests/timers_test.ts new file mode 100644 index 000000000..429e42692 --- /dev/null +++ b/cli/js/tests/timers_test.ts @@ -0,0 +1,353 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { + unitTest, + createResolvable, + assert, + assertEquals, + assertNotEquals +} from "./test_util.ts"; + +function deferred(): { + promise: Promise<{}>; + resolve: (value?: {} | PromiseLike<{}>) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + reject: (reason?: any) => void; +} { + let resolve: (value?: {} | PromiseLike<{}>) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let reject: ((reason?: any) => void) | undefined = undefined; + const promise = new Promise<{}>((res, rej): void => { + resolve = res; + reject = rej; + }); + return { + promise, + resolve: resolve!, + reject: reject! + }; +} + +async function waitForMs(ms: number): Promise { + return new Promise((resolve: () => void): number => setTimeout(resolve, ms)); +} + +unitTest(async function timeoutSuccess(): Promise { + const { promise, resolve } = deferred(); + let count = 0; + setTimeout((): void => { + count++; + resolve(); + }, 500); + await promise; + // count should increment + assertEquals(count, 1); +}); + +unitTest(async function timeoutArgs(): Promise { + const { promise, resolve } = deferred(); + const arg = 1; + setTimeout( + (a, b, c): void => { + assertEquals(a, arg); + assertEquals(b, arg.toString()); + assertEquals(c, [arg]); + resolve(); + }, + 10, + arg, + arg.toString(), + [arg] + ); + await promise; +}); + +unitTest(async function timeoutCancelSuccess(): Promise { + let count = 0; + const id = setTimeout((): void => { + count++; + }, 1); + // Cancelled, count should not increment + clearTimeout(id); + await waitForMs(600); + assertEquals(count, 0); +}); + +unitTest(async function timeoutCancelMultiple(): Promise { + 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 waitForMs(50); +}); + +unitTest(async function timeoutCancelInvalidSilentFail(): Promise { + // Expect no panic + const { promise, resolve } = deferred(); + let count = 0; + const id = setTimeout((): void => { + count++; + // Should have no effect + clearTimeout(id); + resolve(); + }, 500); + await promise; + assertEquals(count, 1); + + // Should silently fail (no panic) + clearTimeout(2147483647); +}); + +unitTest(async function intervalSuccess(): Promise { + const { promise, resolve } = deferred(); + let count = 0; + const id = setInterval((): void => { + count++; + clearInterval(id); + resolve(); + }, 100); + await promise; + // Clear interval + clearInterval(id); + // count should increment twice + assertEquals(count, 1); +}); + +unitTest(async function intervalCancelSuccess(): Promise { + let count = 0; + const id = setInterval((): void => { + count++; + }, 1); + clearInterval(id); + await waitForMs(500); + assertEquals(count, 0); +}); + +unitTest(async function intervalOrdering(): Promise { + const timers: number[] = []; + let timeouts = 0; + function onTimeout(): void { + ++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 waitForMs(500); + assertEquals(timeouts, 1); +}); + +unitTest(async function intervalCancelInvalidSilentFail(): Promise { + // Should silently fail (no panic) + clearInterval(2147483647); +}); + +unitTest(async function fireCallbackImmediatelyWhenDelayOverMaxValue(): Promise< + void +> { + let count = 0; + setTimeout((): void => { + count++; + }, 2 ** 31); + await waitForMs(1); + assertEquals(count, 1); +}); + +unitTest(async function timeoutCallbackThis(): Promise { + const { promise, resolve } = deferred(); + const obj = { + foo(): void { + assertEquals(this, window); + resolve(); + } + }; + setTimeout(obj.foo, 1); + await promise; +}); + +unitTest(async function timeoutBindThis(): Promise { + const thisCheckPassed = [null, undefined, window, globalThis]; + + const thisCheckFailed = [ + 0, + "", + true, + false, + {}, + [], + "foo", + (): void => {}, + Object.prototype + ]; + + for (const thisArg of thisCheckPassed) { + const resolvable = createResolvable(); + let hasThrown = 0; + try { + setTimeout.call(thisArg, () => resolvable.resolve(), 1); + hasThrown = 1; + } catch (err) { + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + await resolvable; + 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); + } +}); + +unitTest(async function clearTimeoutShouldConvertToNumber(): Promise { + let called = false; + const obj = { + valueOf(): number { + called = true; + return 1; + } + }; + clearTimeout((obj as unknown) as number); + assert(called); +}); + +unitTest(function setTimeoutShouldThrowWithBigint(): void { + let hasThrown = 0; + try { + setTimeout((): void => {}, (1n as unknown) as number); + hasThrown = 1; + } catch (err) { + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEquals(hasThrown, 2); +}); + +unitTest(function clearTimeoutShouldThrowWithBigint(): void { + 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); +}); + +unitTest(function testFunctionName(): void { + assertEquals(clearTimeout.name, "clearTimeout"); + assertEquals(clearInterval.name, "clearInterval"); +}); + +unitTest(function testFunctionParamsLength(): void { + assertEquals(setTimeout.length, 1); + assertEquals(setInterval.length, 1); + assertEquals(clearTimeout.length, 0); + assertEquals(clearInterval.length, 0); +}); + +unitTest(function clearTimeoutAndClearIntervalNotBeEquals(): void { + assertNotEquals(clearTimeout, clearInterval); +}); + +unitTest(async function timerMaxCpuBug(): Promise { + // There was a bug where clearing a timeout would cause Deno to use 100% CPU. + clearTimeout(setTimeout(() => {}, 1000)); + // We can check this by counting how many ops have triggered in the interim. + // Certainly less than 10 ops should have been dispatched in next 100 ms. + const { opsDispatched } = Deno.metrics(); + await waitForMs(100); + const opsDispatched_ = Deno.metrics().opsDispatched; + assert(opsDispatched_ - opsDispatched < 10); +}); + +unitTest(async function timerBasicMicrotaskOrdering(): Promise { + let s = ""; + let count = 0; + const { promise, resolve } = deferred(); + setTimeout(() => { + Promise.resolve().then(() => { + count++; + s += "de"; + if (count === 2) { + resolve(); + } + }); + }); + setTimeout(() => { + count++; + s += "no"; + if (count === 2) { + resolve(); + } + }); + await promise; + assertEquals(s, "deno"); +}); + +unitTest(async function timerNestedMicrotaskOrdering(): Promise { + let s = ""; + const { promise, resolve } = deferred(); + s += "0"; + setTimeout(() => { + s += "4"; + setTimeout(() => (s += "8")); + Promise.resolve().then(() => { + setTimeout(() => { + s += "9"; + resolve(); + }); + }); + }); + setTimeout(() => (s += "5")); + Promise.resolve().then(() => (s += "2")); + Promise.resolve().then(() => + setTimeout(() => { + s += "6"; + Promise.resolve().then(() => (s += "7")); + }) + ); + Promise.resolve().then(() => Promise.resolve().then(() => (s += "3"))); + s += "1"; + await promise; + assertEquals(s, "0123456789"); +}); diff --git a/cli/js/tests/tls_test.ts b/cli/js/tests/tls_test.ts new file mode 100644 index 000000000..b405a94dd --- /dev/null +++ b/cli/js/tests/tls_test.ts @@ -0,0 +1,214 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { + assert, + assertEquals, + createResolvable, + unitTest +} from "./test_util.ts"; +import { BufWriter, BufReader } from "../../../std/io/bufio.ts"; +import { TextProtoReader } from "../../../std/textproto/mod.ts"; + +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); + +unitTest(async function connectTLSNoPerm(): Promise { + let err; + try { + await Deno.connectTLS({ hostname: "github.com", port: 443 }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest(async function connectTLSCertFileNoReadPerm(): Promise { + let err; + try { + await Deno.connectTLS({ + hostname: "github.com", + port: 443, + certFile: "cli/tests/tls/RootCA.crt" + }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest( + { perms: { read: true, net: true } }, + async function listenTLSNonExistentCertKeyFiles(): Promise { + let err; + const options = { + hostname: "localhost", + port: 4500, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/tls/localhost.key" + }; + + try { + Deno.listenTLS({ + ...options, + certFile: "./non/existent/file" + }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); + + try { + Deno.listenTLS({ + ...options, + keyFile: "./non/existent/file" + }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.NotFound); + } +); + +unitTest( + { perms: { net: true } }, + async function listenTLSNoReadPerm(): Promise { + let err; + try { + Deno.listenTLS({ + hostname: "localhost", + port: 4500, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/tls/localhost.key" + }); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); + } +); + +unitTest( + { + perms: { read: true, write: true, net: true } + }, + async function listenTLSEmptyKeyFile(): Promise { + let err; + const options = { + hostname: "localhost", + port: 4500, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/tls/localhost.key" + }; + + const testDir = Deno.makeTempDirSync(); + const keyFilename = testDir + "/key.pem"; + Deno.writeFileSync(keyFilename, new Uint8Array([]), { + mode: 0o666 + }); + + try { + Deno.listenTLS({ + ...options, + keyFile: keyFilename + }); + } catch (e) { + err = e; + } + assert(err instanceof Error); + } +); + +unitTest( + { perms: { read: true, write: true, net: true } }, + async function listenTLSEmptyCertFile(): Promise { + let err; + const options = { + hostname: "localhost", + port: 4500, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/tls/localhost.key" + }; + + const testDir = Deno.makeTempDirSync(); + const certFilename = testDir + "/cert.crt"; + Deno.writeFileSync(certFilename, new Uint8Array([]), { + mode: 0o666 + }); + + try { + Deno.listenTLS({ + ...options, + certFile: certFilename + }); + } catch (e) { + err = e; + } + assert(err instanceof Error); + } +); + +unitTest( + { perms: { read: true, net: true } }, + async function dialAndListenTLS(): Promise { + const resolvable = createResolvable(); + const hostname = "localhost"; + const port = 4500; + + const listener = Deno.listenTLS({ + hostname, + port, + certFile: "cli/tests/tls/localhost.crt", + keyFile: "cli/tests/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): Promise => { + assert(conn.remoteAddr != null); + assert(conn.localAddr != null); + await conn.write(response); + // TODO(bartlomieju): this might be a bug + setTimeout(() => { + conn.close(); + resolvable.resolve(); + }, 0); + } + ); + + const conn = await Deno.connectTLS({ + hostname, + port, + certFile: "cli/tests/tls/RootCA.pem" + }); + 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 !== Deno.EOF, `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 !== Deno.EOF); + 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 resolvable; + } +); diff --git a/cli/js/tests/truncate_test.ts b/cli/js/tests/truncate_test.ts new file mode 100644 index 000000000..3fd85c990 --- /dev/null +++ b/cli/js/tests/truncate_test.ts @@ -0,0 +1,80 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assertEquals, assert } from "./test_util.ts"; + +function readDataSync(name: string): string { + const data = Deno.readFileSync(name); + const decoder = new TextDecoder("utf-8"); + const text = decoder.decode(data); + return text; +} + +async function readData(name: string): Promise { + const data = await Deno.readFile(name); + const decoder = new TextDecoder("utf-8"); + const text = decoder.decode(data); + return text; +} + +unitTest( + { perms: { read: true, write: true } }, + function truncateSyncSuccess(): void { + const enc = new TextEncoder(); + const d = enc.encode("Hello"); + const filename = Deno.makeTempDirSync() + "/test_truncateSync.txt"; + Deno.writeFileSync(filename, d); + Deno.truncateSync(filename, 20); + let data = readDataSync(filename); + assertEquals(data.length, 20); + Deno.truncateSync(filename, 5); + data = readDataSync(filename); + assertEquals(data.length, 5); + Deno.truncateSync(filename, -5); + data = readDataSync(filename); + assertEquals(data.length, 0); + Deno.removeSync(filename); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function truncateSuccess(): Promise { + const enc = new TextEncoder(); + const d = enc.encode("Hello"); + const filename = Deno.makeTempDirSync() + "/test_truncate.txt"; + await Deno.writeFile(filename, d); + await Deno.truncate(filename, 20); + let data = await readData(filename); + assertEquals(data.length, 20); + await Deno.truncate(filename, 5); + data = await readData(filename); + assertEquals(data.length, 5); + await Deno.truncate(filename, -5); + data = await readData(filename); + assertEquals(data.length, 0); + await Deno.remove(filename); + } +); + +unitTest({ perms: { write: false } }, function truncateSyncPerm(): void { + let err; + try { + Deno.mkdirSync("/test_truncateSyncPermission.txt"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); + +unitTest({ perms: { write: false } }, async function truncatePerm(): Promise< + void +> { + let err; + try { + await Deno.mkdir("/test_truncatePermission.txt"); + } catch (e) { + err = e; + } + assert(err instanceof Deno.errors.PermissionDenied); + assertEquals(err.name, "PermissionDenied"); +}); diff --git a/cli/js/tests/tty_test.ts b/cli/js/tests/tty_test.ts new file mode 100644 index 000000000..116b0dfe9 --- /dev/null +++ b/cli/js/tests/tty_test.ts @@ -0,0 +1,23 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +// Note tests for Deno.setRaw is in integration tests. + +unitTest({ perms: { read: true } }, function isatty(): void { + // CI not under TTY, so cannot test stdin/stdout/stderr. + const f = Deno.openSync("cli/tests/hello.txt"); + assert(!Deno.isatty(f.rid)); + f.close(); +}); + +unitTest(function isattyError(): void { + 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/js/tests/unit_test_runner.ts b/cli/js/tests/unit_test_runner.ts new file mode 100755 index 000000000..a5b7c3a48 --- /dev/null +++ b/cli/js/tests/unit_test_runner.ts @@ -0,0 +1,108 @@ +#!/usr/bin/env -S deno run --reload --allow-run +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import "./unit_tests.ts"; +import { + permissionCombinations, + parseUnitTestOutput, + Permissions +} from "./test_util.ts"; + +interface TestResult { + perms: string; + output?: string; + result: number; +} + +function permsToCliFlags(perms: Permissions): string[] { + return Object.keys(perms) + .map(key => { + if (!perms[key as keyof Permissions]) return ""; + + const cliFlag = key.replace( + /\.?([A-Z])/g, + (x, y): string => `-${y.toLowerCase()}` + ); + return `--allow-${cliFlag}`; + }) + .filter((e): boolean => e.length > 0); +} + +function fmtPerms(perms: Permissions): string { + let fmt = permsToCliFlags(perms).join(" "); + + if (!fmt) { + fmt = ""; + } + + return fmt; +} + +async function main(): Promise { + console.log( + "Discovered permission combinations for tests:", + permissionCombinations.size + ); + + for (const perms of permissionCombinations.values()) { + console.log("\t" + fmtPerms(perms)); + } + + const testResults = new Set(); + + for (const perms of permissionCombinations.values()) { + const permsFmt = fmtPerms(perms); + console.log(`Running tests for: ${permsFmt}`); + const cliPerms = permsToCliFlags(perms); + // run subsequent tests using same deno executable + const args = [ + Deno.execPath(), + "run", + ...cliPerms, + "cli/js/tests/unit_tests.ts" + ]; + + const p = Deno.run({ + args, + stdout: "piped" + }); + + const { actual, expected, resultOutput } = await parseUnitTestOutput( + p.stdout!, + true + ); + + let result = 0; + + if (!actual && !expected) { + console.error("Bad cli/js/tests/unit_test.ts output"); + result = 1; + } else if (expected !== actual) { + result = 1; + } + + testResults.add({ + perms: permsFmt, + output: resultOutput, + result + }); + } + + // if any run tests returned non-zero status then whole test + // run should fail + let testsFailed = false; + + for (const testResult of testResults) { + console.log(`Summary for ${testResult.perms}`); + console.log(testResult.output + "\n"); + testsFailed = testsFailed || Boolean(testResult.result); + } + + if (testsFailed) { + console.error("Unit tests failed"); + Deno.exit(1); + } + + console.log("Unit tests passed"); +} + +main(); diff --git a/cli/js/tests/unit_tests.ts b/cli/js/tests/unit_tests.ts new file mode 100644 index 000000000..cc51e6ade --- /dev/null +++ b/cli/js/tests/unit_tests.ts @@ -0,0 +1,69 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +// This test is executed as part of tools/test.py +// But it can also be run manually: ./target/debug/deno cli/js/tests/unit_tests.ts + +import "./blob_test.ts"; +import "./body_test.ts"; +import "./buffer_test.ts"; +import "./build_test.ts"; +import "./chmod_test.ts"; +import "./chown_test.ts"; +import "./compiler_api_test.ts"; +import "./console_test.ts"; +import "./copy_file_test.ts"; +import "./custom_event_test.ts"; +import "./dir_test.ts"; +import "./dispatch_minimal_test.ts"; +import "./dispatch_json_test.ts"; +import "./error_stack_test.ts"; +import "./event_test.ts"; +import "./event_target_test.ts"; +import "./fetch_test.ts"; +import "./file_test.ts"; +import "./files_test.ts"; +import "./form_data_test.ts"; +import "./format_error_test.ts"; +import "./fs_events_test.ts"; +import "./get_random_values_test.ts"; +import "./globals_test.ts"; +import "./headers_test.ts"; +import "./internals_test.ts"; +import "./link_test.ts"; +import "./location_test.ts"; +import "./make_temp_test.ts"; +import "./metrics_test.ts"; +import "./dom_iterable_test.ts"; +import "./mkdir_test.ts"; +import "./net_test.ts"; +import "./os_test.ts"; +import "./permissions_test.ts"; +import "./process_test.ts"; +import "./realpath_test.ts"; +import "./read_dir_test.ts"; +import "./read_file_test.ts"; +import "./read_link_test.ts"; +import "./remove_test.ts"; +import "./rename_test.ts"; +import "./request_test.ts"; +import "./resources_test.ts"; +import "./signal_test.ts"; +import "./stat_test.ts"; +import "./symbols_test.ts"; +import "./symlink_test.ts"; +import "./text_encoding_test.ts"; +import "./testing_test.ts"; +import "./timers_test.ts"; +import "./tls_test.ts"; +import "./truncate_test.ts"; +import "./tty_test.ts"; +import "./url_test.ts"; +import "./url_search_params_test.ts"; +import "./utime_test.ts"; +import "./write_file_test.ts"; +import "./performance_test.ts"; +import "./version_test.ts"; + +if (import.meta.main) { + await Deno.runTests(); +} diff --git a/cli/js/tests/url_search_params_test.ts b/cli/js/tests/url_search_params_test.ts new file mode 100644 index 000000000..b256395a0 --- /dev/null +++ b/cli/js/tests/url_search_params_test.ts @@ -0,0 +1,245 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest(function urlSearchParamsInitString(): void { + 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" + ); +}); + +unitTest(function urlSearchParamsInitIterable(): void { + const init = [ + ["a", "54"], + ["b", "true"] + ]; + const searchParams = new URLSearchParams(init); + assertEquals(searchParams.toString(), "a=54&b=true"); +}); + +unitTest(function urlSearchParamsInitRecord(): void { + const init = { a: "54", b: "true" }; + const searchParams = new URLSearchParams(init); + assertEquals(searchParams.toString(), "a=54&b=true"); +}); + +unitTest(function urlSearchParamsInit(): void { + const params1 = new URLSearchParams("a=b"); + assertEquals(params1.toString(), "a=b"); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const params2 = new URLSearchParams(params1 as any); + assertEquals(params2.toString(), "a=b"); +}); + +unitTest(function urlSearchParamsAppendSuccess(): void { + const searchParams = new URLSearchParams(); + searchParams.append("a", "true"); + assertEquals(searchParams.toString(), "a=true"); +}); + +unitTest(function urlSearchParamsDeleteSuccess(): void { + const init = "a=54&b=true"; + const searchParams = new URLSearchParams(init); + searchParams.delete("b"); + assertEquals(searchParams.toString(), "a=54"); +}); + +unitTest(function urlSearchParamsGetAllSuccess(): void { + 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"), []); +}); + +unitTest(function urlSearchParamsGetSuccess(): void { + 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); +}); + +unitTest(function urlSearchParamsHasSuccess(): void { + 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")); +}); + +unitTest(function urlSearchParamsSetReplaceFirstAndRemoveOthers(): void { + const init = "a=54&b=true&a=true"; + const searchParams = new URLSearchParams(init); + searchParams.set("a", "false"); + assertEquals(searchParams.toString(), "a=false&b=true"); +}); + +unitTest(function urlSearchParamsSetAppendNew(): void { + 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"); +}); + +unitTest(function urlSearchParamsSortSuccess(): void { + 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"); +}); + +unitTest(function urlSearchParamsForEachSuccess(): void { + const init = [ + ["a", "54"], + ["b", "true"] + ]; + const searchParams = new URLSearchParams(init); + let callNum = 0; + searchParams.forEach((value, key, parent): void => { + assertEquals(searchParams, parent); + assertEquals(value, init[callNum][1]); + assertEquals(key, init[callNum][0]); + callNum++; + }); + assertEquals(callNum, init.length); +}); + +unitTest(function urlSearchParamsMissingName(): void { + const init = "=4"; + const searchParams = new URLSearchParams(init); + assertEquals(searchParams.get(""), "4"); + assertEquals(searchParams.toString(), "=4"); +}); + +unitTest(function urlSearchParamsMissingValue(): void { + const init = "4="; + const searchParams = new URLSearchParams(init); + assertEquals(searchParams.get("4"), ""); + assertEquals(searchParams.toString(), "4="); +}); + +unitTest(function urlSearchParamsMissingEqualSign(): void { + const init = "4"; + const searchParams = new URLSearchParams(init); + assertEquals(searchParams.get("4"), ""); + assertEquals(searchParams.toString(), "4="); +}); + +unitTest(function urlSearchParamsMissingPair(): void { + const init = "c=4&&a=54&"; + const searchParams = new URLSearchParams(init); + assertEquals(searchParams.toString(), "c=4&a=54"); +}); + +// If pair does not contain exactly two items, then throw a TypeError. +// ref https://url.spec.whatwg.org/#interface-urlsearchparams +unitTest(function urlSearchParamsShouldThrowTypeError(): void { + 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); +}); + +unitTest(function urlSearchParamsAppendArgumentsCheck(): void { + const methodRequireOneParam = ["delete", "getAll", "get", "has", "forEach"]; + + const methodRequireTwoParams = ["append", "set"]; + + methodRequireOneParam + .concat(methodRequireTwoParams) + .forEach((method: string): void => { + const searchParams = new URLSearchParams(); + let hasThrown = 0; + try { + // @ts-ignore + searchParams[method](); + hasThrown = 1; + } catch (err) { + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEquals(hasThrown, 2); + }); + + methodRequireTwoParams.forEach((method: string): void => { + const searchParams = new URLSearchParams(); + let hasThrown = 0; + try { + // @ts-ignore + searchParams[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 +unitTest(function urlSearchParamsDeletingAppendedMultiple(): void { + 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 +unitTest(function urlSearchParamsCustomSymbolIterator(): void { + 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"); +}); + +unitTest( + function urlSearchParamsCustomSymbolIteratorWithNonStringParams(): void { + const params = {}; + // @ts-ignore + params[Symbol.iterator] = function*(): IterableIterator<[number, number]> { + yield [1, 2]; + }; + const params1 = new URLSearchParams((params as unknown) as string[][]); + assertEquals(params1.get("1"), "2"); + } +); diff --git a/cli/js/tests/url_test.ts b/cli/js/tests/url_test.ts new file mode 100644 index 000000000..46468c8ae --- /dev/null +++ b/cli/js/tests/url_test.ts @@ -0,0 +1,208 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals, assertThrows } from "./test_util.ts"; + +unitTest(function urlParsing(): void { + 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" + ); + assertEquals( + JSON.stringify({ key: url }), + `{"key":"https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat"}` + ); +}); + +unitTest(function urlModifications(): void { + 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" + ); +}); + +unitTest(function urlModifyHref(): void { + 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"); +}); + +unitTest(function urlModifyPathname(): void { + const url = new URL("http://foo.bar/baz%qat/qux%quux"); + assertEquals(url.pathname, "/baz%qat/qux%quux"); + url.pathname = url.pathname; + assertEquals(url.pathname, "/baz%qat/qux%quux"); + url.pathname = "baz#qat qux"; + assertEquals(url.pathname, "/baz%23qat%20qux"); + url.pathname = url.pathname; + assertEquals(url.pathname, "/baz%23qat%20qux"); +}); + +unitTest(function urlModifyHash(): void { + const url = new URL("http://foo.bar"); + url.hash = "%foo bar/qat%qux#bar"; + assertEquals(url.hash, "#%foo%20bar/qat%qux#bar"); + url.hash = url.hash; + assertEquals(url.hash, "#%foo%20bar/qat%qux#bar"); +}); + +unitTest(function urlSearchParamsReuse(): void { + 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."); +}); + +unitTest(function urlBaseURL(): void { + const base = new URL( + "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat" + ); + const url = new URL("/foo/bar?baz=foo#qux", base); + assertEquals(url.href, "https://foo:bar@baz.qat:8000/foo/bar?baz=foo#qux"); +}); + +unitTest(function urlBaseString(): void { + const url = new URL( + "/foo/bar?baz=foo#qux", + "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat" + ); + assertEquals(url.href, "https://foo:bar@baz.qat:8000/foo/bar?baz=foo#qux"); +}); + +unitTest(function urlRelativeWithBase(): void { + assertEquals(new URL("", "file:///a/a/a").href, "file:///a/a/a"); + assertEquals(new URL(".", "file:///a/a/a").href, "file:///a/a/"); + assertEquals(new URL("..", "file:///a/a/a").href, "file:///a/"); + assertEquals(new URL("b", "file:///a/a/a").href, "file:///a/a/b"); + assertEquals(new URL("b", "file:///a/a/a/").href, "file:///a/a/a/b"); + assertEquals(new URL("b/", "file:///a/a/a").href, "file:///a/a/b/"); + assertEquals(new URL("../b", "file:///a/a/a").href, "file:///a/b"); +}); + +unitTest(function emptyBasePath(): void { + assertEquals(new URL("", "http://example.com").href, "http://example.com/"); +}); + +unitTest(function deletingAllParamsRemovesQuestionMarkFromURL(): void { + const url = new URL("http://example.com/?param1¶m2"); + url.searchParams.delete("param1"); + url.searchParams.delete("param2"); + assertEquals(url.href, "http://example.com/"); + assertEquals(url.search, ""); +}); + +unitTest(function removingNonExistentParamRemovesQuestionMarkFromURL(): void { + 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, ""); +}); + +unitTest(function sortingNonExistentParamRemovesQuestionMarkFromURL(): void { + 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, ""); +}); + +/* +unitTest(function customInspectFunction(): void { + 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: "?" }' + ); +}); +*/ + +unitTest(function protocolNotHttpOrFile() { + const url = new URL("about:blank"); + assertEquals(url.href, "about:blank"); + assertEquals(url.protocol, "about:"); + assertEquals(url.origin, "null"); +}); + +unitTest(function createBadUrl(): void { + assertThrows(() => { + new URL("0.0.0.0:8080"); + }); +}); + +if (import.meta.main) { + Deno.runTests(); +} diff --git a/cli/js/tests/utime_test.ts b/cli/js/tests/utime_test.ts new file mode 100644 index 000000000..8cd34d39a --- /dev/null +++ b/cli/js/tests/utime_test.ts @@ -0,0 +1,193 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert } from "./test_util.ts"; + +// Allow 10 second difference. +// Note this might not be enough for FAT (but we are not testing on such fs). +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function assertFuzzyTimestampEquals(t1: any, t2: number): void { + assert(typeof t1 === "number"); + assert(Math.abs(t1 - t2) < 10); +} + +unitTest( + { perms: { read: true, write: true } }, + function utimeSyncFileSuccess(): void { + 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); + assertFuzzyTimestampEquals(fileInfo.accessed, atime); + assertFuzzyTimestampEquals(fileInfo.modified, mtime); + } +); + +unitTest( + { perms: { read: true, write: true } }, + function utimeSyncDirectorySuccess(): void { + const testDir = Deno.makeTempDirSync(); + + const atime = 1000; + const mtime = 50000; + Deno.utimeSync(testDir, atime, mtime); + + const dirInfo = Deno.statSync(testDir); + assertFuzzyTimestampEquals(dirInfo.accessed, atime); + assertFuzzyTimestampEquals(dirInfo.modified, mtime); + } +); + +unitTest( + { perms: { read: true, write: true } }, + function utimeSyncDateSuccess(): void { + const testDir = Deno.makeTempDirSync(); + + const atime = 1000; + const mtime = 50000; + Deno.utimeSync(testDir, new Date(atime * 1000), new Date(mtime * 1000)); + + const dirInfo = Deno.statSync(testDir); + assertFuzzyTimestampEquals(dirInfo.accessed, atime); + assertFuzzyTimestampEquals(dirInfo.modified, mtime); + } +); + +unitTest( + { perms: { read: true, write: true } }, + function utimeSyncLargeNumberSuccess(): void { + 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); + assertFuzzyTimestampEquals(dirInfo.accessed, atime); + assertFuzzyTimestampEquals(dirInfo.modified, mtime); + } +); + +unitTest( + { perms: { read: true, write: true } }, + function utimeSyncNotFound(): void { + const atime = 1000; + const mtime = 50000; + + let caughtError = false; + try { + Deno.utimeSync("/baddir", atime, mtime); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtError); + } +); + +unitTest( + { perms: { read: true, write: false } }, + function utimeSyncPerm(): void { + const atime = 1000; + const mtime = 50000; + + let caughtError = false; + try { + Deno.utimeSync("/some_dir", atime, mtime); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function utimeFileSuccess(): Promise { + 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); + assertFuzzyTimestampEquals(fileInfo.accessed, atime); + assertFuzzyTimestampEquals(fileInfo.modified, mtime); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function utimeDirectorySuccess(): Promise { + const testDir = Deno.makeTempDirSync(); + + const atime = 1000; + const mtime = 50000; + await Deno.utime(testDir, atime, mtime); + + const dirInfo = Deno.statSync(testDir); + assertFuzzyTimestampEquals(dirInfo.accessed, atime); + assertFuzzyTimestampEquals(dirInfo.modified, mtime); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function utimeDateSuccess(): Promise { + const testDir = Deno.makeTempDirSync(); + + const atime = 1000; + const mtime = 50000; + await Deno.utime(testDir, new Date(atime * 1000), new Date(mtime * 1000)); + + const dirInfo = Deno.statSync(testDir); + assertFuzzyTimestampEquals(dirInfo.accessed, atime); + assertFuzzyTimestampEquals(dirInfo.modified, mtime); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function utimeNotFound(): Promise { + const atime = 1000; + const mtime = 50000; + + let caughtError = false; + try { + await Deno.utime("/baddir", atime, mtime); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtError); + } +); + +unitTest( + { perms: { read: true, write: false } }, + async function utimeSyncPerm(): Promise { + const atime = 1000; + const mtime = 50000; + + let caughtError = false; + try { + await Deno.utime("/some_dir", atime, mtime); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); + } +); diff --git a/cli/js/tests/version_test.ts b/cli/js/tests/version_test.ts new file mode 100644 index 000000000..0417b27de --- /dev/null +++ b/cli/js/tests/version_test.ts @@ -0,0 +1,8 @@ +import { unitTest, assert } from "./test_util.ts"; + +unitTest(function version(): void { + const pattern = /^\d+\.\d+\.\d+/; + assert(pattern.test(Deno.version.deno)); + assert(pattern.test(Deno.version.v8)); + assert(pattern.test(Deno.version.typescript)); +}); diff --git a/cli/js/tests/write_file_test.ts b/cli/js/tests/write_file_test.ts new file mode 100644 index 000000000..c06c5b330 --- /dev/null +++ b/cli/js/tests/write_file_test.ts @@ -0,0 +1,228 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +import { unitTest, assert, assertEquals } from "./test_util.ts"; + +unitTest( + { perms: { read: true, write: true } }, + function writeFileSyncSuccess(): void { + 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("Hello", actual); + } +); + +unitTest({ perms: { write: true } }, function writeFileSyncFail(): void { + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + const filename = "/baddir/test.txt"; + // The following should fail because /baddir doesn't exist (hopefully). + let caughtError = false; + try { + Deno.writeFileSync(filename, data); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtError); +}); + +unitTest({ perms: { write: false } }, function writeFileSyncPerm(): void { + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + const filename = "/baddir/test.txt"; + // The following should fail due to no write permission + let caughtError = false; + try { + Deno.writeFileSync(filename, data); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); +}); + +unitTest( + { perms: { read: true, write: true } }, + function writeFileSyncUpdateMode(): void { + if (Deno.build.os !== "win") { + 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); + } + } +); + +unitTest( + { perms: { read: true, write: true } }, + function writeFileSyncCreate(): void { + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + const filename = Deno.makeTempDirSync() + "/test.txt"; + let caughtError = false; + // if create turned off, the file won't be created + try { + Deno.writeFileSync(filename, data, { create: false }); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtError); + + // 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("Hello", actual); + } +); + +unitTest( + { perms: { read: true, write: true } }, + function writeFileSyncAppend(): void { + 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("HelloHello", actual); + // Now attempt overwrite + Deno.writeFileSync(filename, data, { append: false }); + dataRead = Deno.readFileSync(filename); + actual = dec.decode(dataRead); + assertEquals("Hello", actual); + // append not set should also overwrite + Deno.writeFileSync(filename, data); + dataRead = Deno.readFileSync(filename); + actual = dec.decode(dataRead); + assertEquals("Hello", actual); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function writeFileSuccess(): Promise { + 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("Hello", actual); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function writeFileNotFound(): Promise { + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + const filename = "/baddir/test.txt"; + // The following should fail because /baddir doesn't exist (hopefully). + let caughtError = false; + try { + await Deno.writeFile(filename, data); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.NotFound); + } + assert(caughtError); + } +); + +unitTest( + { perms: { read: true, write: false } }, + async function writeFilePerm(): Promise { + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + const filename = "/baddir/test.txt"; + // The following should fail due to no write permission + let caughtError = false; + try { + await Deno.writeFile(filename, data); + } catch (e) { + caughtError = true; + assert(e instanceof Deno.errors.PermissionDenied); + } + assert(caughtError); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function writeFileUpdateMode(): Promise { + if (Deno.build.os !== "win") { + 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); + } + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function writeFileCreate(): Promise { + const enc = new TextEncoder(); + const data = enc.encode("Hello"); + const filename = Deno.makeTempDirSync() + "/test.txt"; + let caughtError = false; + // if create turned off, the file won't be created + try { + await Deno.writeFile(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.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("Hello", actual); + } +); + +unitTest( + { perms: { read: true, write: true } }, + async function writeFileAppend(): Promise { + 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("HelloHello", actual); + // Now attempt overwrite + await Deno.writeFile(filename, data, { append: false }); + dataRead = Deno.readFileSync(filename); + actual = dec.decode(dataRead); + assertEquals("Hello", actual); + // append not set should also overwrite + await Deno.writeFile(filename, data); + dataRead = Deno.readFileSync(filename); + actual = dec.decode(dataRead); + assertEquals("Hello", actual); + } +); diff --git a/cli/js/text_encoding_test.ts b/cli/js/text_encoding_test.ts deleted file mode 100644 index e85655feb..000000000 --- a/cli/js/text_encoding_test.ts +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest(function btoaSuccess(): void { - const text = "hello world"; - const encoded = btoa(text); - assertEquals(encoded, "aGVsbG8gd29ybGQ="); -}); - -unitTest(function atobSuccess(): void { - const encoded = "aGVsbG8gd29ybGQ="; - const decoded = atob(encoded); - assertEquals(decoded, "hello world"); -}); - -unitTest(function atobWithAsciiWhitespace(): void { - 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"); - } -}); - -unitTest(function atobThrows(): void { - let threw = false; - try { - atob("aGVsbG8gd29ybGQ=="); - } catch (e) { - threw = true; - } - assert(threw); -}); - -unitTest(function atobThrows2(): void { - let threw = false; - try { - atob("aGVsbG8gd29ybGQ==="); - } catch (e) { - threw = true; - } - assert(threw); -}); - -unitTest(function btoaFailed(): void { - const text = "你好"; - let err; - try { - btoa(text); - } catch (e) { - err = e; - } - assert(!!err); - assert(err instanceof TypeError); -}); - -unitTest(function textDecoder2(): void { - // prettier-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), "𝓽𝓮𝔁𝓽"); -}); - -unitTest(function textDecoderIgnoreBOM(): void { - // prettier-ignore - const fixture = new Uint8Array([ - 0xef, 0xbb, 0xbf, - 0xf0, 0x9d, 0x93, 0xbd, - 0xf0, 0x9d, 0x93, 0xae, - 0xf0, 0x9d, 0x94, 0x81, - 0xf0, 0x9d, 0x93, 0xbd - ]); - const decoder = new TextDecoder("utf-8", { ignoreBOM: true }); - assertEquals(decoder.decode(fixture), "𝓽𝓮𝔁𝓽"); -}); - -unitTest(function textDecoderNotBOM(): void { - // prettier-ignore - const fixture = new Uint8Array([ - 0xef, 0xbb, 0x89, - 0xf0, 0x9d, 0x93, 0xbd, - 0xf0, 0x9d, 0x93, 0xae, - 0xf0, 0x9d, 0x94, 0x81, - 0xf0, 0x9d, 0x93, 0xbd - ]); - const decoder = new TextDecoder("utf-8", { ignoreBOM: true }); - assertEquals(decoder.decode(fixture), "ﻉ𝓽𝓮𝔁𝓽"); -}); - -unitTest(function textDecoderASCII(): void { - const fixture = new Uint8Array([0x89, 0x95, 0x9f, 0xbf]); - const decoder = new TextDecoder("ascii"); - assertEquals(decoder.decode(fixture), "‰•Ÿ¿"); -}); - -unitTest(function textDecoderErrorEncoding(): void { - let didThrow = false; - try { - new TextDecoder("foo"); - } catch (e) { - didThrow = true; - assertEquals(e.message, "The encoding label provided ('foo') is invalid."); - } - assert(didThrow); -}); - -unitTest(function textEncoder(): void { - const fixture = "𝓽𝓮𝔁𝓽"; - const encoder = new TextEncoder(); - // prettier-ignore - assertEquals(Array.from(encoder.encode(fixture)), [ - 0xf0, 0x9d, 0x93, 0xbd, - 0xf0, 0x9d, 0x93, 0xae, - 0xf0, 0x9d, 0x94, 0x81, - 0xf0, 0x9d, 0x93, 0xbd - ]); -}); - -unitTest(function textEncodeInto(): void { - 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); - // prettier-ignore - assertEquals(Array.from(bytes), [ - 0x74, 0x65, 0x78, 0x74, 0x00, - ]); -}); - -unitTest(function textEncodeInto2(): void { - 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); - // prettier-ignore - assertEquals(Array.from(bytes), [ - 0xf0, 0x9d, 0x93, 0xbd, - 0xf0, 0x9d, 0x93, 0xae, - 0xf0, 0x9d, 0x94, 0x81, - 0xf0, 0x9d, 0x93, 0xbd, 0x00, - ]); -}); - -unitTest(function textDecoderSharedUint8Array(): void { - 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"); -}); - -unitTest(function textDecoderSharedInt32Array(): void { - 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"); -}); - -unitTest(function toStringShouldBeWebCompatibility(): void { - const encoder = new TextEncoder(); - assertEquals(encoder.toString(), "[object TextEncoder]"); - - const decoder = new TextDecoder(); - assertEquals(decoder.toString(), "[object TextDecoder]"); -}); diff --git a/cli/js/timers_test.ts b/cli/js/timers_test.ts deleted file mode 100644 index 429e42692..000000000 --- a/cli/js/timers_test.ts +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { - unitTest, - createResolvable, - assert, - assertEquals, - assertNotEquals -} from "./test_util.ts"; - -function deferred(): { - promise: Promise<{}>; - resolve: (value?: {} | PromiseLike<{}>) => void; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - reject: (reason?: any) => void; -} { - let resolve: (value?: {} | PromiseLike<{}>) => void; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let reject: ((reason?: any) => void) | undefined = undefined; - const promise = new Promise<{}>((res, rej): void => { - resolve = res; - reject = rej; - }); - return { - promise, - resolve: resolve!, - reject: reject! - }; -} - -async function waitForMs(ms: number): Promise { - return new Promise((resolve: () => void): number => setTimeout(resolve, ms)); -} - -unitTest(async function timeoutSuccess(): Promise { - const { promise, resolve } = deferred(); - let count = 0; - setTimeout((): void => { - count++; - resolve(); - }, 500); - await promise; - // count should increment - assertEquals(count, 1); -}); - -unitTest(async function timeoutArgs(): Promise { - const { promise, resolve } = deferred(); - const arg = 1; - setTimeout( - (a, b, c): void => { - assertEquals(a, arg); - assertEquals(b, arg.toString()); - assertEquals(c, [arg]); - resolve(); - }, - 10, - arg, - arg.toString(), - [arg] - ); - await promise; -}); - -unitTest(async function timeoutCancelSuccess(): Promise { - let count = 0; - const id = setTimeout((): void => { - count++; - }, 1); - // Cancelled, count should not increment - clearTimeout(id); - await waitForMs(600); - assertEquals(count, 0); -}); - -unitTest(async function timeoutCancelMultiple(): Promise { - 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 waitForMs(50); -}); - -unitTest(async function timeoutCancelInvalidSilentFail(): Promise { - // Expect no panic - const { promise, resolve } = deferred(); - let count = 0; - const id = setTimeout((): void => { - count++; - // Should have no effect - clearTimeout(id); - resolve(); - }, 500); - await promise; - assertEquals(count, 1); - - // Should silently fail (no panic) - clearTimeout(2147483647); -}); - -unitTest(async function intervalSuccess(): Promise { - const { promise, resolve } = deferred(); - let count = 0; - const id = setInterval((): void => { - count++; - clearInterval(id); - resolve(); - }, 100); - await promise; - // Clear interval - clearInterval(id); - // count should increment twice - assertEquals(count, 1); -}); - -unitTest(async function intervalCancelSuccess(): Promise { - let count = 0; - const id = setInterval((): void => { - count++; - }, 1); - clearInterval(id); - await waitForMs(500); - assertEquals(count, 0); -}); - -unitTest(async function intervalOrdering(): Promise { - const timers: number[] = []; - let timeouts = 0; - function onTimeout(): void { - ++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 waitForMs(500); - assertEquals(timeouts, 1); -}); - -unitTest(async function intervalCancelInvalidSilentFail(): Promise { - // Should silently fail (no panic) - clearInterval(2147483647); -}); - -unitTest(async function fireCallbackImmediatelyWhenDelayOverMaxValue(): Promise< - void -> { - let count = 0; - setTimeout((): void => { - count++; - }, 2 ** 31); - await waitForMs(1); - assertEquals(count, 1); -}); - -unitTest(async function timeoutCallbackThis(): Promise { - const { promise, resolve } = deferred(); - const obj = { - foo(): void { - assertEquals(this, window); - resolve(); - } - }; - setTimeout(obj.foo, 1); - await promise; -}); - -unitTest(async function timeoutBindThis(): Promise { - const thisCheckPassed = [null, undefined, window, globalThis]; - - const thisCheckFailed = [ - 0, - "", - true, - false, - {}, - [], - "foo", - (): void => {}, - Object.prototype - ]; - - for (const thisArg of thisCheckPassed) { - const resolvable = createResolvable(); - let hasThrown = 0; - try { - setTimeout.call(thisArg, () => resolvable.resolve(), 1); - hasThrown = 1; - } catch (err) { - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - await resolvable; - 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); - } -}); - -unitTest(async function clearTimeoutShouldConvertToNumber(): Promise { - let called = false; - const obj = { - valueOf(): number { - called = true; - return 1; - } - }; - clearTimeout((obj as unknown) as number); - assert(called); -}); - -unitTest(function setTimeoutShouldThrowWithBigint(): void { - let hasThrown = 0; - try { - setTimeout((): void => {}, (1n as unknown) as number); - hasThrown = 1; - } catch (err) { - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); -}); - -unitTest(function clearTimeoutShouldThrowWithBigint(): void { - 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); -}); - -unitTest(function testFunctionName(): void { - assertEquals(clearTimeout.name, "clearTimeout"); - assertEquals(clearInterval.name, "clearInterval"); -}); - -unitTest(function testFunctionParamsLength(): void { - assertEquals(setTimeout.length, 1); - assertEquals(setInterval.length, 1); - assertEquals(clearTimeout.length, 0); - assertEquals(clearInterval.length, 0); -}); - -unitTest(function clearTimeoutAndClearIntervalNotBeEquals(): void { - assertNotEquals(clearTimeout, clearInterval); -}); - -unitTest(async function timerMaxCpuBug(): Promise { - // There was a bug where clearing a timeout would cause Deno to use 100% CPU. - clearTimeout(setTimeout(() => {}, 1000)); - // We can check this by counting how many ops have triggered in the interim. - // Certainly less than 10 ops should have been dispatched in next 100 ms. - const { opsDispatched } = Deno.metrics(); - await waitForMs(100); - const opsDispatched_ = Deno.metrics().opsDispatched; - assert(opsDispatched_ - opsDispatched < 10); -}); - -unitTest(async function timerBasicMicrotaskOrdering(): Promise { - let s = ""; - let count = 0; - const { promise, resolve } = deferred(); - setTimeout(() => { - Promise.resolve().then(() => { - count++; - s += "de"; - if (count === 2) { - resolve(); - } - }); - }); - setTimeout(() => { - count++; - s += "no"; - if (count === 2) { - resolve(); - } - }); - await promise; - assertEquals(s, "deno"); -}); - -unitTest(async function timerNestedMicrotaskOrdering(): Promise { - let s = ""; - const { promise, resolve } = deferred(); - s += "0"; - setTimeout(() => { - s += "4"; - setTimeout(() => (s += "8")); - Promise.resolve().then(() => { - setTimeout(() => { - s += "9"; - resolve(); - }); - }); - }); - setTimeout(() => (s += "5")); - Promise.resolve().then(() => (s += "2")); - Promise.resolve().then(() => - setTimeout(() => { - s += "6"; - Promise.resolve().then(() => (s += "7")); - }) - ); - Promise.resolve().then(() => Promise.resolve().then(() => (s += "3"))); - s += "1"; - await promise; - assertEquals(s, "0123456789"); -}); diff --git a/cli/js/tls_test.ts b/cli/js/tls_test.ts deleted file mode 100644 index 99900ab57..000000000 --- a/cli/js/tls_test.ts +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { - assert, - assertEquals, - createResolvable, - unitTest -} from "./test_util.ts"; -import { BufWriter, BufReader } from "../../std/io/bufio.ts"; -import { TextProtoReader } from "../../std/textproto/mod.ts"; - -const encoder = new TextEncoder(); -const decoder = new TextDecoder(); - -unitTest(async function connectTLSNoPerm(): Promise { - let err; - try { - await Deno.connectTLS({ hostname: "github.com", port: 443 }); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest(async function connectTLSCertFileNoReadPerm(): Promise { - let err; - try { - await Deno.connectTLS({ - hostname: "github.com", - port: 443, - certFile: "cli/tests/tls/RootCA.crt" - }); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest( - { perms: { read: true, net: true } }, - async function listenTLSNonExistentCertKeyFiles(): Promise { - let err; - const options = { - hostname: "localhost", - port: 4500, - certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/tls/localhost.key" - }; - - try { - Deno.listenTLS({ - ...options, - certFile: "./non/existent/file" - }); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); - - try { - Deno.listenTLS({ - ...options, - keyFile: "./non/existent/file" - }); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.NotFound); - } -); - -unitTest( - { perms: { net: true } }, - async function listenTLSNoReadPerm(): Promise { - let err; - try { - Deno.listenTLS({ - hostname: "localhost", - port: 4500, - certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/tls/localhost.key" - }); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); - } -); - -unitTest( - { - perms: { read: true, write: true, net: true } - }, - async function listenTLSEmptyKeyFile(): Promise { - let err; - const options = { - hostname: "localhost", - port: 4500, - certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/tls/localhost.key" - }; - - const testDir = Deno.makeTempDirSync(); - const keyFilename = testDir + "/key.pem"; - Deno.writeFileSync(keyFilename, new Uint8Array([]), { - mode: 0o666 - }); - - try { - Deno.listenTLS({ - ...options, - keyFile: keyFilename - }); - } catch (e) { - err = e; - } - assert(err instanceof Error); - } -); - -unitTest( - { perms: { read: true, write: true, net: true } }, - async function listenTLSEmptyCertFile(): Promise { - let err; - const options = { - hostname: "localhost", - port: 4500, - certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/tls/localhost.key" - }; - - const testDir = Deno.makeTempDirSync(); - const certFilename = testDir + "/cert.crt"; - Deno.writeFileSync(certFilename, new Uint8Array([]), { - mode: 0o666 - }); - - try { - Deno.listenTLS({ - ...options, - certFile: certFilename - }); - } catch (e) { - err = e; - } - assert(err instanceof Error); - } -); - -unitTest( - { perms: { read: true, net: true } }, - async function dialAndListenTLS(): Promise { - const resolvable = createResolvable(); - const hostname = "localhost"; - const port = 4500; - - const listener = Deno.listenTLS({ - hostname, - port, - certFile: "cli/tests/tls/localhost.crt", - keyFile: "cli/tests/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): Promise => { - assert(conn.remoteAddr != null); - assert(conn.localAddr != null); - await conn.write(response); - // TODO(bartlomieju): this might be a bug - setTimeout(() => { - conn.close(); - resolvable.resolve(); - }, 0); - } - ); - - const conn = await Deno.connectTLS({ - hostname, - port, - certFile: "cli/tests/tls/RootCA.pem" - }); - 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 !== Deno.EOF, `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 !== Deno.EOF); - 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 resolvable; - } -); diff --git a/cli/js/truncate_test.ts b/cli/js/truncate_test.ts deleted file mode 100644 index 3fd85c990..000000000 --- a/cli/js/truncate_test.ts +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assertEquals, assert } from "./test_util.ts"; - -function readDataSync(name: string): string { - const data = Deno.readFileSync(name); - const decoder = new TextDecoder("utf-8"); - const text = decoder.decode(data); - return text; -} - -async function readData(name: string): Promise { - const data = await Deno.readFile(name); - const decoder = new TextDecoder("utf-8"); - const text = decoder.decode(data); - return text; -} - -unitTest( - { perms: { read: true, write: true } }, - function truncateSyncSuccess(): void { - const enc = new TextEncoder(); - const d = enc.encode("Hello"); - const filename = Deno.makeTempDirSync() + "/test_truncateSync.txt"; - Deno.writeFileSync(filename, d); - Deno.truncateSync(filename, 20); - let data = readDataSync(filename); - assertEquals(data.length, 20); - Deno.truncateSync(filename, 5); - data = readDataSync(filename); - assertEquals(data.length, 5); - Deno.truncateSync(filename, -5); - data = readDataSync(filename); - assertEquals(data.length, 0); - Deno.removeSync(filename); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function truncateSuccess(): Promise { - const enc = new TextEncoder(); - const d = enc.encode("Hello"); - const filename = Deno.makeTempDirSync() + "/test_truncate.txt"; - await Deno.writeFile(filename, d); - await Deno.truncate(filename, 20); - let data = await readData(filename); - assertEquals(data.length, 20); - await Deno.truncate(filename, 5); - data = await readData(filename); - assertEquals(data.length, 5); - await Deno.truncate(filename, -5); - data = await readData(filename); - assertEquals(data.length, 0); - await Deno.remove(filename); - } -); - -unitTest({ perms: { write: false } }, function truncateSyncPerm(): void { - let err; - try { - Deno.mkdirSync("/test_truncateSyncPermission.txt"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); - -unitTest({ perms: { write: false } }, async function truncatePerm(): Promise< - void -> { - let err; - try { - await Deno.mkdir("/test_truncatePermission.txt"); - } catch (e) { - err = e; - } - assert(err instanceof Deno.errors.PermissionDenied); - assertEquals(err.name, "PermissionDenied"); -}); diff --git a/cli/js/tty_test.ts b/cli/js/tty_test.ts deleted file mode 100644 index 116b0dfe9..000000000 --- a/cli/js/tty_test.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -// Note tests for Deno.setRaw is in integration tests. - -unitTest({ perms: { read: true } }, function isatty(): void { - // CI not under TTY, so cannot test stdin/stdout/stderr. - const f = Deno.openSync("cli/tests/hello.txt"); - assert(!Deno.isatty(f.rid)); - f.close(); -}); - -unitTest(function isattyError(): void { - 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/js/unit_test_runner.ts b/cli/js/unit_test_runner.ts deleted file mode 100755 index f32de96f8..000000000 --- a/cli/js/unit_test_runner.ts +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env -S deno run --reload --allow-run -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import "./unit_tests.ts"; -import { - permissionCombinations, - parseUnitTestOutput, - Permissions -} from "./test_util.ts"; - -interface TestResult { - perms: string; - output?: string; - result: number; -} - -function permsToCliFlags(perms: Permissions): string[] { - return Object.keys(perms) - .map(key => { - if (!perms[key as keyof Permissions]) return ""; - - const cliFlag = key.replace( - /\.?([A-Z])/g, - (x, y): string => `-${y.toLowerCase()}` - ); - return `--allow-${cliFlag}`; - }) - .filter((e): boolean => e.length > 0); -} - -function fmtPerms(perms: Permissions): string { - let fmt = permsToCliFlags(perms).join(" "); - - if (!fmt) { - fmt = ""; - } - - return fmt; -} - -async function main(): Promise { - console.log( - "Discovered permission combinations for tests:", - permissionCombinations.size - ); - - for (const perms of permissionCombinations.values()) { - console.log("\t" + fmtPerms(perms)); - } - - const testResults = new Set(); - - for (const perms of permissionCombinations.values()) { - const permsFmt = fmtPerms(perms); - console.log(`Running tests for: ${permsFmt}`); - const cliPerms = permsToCliFlags(perms); - // run subsequent tests using same deno executable - const args = [Deno.execPath(), "run", ...cliPerms, "cli/js/unit_tests.ts"]; - - const p = Deno.run({ - args, - stdout: "piped" - }); - - const { actual, expected, resultOutput } = await parseUnitTestOutput( - p.stdout!, - true - ); - - let result = 0; - - if (!actual && !expected) { - console.error("Bad cli/js/unit_test.ts output"); - result = 1; - } else if (expected !== actual) { - result = 1; - } - - testResults.add({ - perms: permsFmt, - output: resultOutput, - result - }); - } - - // if any run tests returned non-zero status then whole test - // run should fail - let testsFailed = false; - - for (const testResult of testResults) { - console.log(`Summary for ${testResult.perms}`); - console.log(testResult.output + "\n"); - testsFailed = testsFailed || Boolean(testResult.result); - } - - if (testsFailed) { - console.error("Unit tests failed"); - Deno.exit(1); - } - - console.log("Unit tests passed"); -} - -main(); diff --git a/cli/js/unit_tests.ts b/cli/js/unit_tests.ts deleted file mode 100644 index 2b02f8dcf..000000000 --- a/cli/js/unit_tests.ts +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -// This test is executed as part of tools/test.py -// But it can also be run manually: ./target/debug/deno cli/js/unit_tests.ts - -import "./blob_test.ts"; -import "./body_test.ts"; -import "./buffer_test.ts"; -import "./build_test.ts"; -import "./chmod_test.ts"; -import "./chown_test.ts"; -import "./compiler_api_test.ts"; -import "./console_test.ts"; -import "./copy_file_test.ts"; -import "./custom_event_test.ts"; -import "./dir_test.ts"; -import "./dispatch_minimal_test.ts"; -import "./dispatch_json_test.ts"; -import "./error_stack_test.ts"; -import "./event_test.ts"; -import "./event_target_test.ts"; -import "./fetch_test.ts"; -import "./file_test.ts"; -import "./files_test.ts"; -import "./form_data_test.ts"; -import "./format_error_test.ts"; -import "./fs_events_test.ts"; -import "./get_random_values_test.ts"; -import "./globals_test.ts"; -import "./headers_test.ts"; -import "./internals_test.ts"; -import "./link_test.ts"; -import "./location_test.ts"; -import "./make_temp_test.ts"; -import "./metrics_test.ts"; -import "./mixins/dom_iterable_test.ts"; -import "./mkdir_test.ts"; -import "./net_test.ts"; -import "./os_test.ts"; -import "./permissions_test.ts"; -import "./process_test.ts"; -import "./realpath_test.ts"; -import "./read_dir_test.ts"; -import "./read_file_test.ts"; -import "./read_link_test.ts"; -import "./remove_test.ts"; -import "./rename_test.ts"; -import "./request_test.ts"; -import "./resources_test.ts"; -import "./signal_test.ts"; -import "./stat_test.ts"; -import "./symbols_test.ts"; -import "./symlink_test.ts"; -import "./text_encoding_test.ts"; -import "./timers_test.ts"; -import "./testing_test.ts"; -import "./tls_test.ts"; -import "./truncate_test.ts"; -import "./tty_test.ts"; -import "./url_test.ts"; -import "./url_search_params_test.ts"; -import "./utime_test.ts"; -import "./write_file_test.ts"; -import "./performance_test.ts"; -import "./version_test.ts"; - -if (import.meta.main) { - await Deno.runTests(); -} diff --git a/cli/js/url_search_params_test.ts b/cli/js/url_search_params_test.ts deleted file mode 100644 index b256395a0..000000000 --- a/cli/js/url_search_params_test.ts +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest(function urlSearchParamsInitString(): void { - 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" - ); -}); - -unitTest(function urlSearchParamsInitIterable(): void { - const init = [ - ["a", "54"], - ["b", "true"] - ]; - const searchParams = new URLSearchParams(init); - assertEquals(searchParams.toString(), "a=54&b=true"); -}); - -unitTest(function urlSearchParamsInitRecord(): void { - const init = { a: "54", b: "true" }; - const searchParams = new URLSearchParams(init); - assertEquals(searchParams.toString(), "a=54&b=true"); -}); - -unitTest(function urlSearchParamsInit(): void { - const params1 = new URLSearchParams("a=b"); - assertEquals(params1.toString(), "a=b"); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const params2 = new URLSearchParams(params1 as any); - assertEquals(params2.toString(), "a=b"); -}); - -unitTest(function urlSearchParamsAppendSuccess(): void { - const searchParams = new URLSearchParams(); - searchParams.append("a", "true"); - assertEquals(searchParams.toString(), "a=true"); -}); - -unitTest(function urlSearchParamsDeleteSuccess(): void { - const init = "a=54&b=true"; - const searchParams = new URLSearchParams(init); - searchParams.delete("b"); - assertEquals(searchParams.toString(), "a=54"); -}); - -unitTest(function urlSearchParamsGetAllSuccess(): void { - 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"), []); -}); - -unitTest(function urlSearchParamsGetSuccess(): void { - 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); -}); - -unitTest(function urlSearchParamsHasSuccess(): void { - 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")); -}); - -unitTest(function urlSearchParamsSetReplaceFirstAndRemoveOthers(): void { - const init = "a=54&b=true&a=true"; - const searchParams = new URLSearchParams(init); - searchParams.set("a", "false"); - assertEquals(searchParams.toString(), "a=false&b=true"); -}); - -unitTest(function urlSearchParamsSetAppendNew(): void { - 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"); -}); - -unitTest(function urlSearchParamsSortSuccess(): void { - 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"); -}); - -unitTest(function urlSearchParamsForEachSuccess(): void { - const init = [ - ["a", "54"], - ["b", "true"] - ]; - const searchParams = new URLSearchParams(init); - let callNum = 0; - searchParams.forEach((value, key, parent): void => { - assertEquals(searchParams, parent); - assertEquals(value, init[callNum][1]); - assertEquals(key, init[callNum][0]); - callNum++; - }); - assertEquals(callNum, init.length); -}); - -unitTest(function urlSearchParamsMissingName(): void { - const init = "=4"; - const searchParams = new URLSearchParams(init); - assertEquals(searchParams.get(""), "4"); - assertEquals(searchParams.toString(), "=4"); -}); - -unitTest(function urlSearchParamsMissingValue(): void { - const init = "4="; - const searchParams = new URLSearchParams(init); - assertEquals(searchParams.get("4"), ""); - assertEquals(searchParams.toString(), "4="); -}); - -unitTest(function urlSearchParamsMissingEqualSign(): void { - const init = "4"; - const searchParams = new URLSearchParams(init); - assertEquals(searchParams.get("4"), ""); - assertEquals(searchParams.toString(), "4="); -}); - -unitTest(function urlSearchParamsMissingPair(): void { - const init = "c=4&&a=54&"; - const searchParams = new URLSearchParams(init); - assertEquals(searchParams.toString(), "c=4&a=54"); -}); - -// If pair does not contain exactly two items, then throw a TypeError. -// ref https://url.spec.whatwg.org/#interface-urlsearchparams -unitTest(function urlSearchParamsShouldThrowTypeError(): void { - 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); -}); - -unitTest(function urlSearchParamsAppendArgumentsCheck(): void { - const methodRequireOneParam = ["delete", "getAll", "get", "has", "forEach"]; - - const methodRequireTwoParams = ["append", "set"]; - - methodRequireOneParam - .concat(methodRequireTwoParams) - .forEach((method: string): void => { - const searchParams = new URLSearchParams(); - let hasThrown = 0; - try { - // @ts-ignore - searchParams[method](); - hasThrown = 1; - } catch (err) { - if (err instanceof TypeError) { - hasThrown = 2; - } else { - hasThrown = 3; - } - } - assertEquals(hasThrown, 2); - }); - - methodRequireTwoParams.forEach((method: string): void => { - const searchParams = new URLSearchParams(); - let hasThrown = 0; - try { - // @ts-ignore - searchParams[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 -unitTest(function urlSearchParamsDeletingAppendedMultiple(): void { - 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 -unitTest(function urlSearchParamsCustomSymbolIterator(): void { - 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"); -}); - -unitTest( - function urlSearchParamsCustomSymbolIteratorWithNonStringParams(): void { - const params = {}; - // @ts-ignore - params[Symbol.iterator] = function*(): IterableIterator<[number, number]> { - yield [1, 2]; - }; - const params1 = new URLSearchParams((params as unknown) as string[][]); - assertEquals(params1.get("1"), "2"); - } -); diff --git a/cli/js/url_test.ts b/cli/js/url_test.ts deleted file mode 100644 index 46468c8ae..000000000 --- a/cli/js/url_test.ts +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals, assertThrows } from "./test_util.ts"; - -unitTest(function urlParsing(): void { - 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" - ); - assertEquals( - JSON.stringify({ key: url }), - `{"key":"https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat"}` - ); -}); - -unitTest(function urlModifications(): void { - 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" - ); -}); - -unitTest(function urlModifyHref(): void { - 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"); -}); - -unitTest(function urlModifyPathname(): void { - const url = new URL("http://foo.bar/baz%qat/qux%quux"); - assertEquals(url.pathname, "/baz%qat/qux%quux"); - url.pathname = url.pathname; - assertEquals(url.pathname, "/baz%qat/qux%quux"); - url.pathname = "baz#qat qux"; - assertEquals(url.pathname, "/baz%23qat%20qux"); - url.pathname = url.pathname; - assertEquals(url.pathname, "/baz%23qat%20qux"); -}); - -unitTest(function urlModifyHash(): void { - const url = new URL("http://foo.bar"); - url.hash = "%foo bar/qat%qux#bar"; - assertEquals(url.hash, "#%foo%20bar/qat%qux#bar"); - url.hash = url.hash; - assertEquals(url.hash, "#%foo%20bar/qat%qux#bar"); -}); - -unitTest(function urlSearchParamsReuse(): void { - 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."); -}); - -unitTest(function urlBaseURL(): void { - const base = new URL( - "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat" - ); - const url = new URL("/foo/bar?baz=foo#qux", base); - assertEquals(url.href, "https://foo:bar@baz.qat:8000/foo/bar?baz=foo#qux"); -}); - -unitTest(function urlBaseString(): void { - const url = new URL( - "/foo/bar?baz=foo#qux", - "https://foo:bar@baz.qat:8000/qux/quux?foo=bar&baz=12#qat" - ); - assertEquals(url.href, "https://foo:bar@baz.qat:8000/foo/bar?baz=foo#qux"); -}); - -unitTest(function urlRelativeWithBase(): void { - assertEquals(new URL("", "file:///a/a/a").href, "file:///a/a/a"); - assertEquals(new URL(".", "file:///a/a/a").href, "file:///a/a/"); - assertEquals(new URL("..", "file:///a/a/a").href, "file:///a/"); - assertEquals(new URL("b", "file:///a/a/a").href, "file:///a/a/b"); - assertEquals(new URL("b", "file:///a/a/a/").href, "file:///a/a/a/b"); - assertEquals(new URL("b/", "file:///a/a/a").href, "file:///a/a/b/"); - assertEquals(new URL("../b", "file:///a/a/a").href, "file:///a/b"); -}); - -unitTest(function emptyBasePath(): void { - assertEquals(new URL("", "http://example.com").href, "http://example.com/"); -}); - -unitTest(function deletingAllParamsRemovesQuestionMarkFromURL(): void { - const url = new URL("http://example.com/?param1¶m2"); - url.searchParams.delete("param1"); - url.searchParams.delete("param2"); - assertEquals(url.href, "http://example.com/"); - assertEquals(url.search, ""); -}); - -unitTest(function removingNonExistentParamRemovesQuestionMarkFromURL(): void { - 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, ""); -}); - -unitTest(function sortingNonExistentParamRemovesQuestionMarkFromURL(): void { - 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, ""); -}); - -/* -unitTest(function customInspectFunction(): void { - 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: "?" }' - ); -}); -*/ - -unitTest(function protocolNotHttpOrFile() { - const url = new URL("about:blank"); - assertEquals(url.href, "about:blank"); - assertEquals(url.protocol, "about:"); - assertEquals(url.origin, "null"); -}); - -unitTest(function createBadUrl(): void { - assertThrows(() => { - new URL("0.0.0.0:8080"); - }); -}); - -if (import.meta.main) { - Deno.runTests(); -} diff --git a/cli/js/utime_test.ts b/cli/js/utime_test.ts deleted file mode 100644 index 8cd34d39a..000000000 --- a/cli/js/utime_test.ts +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; - -// Allow 10 second difference. -// Note this might not be enough for FAT (but we are not testing on such fs). -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function assertFuzzyTimestampEquals(t1: any, t2: number): void { - assert(typeof t1 === "number"); - assert(Math.abs(t1 - t2) < 10); -} - -unitTest( - { perms: { read: true, write: true } }, - function utimeSyncFileSuccess(): void { - 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); - assertFuzzyTimestampEquals(fileInfo.accessed, atime); - assertFuzzyTimestampEquals(fileInfo.modified, mtime); - } -); - -unitTest( - { perms: { read: true, write: true } }, - function utimeSyncDirectorySuccess(): void { - const testDir = Deno.makeTempDirSync(); - - const atime = 1000; - const mtime = 50000; - Deno.utimeSync(testDir, atime, mtime); - - const dirInfo = Deno.statSync(testDir); - assertFuzzyTimestampEquals(dirInfo.accessed, atime); - assertFuzzyTimestampEquals(dirInfo.modified, mtime); - } -); - -unitTest( - { perms: { read: true, write: true } }, - function utimeSyncDateSuccess(): void { - const testDir = Deno.makeTempDirSync(); - - const atime = 1000; - const mtime = 50000; - Deno.utimeSync(testDir, new Date(atime * 1000), new Date(mtime * 1000)); - - const dirInfo = Deno.statSync(testDir); - assertFuzzyTimestampEquals(dirInfo.accessed, atime); - assertFuzzyTimestampEquals(dirInfo.modified, mtime); - } -); - -unitTest( - { perms: { read: true, write: true } }, - function utimeSyncLargeNumberSuccess(): void { - 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); - assertFuzzyTimestampEquals(dirInfo.accessed, atime); - assertFuzzyTimestampEquals(dirInfo.modified, mtime); - } -); - -unitTest( - { perms: { read: true, write: true } }, - function utimeSyncNotFound(): void { - const atime = 1000; - const mtime = 50000; - - let caughtError = false; - try { - Deno.utimeSync("/baddir", atime, mtime); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtError); - } -); - -unitTest( - { perms: { read: true, write: false } }, - function utimeSyncPerm(): void { - const atime = 1000; - const mtime = 50000; - - let caughtError = false; - try { - Deno.utimeSync("/some_dir", atime, mtime); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function utimeFileSuccess(): Promise { - 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); - assertFuzzyTimestampEquals(fileInfo.accessed, atime); - assertFuzzyTimestampEquals(fileInfo.modified, mtime); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function utimeDirectorySuccess(): Promise { - const testDir = Deno.makeTempDirSync(); - - const atime = 1000; - const mtime = 50000; - await Deno.utime(testDir, atime, mtime); - - const dirInfo = Deno.statSync(testDir); - assertFuzzyTimestampEquals(dirInfo.accessed, atime); - assertFuzzyTimestampEquals(dirInfo.modified, mtime); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function utimeDateSuccess(): Promise { - const testDir = Deno.makeTempDirSync(); - - const atime = 1000; - const mtime = 50000; - await Deno.utime(testDir, new Date(atime * 1000), new Date(mtime * 1000)); - - const dirInfo = Deno.statSync(testDir); - assertFuzzyTimestampEquals(dirInfo.accessed, atime); - assertFuzzyTimestampEquals(dirInfo.modified, mtime); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function utimeNotFound(): Promise { - const atime = 1000; - const mtime = 50000; - - let caughtError = false; - try { - await Deno.utime("/baddir", atime, mtime); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtError); - } -); - -unitTest( - { perms: { read: true, write: false } }, - async function utimeSyncPerm(): Promise { - const atime = 1000; - const mtime = 50000; - - let caughtError = false; - try { - await Deno.utime("/some_dir", atime, mtime); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); - } -); diff --git a/cli/js/version_test.ts b/cli/js/version_test.ts deleted file mode 100644 index 0417b27de..000000000 --- a/cli/js/version_test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { unitTest, assert } from "./test_util.ts"; - -unitTest(function version(): void { - const pattern = /^\d+\.\d+\.\d+/; - assert(pattern.test(Deno.version.deno)); - assert(pattern.test(Deno.version.v8)); - assert(pattern.test(Deno.version.typescript)); -}); diff --git a/cli/js/write_file_test.ts b/cli/js/write_file_test.ts deleted file mode 100644 index c06c5b330..000000000 --- a/cli/js/write_file_test.ts +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert, assertEquals } from "./test_util.ts"; - -unitTest( - { perms: { read: true, write: true } }, - function writeFileSyncSuccess(): void { - 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("Hello", actual); - } -); - -unitTest({ perms: { write: true } }, function writeFileSyncFail(): void { - const enc = new TextEncoder(); - const data = enc.encode("Hello"); - const filename = "/baddir/test.txt"; - // The following should fail because /baddir doesn't exist (hopefully). - let caughtError = false; - try { - Deno.writeFileSync(filename, data); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtError); -}); - -unitTest({ perms: { write: false } }, function writeFileSyncPerm(): void { - const enc = new TextEncoder(); - const data = enc.encode("Hello"); - const filename = "/baddir/test.txt"; - // The following should fail due to no write permission - let caughtError = false; - try { - Deno.writeFileSync(filename, data); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); -}); - -unitTest( - { perms: { read: true, write: true } }, - function writeFileSyncUpdateMode(): void { - if (Deno.build.os !== "win") { - 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); - } - } -); - -unitTest( - { perms: { read: true, write: true } }, - function writeFileSyncCreate(): void { - const enc = new TextEncoder(); - const data = enc.encode("Hello"); - const filename = Deno.makeTempDirSync() + "/test.txt"; - let caughtError = false; - // if create turned off, the file won't be created - try { - Deno.writeFileSync(filename, data, { create: false }); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtError); - - // 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("Hello", actual); - } -); - -unitTest( - { perms: { read: true, write: true } }, - function writeFileSyncAppend(): void { - 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("HelloHello", actual); - // Now attempt overwrite - Deno.writeFileSync(filename, data, { append: false }); - dataRead = Deno.readFileSync(filename); - actual = dec.decode(dataRead); - assertEquals("Hello", actual); - // append not set should also overwrite - Deno.writeFileSync(filename, data); - dataRead = Deno.readFileSync(filename); - actual = dec.decode(dataRead); - assertEquals("Hello", actual); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function writeFileSuccess(): Promise { - 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("Hello", actual); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function writeFileNotFound(): Promise { - const enc = new TextEncoder(); - const data = enc.encode("Hello"); - const filename = "/baddir/test.txt"; - // The following should fail because /baddir doesn't exist (hopefully). - let caughtError = false; - try { - await Deno.writeFile(filename, data); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.NotFound); - } - assert(caughtError); - } -); - -unitTest( - { perms: { read: true, write: false } }, - async function writeFilePerm(): Promise { - const enc = new TextEncoder(); - const data = enc.encode("Hello"); - const filename = "/baddir/test.txt"; - // The following should fail due to no write permission - let caughtError = false; - try { - await Deno.writeFile(filename, data); - } catch (e) { - caughtError = true; - assert(e instanceof Deno.errors.PermissionDenied); - } - assert(caughtError); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function writeFileUpdateMode(): Promise { - if (Deno.build.os !== "win") { - 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); - } - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function writeFileCreate(): Promise { - const enc = new TextEncoder(); - const data = enc.encode("Hello"); - const filename = Deno.makeTempDirSync() + "/test.txt"; - let caughtError = false; - // if create turned off, the file won't be created - try { - await Deno.writeFile(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.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("Hello", actual); - } -); - -unitTest( - { perms: { read: true, write: true } }, - async function writeFileAppend(): Promise { - 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("HelloHello", actual); - // Now attempt overwrite - await Deno.writeFile(filename, data, { append: false }); - dataRead = Deno.readFileSync(filename); - actual = dec.decode(dataRead); - assertEquals("Hello", actual); - // append not set should also overwrite - await Deno.writeFile(filename, data); - dataRead = Deno.readFileSync(filename); - actual = dec.decode(dataRead); - assertEquals("Hello", actual); - } -); -- cgit v1.2.3