mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
BREAKING(testing, assert): move std/testing/asserts
to std/assert
(#3445)
This commit is contained in:
parent
2e647b0bea
commit
239e85ad6a
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@ -94,9 +94,6 @@ jobs:
|
||||
- name: Check Import paths in Docs
|
||||
run: "deno task lint:doc-imports"
|
||||
|
||||
- name: Check non-test assertions
|
||||
run: deno task lint:check-assertions
|
||||
|
||||
- name: Spell-check
|
||||
uses: crate-ci/typos@master
|
||||
with:
|
||||
|
@ -106,13 +106,6 @@ _For maintainers_:
|
||||
|
||||
To release a new version a tag in the form of `x.y.z` should be added.
|
||||
|
||||
### Internal Assertions
|
||||
|
||||
All internal non-test code, that is files that do not have `test` or `bench` in
|
||||
the name, must use the assertion functions within `_utils/asserts.ts` and not
|
||||
`testing/asserts.ts`. This is to create a separation of concerns between
|
||||
internal and testing assertions.
|
||||
|
||||
### Types
|
||||
|
||||
Deno is moving away from non-native IO functions and interfaces in favor of the
|
||||
|
@ -1,40 +0,0 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
createGraph,
|
||||
Module,
|
||||
} from "https://deno.land/x/deno_graph@0.37.1/mod.ts";
|
||||
import { walk } from "../fs/walk.ts";
|
||||
|
||||
const ROOT = new URL("../", import.meta.url);
|
||||
const EXTS = [".mjs", ".ts"];
|
||||
const SKIP = [/(test|bench)/];
|
||||
const BAD_IMPORT = new URL("../testing/asserts.ts", import.meta.url);
|
||||
|
||||
async function getFilePaths(): Promise<string[]> {
|
||||
const paths: string[] = [];
|
||||
for await (const { path } of walk(ROOT, { exts: EXTS, skip: SKIP })) {
|
||||
paths.push("file://" + path);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
function hasBadImports({ dependencies }: Module): boolean {
|
||||
return Object.values(dependencies!)
|
||||
.some(({ code }) => code?.specifier?.includes(BAD_IMPORT.href));
|
||||
}
|
||||
|
||||
async function getFilePathsWithBadImports(): Promise<string[]> {
|
||||
const paths = await getFilePaths();
|
||||
const { modules } = await createGraph(paths);
|
||||
return modules.filter(hasBadImports)
|
||||
.map(({ specifier }: Module) => specifier);
|
||||
}
|
||||
|
||||
const paths = await getFilePathsWithBadImports();
|
||||
if (paths.length > 0) {
|
||||
console.error(
|
||||
"Non-test code must use `_util/assert.ts` for assertions. Please fix:",
|
||||
);
|
||||
paths.forEach((path) => console.error("- " + path));
|
||||
Deno.exit(1);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
/**
|
||||
* All internal non-test code, that is files that do not have `test` or `bench` in the name, must use the assertion functions within `_utils/asserts.ts` and not `testing/asserts.ts`. This is to create a separation of concerns between internal and testing assertions.
|
||||
*/
|
||||
|
||||
export class DenoStdInternalError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "DenoStdInternalError";
|
||||
}
|
||||
}
|
||||
|
||||
/** Make an assertion, if not `true`, then throw. */
|
||||
export function assert(expr: unknown, msg = ""): asserts expr {
|
||||
if (!expr) {
|
||||
throw new DenoStdInternalError(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/** Use this to assert unreachable code. */
|
||||
export function unreachable(): never {
|
||||
throw new DenoStdInternalError("unreachable");
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, DenoStdInternalError, unreachable } from "./asserts.ts";
|
||||
import { assertThrows } from "../testing/asserts.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "assert valid scenario",
|
||||
fn() {
|
||||
assert(true);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "assert invalid scenario, no message",
|
||||
fn() {
|
||||
assertThrows(() => {
|
||||
assert(false);
|
||||
}, DenoStdInternalError);
|
||||
},
|
||||
});
|
||||
Deno.test({
|
||||
name: "assert invalid scenario, with message",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => {
|
||||
assert(false, "Oops! Should be true");
|
||||
},
|
||||
DenoStdInternalError,
|
||||
"Oops! Should be true",
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test("assert unreachable", function () {
|
||||
let didThrow = false;
|
||||
try {
|
||||
unreachable();
|
||||
} catch (e) {
|
||||
assert(e instanceof DenoStdInternalError);
|
||||
assert(e.message === "unreachable");
|
||||
didThrow = true;
|
||||
}
|
||||
assert(didThrow);
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { diff, diffstr, DiffType } from "./_diff.ts";
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { diff, diffstr, DiffType } from "./diff.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "empty",
|
@ -42,7 +42,7 @@ export { type TarInfo, type TarMeta, type TarOptions };
|
||||
|
||||
import { MultiReader } from "../io/multi_reader.ts";
|
||||
import { Buffer } from "../io/buffer.ts";
|
||||
import { assert } from "../_util/asserts.ts";
|
||||
import { assert } from "../assert/assert.ts";
|
||||
import { recordSize } from "./_common.ts";
|
||||
|
||||
const ustar = "ustar\u000000";
|
||||
|
@ -9,7 +9,7 @@
|
||||
* **to run this test**
|
||||
* deno run --allow-read archive/tar_test.ts
|
||||
*/
|
||||
import { assert, assertEquals } from "../testing/asserts.ts";
|
||||
import { assert, assertEquals } from "../assert/mod.ts";
|
||||
import { resolve } from "../path/mod.ts";
|
||||
import { Tar } from "./tar.ts";
|
||||
import { Untar } from "./untar.ts";
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, assertEquals, assertExists } from "../testing/asserts.ts";
|
||||
import { assert, assertEquals, assertExists } from "../assert/mod.ts";
|
||||
import { resolve } from "../path/mod.ts";
|
||||
import { Tar, type TarMeta } from "./tar.ts";
|
||||
import { TarEntry, type TarHeader, Untar } from "./untar.ts";
|
||||
|
2
assert/_constants.ts
Normal file
2
assert/_constants.ts
Normal file
@ -0,0 +1,2 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
export const CAN_NOT_DISPLAY = "[Cannot display]";
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { green, red, stripColor } from "../fmt/colors.ts";
|
||||
import { assertEquals, assertThrows } from "./asserts.ts";
|
||||
import { assertEquals, assertThrows } from "../assert/mod.ts";
|
||||
import { format } from "./_format.ts";
|
||||
|
||||
Deno.test("assert diff formatting (strings)", () => {
|
9
assert/assert.ts
Normal file
9
assert/assert.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/** Make an assertion, error will be thrown if `expr` does not have truthy value. */
|
||||
export function assert(expr: unknown, msg = ""): asserts expr {
|
||||
if (!expr) {
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
41
assert/assert_almost_equals.ts
Normal file
41
assert/assert_almost_equals.ts
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` and `expected` are almost equal numbers through
|
||||
* a given tolerance. It can be used to take into account IEEE-754 double-precision
|
||||
* floating-point representation limitations.
|
||||
* If the values are not almost equal then throw.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assertAlmostEquals, assertThrows } from "https://deno.land/std@$STD_VERSION/assert/mod.ts";
|
||||
*
|
||||
* assertAlmostEquals(0.1, 0.2);
|
||||
*
|
||||
* // Using a custom tolerance value
|
||||
* assertAlmostEquals(0.1 + 0.2, 0.3, 1e-16);
|
||||
* assertThrows(() => assertAlmostEquals(0.1 + 0.2, 0.3, 1e-17));
|
||||
* ```
|
||||
*/
|
||||
export function assertAlmostEquals(
|
||||
actual: number,
|
||||
expected: number,
|
||||
tolerance = 1e-7,
|
||||
msg?: string,
|
||||
) {
|
||||
if (Object.is(actual, expected)) {
|
||||
return;
|
||||
}
|
||||
const delta = Math.abs(expected - actual);
|
||||
if (delta <= tolerance) {
|
||||
return;
|
||||
}
|
||||
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
const f = (n: number) => Number.isInteger(n) ? n : n.toExponential();
|
||||
throw new AssertionError(
|
||||
`Expected actual: "${f(actual)}" to be close to "${f(expected)}": \
|
||||
delta "${f(delta)}" is greater than "${f(tolerance)}"${msgSuffix}`,
|
||||
);
|
||||
}
|
43
assert/assert_almost_equals_test.ts
Normal file
43
assert/assert_almost_equals_test.ts
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertAlmostEquals, AssertionError, assertThrows } from "./mod.ts";
|
||||
|
||||
Deno.test("assert almost equals number", () => {
|
||||
//Default precision
|
||||
assertAlmostEquals(-0, +0);
|
||||
assertAlmostEquals(Math.PI, Math.PI);
|
||||
assertAlmostEquals(0.1 + 0.2, 0.3);
|
||||
assertAlmostEquals(NaN, NaN);
|
||||
assertAlmostEquals(Number.NaN, Number.NaN);
|
||||
assertThrows(() => assertAlmostEquals(1, 2));
|
||||
assertThrows(() => assertAlmostEquals(1, 1.1));
|
||||
|
||||
//Higher precision
|
||||
assertAlmostEquals(0.1 + 0.2, 0.3, 1e-16);
|
||||
assertThrows(
|
||||
() => assertAlmostEquals(0.1 + 0.2, 0.3, 1e-17),
|
||||
AssertionError,
|
||||
`Expected actual: "${
|
||||
(
|
||||
0.1 + 0.2
|
||||
).toExponential()
|
||||
}" to be close to "${(0.3).toExponential()}"`,
|
||||
);
|
||||
|
||||
//Special cases
|
||||
assertAlmostEquals(Infinity, Infinity);
|
||||
assertThrows(
|
||||
() => assertAlmostEquals(0, Infinity),
|
||||
AssertionError,
|
||||
'Expected actual: "0" to be close to "Infinity"',
|
||||
);
|
||||
assertThrows(
|
||||
() => assertAlmostEquals(-Infinity, +Infinity),
|
||||
AssertionError,
|
||||
'Expected actual: "-Infinity" to be close to "Infinity"',
|
||||
);
|
||||
assertThrows(
|
||||
() => assertAlmostEquals(Infinity, NaN),
|
||||
AssertionError,
|
||||
'Expected actual: "Infinity" to be close to "NaN"',
|
||||
);
|
||||
});
|
46
assert/assert_array_includes.ts
Normal file
46
assert/assert_array_includes.ts
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { equal } from "./equal.ts";
|
||||
import { format } from "./_format.ts";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` includes the `expected` values.
|
||||
* If not then an error will be thrown.
|
||||
*
|
||||
* Type parameter can be specified to ensure values under comparison have the same type.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assertArrayIncludes } from "https://deno.land/std@$STD_VERSION/assert/assert_array_includes.ts";
|
||||
*
|
||||
* assertArrayIncludes<number>([1, 2], [2])
|
||||
* ```
|
||||
*/
|
||||
export function assertArrayIncludes<T>(
|
||||
actual: ArrayLike<T>,
|
||||
expected: ArrayLike<T>,
|
||||
msg?: string,
|
||||
) {
|
||||
const missing: unknown[] = [];
|
||||
for (let i = 0; i < expected.length; i++) {
|
||||
let found = false;
|
||||
for (let j = 0; j < actual.length; j++) {
|
||||
if (equal(expected[i], actual[j])) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
missing.push(expected[i]);
|
||||
}
|
||||
}
|
||||
if (missing.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
msg = `Expected actual: "${format(actual)}" to include: "${
|
||||
format(expected)
|
||||
}"${msgSuffix}\nmissing: ${format(missing)}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
34
assert/assert_array_includes_test.ts
Normal file
34
assert/assert_array_includes_test.ts
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertArrayIncludes, AssertionError, assertThrows } from "./mod.ts";
|
||||
|
||||
Deno.test("ArrayContains", function () {
|
||||
const fixture = ["deno", "iz", "luv"];
|
||||
const fixtureObject = [{ deno: "luv" }, { deno: "Js" }];
|
||||
assertArrayIncludes(fixture, ["deno"]);
|
||||
assertArrayIncludes(fixtureObject, [{ deno: "luv" }]);
|
||||
assertArrayIncludes(
|
||||
Uint8Array.from([1, 2, 3, 4]),
|
||||
Uint8Array.from([1, 2, 3]),
|
||||
);
|
||||
assertThrows(
|
||||
() => assertArrayIncludes(fixtureObject, [{ deno: "node" }]),
|
||||
AssertionError,
|
||||
`Expected actual: "[
|
||||
{
|
||||
deno: "luv",
|
||||
},
|
||||
{
|
||||
deno: "Js",
|
||||
},
|
||||
]" to include: "[
|
||||
{
|
||||
deno: "node",
|
||||
},
|
||||
]".
|
||||
missing: [
|
||||
{
|
||||
deno: "node",
|
||||
},
|
||||
]`,
|
||||
);
|
||||
});
|
46
assert/assert_equals.ts
Normal file
46
assert/assert_equals.ts
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { equal } from "./equal.ts";
|
||||
import { format } from "./_format.ts";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
import { red } from "../fmt/colors.ts";
|
||||
import { buildMessage, diff, diffstr } from "../_util/diff.ts";
|
||||
import { CAN_NOT_DISPLAY } from "./_constants.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` and `expected` are equal, deeply. If not
|
||||
* deeply equal, then throw.
|
||||
*
|
||||
* Type parameter can be specified to ensure values under comparison have the same type.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* Deno.test("example", function (): void {
|
||||
* assertEquals("world", "world");
|
||||
* assertEquals({ hello: "world" }, { hello: "world" });
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function assertEquals<T>(actual: T, expected: T, msg?: string) {
|
||||
if (equal(actual, expected)) {
|
||||
return;
|
||||
}
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
let message = `Values are not equal${msgSuffix}`;
|
||||
|
||||
const actualString = format(actual);
|
||||
const expectedString = format(expected);
|
||||
try {
|
||||
const stringDiff = (typeof actual === "string") &&
|
||||
(typeof expected === "string");
|
||||
const diffResult = stringDiff
|
||||
? diffstr(actual as string, expected as string)
|
||||
: diff(actualString.split("\n"), expectedString.split("\n"));
|
||||
const diffMsg = buildMessage(diffResult, { stringDiff }).join("\n");
|
||||
message = `${message}\n${diffMsg}`;
|
||||
} catch {
|
||||
message = `${message}\n${red(CAN_NOT_DISPLAY)} + \n\n`;
|
||||
}
|
||||
throw new AssertionError(message);
|
||||
}
|
212
assert/assert_equals_test.ts
Normal file
212
assert/assert_equals_test.ts
Normal file
@ -0,0 +1,212 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, AssertionError, assertThrows } from "./mod.ts";
|
||||
import { bold, gray, green, red, stripColor, yellow } from "../fmt/colors.ts";
|
||||
|
||||
const createHeader = (): string[] => [
|
||||
"",
|
||||
"",
|
||||
` ${gray(bold("[Diff]"))} ${red(bold("Actual"))} / ${
|
||||
green(
|
||||
bold("Expected"),
|
||||
)
|
||||
}`,
|
||||
"",
|
||||
"",
|
||||
];
|
||||
|
||||
const added: (s: string) => string = (s: string): string =>
|
||||
green(bold(stripColor(s)));
|
||||
const removed: (s: string) => string = (s: string): string =>
|
||||
red(bold(stripColor(s)));
|
||||
|
||||
Deno.test({
|
||||
name: "pass case",
|
||||
fn() {
|
||||
assertEquals({ a: 10 }, { a: 10 });
|
||||
assertEquals(true, true);
|
||||
assertEquals(10, 10);
|
||||
assertEquals("abc", "abc");
|
||||
assertEquals({ a: 10, b: { c: "1" } }, { a: 10, b: { c: "1" } });
|
||||
assertEquals(new Date("invalid"), new Date("invalid"));
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "failed with number",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => assertEquals(1, 2),
|
||||
AssertionError,
|
||||
[
|
||||
"Values are not equal.",
|
||||
...createHeader(),
|
||||
removed(`- ${yellow("1")}`),
|
||||
added(`+ ${yellow("2")}`),
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "failed with number vs string",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => assertEquals<unknown>(1, "1"),
|
||||
AssertionError,
|
||||
[
|
||||
"Values are not equal.",
|
||||
...createHeader(),
|
||||
removed(`- ${yellow("1")}`),
|
||||
added(`+ "1"`),
|
||||
].join("\n"),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "failed with array",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => assertEquals([1, "2", 3], ["1", "2", 3]),
|
||||
AssertionError,
|
||||
`
|
||||
[
|
||||
- 1,
|
||||
+ "1",
|
||||
"2",
|
||||
3,
|
||||
]`,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "failed with object",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => assertEquals({ a: 1, b: "2", c: 3 }, { a: 1, b: 2, c: [3] }),
|
||||
AssertionError,
|
||||
`
|
||||
{
|
||||
a: 1,
|
||||
+ b: 2,
|
||||
+ c: [
|
||||
+ 3,
|
||||
+ ],
|
||||
- b: "2",
|
||||
- c: 3,
|
||||
}`,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "failed with date",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() =>
|
||||
assertEquals(
|
||||
new Date(2019, 0, 3, 4, 20, 1, 10),
|
||||
new Date(2019, 0, 3, 4, 20, 1, 20),
|
||||
),
|
||||
AssertionError,
|
||||
[
|
||||
"Values are not equal.",
|
||||
...createHeader(),
|
||||
removed(`- ${new Date(2019, 0, 3, 4, 20, 1, 10).toISOString()}`),
|
||||
added(`+ ${new Date(2019, 0, 3, 4, 20, 1, 20).toISOString()}`),
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
assertThrows(
|
||||
() =>
|
||||
assertEquals(new Date("invalid"), new Date(2019, 0, 3, 4, 20, 1, 20)),
|
||||
AssertionError,
|
||||
[
|
||||
"Values are not equal.",
|
||||
...createHeader(),
|
||||
removed(`- ${new Date("invalid")}`),
|
||||
added(`+ ${new Date(2019, 0, 3, 4, 20, 1, 20).toISOString()}`),
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "failed with custom msg",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => assertEquals(1, 2, "CUSTOM MESSAGE"),
|
||||
AssertionError,
|
||||
[
|
||||
"Values are not equal: CUSTOM MESSAGE",
|
||||
...createHeader(),
|
||||
removed(`- ${yellow("1")}`),
|
||||
added(`+ ${yellow("2")}`),
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test(
|
||||
"assertEquals compares objects structurally if one object's constructor is undefined and the other is Object",
|
||||
() => {
|
||||
const a = Object.create(null);
|
||||
a.prop = "test";
|
||||
const b = {
|
||||
prop: "test",
|
||||
};
|
||||
|
||||
assertEquals(a, b);
|
||||
assertEquals(b, a);
|
||||
},
|
||||
);
|
||||
|
||||
Deno.test("assertEquals diff for differently ordered objects", () => {
|
||||
assertThrows(
|
||||
() => {
|
||||
assertEquals(
|
||||
{
|
||||
aaaaaaaaaaaaaaaaaaaaaaaa: 0,
|
||||
bbbbbbbbbbbbbbbbbbbbbbbb: 0,
|
||||
ccccccccccccccccccccccc: 0,
|
||||
},
|
||||
{
|
||||
ccccccccccccccccccccccc: 1,
|
||||
aaaaaaaaaaaaaaaaaaaaaaaa: 0,
|
||||
bbbbbbbbbbbbbbbbbbbbbbbb: 0,
|
||||
},
|
||||
);
|
||||
},
|
||||
AssertionError,
|
||||
`
|
||||
{
|
||||
aaaaaaaaaaaaaaaaaaaaaaaa: 0,
|
||||
bbbbbbbbbbbbbbbbbbbbbbbb: 0,
|
||||
- ccccccccccccccccccccccc: 0,
|
||||
+ ccccccccccccccccccccccc: 1,
|
||||
}`,
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("assertEquals same Set with object keys", () => {
|
||||
const data = [
|
||||
{
|
||||
id: "_1p7ZED73OF98VbT1SzSkjn",
|
||||
type: { id: "_ETGENUS" },
|
||||
name: "Thuja",
|
||||
friendlyId: "g-thuja",
|
||||
},
|
||||
{
|
||||
id: "_567qzghxZmeQ9pw3q09bd3",
|
||||
type: { id: "_ETGENUS" },
|
||||
name: "Pinus",
|
||||
friendlyId: "g-pinus",
|
||||
},
|
||||
];
|
||||
assertEquals(data, data);
|
||||
assertEquals(new Set(data), new Set(data));
|
||||
});
|
18
assert/assert_exists.ts
Normal file
18
assert/assert_exists.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that actual is not null or undefined.
|
||||
* If not then throw.
|
||||
*/
|
||||
export function assertExists<T>(
|
||||
actual: T,
|
||||
msg?: string,
|
||||
): asserts actual is NonNullable<T> {
|
||||
if (actual === undefined || actual === null) {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
msg =
|
||||
`Expected actual: "${actual}" to not be null or undefined${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
35
assert/assert_exists_test.ts
Normal file
35
assert/assert_exists_test.ts
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, assertEquals, assertExists, AssertionError } from "./mod.ts";
|
||||
|
||||
Deno.test("AssertExists", function () {
|
||||
assertExists("Denosaurus");
|
||||
assertExists(false);
|
||||
assertExists(0);
|
||||
assertExists("");
|
||||
assertExists(-0);
|
||||
assertExists(0);
|
||||
assertExists(NaN);
|
||||
|
||||
const value = new URLSearchParams({ value: "test" }).get("value");
|
||||
assertExists(value);
|
||||
assertEquals(value.length, 4);
|
||||
|
||||
let didThrow;
|
||||
try {
|
||||
assertExists(undefined);
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
didThrow = false;
|
||||
try {
|
||||
assertExists(null);
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
});
|
10
assert/assert_false.ts
Normal file
10
assert/assert_false.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/** Make an assertion, error will be thrown if `expr` have truthy value. */
|
||||
type Falsy = false | 0 | 0n | "" | null | undefined;
|
||||
export function assertFalse(expr: unknown, msg = ""): asserts expr is Falsy {
|
||||
if (expr) {
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
18
assert/assert_false_test.ts
Normal file
18
assert/assert_false_test.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertFalse, assertThrows } from "./mod.ts";
|
||||
|
||||
Deno.test("Assert False with falsy values", () => {
|
||||
assertFalse(false);
|
||||
assertFalse(0);
|
||||
assertFalse("");
|
||||
assertFalse(null);
|
||||
assertFalse(undefined);
|
||||
});
|
||||
|
||||
Deno.test("Assert False with truthy values", () => {
|
||||
assertThrows(() => assertFalse(true));
|
||||
assertThrows(() => assertFalse(1));
|
||||
assertThrows(() => assertFalse("a"));
|
||||
assertThrows(() => assertFalse({}));
|
||||
assertThrows(() => assertFalse([]));
|
||||
});
|
47
assert/assert_instance_of.ts
Normal file
47
assert/assert_instance_of.ts
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
type AnyConstructor = new (...args: any[]) => any;
|
||||
type GetConstructorType<T extends AnyConstructor> = T extends // deno-lint-ignore no-explicit-any
|
||||
new (...args: any) => infer C ? C
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Make an assertion that `obj` is an instance of `type`.
|
||||
* If not then throw.
|
||||
*/
|
||||
export function assertInstanceOf<T extends AnyConstructor>(
|
||||
actual: unknown,
|
||||
expectedType: T,
|
||||
msg = "",
|
||||
): asserts actual is GetConstructorType<T> {
|
||||
if (actual instanceof expectedType) return;
|
||||
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
const expectedTypeStr = expectedType.name;
|
||||
|
||||
let actualTypeStr = "";
|
||||
if (actual === null) {
|
||||
actualTypeStr = "null";
|
||||
} else if (actual === undefined) {
|
||||
actualTypeStr = "undefined";
|
||||
} else if (typeof actual === "object") {
|
||||
actualTypeStr = actual.constructor?.name ?? "Object";
|
||||
} else {
|
||||
actualTypeStr = typeof actual;
|
||||
}
|
||||
|
||||
if (expectedTypeStr == actualTypeStr) {
|
||||
msg =
|
||||
`Expected object to be an instance of "${expectedTypeStr}"${msgSuffix}`;
|
||||
} else if (actualTypeStr == "function") {
|
||||
msg =
|
||||
`Expected object to be an instance of "${expectedTypeStr}" but was not an instanced object${msgSuffix}`;
|
||||
} else {
|
||||
msg =
|
||||
`Expected object to be an instance of "${expectedTypeStr}" but was "${actualTypeStr}"${msgSuffix}`;
|
||||
}
|
||||
|
||||
throw new AssertionError(msg);
|
||||
}
|
116
assert/assert_instance_of_test.ts
Normal file
116
assert/assert_instance_of_test.ts
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertInstanceOf, AssertionError, assertThrows } from "./mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "assertInstanceOf",
|
||||
fn() {
|
||||
class TestClass1 {}
|
||||
class TestClass2 {}
|
||||
class TestClass3 {}
|
||||
|
||||
// Regular types
|
||||
assertInstanceOf(new Date(), Date);
|
||||
assertInstanceOf(new Number(), Number);
|
||||
assertInstanceOf(Promise.resolve(), Promise);
|
||||
assertInstanceOf(new TestClass1(), TestClass1);
|
||||
|
||||
// Throwing cases
|
||||
assertThrows(
|
||||
() => assertInstanceOf(new Date(), RegExp),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "RegExp" but was "Date".`,
|
||||
);
|
||||
assertThrows(
|
||||
() => assertInstanceOf(5, Date),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "Date" but was "number".`,
|
||||
);
|
||||
assertThrows(
|
||||
() => assertInstanceOf(new TestClass1(), TestClass2),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "TestClass2" but was "TestClass1".`,
|
||||
);
|
||||
|
||||
// Custom message
|
||||
assertThrows(
|
||||
() => assertInstanceOf(new Date(), RegExp, "Custom message"),
|
||||
AssertionError,
|
||||
"Custom message",
|
||||
);
|
||||
|
||||
// Edge cases
|
||||
assertThrows(
|
||||
() => assertInstanceOf(5, Number),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "Number" but was "number".`,
|
||||
);
|
||||
|
||||
let TestClassWithSameName: new () => unknown;
|
||||
{
|
||||
class TestClass3 {}
|
||||
TestClassWithSameName = TestClass3;
|
||||
}
|
||||
assertThrows(
|
||||
() => assertInstanceOf(new TestClassWithSameName(), TestClass3),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "TestClass3".`,
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
() => assertInstanceOf(TestClass1, TestClass1),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "TestClass1" but was not an instanced object.`,
|
||||
);
|
||||
assertThrows(
|
||||
() => assertInstanceOf(() => {}, TestClass1),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "TestClass1" but was not an instanced object.`,
|
||||
);
|
||||
assertThrows(
|
||||
() => assertInstanceOf(null, TestClass1),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "TestClass1" but was "null".`,
|
||||
);
|
||||
assertThrows(
|
||||
() => assertInstanceOf(undefined, TestClass1),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "TestClass1" but was "undefined".`,
|
||||
);
|
||||
assertThrows(
|
||||
() => assertInstanceOf({}, TestClass1),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "TestClass1" but was "Object".`,
|
||||
);
|
||||
assertThrows(
|
||||
() => assertInstanceOf(Object.create(null), TestClass1),
|
||||
AssertionError,
|
||||
`Expected object to be an instance of "TestClass1" but was "Object".`,
|
||||
);
|
||||
|
||||
// Test TypeScript types functionality, wrapped in a function that never runs
|
||||
// deno-lint-ignore no-unused-vars
|
||||
function typeScriptTests() {
|
||||
class ClassWithProperty {
|
||||
property = "prop1";
|
||||
}
|
||||
const testInstance = new ClassWithProperty() as unknown;
|
||||
|
||||
// @ts-expect-error: `testInstance` is `unknown` so setting its property before `assertInstanceOf` should give a type error.
|
||||
testInstance.property = "prop2";
|
||||
|
||||
assertInstanceOf(testInstance, ClassWithProperty);
|
||||
|
||||
// Now `testInstance` should be of type `ClassWithProperty`
|
||||
testInstance.property = "prop3";
|
||||
|
||||
let x = 5 as unknown;
|
||||
|
||||
// @ts-expect-error: `x` is `unknown` so adding to it shouldn't work
|
||||
x += 5;
|
||||
assertInstanceOf(x, Number);
|
||||
|
||||
// @ts-expect-error: `x` is now `Number` rather than `number`, so this should still give a type error.
|
||||
x += 5;
|
||||
}
|
||||
},
|
||||
});
|
39
assert/assert_is_error.ts
Normal file
39
assert/assert_is_error.ts
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
import { stripColor } from "../fmt/colors.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `error` is an `Error`.
|
||||
* If not then an error will be thrown.
|
||||
* An error class and a string that should be included in the
|
||||
* error message can also be asserted.
|
||||
*/
|
||||
export function assertIsError<E extends Error = Error>(
|
||||
error: unknown,
|
||||
// deno-lint-ignore no-explicit-any
|
||||
ErrorClass?: new (...args: any[]) => E,
|
||||
msgIncludes?: string,
|
||||
msg?: string,
|
||||
): asserts error is E {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
if (error instanceof Error === false) {
|
||||
throw new AssertionError(
|
||||
`Expected "error" to be an Error object${msgSuffix}}`,
|
||||
);
|
||||
}
|
||||
if (ErrorClass && !(error instanceof ErrorClass)) {
|
||||
msg = `Expected error to be instance of "${ErrorClass.name}", but was "${
|
||||
typeof error === "object" ? error?.constructor?.name : "[not an object]"
|
||||
}"${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
if (
|
||||
msgIncludes && (!(error instanceof Error) ||
|
||||
!stripColor(error.message).includes(stripColor(msgIncludes)))
|
||||
) {
|
||||
msg = `Expected error message to include "${msgIncludes}", but got "${
|
||||
error instanceof Error ? error.message : "[not an Error]"
|
||||
}"${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
37
assert/assert_is_error_test.ts
Normal file
37
assert/assert_is_error_test.ts
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError, assertIsError, assertThrows } from "./mod.ts";
|
||||
|
||||
Deno.test("Assert Is Error Non-Error Fail", () => {
|
||||
assertThrows(
|
||||
() => assertIsError("Panic!", undefined, "Panic!"),
|
||||
AssertionError,
|
||||
`Expected "error" to be an Error object.`,
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
() => assertIsError(null),
|
||||
AssertionError,
|
||||
`Expected "error" to be an Error object.`,
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
() => assertIsError(undefined),
|
||||
AssertionError,
|
||||
`Expected "error" to be an Error object.`,
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Assert Is Error Parent Error", () => {
|
||||
assertIsError(new AssertionError("Fail!"), Error, "Fail!");
|
||||
});
|
||||
|
||||
Deno.test("Assert Is Error with custom Error", () => {
|
||||
class CustomError extends Error {}
|
||||
class AnotherCustomError extends Error {}
|
||||
assertIsError(new CustomError("failed"), CustomError, "fail");
|
||||
assertThrows(
|
||||
() => assertIsError(new AnotherCustomError("failed"), CustomError, "fail"),
|
||||
AssertionError,
|
||||
'Expected error to be instance of "CustomError", but was "AnotherCustomError".',
|
||||
);
|
||||
});
|
18
assert/assert_match.ts
Normal file
18
assert/assert_match.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` match RegExp `expected`. If not
|
||||
* then throw.
|
||||
*/
|
||||
export function assertMatch(
|
||||
actual: string,
|
||||
expected: RegExp,
|
||||
msg?: string,
|
||||
) {
|
||||
if (!expected.test(actual)) {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
msg = `Expected actual: "${actual}" to match: "${expected}"${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
21
assert/assert_match_test.ts
Normal file
21
assert/assert_match_test.ts
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, AssertionError, assertMatch } from "./mod.ts";
|
||||
|
||||
Deno.test("AssertStringMatching", function () {
|
||||
assertMatch("foobar@deno.com", RegExp(/[a-zA-Z]+@[a-zA-Z]+.com/));
|
||||
});
|
||||
|
||||
Deno.test("AssertStringMatchingThrows", function () {
|
||||
let didThrow = false;
|
||||
try {
|
||||
assertMatch("Denosaurus from Jurassic", RegExp(/Raptor/));
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
assert(
|
||||
e.message ===
|
||||
`Expected actual: "Denosaurus from Jurassic" to match: "/Raptor/".`,
|
||||
);
|
||||
didThrow = true;
|
||||
}
|
||||
assert(didThrow);
|
||||
});
|
38
assert/assert_not_equals.ts
Normal file
38
assert/assert_not_equals.ts
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { equal } from "./equal.ts";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` and `expected` are not equal, deeply.
|
||||
* If not then throw.
|
||||
*
|
||||
* Type parameter can be specified to ensure values under comparison have the same type.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assertNotEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_not_equals.ts";
|
||||
*
|
||||
* assertNotEquals<number>(1, 2)
|
||||
* ```
|
||||
*/
|
||||
export function assertNotEquals<T>(actual: T, expected: T, msg?: string) {
|
||||
if (!equal(actual, expected)) {
|
||||
return;
|
||||
}
|
||||
let actualString: string;
|
||||
let expectedString: string;
|
||||
try {
|
||||
actualString = String(actual);
|
||||
} catch {
|
||||
actualString = "[Cannot display]";
|
||||
}
|
||||
try {
|
||||
expectedString = String(expected);
|
||||
} catch {
|
||||
expectedString = "[Cannot display]";
|
||||
}
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
throw new AssertionError(
|
||||
`Expected actual: ${actualString} not to be: ${expectedString}${msgSuffix}`,
|
||||
);
|
||||
}
|
28
assert/assert_not_equals_test.ts
Normal file
28
assert/assert_not_equals_test.ts
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
AssertionError,
|
||||
assertNotEquals,
|
||||
} from "./mod.ts";
|
||||
|
||||
Deno.test("NotEquals", function () {
|
||||
const a = { foo: "bar" };
|
||||
const b = { bar: "foo" };
|
||||
assertNotEquals<unknown>(a, b);
|
||||
assertNotEquals("Denosaurus", "Tyrannosaurus");
|
||||
assertNotEquals(
|
||||
new Date(2019, 0, 3, 4, 20, 1, 10),
|
||||
new Date(2019, 0, 3, 4, 20, 1, 20),
|
||||
);
|
||||
assertNotEquals(new Date("invalid"), new Date(2019, 0, 3, 4, 20, 1, 20));
|
||||
let didThrow;
|
||||
try {
|
||||
assertNotEquals("Raptor", "Raptor");
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
});
|
18
assert/assert_not_instance_of.ts
Normal file
18
assert/assert_not_instance_of.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertFalse } from "./assert_false.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `obj` is not an instance of `type`.
|
||||
* If so, then throw.
|
||||
*/
|
||||
export function assertNotInstanceOf<A, T>(
|
||||
actual: A,
|
||||
// deno-lint-ignore no-explicit-any
|
||||
unexpectedType: new (...args: any[]) => T,
|
||||
msg?: string,
|
||||
): asserts actual is Exclude<A, T> {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
msg =
|
||||
`Expected object to not be an instance of "${typeof unexpectedType}"${msgSuffix}`;
|
||||
assertFalse(actual instanceof unexpectedType, msg);
|
||||
}
|
11
assert/assert_not_instance_of_test.ts
Normal file
11
assert/assert_not_instance_of_test.ts
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertNotInstanceOf } from "./mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "assertNotInstanceOf",
|
||||
fn() {
|
||||
assertNotInstanceOf("not a number", Number);
|
||||
assertNotInstanceOf(42, String);
|
||||
assertNotInstanceOf(new URL("http://example.com"), Boolean);
|
||||
},
|
||||
});
|
19
assert/assert_not_match.ts
Normal file
19
assert/assert_not_match.ts
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` not match RegExp `expected`. If match
|
||||
* then throw.
|
||||
*/
|
||||
export function assertNotMatch(
|
||||
actual: string,
|
||||
expected: RegExp,
|
||||
msg?: string,
|
||||
) {
|
||||
if (expected.test(actual)) {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
msg =
|
||||
`Expected actual: "${actual}" to not match: "${expected}"${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
21
assert/assert_not_match_test.ts
Normal file
21
assert/assert_not_match_test.ts
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, AssertionError, assertNotMatch } from "./mod.ts";
|
||||
|
||||
Deno.test("AssertStringNotMatching", function () {
|
||||
assertNotMatch("foobar.deno.com", RegExp(/[a-zA-Z]+@[a-zA-Z]+.com/));
|
||||
});
|
||||
|
||||
Deno.test("AssertStringNotMatchingThrows", function () {
|
||||
let didThrow = false;
|
||||
try {
|
||||
assertNotMatch("Denosaurus from Jurassic", RegExp(/from/));
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
assert(
|
||||
e.message ===
|
||||
`Expected actual: "Denosaurus from Jurassic" to not match: "/from/".`,
|
||||
);
|
||||
didThrow = true;
|
||||
}
|
||||
assert(didThrow);
|
||||
});
|
30
assert/assert_not_strict_equals.ts
Normal file
30
assert/assert_not_strict_equals.ts
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
import { format } from "./_format.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` and `expected` are not strictly equal.
|
||||
* If the values are strictly equal then throw.
|
||||
*
|
||||
* ```ts
|
||||
* import { assertNotStrictEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_not_strict_equals.ts";
|
||||
*
|
||||
* assertNotStrictEquals(1, 1)
|
||||
* ```
|
||||
*/
|
||||
export function assertNotStrictEquals<T>(
|
||||
actual: T,
|
||||
expected: T,
|
||||
msg?: string,
|
||||
) {
|
||||
if (!Object.is(actual, expected)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
throw new AssertionError(
|
||||
`Expected "actual" to be strictly unequal to: ${
|
||||
format(actual)
|
||||
}${msgSuffix}\n`,
|
||||
);
|
||||
}
|
29
assert/assert_not_strict_equals_test.ts
Normal file
29
assert/assert_not_strict_equals_test.ts
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError, assertNotStrictEquals, assertThrows } from "./mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "strictly unequal pass case",
|
||||
fn() {
|
||||
assertNotStrictEquals(true, false);
|
||||
assertNotStrictEquals(10, 11);
|
||||
assertNotStrictEquals("abc", "xyz");
|
||||
assertNotStrictEquals<unknown>(1, "1");
|
||||
assertNotStrictEquals(-0, +0);
|
||||
|
||||
const xs = [1, false, "foo"];
|
||||
const ys = [1, true, "bar"];
|
||||
assertNotStrictEquals(xs, ys);
|
||||
|
||||
const x = { a: 1 };
|
||||
const y = { a: 2 };
|
||||
assertNotStrictEquals(x, y);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "strictly unequal fail case",
|
||||
fn() {
|
||||
assertThrows(() => assertNotStrictEquals(1, 1), AssertionError);
|
||||
assertThrows(() => assertNotStrictEquals(NaN, NaN), AssertionError);
|
||||
},
|
||||
});
|
92
assert/assert_object_match.ts
Normal file
92
assert/assert_object_match.ts
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals } from "./assert_equals.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` object is a subset of `expected` object, deeply.
|
||||
* If not, then throw.
|
||||
*/
|
||||
export function assertObjectMatch(
|
||||
// deno-lint-ignore no-explicit-any
|
||||
actual: Record<PropertyKey, any>,
|
||||
expected: Record<PropertyKey, unknown>,
|
||||
msg?: string,
|
||||
) {
|
||||
type loose = Record<PropertyKey, unknown>;
|
||||
|
||||
function filter(a: loose, b: loose) {
|
||||
const seen = new WeakMap();
|
||||
return fn(a, b);
|
||||
|
||||
function fn(a: loose, b: loose): loose {
|
||||
// Prevent infinite loop with circular references with same filter
|
||||
if ((seen.has(a)) && (seen.get(a) === b)) {
|
||||
return a;
|
||||
}
|
||||
try {
|
||||
seen.set(a, b);
|
||||
} catch (err) {
|
||||
if (err instanceof TypeError) {
|
||||
throw new TypeError(
|
||||
`Cannot assertObjectMatch ${
|
||||
a === null ? null : `type ${typeof a}`
|
||||
}`,
|
||||
);
|
||||
} else throw err;
|
||||
}
|
||||
// Filter keys and symbols which are present in both actual and expected
|
||||
const filtered = {} as loose;
|
||||
const entries = [
|
||||
...Object.getOwnPropertyNames(a),
|
||||
...Object.getOwnPropertySymbols(a),
|
||||
]
|
||||
.filter((key) => key in b)
|
||||
.map((key) => [key, a[key as string]]) as Array<[string, unknown]>;
|
||||
for (const [key, value] of entries) {
|
||||
// On array references, build a filtered array and filter nested objects inside
|
||||
if (Array.isArray(value)) {
|
||||
const subset = (b as loose)[key];
|
||||
if (Array.isArray(subset)) {
|
||||
filtered[key] = fn({ ...value }, { ...subset });
|
||||
continue;
|
||||
}
|
||||
} // On regexp references, keep value as it to avoid loosing pattern and flags
|
||||
else if (value instanceof RegExp) {
|
||||
filtered[key] = value;
|
||||
continue;
|
||||
} // On nested objects references, build a filtered object recursively
|
||||
else if (typeof value === "object" && value !== null) {
|
||||
const subset = (b as loose)[key];
|
||||
if ((typeof subset === "object") && (subset)) {
|
||||
// When both operands are maps, build a filtered map with common keys and filter nested objects inside
|
||||
if ((value instanceof Map) && (subset instanceof Map)) {
|
||||
filtered[key] = new Map(
|
||||
[...value].filter(([k]) => subset.has(k)).map((
|
||||
[k, v],
|
||||
) => [k, typeof v === "object" ? fn(v, subset.get(k)) : v]),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// When both operands are set, build a filtered set with common values
|
||||
if ((value instanceof Set) && (subset instanceof Set)) {
|
||||
filtered[key] = new Set([...value].filter((v) => subset.has(v)));
|
||||
continue;
|
||||
}
|
||||
filtered[key] = fn(value as loose, subset as loose);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
filtered[key] = value;
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
}
|
||||
return assertEquals(
|
||||
// get the intersection of "actual" and "expected"
|
||||
// side effect: all the instances' constructor field is "Object" now.
|
||||
filter(actual, expected),
|
||||
// set (nested) instances' constructor field to be "Object" without changing expected value.
|
||||
// see https://github.com/denoland/deno_std/pull/1419
|
||||
filter(expected, expected),
|
||||
msg,
|
||||
);
|
||||
}
|
339
assert/assert_object_match_test.ts
Normal file
339
assert/assert_object_match_test.ts
Normal file
@ -0,0 +1,339 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
AssertionError,
|
||||
assertObjectMatch,
|
||||
assertThrows,
|
||||
} from "./mod.ts";
|
||||
|
||||
Deno.test("AssertObjectMatching", function () {
|
||||
const sym = Symbol("foo");
|
||||
const a = { foo: true, bar: false };
|
||||
const b = { ...a, baz: a };
|
||||
const c = { ...b, qux: b };
|
||||
const d = { corge: c, grault: c };
|
||||
const e = { foo: true } as { [key: string]: unknown };
|
||||
e.bar = e;
|
||||
const f = { [sym]: true, bar: false };
|
||||
interface r {
|
||||
foo: boolean;
|
||||
bar: boolean;
|
||||
}
|
||||
const g: r = { foo: true, bar: false };
|
||||
const h = { foo: [1, 2, 3], bar: true };
|
||||
const i = { foo: [a, e], bar: true };
|
||||
const j = { foo: [[1, 2, 3]], bar: true };
|
||||
const k = { foo: [[1, [2, [3]]]], bar: true };
|
||||
const l = { foo: [[1, [2, [a, e, j, k]]]], bar: true };
|
||||
const m = { foo: /abc+/i, bar: [/abc/g, /abc/m] };
|
||||
const n = {
|
||||
foo: new Set(["foo", "bar"]),
|
||||
bar: new Map([
|
||||
["foo", 1],
|
||||
["bar", 2],
|
||||
]),
|
||||
baz: new Map([
|
||||
["a", a],
|
||||
["b", b],
|
||||
]),
|
||||
};
|
||||
|
||||
// Simple subset
|
||||
assertObjectMatch(a, {
|
||||
foo: true,
|
||||
});
|
||||
// Subset with another subset
|
||||
assertObjectMatch(b, {
|
||||
foo: true,
|
||||
baz: { bar: false },
|
||||
});
|
||||
// Subset with multiple subsets
|
||||
assertObjectMatch(c, {
|
||||
foo: true,
|
||||
baz: { bar: false },
|
||||
qux: {
|
||||
baz: { foo: true },
|
||||
},
|
||||
});
|
||||
// Subset with same object reference as subset
|
||||
assertObjectMatch(d, {
|
||||
corge: {
|
||||
foo: true,
|
||||
qux: { bar: false },
|
||||
},
|
||||
grault: {
|
||||
bar: false,
|
||||
qux: { foo: true },
|
||||
},
|
||||
});
|
||||
// Subset with circular reference
|
||||
assertObjectMatch(e, {
|
||||
foo: true,
|
||||
bar: {
|
||||
bar: {
|
||||
bar: {
|
||||
foo: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
// Subset with interface
|
||||
assertObjectMatch(g, { bar: false });
|
||||
// Subset with same symbol
|
||||
assertObjectMatch(f, {
|
||||
[sym]: true,
|
||||
});
|
||||
// Subset with array inside
|
||||
assertObjectMatch(h, { foo: [] });
|
||||
assertObjectMatch(h, { foo: [1, 2] });
|
||||
assertObjectMatch(h, { foo: [1, 2, 3] });
|
||||
assertObjectMatch(i, { foo: [{ bar: false }] });
|
||||
assertObjectMatch(i, {
|
||||
foo: [{ bar: false }, { bar: { bar: { bar: { foo: true } } } }],
|
||||
});
|
||||
// Subset with nested array inside
|
||||
assertObjectMatch(j, { foo: [[1, 2, 3]] });
|
||||
assertObjectMatch(k, { foo: [[1, [2, [3]]]] });
|
||||
assertObjectMatch(l, { foo: [[1, [2, [a, e, j, k]]]] });
|
||||
// Regexp
|
||||
assertObjectMatch(m, { foo: /abc+/i });
|
||||
assertObjectMatch(m, { bar: [/abc/g, /abc/m] });
|
||||
//Built-in data structures
|
||||
assertObjectMatch(n, { foo: new Set(["foo"]) });
|
||||
assertObjectMatch(n, { bar: new Map([["bar", 2]]) });
|
||||
assertObjectMatch(n, { baz: new Map([["b", b]]) });
|
||||
assertObjectMatch(n, { baz: new Map([["b", { foo: true }]]) });
|
||||
|
||||
// Missing key
|
||||
{
|
||||
let didThrow;
|
||||
try {
|
||||
assertObjectMatch(
|
||||
{
|
||||
foo: true,
|
||||
},
|
||||
{
|
||||
foo: true,
|
||||
bar: false,
|
||||
},
|
||||
);
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
}
|
||||
// Simple subset
|
||||
{
|
||||
let didThrow;
|
||||
try {
|
||||
assertObjectMatch(a, {
|
||||
foo: false,
|
||||
});
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
}
|
||||
// Subset with another subset
|
||||
{
|
||||
let didThrow;
|
||||
try {
|
||||
assertObjectMatch(b, {
|
||||
foo: true,
|
||||
baz: { bar: true },
|
||||
});
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
}
|
||||
// Subset with multiple subsets
|
||||
{
|
||||
let didThrow;
|
||||
try {
|
||||
assertObjectMatch(c, {
|
||||
foo: true,
|
||||
baz: { bar: false },
|
||||
qux: {
|
||||
baz: { foo: false },
|
||||
},
|
||||
});
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
}
|
||||
// Subset with same object reference as subset
|
||||
{
|
||||
let didThrow;
|
||||
try {
|
||||
assertObjectMatch(d, {
|
||||
corge: {
|
||||
foo: true,
|
||||
qux: { bar: true },
|
||||
},
|
||||
grault: {
|
||||
bar: false,
|
||||
qux: { foo: false },
|
||||
},
|
||||
});
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
}
|
||||
// Subset with circular reference
|
||||
{
|
||||
let didThrow;
|
||||
try {
|
||||
assertObjectMatch(e, {
|
||||
foo: true,
|
||||
bar: {
|
||||
bar: {
|
||||
bar: {
|
||||
foo: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
}
|
||||
// Subset with symbol key but with string key subset
|
||||
{
|
||||
let didThrow;
|
||||
try {
|
||||
assertObjectMatch(f, {
|
||||
foo: true,
|
||||
});
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
}
|
||||
// Subset with array inside but doesn't match key subset
|
||||
{
|
||||
let didThrow;
|
||||
try {
|
||||
assertObjectMatch(i, {
|
||||
foo: [1, 2, 3, 4],
|
||||
});
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
}
|
||||
{
|
||||
let didThrow;
|
||||
try {
|
||||
assertObjectMatch(i, {
|
||||
foo: [{ bar: true }, { foo: false }],
|
||||
});
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
}
|
||||
// actual/expected value as instance of class
|
||||
{
|
||||
class A {
|
||||
a: number;
|
||||
constructor(a: number) {
|
||||
this.a = a;
|
||||
}
|
||||
}
|
||||
assertObjectMatch({ test: new A(1) }, { test: { a: 1 } });
|
||||
assertObjectMatch({ test: { a: 1 } }, { test: { a: 1 } });
|
||||
assertObjectMatch({ test: { a: 1 } }, { test: new A(1) });
|
||||
assertObjectMatch({ test: new A(1) }, { test: new A(1) });
|
||||
}
|
||||
{
|
||||
// actual/expected contains same instance of Map/TypedArray/etc
|
||||
const body = new Uint8Array([0, 1, 2]);
|
||||
assertObjectMatch({ body, foo: "foo" }, { body });
|
||||
}
|
||||
{
|
||||
// match subsets of arrays
|
||||
assertObjectMatch(
|
||||
{ positions: [[1, 2, 3, 4]] },
|
||||
{
|
||||
positions: [[1, 2, 3]],
|
||||
},
|
||||
);
|
||||
}
|
||||
//Regexp
|
||||
assertThrows(() => assertObjectMatch(m, { foo: /abc+/ }), AssertionError);
|
||||
assertThrows(() => assertObjectMatch(m, { foo: /abc*/i }), AssertionError);
|
||||
assertThrows(
|
||||
() => assertObjectMatch(m, { bar: [/abc/m, /abc/g] }),
|
||||
AssertionError,
|
||||
);
|
||||
//Built-in data structures
|
||||
assertThrows(
|
||||
() => assertObjectMatch(n, { foo: new Set(["baz"]) }),
|
||||
AssertionError,
|
||||
);
|
||||
assertThrows(
|
||||
() => assertObjectMatch(n, { bar: new Map([["bar", 3]]) }),
|
||||
AssertionError,
|
||||
);
|
||||
assertThrows(
|
||||
() => assertObjectMatch(n, { baz: new Map([["a", { baz: true }]]) }),
|
||||
AssertionError,
|
||||
);
|
||||
// null in the first argument throws an assertion error, rather than a TypeError: Invalid value used as weak map key
|
||||
assertThrows(
|
||||
() => assertObjectMatch({ foo: null }, { foo: { bar: 42 } }),
|
||||
AssertionError,
|
||||
);
|
||||
assertObjectMatch({ foo: null, bar: null }, { foo: null });
|
||||
assertObjectMatch({ foo: undefined, bar: null }, { foo: undefined });
|
||||
assertThrows(
|
||||
() => assertObjectMatch({ foo: undefined, bar: null }, { foo: null }),
|
||||
AssertionError,
|
||||
);
|
||||
// Non mapable primative types should throw a readable type error
|
||||
assertThrows(
|
||||
// @ts-expect-error Argument of type 'null' is not assignable to parameter of type 'Record<PropertyKey, any>'
|
||||
() => assertObjectMatch(null, { foo: 42 }),
|
||||
TypeError,
|
||||
"assertObjectMatch",
|
||||
);
|
||||
// @ts-expect-error Argument of type 'null' is not assignable to parameter of type 'Record<PropertyKey, any>'
|
||||
assertThrows(() => assertObjectMatch(null, { foo: 42 }), TypeError, "null"); // since typeof null is "object", want to make sure user knows the bad value is "null"
|
||||
assertThrows(
|
||||
// @ts-expect-error Argument of type 'undefined' is not assignable to parameter of type 'Record<PropertyKey, any>'
|
||||
() => assertObjectMatch(undefined, { foo: 42 }),
|
||||
TypeError,
|
||||
"assertObjectMatch",
|
||||
);
|
||||
// @ts-expect-error Argument of type 'number' is not assignable to parameter of type 'Record<PropertyKey, any>'
|
||||
assertThrows(() => assertObjectMatch(21, 42), TypeError, "assertObjectMatch");
|
||||
assertThrows(
|
||||
// @ts-expect-error Argument of type 'string' is not assignable to parameter of type 'Record<PropertyKey, any>'
|
||||
() => assertObjectMatch("string", "string"),
|
||||
TypeError,
|
||||
"assertObjectMatch",
|
||||
);
|
||||
});
|
144
assert/assert_rejects.ts
Normal file
144
assert/assert_rejects.ts
Normal file
@ -0,0 +1,144 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
import { assertIsError } from "./assert_is_error.ts";
|
||||
|
||||
/**
|
||||
* Executes a function which returns a promise, expecting it to reject.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assertRejects } from "https://deno.land/std@$STD_VERSION/assert/assert_rejects.ts";
|
||||
*
|
||||
* Deno.test("doesThrow", async function () {
|
||||
* await assertRejects(
|
||||
* async () => {
|
||||
* throw new TypeError("hello world!");
|
||||
* },
|
||||
* );
|
||||
* await assertRejects(
|
||||
* async () => {
|
||||
* return Promise.reject(new Error());
|
||||
* },
|
||||
* );
|
||||
* });
|
||||
*
|
||||
* // This test will not pass.
|
||||
* Deno.test("fails", async function () {
|
||||
* await assertRejects(
|
||||
* async () => {
|
||||
* console.log("Hello world");
|
||||
* },
|
||||
* );
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function assertRejects(
|
||||
fn: () => PromiseLike<unknown>,
|
||||
msg?: string,
|
||||
): Promise<unknown>;
|
||||
/**
|
||||
* Executes a function which returns a promise, expecting it to reject.
|
||||
* If it does not, then it throws. An error class and a string that should be
|
||||
* included in the error message can also be asserted.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assertRejects } from "https://deno.land/std@$STD_VERSION/assert/assert_rejects.ts";
|
||||
*
|
||||
* Deno.test("doesThrow", async function () {
|
||||
* await assertRejects(async () => {
|
||||
* throw new TypeError("hello world!");
|
||||
* }, TypeError);
|
||||
* await assertRejects(
|
||||
* async () => {
|
||||
* throw new TypeError("hello world!");
|
||||
* },
|
||||
* TypeError,
|
||||
* "hello",
|
||||
* );
|
||||
* });
|
||||
*
|
||||
* // This test will not pass.
|
||||
* Deno.test("fails", async function () {
|
||||
* await assertRejects(
|
||||
* async () => {
|
||||
* console.log("Hello world");
|
||||
* },
|
||||
* );
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function assertRejects<E extends Error = Error>(
|
||||
fn: () => PromiseLike<unknown>,
|
||||
// deno-lint-ignore no-explicit-any
|
||||
ErrorClass: new (...args: any[]) => E,
|
||||
msgIncludes?: string,
|
||||
msg?: string,
|
||||
): Promise<E>;
|
||||
export async function assertRejects<E extends Error = Error>(
|
||||
fn: () => PromiseLike<unknown>,
|
||||
errorClassOrMsg?:
|
||||
// deno-lint-ignore no-explicit-any
|
||||
| (new (...args: any[]) => E)
|
||||
| string,
|
||||
msgIncludesOrMsg?: string,
|
||||
msg?: string,
|
||||
): Promise<E | Error | unknown> {
|
||||
// deno-lint-ignore no-explicit-any
|
||||
let ErrorClass: (new (...args: any[]) => E) | undefined = undefined;
|
||||
let msgIncludes: string | undefined = undefined;
|
||||
let err;
|
||||
|
||||
if (typeof errorClassOrMsg !== "string") {
|
||||
if (
|
||||
errorClassOrMsg === undefined ||
|
||||
errorClassOrMsg.prototype instanceof Error ||
|
||||
errorClassOrMsg.prototype === Error.prototype
|
||||
) {
|
||||
// deno-lint-ignore no-explicit-any
|
||||
ErrorClass = errorClassOrMsg as new (...args: any[]) => E;
|
||||
msgIncludes = msgIncludesOrMsg;
|
||||
}
|
||||
} else {
|
||||
msg = errorClassOrMsg;
|
||||
}
|
||||
let doesThrow = false;
|
||||
let isPromiseReturned = false;
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
try {
|
||||
const possiblePromise = fn();
|
||||
if (
|
||||
possiblePromise &&
|
||||
typeof possiblePromise === "object" &&
|
||||
typeof possiblePromise.then === "function"
|
||||
) {
|
||||
isPromiseReturned = true;
|
||||
await possiblePromise;
|
||||
}
|
||||
} catch (error) {
|
||||
if (!isPromiseReturned) {
|
||||
throw new AssertionError(
|
||||
`Function throws when expected to reject${msgSuffix}`,
|
||||
);
|
||||
}
|
||||
if (ErrorClass) {
|
||||
if (error instanceof Error === false) {
|
||||
throw new AssertionError(`A non-Error object was rejected${msgSuffix}`);
|
||||
}
|
||||
assertIsError(
|
||||
error,
|
||||
ErrorClass,
|
||||
msgIncludes,
|
||||
msg,
|
||||
);
|
||||
}
|
||||
err = error;
|
||||
doesThrow = true;
|
||||
}
|
||||
if (!doesThrow) {
|
||||
throw new AssertionError(
|
||||
`Expected function to reject${msgSuffix}`,
|
||||
);
|
||||
}
|
||||
return err;
|
||||
}
|
109
assert/assert_rejects_test.ts
Normal file
109
assert/assert_rejects_test.ts
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, assertEquals, AssertionError, assertRejects } from "./mod.ts";
|
||||
|
||||
Deno.test("assertRejects with return type", async () => {
|
||||
await assertRejects(() => {
|
||||
return Promise.reject(new Error());
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test("assertRejects with synchronous function that throws", async () => {
|
||||
await assertRejects(() =>
|
||||
assertRejects(() => {
|
||||
throw new Error();
|
||||
})
|
||||
);
|
||||
await assertRejects(
|
||||
() =>
|
||||
assertRejects(() => {
|
||||
throw { wrong: "true" };
|
||||
}),
|
||||
AssertionError,
|
||||
"Function throws when expected to reject.",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("assertRejects with PromiseLike", async () => {
|
||||
await assertRejects(
|
||||
() => ({
|
||||
then() {
|
||||
throw new Error("some error");
|
||||
},
|
||||
}),
|
||||
Error,
|
||||
"some error",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("assertRejects with non-error value rejected and error class", async () => {
|
||||
await assertRejects(
|
||||
() => {
|
||||
return assertRejects(
|
||||
() => {
|
||||
return Promise.reject("Panic!");
|
||||
},
|
||||
Error,
|
||||
"Panic!",
|
||||
);
|
||||
},
|
||||
AssertionError,
|
||||
"A non-Error object was rejected.",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("assertRejects with non-error value rejected", async () => {
|
||||
await assertRejects(() => {
|
||||
return Promise.reject(null);
|
||||
});
|
||||
await assertRejects(() => {
|
||||
return Promise.reject(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test("assertRejects with error class", async () => {
|
||||
await assertRejects(
|
||||
() => {
|
||||
return Promise.reject(new Error("foo"));
|
||||
},
|
||||
Error,
|
||||
"foo",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("assertRejects resolves with caught error", async () => {
|
||||
const error = await assertRejects(
|
||||
() => {
|
||||
return Promise.reject(new Error("foo"));
|
||||
},
|
||||
);
|
||||
assert(error instanceof Error);
|
||||
assertEquals(error.message, "foo");
|
||||
});
|
||||
|
||||
Deno.test("Assert Throws Async Parent Error", async () => {
|
||||
await assertRejects(
|
||||
() => {
|
||||
return Promise.reject(new AssertionError("Fail!"));
|
||||
},
|
||||
Error,
|
||||
"Fail!",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test(
|
||||
"Assert Throws Async promise rejected with custom Error",
|
||||
async () => {
|
||||
class CustomError extends Error {}
|
||||
class AnotherCustomError extends Error {}
|
||||
await assertRejects(
|
||||
() =>
|
||||
assertRejects(
|
||||
() => Promise.reject(new AnotherCustomError("failed")),
|
||||
CustomError,
|
||||
"fail",
|
||||
),
|
||||
AssertionError,
|
||||
'Expected error to be instance of "CustomError", but was "AnotherCustomError".',
|
||||
);
|
||||
},
|
||||
);
|
69
assert/assert_strict_equals.ts
Normal file
69
assert/assert_strict_equals.ts
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { format } from "./_format.ts";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
import { buildMessage, diff, diffstr } from "../_util/diff.ts";
|
||||
import { CAN_NOT_DISPLAY } from "./_constants.ts";
|
||||
import { red } from "../fmt/colors.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that `actual` and `expected` are strictly equal. If
|
||||
* not then throw.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assertStrictEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_strict_equals.ts";
|
||||
*
|
||||
* Deno.test("isStrictlyEqual", function (): void {
|
||||
* const a = {};
|
||||
* const b = a;
|
||||
* assertStrictEquals(a, b);
|
||||
* });
|
||||
*
|
||||
* // This test fails
|
||||
* Deno.test("isNotStrictlyEqual", function (): void {
|
||||
* const a = {};
|
||||
* const b = {};
|
||||
* assertStrictEquals(a, b);
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function assertStrictEquals<T>(
|
||||
actual: unknown,
|
||||
expected: T,
|
||||
msg?: string,
|
||||
): asserts actual is T {
|
||||
if (Object.is(actual, expected)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
let message: string;
|
||||
|
||||
const actualString = format(actual);
|
||||
const expectedString = format(expected);
|
||||
|
||||
if (actualString === expectedString) {
|
||||
const withOffset = actualString
|
||||
.split("\n")
|
||||
.map((l) => ` ${l}`)
|
||||
.join("\n");
|
||||
message =
|
||||
`Values have the same structure but are not reference-equal${msgSuffix}\n\n${
|
||||
red(withOffset)
|
||||
}\n`;
|
||||
} else {
|
||||
try {
|
||||
const stringDiff = (typeof actual === "string") &&
|
||||
(typeof expected === "string");
|
||||
const diffResult = stringDiff
|
||||
? diffstr(actual as string, expected as string)
|
||||
: diff(actualString.split("\n"), expectedString.split("\n"));
|
||||
const diffMsg = buildMessage(diffResult, { stringDiff }).join("\n");
|
||||
message = `Values are not strictly equal${msgSuffix}\n${diffMsg}`;
|
||||
} catch {
|
||||
message = `\n${red(CAN_NOT_DISPLAY)} + \n\n`;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError(message);
|
||||
}
|
93
assert/assert_strict_equals_test.ts
Normal file
93
assert/assert_strict_equals_test.ts
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError, assertStrictEquals, assertThrows } from "./mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "strict types test",
|
||||
fn() {
|
||||
const x = { number: 2 };
|
||||
|
||||
const y = x as Record<never, never>;
|
||||
const z = x as unknown;
|
||||
|
||||
// y.number;
|
||||
// ~~~~~~
|
||||
// Property 'number' does not exist on type 'Record<never, never>'.deno-ts(2339)
|
||||
|
||||
assertStrictEquals(y, x);
|
||||
y.number; // ok
|
||||
|
||||
// z.number;
|
||||
// ~
|
||||
// Object is of type 'unknown'.deno-ts(2571)
|
||||
|
||||
assertStrictEquals(z, x);
|
||||
z.number; // ok
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "strict pass case",
|
||||
fn() {
|
||||
assertStrictEquals(true, true);
|
||||
assertStrictEquals(10, 10);
|
||||
assertStrictEquals("abc", "abc");
|
||||
assertStrictEquals(NaN, NaN);
|
||||
|
||||
const xs = [1, false, "foo"];
|
||||
const ys = xs;
|
||||
assertStrictEquals(xs, ys);
|
||||
|
||||
const x = { a: 1 };
|
||||
const y = x;
|
||||
assertStrictEquals(x, y);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "strict failed with structure diff",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => assertStrictEquals({ a: 1, b: 2 }, { a: 1, c: [3] }),
|
||||
AssertionError,
|
||||
`
|
||||
{
|
||||
a: 1,
|
||||
+ c: [
|
||||
+ 3,
|
||||
+ ],
|
||||
- b: 2,
|
||||
}`,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "strict failed with reference diff",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => assertStrictEquals({ a: 1, b: 2 }, { a: 1, b: 2 }),
|
||||
AssertionError,
|
||||
`Values have the same structure but are not reference-equal.
|
||||
|
||||
{
|
||||
a: 1,
|
||||
b: 2,
|
||||
}`,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "strict failed with custom msg",
|
||||
fn() {
|
||||
assertThrows(
|
||||
() => assertStrictEquals({ a: 1 }, { a: 1 }, "CUSTOM MESSAGE"),
|
||||
AssertionError,
|
||||
`Values have the same structure but are not reference-equal: CUSTOM MESSAGE
|
||||
|
||||
{
|
||||
a: 1,
|
||||
}`,
|
||||
);
|
||||
},
|
||||
});
|
18
assert/assert_string_includes.ts
Normal file
18
assert/assert_string_includes.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Make an assertion that actual includes expected. If not
|
||||
* then throw.
|
||||
*/
|
||||
export function assertStringIncludes(
|
||||
actual: string,
|
||||
expected: string,
|
||||
msg?: string,
|
||||
) {
|
||||
if (!actual.includes(expected)) {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
msg = `Expected actual: "${actual}" to contain: "${expected}"${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
}
|
37
assert/assert_string_includes_test.ts
Normal file
37
assert/assert_string_includes_test.ts
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
AssertionError,
|
||||
assertStringIncludes,
|
||||
} from "./mod.ts";
|
||||
|
||||
Deno.test("AssertStringIncludes", function () {
|
||||
assertStringIncludes("Denosaurus", "saur");
|
||||
assertStringIncludes("Denosaurus", "Deno");
|
||||
assertStringIncludes("Denosaurus", "rus");
|
||||
let didThrow;
|
||||
try {
|
||||
assertStringIncludes("Denosaurus", "Raptor");
|
||||
didThrow = false;
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
didThrow = true;
|
||||
}
|
||||
assertEquals(didThrow, true);
|
||||
});
|
||||
|
||||
Deno.test("AssertStringContainsThrow", function () {
|
||||
let didThrow = false;
|
||||
try {
|
||||
assertStringIncludes("Denosaurus from Jurassic", "Raptor");
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
assert(
|
||||
e.message ===
|
||||
`Expected actual: "Denosaurus from Jurassic" to contain: "Raptor".`,
|
||||
);
|
||||
didThrow = true;
|
||||
}
|
||||
assert(didThrow);
|
||||
});
|
121
assert/assert_throws.ts
Normal file
121
assert/assert_throws.ts
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertIsError } from "./assert_is_error.ts";
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/**
|
||||
* Executes a function, expecting it to throw. If it does not, then it
|
||||
* throws.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assertThrows } from "https://deno.land/std@$STD_VERSION/assert/assert_throws.ts";
|
||||
*
|
||||
* Deno.test("doesThrow", function (): void {
|
||||
* assertThrows((): void => {
|
||||
* throw new TypeError("hello world!");
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* // This test will not pass.
|
||||
* Deno.test("fails", function (): void {
|
||||
* assertThrows((): void => {
|
||||
* console.log("Hello world");
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function assertThrows(
|
||||
fn: () => unknown,
|
||||
msg?: string,
|
||||
): unknown;
|
||||
/**
|
||||
* Executes a function, expecting it to throw. If it does not, then it
|
||||
* throws. An error class and a string that should be included in the
|
||||
* error message can also be asserted.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { assertThrows } from "https://deno.land/std@$STD_VERSION/assert/assert_throws.ts";
|
||||
*
|
||||
* Deno.test("doesThrow", function (): void {
|
||||
* assertThrows((): void => {
|
||||
* throw new TypeError("hello world!");
|
||||
* }, TypeError);
|
||||
* assertThrows(
|
||||
* (): void => {
|
||||
* throw new TypeError("hello world!");
|
||||
* },
|
||||
* TypeError,
|
||||
* "hello",
|
||||
* );
|
||||
* });
|
||||
*
|
||||
* // This test will not pass.
|
||||
* Deno.test("fails", function (): void {
|
||||
* assertThrows((): void => {
|
||||
* console.log("Hello world");
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function assertThrows<E extends Error = Error>(
|
||||
fn: () => unknown,
|
||||
// deno-lint-ignore no-explicit-any
|
||||
ErrorClass: new (...args: any[]) => E,
|
||||
msgIncludes?: string,
|
||||
msg?: string,
|
||||
): E;
|
||||
export function assertThrows<E extends Error = Error>(
|
||||
fn: () => unknown,
|
||||
errorClassOrMsg?:
|
||||
// deno-lint-ignore no-explicit-any
|
||||
| (new (...args: any[]) => E)
|
||||
| string,
|
||||
msgIncludesOrMsg?: string,
|
||||
msg?: string,
|
||||
): E | Error | unknown {
|
||||
// deno-lint-ignore no-explicit-any
|
||||
let ErrorClass: (new (...args: any[]) => E) | undefined = undefined;
|
||||
let msgIncludes: string | undefined = undefined;
|
||||
let err;
|
||||
|
||||
if (typeof errorClassOrMsg !== "string") {
|
||||
if (
|
||||
errorClassOrMsg === undefined ||
|
||||
errorClassOrMsg.prototype instanceof Error ||
|
||||
errorClassOrMsg.prototype === Error.prototype
|
||||
) {
|
||||
// deno-lint-ignore no-explicit-any
|
||||
ErrorClass = errorClassOrMsg as new (...args: any[]) => E;
|
||||
msgIncludes = msgIncludesOrMsg;
|
||||
} else {
|
||||
msg = msgIncludesOrMsg;
|
||||
}
|
||||
} else {
|
||||
msg = errorClassOrMsg;
|
||||
}
|
||||
let doesThrow = false;
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
try {
|
||||
fn();
|
||||
} catch (error) {
|
||||
if (ErrorClass) {
|
||||
if (error instanceof Error === false) {
|
||||
throw new AssertionError(`A non-Error object was thrown${msgSuffix}`);
|
||||
}
|
||||
assertIsError(
|
||||
error,
|
||||
ErrorClass,
|
||||
msgIncludes,
|
||||
msg,
|
||||
);
|
||||
}
|
||||
err = error;
|
||||
doesThrow = true;
|
||||
}
|
||||
if (!doesThrow) {
|
||||
msg = `Expected function to throw${msgSuffix}`;
|
||||
throw new AssertionError(msg);
|
||||
}
|
||||
return err;
|
||||
}
|
129
assert/assert_throws_test.ts
Normal file
129
assert/assert_throws_test.ts
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assert,
|
||||
assertEquals,
|
||||
AssertionError,
|
||||
assertThrows,
|
||||
fail,
|
||||
} from "./mod.ts";
|
||||
|
||||
Deno.test("assertThrows with wrong error class", () => {
|
||||
assertThrows(
|
||||
() => {
|
||||
//This next assertThrows will throw an AssertionError due to the wrong
|
||||
//expected error class
|
||||
assertThrows(
|
||||
() => {
|
||||
fail("foo");
|
||||
},
|
||||
TypeError,
|
||||
"Failed assertion: foo",
|
||||
);
|
||||
},
|
||||
AssertionError,
|
||||
`Expected error to be instance of "TypeError", but was "AssertionError"`,
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("assertThrows with return type", () => {
|
||||
assertThrows(() => {
|
||||
throw new Error();
|
||||
});
|
||||
});
|
||||
|
||||
Deno.test("assertThrows with non-error value thrown and error class", () => {
|
||||
assertThrows(
|
||||
() => {
|
||||
assertThrows(
|
||||
() => {
|
||||
throw "Panic!";
|
||||
},
|
||||
Error,
|
||||
"Panic!",
|
||||
);
|
||||
},
|
||||
AssertionError,
|
||||
"A non-Error object was thrown.",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("assertThrows with non-error value thrown", () => {
|
||||
assertThrows(
|
||||
() => {
|
||||
throw "Panic!";
|
||||
},
|
||||
);
|
||||
assertThrows(
|
||||
() => {
|
||||
throw null;
|
||||
},
|
||||
);
|
||||
assertThrows(
|
||||
() => {
|
||||
throw undefined;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("assertThrows with error class", () => {
|
||||
assertThrows(
|
||||
() => {
|
||||
throw new Error("foo");
|
||||
},
|
||||
Error,
|
||||
"foo",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("assertThrows with thrown error returns caught error", () => {
|
||||
const error = assertThrows(
|
||||
() => {
|
||||
throw new Error("foo");
|
||||
},
|
||||
);
|
||||
assert(error instanceof Error);
|
||||
assertEquals(error.message, "foo");
|
||||
});
|
||||
|
||||
Deno.test("assertThrows with thrown non-error returns caught error", () => {
|
||||
const stringError = assertThrows(
|
||||
() => {
|
||||
throw "Panic!";
|
||||
},
|
||||
);
|
||||
assert(typeof stringError === "string");
|
||||
assertEquals(stringError, "Panic!");
|
||||
|
||||
const numberError = assertThrows(
|
||||
() => {
|
||||
throw 1;
|
||||
},
|
||||
);
|
||||
assert(typeof numberError === "number");
|
||||
assertEquals(numberError, 1);
|
||||
|
||||
const nullError = assertThrows(
|
||||
() => {
|
||||
throw null;
|
||||
},
|
||||
);
|
||||
assert(nullError === null);
|
||||
|
||||
const undefinedError = assertThrows(
|
||||
() => {
|
||||
throw undefined;
|
||||
},
|
||||
);
|
||||
assert(typeof undefinedError === "undefined");
|
||||
assertEquals(undefinedError, undefined);
|
||||
});
|
||||
|
||||
Deno.test("Assert Throws Parent Error", () => {
|
||||
assertThrows(
|
||||
() => {
|
||||
throw new AssertionError("Fail!");
|
||||
},
|
||||
Error,
|
||||
"Fail!",
|
||||
);
|
||||
});
|
7
assert/assertion_error.ts
Normal file
7
assert/assertion_error.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
export class AssertionError extends Error {
|
||||
override name = "AssertionError";
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
}
|
||||
}
|
111
assert/equal.ts
Normal file
111
assert/equal.ts
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
function isKeyedCollection(x: unknown): x is Set<unknown> {
|
||||
return [Symbol.iterator, "size"].every((k) => k in (x as Set<unknown>));
|
||||
}
|
||||
|
||||
function constructorsEqual(a: object, b: object) {
|
||||
return a.constructor === b.constructor ||
|
||||
a.constructor === Object && !b.constructor ||
|
||||
!a.constructor && b.constructor === Object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep equality comparison used in assertions
|
||||
* @param c actual value
|
||||
* @param d expected value
|
||||
*/
|
||||
export function equal(c: unknown, d: unknown): boolean {
|
||||
const seen = new Map();
|
||||
return (function compare(a: unknown, b: unknown): boolean {
|
||||
// Have to render RegExp & Date for string comparison
|
||||
// unless it's mistreated as object
|
||||
if (
|
||||
a &&
|
||||
b &&
|
||||
((a instanceof RegExp && b instanceof RegExp) ||
|
||||
(a instanceof URL && b instanceof URL))
|
||||
) {
|
||||
return String(a) === String(b);
|
||||
}
|
||||
if (a instanceof Date && b instanceof Date) {
|
||||
const aTime = a.getTime();
|
||||
const bTime = b.getTime();
|
||||
// Check for NaN equality manually since NaN is not
|
||||
// equal to itself.
|
||||
if (Number.isNaN(aTime) && Number.isNaN(bTime)) {
|
||||
return true;
|
||||
}
|
||||
return aTime === bTime;
|
||||
}
|
||||
if (typeof a === "number" && typeof b === "number") {
|
||||
return Number.isNaN(a) && Number.isNaN(b) || a === b;
|
||||
}
|
||||
if (Object.is(a, b)) {
|
||||
return true;
|
||||
}
|
||||
if (a && typeof a === "object" && b && typeof b === "object") {
|
||||
if (a && b && !constructorsEqual(a, b)) {
|
||||
return false;
|
||||
}
|
||||
if (a instanceof WeakMap || b instanceof WeakMap) {
|
||||
if (!(a instanceof WeakMap && b instanceof WeakMap)) return false;
|
||||
throw new TypeError("cannot compare WeakMap instances");
|
||||
}
|
||||
if (a instanceof WeakSet || b instanceof WeakSet) {
|
||||
if (!(a instanceof WeakSet && b instanceof WeakSet)) return false;
|
||||
throw new TypeError("cannot compare WeakSet instances");
|
||||
}
|
||||
if (seen.get(a) === b) {
|
||||
return true;
|
||||
}
|
||||
if (Object.keys(a || {}).length !== Object.keys(b || {}).length) {
|
||||
return false;
|
||||
}
|
||||
seen.set(a, b);
|
||||
if (isKeyedCollection(a) && isKeyedCollection(b)) {
|
||||
if (a.size !== b.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let unmatchedEntries = a.size;
|
||||
|
||||
for (const [aKey, aValue] of a.entries()) {
|
||||
for (const [bKey, bValue] of b.entries()) {
|
||||
/* Given that Map keys can be references, we need
|
||||
* to ensure that they are also deeply equal */
|
||||
if (
|
||||
(aKey === aValue && bKey === bValue && compare(aKey, bKey)) ||
|
||||
(compare(aKey, bKey) && compare(aValue, bValue))
|
||||
) {
|
||||
unmatchedEntries--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return unmatchedEntries === 0;
|
||||
}
|
||||
const merged = { ...a, ...b };
|
||||
for (
|
||||
const key of [
|
||||
...Object.getOwnPropertyNames(merged),
|
||||
...Object.getOwnPropertySymbols(merged),
|
||||
]
|
||||
) {
|
||||
type Key = keyof typeof merged;
|
||||
if (!compare(a && a[key as Key], b && b[key as Key])) {
|
||||
return false;
|
||||
}
|
||||
if (((key in a) && (!(key in b))) || ((key in b) && (!(key in a)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (a instanceof WeakRef || b instanceof WeakRef) {
|
||||
if (!(a instanceof WeakRef && b instanceof WeakRef)) return false;
|
||||
return compare(a.deref(), b.deref());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})(c, d);
|
||||
}
|
266
assert/equal_test.ts
Normal file
266
assert/equal_test.ts
Normal file
@ -0,0 +1,266 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, assertFalse, assertThrows, equal } from "./mod.ts";
|
||||
|
||||
Deno.test("EqualDifferentZero", () => {
|
||||
assert(equal(0, -0));
|
||||
assert(equal(0, +0));
|
||||
assert(equal(+0, -0));
|
||||
assert(equal([0], [-0]));
|
||||
assert(equal(["hello", 12.21, 0], ["hello", 12.21, -0]));
|
||||
assert(equal(["hello", 12.21, 0], ["hello", 12.21, +0]));
|
||||
assert(equal(["hello", 12.21, -0], ["hello", 12.21, +0]));
|
||||
assert(equal({ msg: "hello", case: 0 }, { msg: "hello", case: -0 }));
|
||||
assert(equal({ msg: "hello", array: [0] }, { msg: "hello", array: [-0] }));
|
||||
});
|
||||
|
||||
Deno.test("Equal", function () {
|
||||
assert(equal("world", "world"));
|
||||
assert(!equal("hello", "world"));
|
||||
assertFalse(equal("hello", "world"));
|
||||
assert(equal(5, 5));
|
||||
assert(!equal(5, 6));
|
||||
assertFalse(equal(5, 6));
|
||||
assert(equal(NaN, NaN));
|
||||
assert(equal({ hello: "world" }, { hello: "world" }));
|
||||
assert(!equal({ world: "hello" }, { hello: "world" }));
|
||||
assertFalse(equal({ world: "hello" }, { hello: "world" }));
|
||||
assert(
|
||||
equal(
|
||||
{ hello: "world", hi: { there: "everyone" } },
|
||||
{ hello: "world", hi: { there: "everyone" } },
|
||||
),
|
||||
);
|
||||
assert(
|
||||
!equal(
|
||||
{ hello: "world", hi: { there: "everyone" } },
|
||||
{ hello: "world", hi: { there: "everyone else" } },
|
||||
),
|
||||
);
|
||||
assertFalse(
|
||||
equal(
|
||||
{ hello: "world", hi: { there: "everyone" } },
|
||||
{ hello: "world", hi: { there: "everyone else" } },
|
||||
),
|
||||
);
|
||||
assert(equal({ [Symbol.for("foo")]: "bar" }, { [Symbol.for("foo")]: "bar" }));
|
||||
assert(!equal({ [Symbol("foo")]: "bar" }, { [Symbol("foo")]: "bar" }));
|
||||
assertFalse(equal({ [Symbol("foo")]: "bar" }, { [Symbol("foo")]: "bar" }));
|
||||
|
||||
assert(equal(/deno/, /deno/));
|
||||
assert(!equal(/deno/, /node/));
|
||||
assertFalse(equal(/deno/, /node/));
|
||||
assert(equal(new Date(2019, 0, 3), new Date(2019, 0, 3)));
|
||||
assert(!equal(new Date(2019, 0, 3), new Date(2019, 1, 3)));
|
||||
assertFalse(equal(new Date(2019, 0, 3), new Date(2019, 1, 3)));
|
||||
assert(
|
||||
!equal(
|
||||
new Date(2019, 0, 3, 4, 20, 1, 10),
|
||||
new Date(2019, 0, 3, 4, 20, 1, 20),
|
||||
),
|
||||
);
|
||||
assertFalse(
|
||||
equal(
|
||||
new Date(2019, 0, 3, 4, 20, 1, 10),
|
||||
new Date(2019, 0, 3, 4, 20, 1, 20),
|
||||
),
|
||||
);
|
||||
assert(equal(new Date("Invalid"), new Date("Invalid")));
|
||||
assert(!equal(new Date("Invalid"), new Date(2019, 0, 3)));
|
||||
assertFalse(equal(new Date("Invalid"), new Date(2019, 0, 3)));
|
||||
assert(!equal(new Date("Invalid"), new Date(2019, 0, 3, 4, 20, 1, 10)));
|
||||
assertFalse(equal(new Date("Invalid"), new Date(2019, 0, 3, 4, 20, 1, 10)));
|
||||
assert(equal(new Set([1]), new Set([1])));
|
||||
assert(!equal(new Set([1]), new Set([2])));
|
||||
assertFalse(equal(new Set([1]), new Set([2])));
|
||||
assert(equal(new Set([1, 2, 3]), new Set([3, 2, 1])));
|
||||
assert(equal(new Set([1, new Set([2, 3])]), new Set([new Set([3, 2]), 1])));
|
||||
assert(!equal(new Set([1, 2]), new Set([3, 2, 1])));
|
||||
assertFalse(equal(new Set([1, 2]), new Set([3, 2, 1])));
|
||||
assert(!equal(new Set([1, 2, 3]), new Set([4, 5, 6])));
|
||||
assertFalse(equal(new Set([1, 2, 3]), new Set([4, 5, 6])));
|
||||
assert(equal(new Set("denosaurus"), new Set("denosaurussss")));
|
||||
assert(equal(new Map(), new Map()));
|
||||
assert(
|
||||
equal(
|
||||
new Map([
|
||||
["foo", "bar"],
|
||||
["baz", "baz"],
|
||||
]),
|
||||
new Map([
|
||||
["foo", "bar"],
|
||||
["baz", "baz"],
|
||||
]),
|
||||
),
|
||||
);
|
||||
assert(
|
||||
equal(
|
||||
new Map([["foo", new Map([["bar", "baz"]])]]),
|
||||
new Map([["foo", new Map([["bar", "baz"]])]]),
|
||||
),
|
||||
);
|
||||
assert(
|
||||
equal(
|
||||
new Map([["foo", { bar: "baz" }]]),
|
||||
new Map([["foo", { bar: "baz" }]]),
|
||||
),
|
||||
);
|
||||
assert(
|
||||
equal(
|
||||
new Map([
|
||||
["foo", "bar"],
|
||||
["baz", "qux"],
|
||||
]),
|
||||
new Map([
|
||||
["baz", "qux"],
|
||||
["foo", "bar"],
|
||||
]),
|
||||
),
|
||||
);
|
||||
assert(equal(new Map([["foo", ["bar"]]]), new Map([["foo", ["bar"]]])));
|
||||
assert(!equal(new Map([["foo", "bar"]]), new Map([["bar", "baz"]])));
|
||||
assertFalse(equal(new Map([["foo", "bar"]]), new Map([["bar", "baz"]])));
|
||||
assertFalse(equal(new Map([["foo", "bar"]]), new Map([["bar", "baz"]])));
|
||||
assert(
|
||||
!equal(
|
||||
new Map([["foo", "bar"]]),
|
||||
new Map([
|
||||
["foo", "bar"],
|
||||
["bar", "baz"],
|
||||
]),
|
||||
),
|
||||
);
|
||||
assertFalse(
|
||||
equal(
|
||||
new Map([["foo", "bar"]]),
|
||||
new Map([
|
||||
["foo", "bar"],
|
||||
["bar", "baz"],
|
||||
]),
|
||||
),
|
||||
);
|
||||
assert(
|
||||
!equal(
|
||||
new Map([["foo", new Map([["bar", "baz"]])]]),
|
||||
new Map([["foo", new Map([["bar", "qux"]])]]),
|
||||
),
|
||||
);
|
||||
assert(equal(new Map([[{ x: 1 }, true]]), new Map([[{ x: 1 }, true]])));
|
||||
assert(!equal(new Map([[{ x: 1 }, true]]), new Map([[{ x: 1 }, false]])));
|
||||
assertFalse(equal(new Map([[{ x: 1 }, true]]), new Map([[{ x: 1 }, false]])));
|
||||
assert(!equal(new Map([[{ x: 1 }, true]]), new Map([[{ x: 2 }, true]])));
|
||||
assertFalse(equal(new Map([[{ x: 1 }, true]]), new Map([[{ x: 2 }, true]])));
|
||||
assert(equal([1, 2, 3], [1, 2, 3]));
|
||||
assert(equal([1, [2, 3]], [1, [2, 3]]));
|
||||
assert(!equal([1, 2, 3, 4], [1, 2, 3]));
|
||||
assertFalse(equal([1, 2, 3, 4], [1, 2, 3]));
|
||||
assert(!equal([1, 2, 3, 4], [1, 2, 3]));
|
||||
assertFalse(equal([1, 2, 3, 4], [1, 2, 3]));
|
||||
assert(!equal([1, 2, 3, 4], [1, 4, 2, 3]));
|
||||
assertFalse(equal([1, 2, 3, 4], [1, 4, 2, 3]));
|
||||
assert(equal(new Uint8Array([1, 2, 3, 4]), new Uint8Array([1, 2, 3, 4])));
|
||||
assert(!equal(new Uint8Array([1, 2, 3, 4]), new Uint8Array([2, 1, 4, 3])));
|
||||
assertFalse(
|
||||
equal(new Uint8Array([1, 2, 3, 4]), new Uint8Array([2, 1, 4, 3])),
|
||||
);
|
||||
assert(
|
||||
equal(new URL("https://example.test"), new URL("https://example.test")),
|
||||
);
|
||||
assert(
|
||||
!equal(
|
||||
new URL("https://example.test"),
|
||||
new URL("https://example.test/with-path"),
|
||||
),
|
||||
);
|
||||
assertFalse(
|
||||
equal(
|
||||
new URL("https://example.test"),
|
||||
new URL("https://example.test/with-path"),
|
||||
),
|
||||
);
|
||||
assert(
|
||||
!equal({ a: undefined, b: undefined }, { a: undefined, c: undefined }),
|
||||
);
|
||||
assertFalse(
|
||||
equal({ a: undefined, b: undefined }, { a: undefined, c: undefined }),
|
||||
);
|
||||
assertFalse(equal({ a: undefined, b: undefined }, { a: undefined }));
|
||||
assertThrows(() => equal(new WeakMap(), new WeakMap()));
|
||||
assertThrows(() => equal(new WeakSet(), new WeakSet()));
|
||||
assert(!equal(new WeakMap(), new WeakSet()));
|
||||
assertFalse(equal(new WeakMap(), new WeakSet()));
|
||||
assert(
|
||||
equal(new WeakRef({ hello: "world" }), new WeakRef({ hello: "world" })),
|
||||
);
|
||||
assert(
|
||||
!equal(new WeakRef({ world: "hello" }), new WeakRef({ hello: "world" })),
|
||||
);
|
||||
assertFalse(
|
||||
equal(new WeakRef({ world: "hello" }), new WeakRef({ hello: "world" })),
|
||||
);
|
||||
assert(!equal({ hello: "world" }, new WeakRef({ hello: "world" })));
|
||||
assertFalse(equal({ hello: "world" }, new WeakRef({ hello: "world" })));
|
||||
assert(
|
||||
!equal(
|
||||
new WeakRef({ hello: "world" }),
|
||||
new (class<T extends object> extends WeakRef<T> {})({ hello: "world" }),
|
||||
),
|
||||
);
|
||||
assertFalse(
|
||||
equal(
|
||||
new WeakRef({ hello: "world" }),
|
||||
new (class<T extends object> extends WeakRef<T> {})({ hello: "world" }),
|
||||
),
|
||||
);
|
||||
assert(
|
||||
!equal(
|
||||
new WeakRef({ hello: "world" }),
|
||||
new (class<T extends object> extends WeakRef<T> {
|
||||
foo = "bar";
|
||||
})({ hello: "world" }),
|
||||
),
|
||||
);
|
||||
assertFalse(
|
||||
equal(
|
||||
new WeakRef({ hello: "world" }),
|
||||
new (class<T extends object> extends WeakRef<T> {
|
||||
foo = "bar";
|
||||
})({ hello: "world" }),
|
||||
),
|
||||
);
|
||||
|
||||
assert(
|
||||
!equal(
|
||||
new (class A {
|
||||
#hello = "world";
|
||||
})(),
|
||||
new (class B {
|
||||
#hello = "world";
|
||||
})(),
|
||||
),
|
||||
);
|
||||
|
||||
assertFalse(
|
||||
equal(
|
||||
new (class A {
|
||||
#hello = "world";
|
||||
})(),
|
||||
new (class B {
|
||||
#hello = "world";
|
||||
})(),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("EqualCircular", () => {
|
||||
const objA: { prop?: unknown } = {};
|
||||
objA.prop = objA;
|
||||
const objB: { prop?: unknown } = {};
|
||||
objB.prop = objB;
|
||||
assert(equal(objA, objB));
|
||||
|
||||
const mapA = new Map();
|
||||
mapA.set("prop", mapA);
|
||||
const mapB = new Map();
|
||||
mapB.set("prop", mapB);
|
||||
assert(equal(mapA, mapB));
|
||||
});
|
10
assert/fail.ts
Normal file
10
assert/fail.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert } from "./assert.ts";
|
||||
|
||||
/**
|
||||
* Forcefully throws a failed assertion
|
||||
*/
|
||||
export function fail(msg?: string): never {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
assert(false, `Failed assertion${msgSuffix}`);
|
||||
}
|
13
assert/fail_test.ts
Normal file
13
assert/fail_test.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError, assertThrows, fail } from "./mod.ts";
|
||||
|
||||
Deno.test("AssertFail", function () {
|
||||
assertThrows(fail, AssertionError, "Failed assertion.");
|
||||
assertThrows(
|
||||
() => {
|
||||
fail("foo");
|
||||
},
|
||||
AssertionError,
|
||||
"Failed assertion: foo",
|
||||
);
|
||||
});
|
35
assert/mod.ts
Normal file
35
assert/mod.ts
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
/** A library of assertion functions.
|
||||
* If the assertion is false an `AssertionError` will be thrown which will
|
||||
* result in pretty-printed diff of failing assertion.
|
||||
*
|
||||
* This module is browser compatible, but do not rely on good formatting of
|
||||
* values for AssertionError messages in browsers.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
export * from "./assert_almost_equals.ts";
|
||||
export * from "./assert_array_includes.ts";
|
||||
export * from "./assert_equals.ts";
|
||||
export * from "./assert_exists.ts";
|
||||
export * from "./assert_false.ts";
|
||||
export * from "./assert_instance_of.ts";
|
||||
export * from "./assert_is_error.ts";
|
||||
export * from "./assert_match.ts";
|
||||
export * from "./assert_not_equals.ts";
|
||||
export * from "./assert_not_instance_of.ts";
|
||||
export * from "./assert_not_match.ts";
|
||||
export * from "./assert_not_strict_equals.ts";
|
||||
export * from "./assert_object_match.ts";
|
||||
export * from "./assert_rejects.ts";
|
||||
export * from "./assert_strict_equals.ts";
|
||||
export * from "./assert_string_includes.ts";
|
||||
export * from "./assert_throws.ts";
|
||||
export * from "./assert.ts";
|
||||
export * from "./assertion_error.ts";
|
||||
export * from "./equal.ts";
|
||||
export * from "./fail.ts";
|
||||
export * from "./unimplemented.ts";
|
||||
export * from "./unreachable.ts";
|
20
assert/shared_test.ts
Normal file
20
assert/shared_test.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertArrayIncludes,
|
||||
assertEquals,
|
||||
assertNotEquals,
|
||||
assertNotStrictEquals,
|
||||
assertStrictEquals,
|
||||
} from "./mod.ts";
|
||||
|
||||
Deno.test({
|
||||
name: "assert* functions with specified type parameter",
|
||||
fn() {
|
||||
assertEquals<string>("hello", "hello");
|
||||
assertNotEquals<number>(1, 2);
|
||||
assertArrayIncludes<boolean>([true, false], [true]);
|
||||
const value = { x: 1 };
|
||||
assertStrictEquals<typeof value>(value, value);
|
||||
assertNotStrictEquals<object>(value, { x: 1 });
|
||||
},
|
||||
});
|
8
assert/unimplemented.ts
Normal file
8
assert/unimplemented.ts
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/** Use this to stub out methods that will throw when invoked. */
|
||||
export function unimplemented(msg?: string): never {
|
||||
const msgSuffix = msg ? `: ${msg}` : ".";
|
||||
throw new AssertionError(`Unimplemented${msgSuffix}`);
|
||||
}
|
14
assert/unimplemented_test.ts
Normal file
14
assert/unimplemented_test.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, AssertionError, unimplemented } from "./mod.ts";
|
||||
|
||||
Deno.test("AssertsUnimplemented", function () {
|
||||
let didThrow = false;
|
||||
try {
|
||||
unimplemented();
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
assert(e.message === "Unimplemented.");
|
||||
didThrow = true;
|
||||
}
|
||||
assert(didThrow);
|
||||
});
|
7
assert/unreachable.ts
Normal file
7
assert/unreachable.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { AssertionError } from "./assertion_error.ts";
|
||||
|
||||
/** Use this to assert unreachable code. */
|
||||
export function unreachable(): never {
|
||||
throw new AssertionError("unreachable");
|
||||
}
|
14
assert/unreachable_test.ts
Normal file
14
assert/unreachable_test.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, AssertionError, unreachable } from "./mod.ts";
|
||||
|
||||
Deno.test("AssertsUnreachable", function () {
|
||||
let didThrow = false;
|
||||
try {
|
||||
unreachable();
|
||||
} catch (e) {
|
||||
assert(e instanceof AssertionError);
|
||||
assert(e.message === "unreachable");
|
||||
didThrow = true;
|
||||
}
|
||||
assert(didThrow);
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, assertRejects } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertRejects } from "../assert/mod.ts";
|
||||
import { deferred } from "./deferred.ts";
|
||||
import { abortable } from "./abortable.ts";
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, assertRejects } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertRejects } from "../assert/mod.ts";
|
||||
import { delay } from "./delay.ts";
|
||||
import { deadline, DeadlineError } from "./deadline.ts";
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, assertStrictEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertStrictEquals } from "../assert/mod.ts";
|
||||
import { debounce, DebouncedFunction } from "./debounce.ts";
|
||||
import { delay } from "./delay.ts";
|
||||
|
||||
|
@ -1,9 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import {
|
||||
assertEquals,
|
||||
assertRejects,
|
||||
assertThrows,
|
||||
} from "../testing/asserts.ts";
|
||||
import { assertEquals, assertRejects, assertThrows } from "../assert/mod.ts";
|
||||
import { deferred } from "./deferred.ts";
|
||||
|
||||
Deno.test("[async] deferred: resolve", async function () {
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { delay } from "./delay.ts";
|
||||
import { assert, assertRejects } from "../testing/asserts.ts";
|
||||
import { assert, assertRejects } from "../assert/mod.ts";
|
||||
|
||||
Deno.test("[async] delay", async function () {
|
||||
const start = new Date();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, assertRejects } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertRejects } from "../assert/mod.ts";
|
||||
import { MuxAsyncIterator } from "./mux_async_iterator.ts";
|
||||
|
||||
async function* gen123(): AsyncIterableIterator<number> {
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
assertEquals,
|
||||
assertRejects,
|
||||
assertStringIncludes,
|
||||
} from "../testing/asserts.ts";
|
||||
} from "../assert/mod.ts";
|
||||
|
||||
Deno.test("[async] pooledMap", async function () {
|
||||
const start = new Date();
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
// This module is browser compatible.
|
||||
|
||||
import { assert } from "../_util/asserts.ts";
|
||||
import { assert } from "../assert/assert.ts";
|
||||
|
||||
export class RetryError extends Error {
|
||||
constructor(cause: unknown, attempts: number) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { _exponentialBackoffWithJitter, retry, RetryError } from "./retry.ts";
|
||||
import { assertEquals, assertRejects } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertRejects } from "../assert/mod.ts";
|
||||
import { FakeTime } from "../testing/time.ts";
|
||||
|
||||
function generateErroringFunction(errorsBeforeSucceeds: number) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { tee } from "./tee.ts";
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
|
||||
/** An example async generator */
|
||||
const gen = async function* iter() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, assertThrows } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertThrows } from "../assert/mod.ts";
|
||||
import { BytesList } from "./bytes_list.ts";
|
||||
import * as bytes from "./mod.ts";
|
||||
function setup() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, assertEquals } from "../testing/asserts.ts";
|
||||
import { assert, assertEquals } from "../assert/mod.ts";
|
||||
import { concat } from "./concat.ts";
|
||||
|
||||
Deno.test("[bytes] concat", () => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert, assertEquals } from "../testing/asserts.ts";
|
||||
import { assert, assertEquals } from "../assert/mod.ts";
|
||||
import { copy } from "./copy.ts";
|
||||
|
||||
Deno.test("[bytes] copy", function () {
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { assert } from "../testing/asserts.ts";
|
||||
import { assert } from "../assert/mod.ts";
|
||||
import { endsWith } from "./ends_with.ts";
|
||||
|
||||
Deno.test("[bytes] endsWith", () => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { equals } from "./equals.ts";
|
||||
import { assert } from "../testing/asserts.ts";
|
||||
import { assert } from "../assert/mod.ts";
|
||||
|
||||
Deno.test("[bytes] equals", () => {
|
||||
const v = equals(new Uint8Array([0, 1, 2, 3]), new Uint8Array([0, 1, 2, 3]));
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { includesNeedle } from "./includes_needle.ts";
|
||||
import { assert } from "../testing/asserts.ts";
|
||||
import { assert } from "../assert/mod.ts";
|
||||
|
||||
Deno.test("[bytes] includesNeedle", () => {
|
||||
const encoder = new TextEncoder();
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { indexOfNeedle } from "./index_of_needle.ts";
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
|
||||
Deno.test("[bytes] indexOfNeedle1", () => {
|
||||
const i = indexOfNeedle(
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
import { lastIndexOfNeedle } from "./last_index_of_needle.ts";
|
||||
|
||||
Deno.test("[bytes] lastIndexOfNeedle1", () => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, assertThrows } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertThrows } from "../assert/mod.ts";
|
||||
import { repeat } from "./repeat.ts";
|
||||
|
||||
Deno.test("[bytes] repeat", () => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assert } from "../testing/asserts.ts";
|
||||
import { assert } from "../assert/mod.ts";
|
||||
import { startsWith } from "./starts_with.ts";
|
||||
|
||||
Deno.test("[bytes] startsWith", () => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
import { ascend, descend } from "./_comparators.ts";
|
||||
|
||||
Deno.test("[collections/comparators] ascend", () => {
|
||||
|
@ -10,7 +10,7 @@ import { mapEntries } from "./map_entries.ts";
|
||||
* @example
|
||||
* ```ts
|
||||
* import { aggregateGroups } from "https://deno.land/std@$STD_VERSION/collections/aggregate_groups.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const foodProperties = {
|
||||
* "Curry": ["spicy", "vegan"],
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
import { aggregateGroups } from "./aggregate_groups.ts";
|
||||
|
||||
function aggregateGroupsTest<T, A>(
|
||||
|
@ -9,7 +9,7 @@
|
||||
* @example
|
||||
* ```ts
|
||||
* import { associateBy } from "https://deno.land/std@$STD_VERSION/collections/associate_by.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const users = [
|
||||
* { id: "a2e", userName: "Anna" },
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
import { associateBy } from "./associate_by.ts";
|
||||
|
||||
function associateByTest<T>(
|
||||
|
@ -9,7 +9,7 @@
|
||||
* @example
|
||||
* ```ts
|
||||
* import { associateWith } from "https://deno.land/std@$STD_VERSION/collections/associate_with.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const names = ["Kim", "Lara", "Jonathan"];
|
||||
* const namesToLength = associateWith(names, (it) => it.length);
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
import { associateWith } from "./associate_with.ts";
|
||||
|
||||
function associateWithTest<T>(
|
||||
|
@ -35,7 +35,7 @@ function getParentIndex(index: number) {
|
||||
* BinaryHeap,
|
||||
* descend,
|
||||
* } from "https://deno.land/std@$STD_VERSION/collections/binary_heap.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const maxHeap = new BinaryHeap<number>();
|
||||
* maxHeap.push(4, 1, 3, 5, 2);
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assert } from "../_util/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
import { assert } from "../assert/assert.ts";
|
||||
import { ascend, BinaryHeap, descend } from "./binary_heap.ts";
|
||||
import { Container, MyMath } from "./_test_utils.ts";
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, assertStrictEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertStrictEquals } from "../assert/mod.ts";
|
||||
import { BinarySearchNode } from "./binary_search_node.ts";
|
||||
|
||||
let parent: BinarySearchNode<number>;
|
||||
|
@ -29,7 +29,7 @@ export * from "./_comparators.ts";
|
||||
* BinarySearchTree,
|
||||
* descend,
|
||||
* } from "https://deno.land/std@$STD_VERSION/collections/binary_search_tree.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const values = [3, 10, 13, 4, 6, 7, 1, 14];
|
||||
* const tree = new BinarySearchTree<number>();
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
assertEquals,
|
||||
assertStrictEquals,
|
||||
assertThrows,
|
||||
} from "../testing/asserts.ts";
|
||||
} from "../assert/mod.ts";
|
||||
import { ascend, BinarySearchTree, descend } from "./binary_search_tree.ts";
|
||||
|
||||
class MyMath {
|
||||
|
@ -7,7 +7,7 @@
|
||||
* @example
|
||||
* ```ts
|
||||
* import { chunk } from "https://deno.land/std@$STD_VERSION/collections/chunk.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const words = [
|
||||
* "lorem",
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { assertEquals, assertThrows } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertThrows } from "../assert/mod.ts";
|
||||
import { chunk } from "./chunk.ts";
|
||||
|
||||
function chunkTest<I>(
|
||||
|
@ -16,7 +16,7 @@ const { hasOwn } = Object;
|
||||
* @example
|
||||
* ```ts
|
||||
* import { deepMerge } from "https://deno.land/std@$STD_VERSION/collections/deep_merge.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const a = { foo: true };
|
||||
* const b = { foo: { bar: true } };
|
||||
@ -69,7 +69,7 @@ function deepMergeInternal<
|
||||
>(
|
||||
record: Readonly<T>,
|
||||
other: Readonly<U>,
|
||||
seen: Set<NonNullable<object>>,
|
||||
seen: Set<NonNullable<unknown>>,
|
||||
options?: Readonly<Options>,
|
||||
) {
|
||||
// Extract options
|
||||
@ -119,15 +119,15 @@ function deepMergeInternal<
|
||||
}
|
||||
|
||||
function mergeObjects(
|
||||
left: Readonly<NonNullable<object>>,
|
||||
right: Readonly<NonNullable<object>>,
|
||||
seen: Set<NonNullable<object>>,
|
||||
left: Readonly<NonNullable<Record<string, unknown>>>,
|
||||
right: Readonly<NonNullable<Record<string, unknown>>>,
|
||||
seen: Set<NonNullable<unknown>>,
|
||||
options: Readonly<DeepMergeOptions> = {
|
||||
arrays: "merge",
|
||||
sets: "merge",
|
||||
maps: "merge",
|
||||
},
|
||||
): Readonly<NonNullable<object>> {
|
||||
): Readonly<NonNullable<Record<string, unknown> | Iterable<unknown>>> {
|
||||
// Recursively merge mergeable objects
|
||||
if (isMergeable(left) && isMergeable(right)) {
|
||||
return deepMergeInternal(left, right, seen, options);
|
||||
@ -177,22 +177,24 @@ function mergeObjects(
|
||||
* are not considered mergeable (it means that reference will be copied)
|
||||
*/
|
||||
function isMergeable(
|
||||
value: NonNullable<object>,
|
||||
value: NonNullable<unknown>,
|
||||
): value is Record<PropertyKey, unknown> {
|
||||
return Object.getPrototypeOf(value) === Object.prototype;
|
||||
}
|
||||
|
||||
function isIterable(
|
||||
value: NonNullable<object>,
|
||||
value: NonNullable<unknown>,
|
||||
): value is Iterable<unknown> {
|
||||
return typeof (value as Iterable<unknown>)[Symbol.iterator] === "function";
|
||||
}
|
||||
|
||||
function isNonNullObject(value: unknown): value is NonNullable<object> {
|
||||
function isNonNullObject(
|
||||
value: unknown,
|
||||
): value is NonNullable<Record<string, unknown>> {
|
||||
return value !== null && typeof value === "object";
|
||||
}
|
||||
|
||||
function getKeys<T extends object>(record: T): Array<keyof T> {
|
||||
function getKeys<T extends Record<string, unknown>>(record: T): Array<keyof T> {
|
||||
const ret = Object.getOwnPropertySymbols(record) as Array<keyof T>;
|
||||
filterInPlace(
|
||||
ret,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
import { assertEquals, assertStrictEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals, assertStrictEquals } from "../assert/mod.ts";
|
||||
import { deepMerge } from "./deep_merge.ts";
|
||||
|
||||
Deno.test("deepMerge: simple merge", () => {
|
||||
|
@ -8,7 +8,7 @@
|
||||
* @example
|
||||
* ```ts
|
||||
* import { distinct } from "https://deno.land/std@$STD_VERSION/collections/distinct.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const numbers = [3, 2, 5, 2, 5];
|
||||
* const distinctNumbers = distinct(numbers);
|
||||
|
@ -8,7 +8,7 @@
|
||||
* @example
|
||||
* ```ts
|
||||
* import { distinctBy } from "https://deno.land/std@$STD_VERSION/collections/distinct_by.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const names = ["Anna", "Kim", "Arnold", "Kate"];
|
||||
* const exampleNamesByFirstLetter = distinctBy(names, (it) => it.charAt(0));
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
import { distinctBy } from "./distinct_by.ts";
|
||||
|
||||
function distinctByTest<I>(
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
import { assertEquals } from "../testing/asserts.ts";
|
||||
import { assertEquals } from "../assert/mod.ts";
|
||||
import { distinct } from "./distinct.ts";
|
||||
|
||||
function distinctTest<I>(
|
||||
|
@ -8,7 +8,7 @@
|
||||
* @example
|
||||
* ```ts
|
||||
* import { dropLastWhile } from "https://deno.land/std@$STD_VERSION/collections/drop_last_while.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
||||
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/assert/assert_equals.ts";
|
||||
*
|
||||
* const numbers = [22, 30, 44];
|
||||
*
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user