summaryrefslogtreecommitdiff
path: root/std/testing
diff options
context:
space:
mode:
Diffstat (limited to 'std/testing')
-rw-r--r--std/testing/README.md248
-rw-r--r--std/testing/_diff.ts228
-rw-r--r--std/testing/_diff_test.ts111
-rw-r--r--std/testing/asserts.ts617
-rw-r--r--std/testing/asserts_test.ts927
-rw-r--r--std/testing/bench.ts363
-rw-r--r--std/testing/bench_example.ts32
-rw-r--r--std/testing/bench_test.ts379
8 files changed, 0 insertions, 2905 deletions
diff --git a/std/testing/README.md b/std/testing/README.md
deleted file mode 100644
index 2cff96a6d..000000000
--- a/std/testing/README.md
+++ /dev/null
@@ -1,248 +0,0 @@
-# Testing
-
-This module provides a few basic utilities to make testing easier and consistent
-in Deno.
-
-## Usage
-
-`testing/asserts.ts` module provides range of assertion helpers. If the
-assertion is false an `AssertionError` will be thrown which will result in
-pretty-printed diff of failing assertion.
-
-- `equal()` - Deep comparison function, where `actual` and `expected` are
- compared deeply, and if they vary, `equal` returns `false`.
-- `assert()` - Expects a boolean value, throws if the value is `false`.
-- `assertEquals()` - Uses the `equal` comparison and throws if the `actual` and
- `expected` are not equal.
-- `assertNotEquals()` - Uses the `equal` comparison and throws if the `actual`
- and `expected` are equal.
-- `assertStrictEquals()` - Compares `actual` and `expected` strictly, therefore
- for non-primitives the values must reference the same instance.
-- `assertStringIncludes()` - Make an assertion that `actual` includes
- `expected`.
-- `assertMatch()` - Make an assertion that `actual` match RegExp `expected`.
-- `assertNotMatch()` - Make an assertion that `actual` not match RegExp
- `expected`.
-- `assertArrayIncludes()` - Make an assertion that `actual` array includes the
- `expected` values.
-- `assertObjectMatch()` - Make an assertion that `actual` object match
- `expected` subset object
-- `assertThrows()` - Expects the passed `fn` to throw. If `fn` does not throw,
- this function does. Also compares any errors thrown to an optional expected
- `Error` class and checks that the error `.message` includes an optional
- string.
-- `assertThrowsAsync()` - Expects the passed `fn` to be async and throw (or
- return a `Promise` that rejects). If the `fn` does not throw or reject, this
- function will throw asynchronously. Also compares any errors thrown to an
- optional expected `Error` class and checks that the error `.message` includes
- an optional string.
-- `unimplemented()` - Use this to stub out methods that will throw when invoked.
-- `unreachable()` - Used to assert unreachable code.
-
-Basic usage:
-
-```ts
-import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
-
-Deno.test({
- name: "testing example",
- fn(): void {
- assertEquals("world", "world");
- assertEquals({ hello: "world" }, { hello: "world" });
- },
-});
-```
-
-Short syntax (named function instead of object):
-
-```ts
-Deno.test("example", function (): void {
- assertEquals("world", "world");
- assertEquals({ hello: "world" }, { hello: "world" });
-});
-```
-
-Using `assertStrictEquals()`:
-
-```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);
-});
-```
-
-Using `assertThrows()`:
-
-```ts
-Deno.test("doesThrow", function (): void {
- assertThrows((): void => {
- throw new TypeError("hello world!");
- });
- 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");
- });
-});
-```
-
-Using `assertThrowsAsync()`:
-
-```ts
-Deno.test("doesThrow", async function (): Promise<void> {
- await assertThrowsAsync(
- async (): Promise<void> => {
- throw new TypeError("hello world!");
- },
- );
- await assertThrowsAsync(async (): Promise<void> => {
- throw new TypeError("hello world!");
- }, TypeError);
- await assertThrowsAsync(
- async (): Promise<void> => {
- throw new TypeError("hello world!");
- },
- TypeError,
- "hello",
- );
- await assertThrowsAsync(
- async (): Promise<void> => {
- return Promise.reject(new Error());
- },
- );
-});
-
-// This test will not pass.
-Deno.test("fails", async function (): Promise<void> {
- await assertThrowsAsync(
- async (): Promise<void> => {
- console.log("Hello world");
- },
- );
-});
-```
-
-## Benching
-
-With this module you can benchmark your code and get information on how is it
-performing.
-
-### Basic usage:
-
-Benchmarks can be registered using the `bench` function, where you can define a
-code, that should be benchmarked. `b.start()` has to be called at the start of
-the part you want to benchmark and `b.stop()` at the end of it, otherwise an
-error will be thrown.
-
-After that simply calling `runBenchmarks()` will benchmark all registered
-benchmarks and log the results in the commandline.
-
-```ts
-import {
- bench,
- runBenchmarks,
-} from "https://deno.land/std@$STD_VERSION/testing/bench.ts";
-
-bench(function forIncrementX1e9(b): void {
- b.start();
- for (let i = 0; i < 1e9; i++);
- b.stop();
-});
-
-runBenchmarks();
-```
-
-Averaging execution time over multiple runs:
-
-```ts
-bench({
- name: "runs100ForIncrementX1e6",
- runs: 100,
- func(b): void {
- b.start();
- for (let i = 0; i < 1e6; i++);
- b.stop();
- },
-});
-```
-
-Running specific benchmarks using regular expressions:
-
-```ts
-runBenchmarks({ only: /desired/, skip: /exceptions/ });
-```
-
-### Processing benchmark results
-
-`runBenchmarks()` returns a `Promise<BenchmarkRunResult>`, so you can process
-the benchmarking results yourself. It contains detailed results of each
-benchmark's run as `BenchmarkResult` s.
-
-```ts
-runBenchmarks()
- .then((results: BenchmarkRunResult) => {
- console.log(results);
- })
- .catch((error: Error) => {
- // ... errors if benchmark was badly constructed.
- });
-```
-
-### Processing benchmarking progress
-
-`runBenchmarks()` accepts an optional progress handler callback function, so you
-can get information on the progress of the running benchmarking.
-
-Using `{ silent: true }` means you wont see the default progression logs in the
-commandline.
-
-```ts
-runBenchmarks({ silent: true }, (p: BenchmarkRunProgress) => {
- // initial progress data.
- if (p.state === ProgressState.BenchmarkingStart) {
- console.log(
- `Starting benchmarking. Queued: ${p.queued.length}, filtered: ${p.filtered}`,
- );
- }
- // ...
-});
-```
-
-#### Benching API
-
-##### `bench(benchmark: BenchmarkDefinition | BenchmarkFunction): void`
-
-Registers a benchmark that will be run once `runBenchmarks` is called.
-
-##### `runBenchmarks(opts?: BenchmarkRunOptions, progressCb?: (p: BenchmarkRunProgress) => void | Promise<void>): Promise<BenchmarkRunResult>`
-
-Runs all registered benchmarks serially. Filtering can be applied by setting
-`BenchmarkRunOptions.only` and/or `BenchmarkRunOptions.skip` to regular
-expressions matching benchmark names. Default progression logs can be turned off
-with the `BenchmarkRunOptions.silent` flag.
-
-##### `clearBenchmarks(opts?: BenchmarkClearOptions): void`
-
-Clears all registered benchmarks, so calling `runBenchmarks()` after it wont run
-them. Filtering can be applied by setting `BenchmarkRunOptions.only` and/or
-`BenchmarkRunOptions.skip` to regular expressions matching benchmark names.
diff --git a/std/testing/_diff.ts b/std/testing/_diff.ts
deleted file mode 100644
index 7d659acd2..000000000
--- a/std/testing/_diff.ts
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-// This module is browser compatible.
-
-interface FarthestPoint {
- y: number;
- id: number;
-}
-
-export enum DiffType {
- removed = "removed",
- common = "common",
- added = "added",
-}
-
-export interface DiffResult<T> {
- type: DiffType;
- value: T;
-}
-
-const REMOVED = 1;
-const COMMON = 2;
-const ADDED = 3;
-
-function createCommon<T>(A: T[], B: T[], reverse?: boolean): T[] {
- const common = [];
- if (A.length === 0 || B.length === 0) return [];
- for (let i = 0; i < Math.min(A.length, B.length); i += 1) {
- if (
- A[reverse ? A.length - i - 1 : i] === B[reverse ? B.length - i - 1 : i]
- ) {
- common.push(A[reverse ? A.length - i - 1 : i]);
- } else {
- return common;
- }
- }
- return common;
-}
-
-/**
- * Renders the differences between the actual and expected values
- * @param A Actual value
- * @param B Expected value
- */
-export function diff<T>(A: T[], B: T[]): Array<DiffResult<T>> {
- const prefixCommon = createCommon(A, B);
- const suffixCommon = createCommon(
- A.slice(prefixCommon.length),
- B.slice(prefixCommon.length),
- true,
- ).reverse();
- A = suffixCommon.length
- ? A.slice(prefixCommon.length, -suffixCommon.length)
- : A.slice(prefixCommon.length);
- B = suffixCommon.length
- ? B.slice(prefixCommon.length, -suffixCommon.length)
- : B.slice(prefixCommon.length);
- const swapped = B.length > A.length;
- [A, B] = swapped ? [B, A] : [A, B];
- const M = A.length;
- const N = B.length;
- if (!M && !N && !suffixCommon.length && !prefixCommon.length) return [];
- if (!N) {
- return [
- ...prefixCommon.map(
- (c): DiffResult<typeof c> => ({ type: DiffType.common, value: c }),
- ),
- ...A.map(
- (a): DiffResult<typeof a> => ({
- type: swapped ? DiffType.added : DiffType.removed,
- value: a,
- }),
- ),
- ...suffixCommon.map(
- (c): DiffResult<typeof c> => ({ type: DiffType.common, value: c }),
- ),
- ];
- }
- const offset = N;
- const delta = M - N;
- const size = M + N + 1;
- const fp = new Array(size).fill({ y: -1 });
- /**
- * INFO:
- * This buffer is used to save memory and improve performance.
- * The first half is used to save route and last half is used to save diff
- * type.
- * This is because, when I kept new uint8array area to save type,performance
- * worsened.
- */
- const routes = new Uint32Array((M * N + size + 1) * 2);
- const diffTypesPtrOffset = routes.length / 2;
- let ptr = 0;
- let p = -1;
-
- function backTrace<T>(
- A: T[],
- B: T[],
- current: FarthestPoint,
- swapped: boolean,
- ): Array<{
- type: DiffType;
- value: T;
- }> {
- const M = A.length;
- const N = B.length;
- const result = [];
- let a = M - 1;
- let b = N - 1;
- let j = routes[current.id];
- let type = routes[current.id + diffTypesPtrOffset];
- while (true) {
- if (!j && !type) break;
- const prev = j;
- if (type === REMOVED) {
- result.unshift({
- type: swapped ? DiffType.removed : DiffType.added,
- value: B[b],
- });
- b -= 1;
- } else if (type === ADDED) {
- result.unshift({
- type: swapped ? DiffType.added : DiffType.removed,
- value: A[a],
- });
- a -= 1;
- } else {
- result.unshift({ type: DiffType.common, value: A[a] });
- a -= 1;
- b -= 1;
- }
- j = routes[prev];
- type = routes[prev + diffTypesPtrOffset];
- }
- return result;
- }
-
- function createFP(
- slide: FarthestPoint,
- down: FarthestPoint,
- k: number,
- M: number,
- ): FarthestPoint {
- if (slide && slide.y === -1 && down && down.y === -1) {
- return { y: 0, id: 0 };
- }
- if (
- (down && down.y === -1) ||
- k === M ||
- (slide && slide.y) > (down && down.y) + 1
- ) {
- const prev = slide.id;
- ptr++;
- routes[ptr] = prev;
- routes[ptr + diffTypesPtrOffset] = ADDED;
- return { y: slide.y, id: ptr };
- } else {
- const prev = down.id;
- ptr++;
- routes[ptr] = prev;
- routes[ptr + diffTypesPtrOffset] = REMOVED;
- return { y: down.y + 1, id: ptr };
- }
- }
-
- function snake<T>(
- k: number,
- slide: FarthestPoint,
- down: FarthestPoint,
- _offset: number,
- A: T[],
- B: T[],
- ): FarthestPoint {
- const M = A.length;
- const N = B.length;
- if (k < -N || M < k) return { y: -1, id: -1 };
- const fp = createFP(slide, down, k, M);
- while (fp.y + k < M && fp.y < N && A[fp.y + k] === B[fp.y]) {
- const prev = fp.id;
- ptr++;
- fp.id = ptr;
- fp.y += 1;
- routes[ptr] = prev;
- routes[ptr + diffTypesPtrOffset] = COMMON;
- }
- return fp;
- }
-
- while (fp[delta + offset].y < N) {
- p = p + 1;
- for (let k = -p; k < delta; ++k) {
- fp[k + offset] = snake(
- k,
- fp[k - 1 + offset],
- fp[k + 1 + offset],
- offset,
- A,
- B,
- );
- }
- for (let k = delta + p; k > delta; --k) {
- fp[k + offset] = snake(
- k,
- fp[k - 1 + offset],
- fp[k + 1 + offset],
- offset,
- A,
- B,
- );
- }
- fp[delta + offset] = snake(
- delta,
- fp[delta - 1 + offset],
- fp[delta + 1 + offset],
- offset,
- A,
- B,
- );
- }
- return [
- ...prefixCommon.map(
- (c): DiffResult<typeof c> => ({ type: DiffType.common, value: c }),
- ),
- ...backTrace(A, B, fp[delta + offset], swapped),
- ...suffixCommon.map(
- (c): DiffResult<typeof c> => ({ type: DiffType.common, value: c }),
- ),
- ];
-}
diff --git a/std/testing/_diff_test.ts b/std/testing/_diff_test.ts
deleted file mode 100644
index ec40c191c..000000000
--- a/std/testing/_diff_test.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-import { diff } from "./_diff.ts";
-import { assertEquals } from "../testing/asserts.ts";
-
-Deno.test({
- name: "empty",
- fn(): void {
- assertEquals(diff([], []), []);
- },
-});
-
-Deno.test({
- name: '"a" vs "b"',
- fn(): void {
- assertEquals(diff(["a"], ["b"]), [
- { type: "removed", value: "a" },
- { type: "added", value: "b" },
- ]);
- },
-});
-
-Deno.test({
- name: '"a" vs "a"',
- fn(): void {
- assertEquals(diff(["a"], ["a"]), [{ type: "common", value: "a" }]);
- },
-});
-
-Deno.test({
- name: '"a" vs ""',
- fn(): void {
- assertEquals(diff(["a"], []), [{ type: "removed", value: "a" }]);
- },
-});
-
-Deno.test({
- name: '"" vs "a"',
- fn(): void {
- assertEquals(diff([], ["a"]), [{ type: "added", value: "a" }]);
- },
-});
-
-Deno.test({
- name: '"a" vs "a, b"',
- fn(): void {
- assertEquals(diff(["a"], ["a", "b"]), [
- { type: "common", value: "a" },
- { type: "added", value: "b" },
- ]);
- },
-});
-
-Deno.test({
- name: '"strength" vs "string"',
- fn(): void {
- assertEquals(diff(Array.from("strength"), Array.from("string")), [
- { type: "common", value: "s" },
- { type: "common", value: "t" },
- { type: "common", value: "r" },
- { type: "removed", value: "e" },
- { type: "added", value: "i" },
- { type: "common", value: "n" },
- { type: "common", value: "g" },
- { type: "removed", value: "t" },
- { type: "removed", value: "h" },
- ]);
- },
-});
-
-Deno.test({
- name: '"strength" vs ""',
- fn(): void {
- assertEquals(diff(Array.from("strength"), Array.from("")), [
- { type: "removed", value: "s" },
- { type: "removed", value: "t" },
- { type: "removed", value: "r" },
- { type: "removed", value: "e" },
- { type: "removed", value: "n" },
- { type: "removed", value: "g" },
- { type: "removed", value: "t" },
- { type: "removed", value: "h" },
- ]);
- },
-});
-
-Deno.test({
- name: '"" vs "strength"',
- fn(): void {
- assertEquals(diff(Array.from(""), Array.from("strength")), [
- { type: "added", value: "s" },
- { type: "added", value: "t" },
- { type: "added", value: "r" },
- { type: "added", value: "e" },
- { type: "added", value: "n" },
- { type: "added", value: "g" },
- { type: "added", value: "t" },
- { type: "added", value: "h" },
- ]);
- },
-});
-
-Deno.test({
- name: '"abc", "c" vs "abc", "bcd", "c"',
- fn(): void {
- assertEquals(diff(["abc", "c"], ["abc", "bcd", "c"]), [
- { type: "common", value: "abc" },
- { type: "added", value: "bcd" },
- { type: "common", value: "c" },
- ]);
- },
-});
diff --git a/std/testing/asserts.ts b/std/testing/asserts.ts
deleted file mode 100644
index 3daf0d83f..000000000
--- a/std/testing/asserts.ts
+++ /dev/null
@@ -1,617 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-// This module is browser compatible. Do not rely on good formatting of values
-// for AssertionError messages in browsers.
-
-import { bold, gray, green, red, stripColor, white } from "../fmt/colors.ts";
-import { diff, DiffResult, DiffType } from "./_diff.ts";
-
-const CAN_NOT_DISPLAY = "[Cannot display]";
-
-interface Constructor {
- // deno-lint-ignore no-explicit-any
- new (...args: any[]): any;
-}
-
-export class AssertionError extends Error {
- constructor(message: string) {
- super(message);
- this.name = "AssertionError";
- }
-}
-
-/**
- * Converts the input into a string. Objects, Sets and Maps are sorted so as to
- * make tests less flaky
- * @param v Value to be formatted
- */
-export function _format(v: unknown): string {
- return globalThis.Deno
- ? Deno.inspect(v, {
- depth: Infinity,
- sorted: true,
- trailingComma: true,
- compact: false,
- iterableLimit: Infinity,
- })
- : `"${String(v).replace(/(?=["\\])/g, "\\")}"`;
-}
-
-/**
- * Colors the output of assertion diffs
- * @param diffType Difference type, either added or removed
- */
-function createColor(diffType: DiffType): (s: string) => string {
- switch (diffType) {
- case DiffType.added:
- return (s: string): string => green(bold(s));
- case DiffType.removed:
- return (s: string): string => red(bold(s));
- default:
- return white;
- }
-}
-
-/**
- * Prefixes `+` or `-` in diff output
- * @param diffType Difference type, either added or removed
- */
-function createSign(diffType: DiffType): string {
- switch (diffType) {
- case DiffType.added:
- return "+ ";
- case DiffType.removed:
- return "- ";
- default:
- return " ";
- }
-}
-
-function buildMessage(diffResult: ReadonlyArray<DiffResult<string>>): string[] {
- const messages: string[] = [];
- messages.push("");
- messages.push("");
- messages.push(
- ` ${gray(bold("[Diff]"))} ${red(bold("Actual"))} / ${
- green(bold("Expected"))
- }`,
- );
- messages.push("");
- messages.push("");
- diffResult.forEach((result: DiffResult<string>): void => {
- const c = createColor(result.type);
- messages.push(c(`${createSign(result.type)}${result.value}`));
- });
- messages.push("");
-
- return messages;
-}
-
-function isKeyedCollection(x: unknown): x is Set<unknown> {
- return [Symbol.iterator, "size"].every((k) => k in (x as Set<unknown>));
-}
-
-/**
- * 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 a.getTime() === b.getTime();
- }
- if (Object.is(a, b)) {
- return true;
- }
- if (a && typeof a === "object" && b && typeof b === "object") {
- if (seen.get(a) === b) {
- return true;
- }
- if (Object.keys(a || {}).length !== Object.keys(b || {}).length) {
- return false;
- }
- 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--;
- }
- }
- }
-
- return unmatchedEntries === 0;
- }
- const merged = { ...a, ...b };
- for (const key in merged) {
- type Key = keyof typeof merged;
- if (!compare(a && a[key as Key], b && b[key as Key])) {
- return false;
- }
- }
- seen.set(a, b);
- return true;
- }
- return false;
- })(c, d);
-}
-
-/** 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);
- }
-}
-
-/**
- * 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.
- * For example:
- *```ts
- *assertEquals<number>(1, 2)
- *```
- */
-export function assertEquals(
- actual: unknown,
- expected: unknown,
- msg?: string,
-): void;
-export function assertEquals<T>(actual: T, expected: T, msg?: string): void;
-export function assertEquals(
- actual: unknown,
- expected: unknown,
- msg?: string,
-): void {
- if (equal(actual, expected)) {
- return;
- }
- let message = "";
- const actualString = _format(actual);
- const expectedString = _format(expected);
- try {
- const diffResult = diff(
- actualString.split("\n"),
- expectedString.split("\n"),
- );
- const diffMsg = buildMessage(diffResult).join("\n");
- message = `Values are not equal:\n${diffMsg}`;
- } catch (e) {
- message = `\n${red(CAN_NOT_DISPLAY)} + \n\n`;
- }
- if (msg) {
- message = msg;
- }
- throw new AssertionError(message);
-}
-
-/**
- * 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.
- * For example:
- *```ts
- *assertNotEquals<number>(1, 2)
- *```
- */
-export function assertNotEquals(
- actual: unknown,
- expected: unknown,
- msg?: string,
-): void;
-export function assertNotEquals<T>(actual: T, expected: T, msg?: string): void;
-export function assertNotEquals(
- actual: unknown,
- expected: unknown,
- msg?: string,
-): void {
- if (!equal(actual, expected)) {
- return;
- }
- let actualString: string;
- let expectedString: string;
- try {
- actualString = String(actual);
- } catch (e) {
- actualString = "[Cannot display]";
- }
- try {
- expectedString = String(expected);
- } catch (e) {
- expectedString = "[Cannot display]";
- }
- if (!msg) {
- msg = `actual: ${actualString} expected: ${expectedString}`;
- }
- throw new AssertionError(msg);
-}
-
-/**
- * Make an assertion that `actual` and `expected` are strictly equal. If
- * not then throw.
- * ```ts
- * assertStrictEquals(1, 2)
- * ```
- */
-export function assertStrictEquals(
- actual: unknown,
- expected: unknown,
- msg?: string,
-): void;
-export function assertStrictEquals<T>(
- actual: T,
- expected: T,
- msg?: string,
-): void;
-export function assertStrictEquals(
- actual: unknown,
- expected: unknown,
- msg?: string,
-): void {
- if (actual === expected) {
- return;
- }
-
- let message: string;
-
- if (msg) {
- message = msg;
- } else {
- 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:\n\n${
- red(withOffset)
- }\n`;
- } else {
- try {
- const diffResult = diff(
- actualString.split("\n"),
- expectedString.split("\n"),
- );
- const diffMsg = buildMessage(diffResult).join("\n");
- message = `Values are not strictly equal:\n${diffMsg}`;
- } catch (e) {
- message = `\n${red(CAN_NOT_DISPLAY)} + \n\n`;
- }
- }
- }
-
- throw new AssertionError(message);
-}
-
-/**
- * Make an assertion that `actual` and `expected` are not strictly equal.
- * If the values are strictly equal then throw.
- * ```ts
- * assertNotStrictEquals(1, 1)
- * ```
- */
-export function assertNotStrictEquals(
- actual: unknown,
- expected: unknown,
- msg?: string,
-): void;
-export function assertNotStrictEquals<T>(
- actual: T,
- expected: T,
- msg?: string,
-): void;
-export function assertNotStrictEquals(
- actual: unknown,
- expected: unknown,
- msg?: string,
-): void {
- if (actual !== expected) {
- return;
- }
-
- throw new AssertionError(
- msg ?? `Expected "actual" to be strictly unequal to: ${_format(actual)}\n`,
- );
-}
-
-/**
- * Make an assertion that actual is not null or undefined. If not
- * then thrown.
- */
-export function assertExists(
- actual: unknown,
- msg?: string,
-): void {
- if (actual === undefined || actual === null) {
- if (!msg) {
- msg =
- `actual: "${actual}" expected to match anything but null or undefined`;
- }
- throw new AssertionError(msg);
- }
-}
-
-/**
- * Make an assertion that actual includes expected. If not
- * then thrown.
- */
-export function assertStringIncludes(
- actual: string,
- expected: string,
- msg?: string,
-): void {
- if (!actual.includes(expected)) {
- if (!msg) {
- msg = `actual: "${actual}" expected to contain: "${expected}"`;
- }
- throw new AssertionError(msg);
- }
-}
-
-/**
- * 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.
- * For example:
- *```ts
- *assertArrayIncludes<number>([1, 2], [2])
- *```
- */
-export function assertArrayIncludes(
- actual: ArrayLike<unknown>,
- expected: ArrayLike<unknown>,
- msg?: string,
-): void;
-export function assertArrayIncludes<T>(
- actual: ArrayLike<T>,
- expected: ArrayLike<T>,
- msg?: string,
-): void;
-export function assertArrayIncludes(
- actual: ArrayLike<unknown>,
- expected: ArrayLike<unknown>,
- msg?: string,
-): void {
- 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;
- }
- if (!msg) {
- msg = `actual: "${_format(actual)}" expected to include: "${
- _format(expected)
- }"\nmissing: ${_format(missing)}`;
- }
- throw new AssertionError(msg);
-}
-
-/**
- * Make an assertion that `actual` match RegExp `expected`. If not
- * then thrown
- */
-export function assertMatch(
- actual: string,
- expected: RegExp,
- msg?: string,
-): void {
- if (!expected.test(actual)) {
- if (!msg) {
- msg = `actual: "${actual}" expected to match: "${expected}"`;
- }
- throw new AssertionError(msg);
- }
-}
-
-/**
- * Make an assertion that `actual` not match RegExp `expected`. If match
- * then thrown
- */
-export function assertNotMatch(
- actual: string,
- expected: RegExp,
- msg?: string,
-): void {
- if (expected.test(actual)) {
- if (!msg) {
- msg = `actual: "${actual}" expected to not match: "${expected}"`;
- }
- throw new AssertionError(msg);
- }
-}
-
-/**
- * Make an assertion that `actual` object is a subset of `expected` object, deeply.
- * If not, then throw.
- */
-export function assertObjectMatch(
- actual: Record<PropertyKey, unknown>,
- expected: Record<PropertyKey, unknown>,
-): void {
- type loose = Record<PropertyKey, unknown>;
- const seen = new WeakMap();
- return assertEquals(
- (function filter(a: loose, b: loose): loose {
- // Prevent infinite loop with circular references with same filter
- if ((seen.has(a)) && (seen.get(a) === b)) {
- return a;
- }
- seen.set(a, b);
- // 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]>;
- // Build filtered object and filter recursively on nested objects references
- for (const [key, value] of entries) {
- if (typeof value === "object") {
- const subset = (b as loose)[key];
- if ((typeof subset === "object") && (subset)) {
- filtered[key] = filter(value as loose, subset as loose);
- continue;
- }
- }
- filtered[key] = value;
- }
- return filtered;
- })(actual, expected),
- expected,
- );
-}
-
-/**
- * Forcefully throws a failed assertion
- */
-export function fail(msg?: string): void {
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
- assert(false, `Failed assertion${msg ? `: ${msg}` : "."}`);
-}
-
-/**
- * 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.
- */
-export function assertThrows<T = void>(
- fn: () => T,
- ErrorClass?: Constructor,
- msgIncludes = "",
- msg?: string,
-): Error {
- let doesThrow = false;
- let error = null;
- try {
- fn();
- } catch (e) {
- if (e instanceof Error === false) {
- throw new AssertionError("A non-Error object was thrown.");
- }
- if (ErrorClass && !(e instanceof ErrorClass)) {
- msg =
- `Expected error to be instance of "${ErrorClass.name}", but was "${e.constructor.name}"${
- msg ? `: ${msg}` : "."
- }`;
- throw new AssertionError(msg);
- }
- if (
- msgIncludes &&
- !stripColor(e.message).includes(stripColor(msgIncludes))
- ) {
- msg =
- `Expected error message to include "${msgIncludes}", but got "${e.message}"${
- msg ? `: ${msg}` : "."
- }`;
- throw new AssertionError(msg);
- }
- doesThrow = true;
- error = e;
- }
- if (!doesThrow) {
- msg = `Expected function to throw${msg ? `: ${msg}` : "."}`;
- throw new AssertionError(msg);
- }
- return error;
-}
-
-/**
- * Executes a function which returns a promise, expecting it to throw or 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.
- */
-export async function assertThrowsAsync<T = void>(
- fn: () => Promise<T>,
- ErrorClass?: Constructor,
- msgIncludes = "",
- msg?: string,
-): Promise<Error> {
- let doesThrow = false;
- let error = null;
- try {
- await fn();
- } catch (e) {
- if (e instanceof Error === false) {
- throw new AssertionError("A non-Error object was thrown or rejected.");
- }
- if (ErrorClass && !(e instanceof ErrorClass)) {
- msg =
- `Expected error to be instance of "${ErrorClass.name}", but got "${e.name}"${
- msg ? `: ${msg}` : "."
- }`;
- throw new AssertionError(msg);
- }
- if (
- msgIncludes &&
- !stripColor(e.message).includes(stripColor(msgIncludes))
- ) {
- msg =
- `Expected error message to include "${msgIncludes}", but got "${e.message}"${
- msg ? `: ${msg}` : "."
- }`;
- throw new AssertionError(msg);
- }
- doesThrow = true;
- error = e;
- }
- if (!doesThrow) {
- msg = `Expected function to throw${msg ? `: ${msg}` : "."}`;
- throw new AssertionError(msg);
- }
- return error;
-}
-
-/** Use this to stub out methods that will throw when invoked. */
-export function unimplemented(msg?: string): never {
- throw new AssertionError(msg || "unimplemented");
-}
-
-/** Use this to assert unreachable code. */
-export function unreachable(): never {
- throw new AssertionError("unreachable");
-}
diff --git a/std/testing/asserts_test.ts b/std/testing/asserts_test.ts
deleted file mode 100644
index 14ffd2962..000000000
--- a/std/testing/asserts_test.ts
+++ /dev/null
@@ -1,927 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-import {
- _format,
- assert,
- assertArrayIncludes,
- assertEquals,
- assertExists,
- AssertionError,
- assertMatch,
- assertNotEquals,
- assertNotMatch,
- assertNotStrictEquals,
- assertObjectMatch,
- assertStrictEquals,
- assertStringIncludes,
- assertThrows,
- assertThrowsAsync,
- equal,
- fail,
- unimplemented,
- unreachable,
-} from "./asserts.ts";
-import { bold, gray, green, red, stripColor, yellow } from "../fmt/colors.ts";
-
-Deno.test("testingEqual", function (): void {
- assert(equal("world", "world"));
- assert(!equal("hello", "world"));
- assert(equal(5, 5));
- assert(!equal(5, 6));
- assert(equal(NaN, NaN));
- assert(equal({ hello: "world" }, { hello: "world" }));
- assert(!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" } },
- ),
- );
- assert(equal(/deno/, /deno/));
- assert(!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)));
- assert(
- !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)));
- assert(!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])));
- 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])));
- assert(!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"]])));
- assert(
- !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]])));
- assert(!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]));
- assert(!equal([1, 2, 3, 4], [1, 2, 3]));
- assert(!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])));
- 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"),
- ),
- );
-});
-
-Deno.test("testingNotEquals", function (): void {
- const a = { foo: "bar" };
- const b = { bar: "foo" };
- assertNotEquals(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);
-});
-
-Deno.test("testingAssertExists", function (): void {
- assertExists("Denosaurus");
- assertExists(false);
- assertExists(0);
- assertExists("");
- assertExists(-0);
- assertExists(0);
- assertExists(NaN);
- 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);
-});
-
-Deno.test("testingAssertStringContains", function (): void {
- 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("testingArrayContains", function (): void {
- 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(
- (): void => assertArrayIncludes(fixtureObject, [{ deno: "node" }]),
- AssertionError,
- `actual: "[
- {
- deno: "luv",
- },
- {
- deno: "Js",
- },
-]" expected to include: "[
- {
- deno: "node",
- },
-]"
-missing: [
- {
- deno: "node",
- },
-]`,
- );
-});
-
-Deno.test("testingAssertStringContainsThrow", function (): void {
- let didThrow = false;
- try {
- assertStringIncludes("Denosaurus from Jurassic", "Raptor");
- } catch (e) {
- assert(
- e.message ===
- `actual: "Denosaurus from Jurassic" expected to contain: "Raptor"`,
- );
- assert(e instanceof AssertionError);
- didThrow = true;
- }
- assert(didThrow);
-});
-
-Deno.test("testingAssertStringMatching", function (): void {
- assertMatch("foobar@deno.com", RegExp(/[a-zA-Z]+@[a-zA-Z]+.com/));
-});
-
-Deno.test("testingAssertStringMatchingThrows", function (): void {
- let didThrow = false;
- try {
- assertMatch("Denosaurus from Jurassic", RegExp(/Raptor/));
- } catch (e) {
- assert(
- e.message ===
- `actual: "Denosaurus from Jurassic" expected to match: "/Raptor/"`,
- );
- assert(e instanceof AssertionError);
- didThrow = true;
- }
- assert(didThrow);
-});
-
-Deno.test("testingAssertStringNotMatching", function (): void {
- assertNotMatch("foobar.deno.com", RegExp(/[a-zA-Z]+@[a-zA-Z]+.com/));
-});
-
-Deno.test("testingAssertStringNotMatchingThrows", function (): void {
- let didThrow = false;
- try {
- assertNotMatch("Denosaurus from Jurassic", RegExp(/from/));
- } catch (e) {
- assert(
- e.message ===
- `actual: "Denosaurus from Jurassic" expected to not match: "/from/"`,
- );
- assert(e instanceof AssertionError);
- didThrow = true;
- }
- assert(didThrow);
-});
-
-Deno.test("testingAssertObjectMatching", function (): void {
- 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 };
- // 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 same symbol
- assertObjectMatch(f, {
- [sym]: 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);
- }
-});
-
-Deno.test("testingAssertsUnimplemented", function (): void {
- let didThrow = false;
- try {
- unimplemented();
- } catch (e) {
- assert(e.message === "unimplemented");
- assert(e instanceof AssertionError);
- didThrow = true;
- }
- assert(didThrow);
-});
-
-Deno.test("testingAssertsUnreachable", function (): void {
- let didThrow = false;
- try {
- unreachable();
- } catch (e) {
- assert(e.message === "unreachable");
- assert(e instanceof AssertionError);
- didThrow = true;
- }
- assert(didThrow);
-});
-
-Deno.test("testingAssertFail", function (): void {
- assertThrows(fail, AssertionError, "Failed assertion.");
- assertThrows(
- (): void => {
- fail("foo");
- },
- AssertionError,
- "Failed assertion: foo",
- );
-});
-
-Deno.test("testingAssertFailWithWrongErrorClass", function (): void {
- assertThrows(
- (): void => {
- //This next assertThrows will throw an AssertionError due to the wrong
- //expected error class
- assertThrows(
- (): void => {
- fail("foo");
- },
- TypeError,
- "Failed assertion: foo",
- );
- },
- AssertionError,
- `Expected error to be instance of "TypeError", but was "AssertionError"`,
- );
-});
-
-Deno.test("testingAssertThrowsWithReturnType", () => {
- assertThrows(() => {
- throw new Error();
- });
-});
-
-Deno.test("testingAssertThrowsAsyncWithReturnType", () => {
- assertThrowsAsync(() => {
- throw new Error();
- });
-});
-
-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(): void {
- 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(): void {
- assertThrows(
- (): void => 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(): void {
- assertThrows(
- (): void => assertEquals(1, "1"),
- AssertionError,
- [
- "Values are not equal:",
- ...createHeader(),
- removed(`- ${yellow("1")}`),
- added(`+ "1"`),
- ].join("\n"),
- );
- },
-});
-
-Deno.test({
- name: "failed with array",
- fn(): void {
- assertThrows(
- (): void => assertEquals([1, "2", 3], ["1", "2", 3]),
- AssertionError,
- `
- [
-- 1,
-+ "1",
- "2",
- 3,
- ]`,
- );
- },
-});
-
-Deno.test({
- name: "failed with object",
- fn(): void {
- assertThrows(
- (): void => 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(): void {
- assertThrows(
- (): void =>
- 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(
- (): void =>
- 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: "strict pass case",
- fn(): void {
- assertStrictEquals(true, true);
- assertStrictEquals(10, 10);
- assertStrictEquals("abc", "abc");
-
- 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(): void {
- assertThrows(
- (): void => 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(): void {
- assertThrows(
- (): void => 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: "strictly unequal pass case",
- fn(): void {
- assertNotStrictEquals(true, false);
- assertNotStrictEquals(10, 11);
- assertNotStrictEquals("abc", "xyz");
- assertNotStrictEquals(1, "1");
-
- 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(): void {
- assertThrows(() => assertNotStrictEquals(1, 1), AssertionError);
- },
-});
-
-Deno.test({
- name: "assert* functions with specified type parameter",
- fn(): void {
- assertEquals<string>("hello", "hello");
- assertNotEquals<number>(1, 2);
- assertArrayIncludes<boolean>([true, false], [true]);
- const value = { x: 1 };
- assertStrictEquals<typeof value>(value, value);
- // deno-lint-ignore ban-types
- assertNotStrictEquals<object>(value, { x: 1 });
- },
-});
-
-Deno.test("Assert Throws Non-Error Fail", () => {
- assertThrows(
- () => {
- assertThrows(
- () => {
- throw "Panic!";
- },
- String,
- "Panic!",
- );
- },
- AssertionError,
- "A non-Error object was thrown.",
- );
-
- assertThrows(
- () => {
- assertThrows(() => {
- throw null;
- });
- },
- AssertionError,
- "A non-Error object was thrown.",
- );
-
- assertThrows(
- () => {
- assertThrows(() => {
- throw undefined;
- });
- },
- AssertionError,
- "A non-Error object was thrown.",
- );
-});
-
-Deno.test("Assert Throws Async Non-Error Fail", () => {
- assertThrowsAsync(
- () => {
- return assertThrowsAsync(
- () => {
- return Promise.reject("Panic!");
- },
- String,
- "Panic!",
- );
- },
- AssertionError,
- "A non-Error object was thrown or rejected.",
- );
-
- assertThrowsAsync(
- () => {
- return assertThrowsAsync(() => {
- return Promise.reject(null);
- });
- },
- AssertionError,
- "A non-Error object was thrown or rejected.",
- );
-
- assertThrowsAsync(
- () => {
- return assertThrowsAsync(() => {
- return Promise.reject(undefined);
- });
- },
- AssertionError,
- "A non-Error object was thrown or rejected.",
- );
-
- assertThrowsAsync(
- () => {
- return assertThrowsAsync(() => {
- throw undefined;
- });
- },
- AssertionError,
- "A non-Error object was thrown or rejected.",
- );
-});
-
-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,
- }`,
- );
-});
-
-// Check that the diff formatter overrides some default behaviours of
-// `Deno.inspect()` which are problematic for diffing.
-Deno.test("assert diff formatting", () => {
- // Wraps objects into multiple lines even when they are small. Prints trailing
- // commas.
- assertEquals(
- stripColor(_format({ a: 1, b: 2 })),
- `{
- a: 1,
- b: 2,
-}`,
- );
-
- // Same for nested small objects.
- assertEquals(
- stripColor(_format([{ x: { a: 1, b: 2 }, y: ["a", "b"] }])),
- `[
- {
- x: {
- a: 1,
- b: 2,
- },
- y: [
- "a",
- "b",
- ],
- },
-]`,
- );
-
- // Grouping is disabled.
- assertEquals(
- stripColor(_format(["i", "i", "i", "i", "i", "i", "i"])),
- `[
- "i",
- "i",
- "i",
- "i",
- "i",
- "i",
- "i",
-]`,
- );
-});
-
-Deno.test("Assert Throws Parent Error", () => {
- assertThrows(
- () => {
- throw new AssertionError("Fail!");
- },
- Error,
- "Fail!",
- );
-});
-
-Deno.test("Assert Throws Async Parent Error", () => {
- assertThrowsAsync(
- () => {
- throw new AssertionError("Fail!");
- },
- Error,
- "Fail!",
- );
-});
diff --git a/std/testing/bench.ts b/std/testing/bench.ts
deleted file mode 100644
index 159a70cf7..000000000
--- a/std/testing/bench.ts
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-import { assert } from "../_util/assert.ts";
-import { deepAssign } from "../_util/deep_assign.ts";
-
-interface BenchmarkClock {
- start: number;
- stop: number;
- for?: string;
-}
-
-/** Provides methods for starting and stopping a benchmark clock. */
-export interface BenchmarkTimer {
- start: () => void;
- stop: () => void;
-}
-
-/** Defines a benchmark through a named function. */
-export interface BenchmarkFunction {
- (b: BenchmarkTimer): void | Promise<void>;
- name: string;
-}
-
-/** Defines a benchmark definition with configurable runs. */
-export interface BenchmarkDefinition {
- func: BenchmarkFunction;
- name: string;
- /** Defines how many times the provided `func` should be benchmarked in succession */
- runs?: number;
-}
-
-/** Defines runBenchmark's run constraints by matching benchmark names. */
-export interface BenchmarkRunOptions {
- /** Only benchmarks which name match this regexp will be run*/
- only?: RegExp;
- /** Benchmarks which name match this regexp will be skipped */
- skip?: RegExp;
- /** Setting it to true prevents default benchmarking progress logs to the commandline*/
- silent?: boolean;
-}
-
-/** Defines clearBenchmark's constraints by matching benchmark names. */
-export interface BenchmarkClearOptions {
- /** Only benchmarks which name match this regexp will be removed */
- only?: RegExp;
- /** Benchmarks which name match this regexp will be kept */
- skip?: RegExp;
-}
-
-/** Defines the result of a single benchmark */
-export interface BenchmarkResult {
- /** The name of the benchmark */
- name: string;
- /** The total time it took to run a given bechmark */
- totalMs: number;
- /** Times the benchmark was run in succession. */
- runsCount: number;
- /** The average time of running the benchmark in milliseconds. */
- measuredRunsAvgMs: number;
- /** The individual measurements in milliseconds it took to run the benchmark.*/
- measuredRunsMs: number[];
-}
-
-/** Defines the result of a `runBenchmarks` call */
-export interface BenchmarkRunResult {
- /** How many benchmark were ignored by the provided `only` and `skip` */
- filtered: number;
- /** The individual results for each benchmark that was run */
- results: BenchmarkResult[];
-}
-
-/** Defines the current progress during the run of `runBenchmarks` */
-export interface BenchmarkRunProgress extends BenchmarkRunResult {
- /** List of the queued benchmarks to run with their name and their run count */
- queued?: Array<{ name: string; runsCount: number }>;
- /** The currently running benchmark with its name, run count and the already finished measurements in milliseconds */
- running?: { name: string; runsCount: number; measuredRunsMs: number[] };
- /** Indicates in which state benchmarking currently is */
- state?: ProgressState;
-}
-
-/** Defines the states `BenchmarkRunProgress` can be in */
-export enum ProgressState {
- BenchmarkingStart = "benchmarking_start",
- BenchStart = "bench_start",
- BenchPartialResult = "bench_partial_result",
- BenchResult = "bench_result",
- BenchmarkingEnd = "benchmarking_end",
-}
-
-export class BenchmarkRunError extends Error {
- benchmarkName?: string;
- constructor(msg: string, benchmarkName?: string) {
- super(msg);
- this.name = "BenchmarkRunError";
- this.benchmarkName = benchmarkName;
- }
-}
-
-function red(text: string): string {
- return Deno.noColor ? text : `\x1b[31m${text}\x1b[0m`;
-}
-
-function blue(text: string): string {
- return Deno.noColor ? text : `\x1b[34m${text}\x1b[0m`;
-}
-
-function verifyOr1Run(runs?: number): number {
- return runs && runs >= 1 && runs !== Infinity ? Math.floor(runs) : 1;
-}
-
-function assertTiming(clock: BenchmarkClock): void {
- // NaN indicates that a benchmark has not been timed properly
- if (!clock.stop) {
- throw new BenchmarkRunError(
- `Running benchmarks FAILED during benchmark named [${clock.for}]. The benchmark timer's stop method must be called`,
- clock.for,
- );
- } else if (!clock.start) {
- throw new BenchmarkRunError(
- `Running benchmarks FAILED during benchmark named [${clock.for}]. The benchmark timer's start method must be called`,
- clock.for,
- );
- } else if (clock.start > clock.stop) {
- throw new BenchmarkRunError(
- `Running benchmarks FAILED during benchmark named [${clock.for}]. The benchmark timer's start method must be called before its stop method`,
- clock.for,
- );
- }
-}
-
-function createBenchmarkTimer(clock: BenchmarkClock): BenchmarkTimer {
- return {
- start(): void {
- clock.start = performance.now();
- },
- stop(): void {
- if (isNaN(clock.start)) {
- throw new BenchmarkRunError(
- `Running benchmarks FAILED during benchmark named [${clock.for}]. The benchmark timer's start method must be called before its stop method`,
- clock.for,
- );
- }
- clock.stop = performance.now();
- },
- };
-}
-
-const candidates: BenchmarkDefinition[] = [];
-
-/** Registers a benchmark as a candidate for the runBenchmarks executor. */
-export function bench(
- benchmark: BenchmarkDefinition | BenchmarkFunction,
-): void {
- if (!benchmark.name) {
- throw new Error("The benchmark function must not be anonymous");
- }
- if (typeof benchmark === "function") {
- candidates.push({ name: benchmark.name, runs: 1, func: benchmark });
- } else {
- candidates.push({
- name: benchmark.name,
- runs: verifyOr1Run(benchmark.runs),
- func: benchmark.func,
- });
- }
-}
-
-/** Clears benchmark candidates which name matches `only` and doesn't match `skip`.
- * Removes all candidates if options were not provided */
-export function clearBenchmarks({
- only = /[^\s]/,
- skip = /$^/,
-}: BenchmarkClearOptions = {}): void {
- const keep = candidates.filter(
- ({ name }): boolean => !only.test(name) || skip.test(name),
- );
- candidates.splice(0, candidates.length);
- candidates.push(...keep);
-}
-
-/**
- * Runs all registered and non-skipped benchmarks serially.
- *
- * @param [progressCb] provides the possibility to get updates of the current progress during the run of the benchmarking
- * @returns results of the benchmarking
- */
-export async function runBenchmarks(
- { only = /[^\s]/, skip = /^\s*$/, silent }: BenchmarkRunOptions = {},
- progressCb?: (progress: BenchmarkRunProgress) => void | Promise<void>,
-): Promise<BenchmarkRunResult> {
- // Filtering candidates by the "only" and "skip" constraint
- const benchmarks: BenchmarkDefinition[] = candidates.filter(
- ({ name }): boolean => only.test(name) && !skip.test(name),
- );
- // Init main counters and error flag
- const filtered = candidates.length - benchmarks.length;
- let failError: Error | undefined = undefined;
- // Setting up a shared benchmark clock and timer
- const clock: BenchmarkClock = { start: NaN, stop: NaN };
- const b = createBenchmarkTimer(clock);
-
- // Init progress data
- const progress: BenchmarkRunProgress = {
- // bench.run is already ensured with verifyOr1Run on register
- queued: benchmarks.map((bench) => ({
- name: bench.name,
- runsCount: bench.runs!,
- })),
- results: [],
- filtered,
- state: ProgressState.BenchmarkingStart,
- };
-
- // Publish initial progress data
- await publishProgress(progress, ProgressState.BenchmarkingStart, progressCb);
-
- if (!silent) {
- console.log(
- "running",
- benchmarks.length,
- `benchmark${benchmarks.length === 1 ? " ..." : "s ..."}`,
- );
- }
-
- // Iterating given benchmark definitions (await-in-loop)
- for (const { name, runs = 0, func } of benchmarks) {
- if (!silent) {
- // See https://github.com/denoland/deno/pull/1452 about groupCollapsed
- console.groupCollapsed(`benchmark ${name} ... `);
- }
-
- // Provide the benchmark name for clock assertions
- clock.for = name;
-
- // Remove benchmark from queued
- assert(progress.queued);
- const queueIndex = progress.queued.findIndex(
- (queued) => queued.name === name && queued.runsCount === runs,
- );
- if (queueIndex != -1) {
- progress.queued.splice(queueIndex, 1);
- }
- // Init the progress of the running benchmark
- progress.running = { name, runsCount: runs, measuredRunsMs: [] };
- // Publish starting of a benchmark
- await publishProgress(progress, ProgressState.BenchStart, progressCb);
-
- // Trying benchmark.func
- let result = "";
- try {
- // Averaging runs
- let pendingRuns = runs;
- let totalMs = 0;
-
- // Would be better 2 not run these serially
- while (true) {
- // b is a benchmark timer interfacing an unset (NaN) benchmark clock
- await func(b);
- // Making sure the benchmark was started/stopped properly
- assertTiming(clock);
-
- // Calculate length of run
- const measuredMs = clock.stop - clock.start;
-
- // Summing up
- totalMs += measuredMs;
- // Adding partial result
- progress.running.measuredRunsMs.push(measuredMs);
- // Publish partial benchmark results
- await publishProgress(
- progress,
- ProgressState.BenchPartialResult,
- progressCb,
- );
-
- // Resetting the benchmark clock
- clock.start = clock.stop = NaN;
- // Once all ran
- if (!--pendingRuns) {
- result = runs == 1
- ? `${totalMs}ms`
- : `${runs} runs avg: ${totalMs / runs}ms`;
- // Adding results
- progress.results.push({
- name,
- totalMs,
- runsCount: runs,
- measuredRunsAvgMs: totalMs / runs,
- measuredRunsMs: progress.running.measuredRunsMs,
- });
- // Clear currently running
- delete progress.running;
- // Publish results of the benchmark
- await publishProgress(
- progress,
- ProgressState.BenchResult,
- progressCb,
- );
- break;
- }
- }
- } catch (err) {
- failError = err;
-
- if (!silent) {
- console.groupEnd();
- console.error(red(err.stack));
- }
-
- break;
- }
-
- if (!silent) {
- // Reporting
- console.log(blue(result));
- console.groupEnd();
- }
-
- // Resetting the benchmark clock
- clock.start = clock.stop = NaN;
- delete clock.for;
- }
-
- // Indicate finished running
- delete progress.queued;
- // Publish final result in Cb too
- await publishProgress(progress, ProgressState.BenchmarkingEnd, progressCb);
-
- if (!silent) {
- // Closing results
- console.log(
- `benchmark result: ${failError ? red("FAIL") : blue("DONE")}. ` +
- `${progress.results.length} measured; ${filtered} filtered`,
- );
- }
-
- // Throw error if there was a failing benchmark
- if (failError) {
- throw failError;
- }
-
- const benchmarkRunResult = {
- filtered,
- results: progress.results,
- };
-
- return benchmarkRunResult;
-}
-
-async function publishProgress(
- progress: BenchmarkRunProgress,
- state: ProgressState,
- progressCb?: (progress: BenchmarkRunProgress) => void | Promise<void>,
-): Promise<void> {
- progressCb && (await progressCb(cloneProgressWithState(progress, state)));
-}
-
-function cloneProgressWithState(
- progress: BenchmarkRunProgress,
- state: ProgressState,
-): BenchmarkRunProgress {
- return deepAssign({}, progress, { state }) as BenchmarkRunProgress;
-}
diff --git a/std/testing/bench_example.ts b/std/testing/bench_example.ts
deleted file mode 100644
index 5af277f1c..000000000
--- a/std/testing/bench_example.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-// https://deno.land/std/testing/bench.ts
-import { bench, BenchmarkTimer, runBenchmarks } from "./bench.ts";
-
-// Basic
-bench(function forIncrementX1e9(b: BenchmarkTimer): void {
- b.start();
- for (let i = 0; i < 1e9; i++);
- b.stop();
-});
-
-// Reporting average measured time for $runs runs of func
-bench({
- name: "runs100ForIncrementX1e6",
- runs: 100,
- func(b): void {
- b.start();
- for (let i = 0; i < 1e6; i++);
- b.stop();
- },
-});
-
-// Itsabug
-bench(function throwing(b): void {
- b.start();
- // Throws bc the timer's stop method is never called
-});
-
-// Bench control
-if (import.meta.main) {
- runBenchmarks({ skip: /throw/ });
-}
diff --git a/std/testing/bench_test.ts b/std/testing/bench_test.ts
deleted file mode 100644
index 6ce7796ca..000000000
--- a/std/testing/bench_test.ts
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-import {
- bench,
- BenchmarkRunError,
- BenchmarkRunProgress,
- clearBenchmarks,
- ProgressState,
- runBenchmarks,
-} from "./bench.ts";
-import {
- assert,
- assertEquals,
- assertThrows,
- assertThrowsAsync,
-} from "./asserts.ts";
-
-Deno.test({
- name: "benching",
-
- fn: async function (): Promise<void> {
- bench(function forIncrementX1e3(b): void {
- b.start();
- for (let i = 0; i < 1e3; i++);
- b.stop();
- });
-
- bench(function forDecrementX1e3(b): void {
- b.start();
- for (let i = 1e3; i > 0; i--);
- b.stop();
- });
-
- bench(async function forAwaitFetchDenolandX10(b): Promise<void> {
- b.start();
- for (let i = 0; i < 10; i++) {
- const r = await fetch("https://deno.land/");
- await r.text();
- }
- b.stop();
- });
-
- bench(async function promiseAllFetchDenolandX10(b): Promise<void> {
- const urls = new Array(10).fill("https://deno.land/");
- b.start();
- await Promise.all(
- urls.map(
- async (denoland: string): Promise<void> => {
- const r = await fetch(denoland);
- await r.text();
- },
- ),
- );
- b.stop();
- });
-
- bench({
- name: "runs100ForIncrementX1e6",
- runs: 100,
- func(b): void {
- b.start();
- for (let i = 0; i < 1e6; i++);
- b.stop();
- },
- });
-
- bench(function throwing(b): void {
- b.start();
- // Throws bc the timer's stop method is never called
- });
-
- const benchResult = await runBenchmarks({ skip: /throw/ });
-
- assertEquals(benchResult.filtered, 1);
- assertEquals(benchResult.results.length, 5);
-
- const resultWithSingleRunsFiltered = benchResult.results.filter(
- ({ name }) => name === "forDecrementX1e3",
- );
- assertEquals(resultWithSingleRunsFiltered.length, 1);
-
- const resultWithSingleRuns = resultWithSingleRunsFiltered[0];
- assert(!!resultWithSingleRuns.runsCount);
- assert(!!resultWithSingleRuns.measuredRunsAvgMs);
- assert(!!resultWithSingleRuns.measuredRunsMs);
- assertEquals(resultWithSingleRuns.runsCount, 1);
- assertEquals(resultWithSingleRuns.measuredRunsMs.length, 1);
-
- const resultWithMultipleRunsFiltered = benchResult.results.filter(
- ({ name }) => name === "runs100ForIncrementX1e6",
- );
- assertEquals(resultWithMultipleRunsFiltered.length, 1);
-
- const resultWithMultipleRuns = resultWithMultipleRunsFiltered[0];
- assert(!!resultWithMultipleRuns.runsCount);
- assert(!!resultWithMultipleRuns.measuredRunsAvgMs);
- assert(!!resultWithMultipleRuns.measuredRunsMs);
- assertEquals(resultWithMultipleRuns.runsCount, 100);
- assertEquals(resultWithMultipleRuns.measuredRunsMs.length, 100);
-
- clearBenchmarks();
- },
-});
-
-Deno.test({
- name: "Bench without name should throw",
- fn() {
- assertThrows(
- (): void => {
- bench(() => {});
- },
- Error,
- "The benchmark function must not be anonymous",
- );
- },
-});
-
-Deno.test({
- name: "Bench without stop should throw",
- fn: async function (): Promise<void> {
- await assertThrowsAsync(
- async (): Promise<void> => {
- bench(function benchWithoutStop(b): void {
- b.start();
- // Throws bc the timer's stop method is never called
- });
- await runBenchmarks({ only: /benchWithoutStop/, silent: true });
- },
- BenchmarkRunError,
- "The benchmark timer's stop method must be called",
- );
- },
-});
-
-Deno.test({
- name: "Bench without start should throw",
- fn: async function (): Promise<void> {
- await assertThrowsAsync(
- async (): Promise<void> => {
- bench(function benchWithoutStart(b): void {
- b.stop();
- // Throws bc the timer's start method is never called
- });
- await runBenchmarks({ only: /benchWithoutStart/, silent: true });
- },
- BenchmarkRunError,
- "The benchmark timer's start method must be called",
- );
- },
-});
-
-Deno.test({
- name: "Bench with stop before start should throw",
- fn: async function (): Promise<void> {
- await assertThrowsAsync(
- async (): Promise<void> => {
- bench(function benchStopBeforeStart(b): void {
- b.stop();
- b.start();
- // Throws bc the timer's stop is called before start
- });
- await runBenchmarks({ only: /benchStopBeforeStart/, silent: true });
- },
- BenchmarkRunError,
- "The benchmark timer's start method must be called before its stop method",
- );
- },
-});
-
-Deno.test({
- name: "clearBenchmarks should clear all candidates",
- fn: async function (): Promise<void> {
- dummyBench("test");
-
- clearBenchmarks();
- const benchingResults = await runBenchmarks({ silent: true });
-
- assertEquals(benchingResults.filtered, 0);
- assertEquals(benchingResults.results.length, 0);
- },
-});
-
-Deno.test({
- name: "clearBenchmarks with only as option",
- fn: async function (): Promise<void> {
- // to reset candidates
- clearBenchmarks();
-
- dummyBench("test");
- dummyBench("onlyclear");
-
- clearBenchmarks({ only: /only/ });
- const benchingResults = await runBenchmarks({ silent: true });
-
- assertEquals(benchingResults.filtered, 0);
- assertEquals(benchingResults.results.length, 1);
- assertEquals(benchingResults.results[0].name, "test");
- },
-});
-
-Deno.test({
- name: "clearBenchmarks with skip as option",
- fn: async function (): Promise<void> {
- // to reset candidates
- clearBenchmarks();
-
- dummyBench("test");
- dummyBench("skipclear");
-
- clearBenchmarks({ skip: /skip/ });
- const benchingResults = await runBenchmarks({ silent: true });
-
- assertEquals(benchingResults.filtered, 0);
- assertEquals(benchingResults.results.length, 1);
- assertEquals(benchingResults.results[0].name, "skipclear");
- },
-});
-
-Deno.test({
- name: "clearBenchmarks with only and skip as option",
- fn: async function (): Promise<void> {
- // to reset candidates
- clearBenchmarks();
-
- dummyBench("test");
- dummyBench("clearonly");
- dummyBench("clearskip");
- dummyBench("clearonly");
-
- clearBenchmarks({ only: /clear/, skip: /skip/ });
- const benchingResults = await runBenchmarks({ silent: true });
-
- assertEquals(benchingResults.filtered, 0);
- assertEquals(benchingResults.results.length, 2);
- assert(!!benchingResults.results.find(({ name }) => name === "test"));
- assert(!!benchingResults.results.find(({ name }) => name === "clearskip"));
- },
-});
-
-Deno.test({
- name: "progressCallback of runBenchmarks",
- fn: async function (): Promise<void> {
- clearBenchmarks();
- dummyBench("skip");
- dummyBench("single");
- dummyBench("multiple", 2);
-
- const progressCallbacks: BenchmarkRunProgress[] = [];
-
- const benchingResults = await runBenchmarks(
- { skip: /skip/, silent: true },
- (progress) => {
- progressCallbacks.push(progress);
- },
- );
-
- let pc = 0;
- // Assert initial progress before running
- let progress = progressCallbacks[pc++];
- assert(progress.queued);
- assertEquals(progress.state, ProgressState.BenchmarkingStart);
- assertEquals(progress.filtered, 1);
- assertEquals(progress.queued.length, 2);
- assertEquals(progress.running, undefined);
- assertEquals(progress.results, []);
-
- // Assert start of bench "single"
- progress = progressCallbacks[pc++];
- assertEquals(progress.state, ProgressState.BenchStart);
- assertEquals(progress.filtered, 1);
- assert(progress.queued);
- assertEquals(progress.queued.length, 1);
- assert(!!progress.queued.find(({ name }) => name == "multiple"));
- assertEquals(progress.running, {
- name: "single",
- runsCount: 1,
- measuredRunsMs: [],
- });
- assertEquals(progress.results, []);
-
- // Assert running result of bench "single"
- progress = progressCallbacks[pc++];
- assertEquals(progress.state, ProgressState.BenchPartialResult);
- assert(progress.queued);
- assertEquals(progress.queued.length, 1);
- assertEquals(progress.running!.measuredRunsMs.length, 1);
- assertEquals(progress.results.length, 0);
-
- // Assert result of bench "single"
- progress = progressCallbacks[pc++];
- assertEquals(progress.state, ProgressState.BenchResult);
- assert(progress.queued);
- assertEquals(progress.queued.length, 1);
- assertEquals(progress.running, undefined);
- assertEquals(progress.results.length, 1);
- assert(!!progress.results.find(({ name }) => name == "single"));
-
- // Assert start of bench "multiple"
- progress = progressCallbacks[pc++];
- assertEquals(progress.state, ProgressState.BenchStart);
- assert(progress.queued);
- assertEquals(progress.queued.length, 0);
- assertEquals(progress.running, {
- name: "multiple",
- runsCount: 2,
- measuredRunsMs: [],
- });
- assertEquals(progress.results.length, 1);
-
- // Assert first result of bench "multiple"
- progress = progressCallbacks[pc++];
- assertEquals(progress.state, ProgressState.BenchPartialResult);
- assert(progress.queued);
- assertEquals(progress.queued.length, 0);
- assertEquals(progress.running!.measuredRunsMs.length, 1);
- assertEquals(progress.results.length, 1);
-
- // Assert second result of bench "multiple"
- progress = progressCallbacks[pc++];
- assertEquals(progress.state, ProgressState.BenchPartialResult);
- assert(progress.queued);
- assertEquals(progress.queued.length, 0);
- assertEquals(progress.running!.measuredRunsMs.length, 2);
- assertEquals(progress.results.length, 1);
-
- // Assert finish of bench "multiple"
- progress = progressCallbacks[pc++];
- assertEquals(progress.state, ProgressState.BenchResult);
- assert(progress.queued);
- assertEquals(progress.queued.length, 0);
- assertEquals(progress.running, undefined);
- assertEquals(progress.results.length, 2);
- assert(!!progress.results.find(({ name }) => name == "single"));
- const resultOfMultiple = progress.results.filter(
- ({ name }) => name == "multiple",
- );
- assertEquals(resultOfMultiple.length, 1);
- assert(!!resultOfMultiple[0].measuredRunsMs);
- assert(!isNaN(resultOfMultiple[0].measuredRunsAvgMs));
- assertEquals(resultOfMultiple[0].measuredRunsMs.length, 2);
-
- // The last progress should equal the final result from promise except the state property
- progress = progressCallbacks[pc++];
- assertEquals(progress.state, ProgressState.BenchmarkingEnd);
- delete progress.state;
- assertEquals(progress, benchingResults);
- },
-});
-
-Deno.test({
- name: "async progressCallback",
- fn: async function (): Promise<void> {
- clearBenchmarks();
- dummyBench("single");
-
- const asyncCallbacks = [];
-
- await runBenchmarks({ silent: true }, (progress) => {
- return new Promise((resolve) => {
- queueMicrotask(() => {
- asyncCallbacks.push(progress);
- resolve();
- });
- });
- });
-
- assertEquals(asyncCallbacks.length, 5);
- },
-});
-
-function dummyBench(name: string, runs = 1): void {
- bench({
- name,
- runs,
- func(b) {
- b.start();
- b.stop();
- },
- });
-}