Skip to content
Permalink
Browse files

Refactor asserts in testing (denoland#227)

  • Loading branch information...
zekth authored and ry committed Mar 5, 2019
1 parent 8fb9f70 commit c734e3234322cea5298a887373fe4ad1591d7c97
Showing with 261 additions and 140 deletions.
  1. +179 −0 testing/asserts.ts
  2. +46 −0 testing/asserts_test.ts
  3. +0 −2 testing/bench.ts
  4. +13 −9 testing/diff.ts
  5. +18 −124 testing/mod.ts
  6. +4 −4 testing/pretty.ts
  7. +1 −1 testing/test.ts
@@ -0,0 +1,179 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { assertEqual as prettyAssertEqual } from "./pretty.ts";

interface Constructor {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
new (...args: any[]): any;
}

/** Make an assertion, if not `true`, then throw. */
export function assert(expr: boolean, msg = ""): void {
if (!expr) {
throw new Error(msg);
}
}

/**
* Make an assertion that `actual` and `expected` are equal, deeply. If not
* deeply equal, then throw.
*/
export function equal(actual: unknown, expected: unknown, msg?: string): void {
prettyAssertEqual(actual, expected, msg);
}

/**
* Make an assertion that `actual` and `expected` are strictly equal. If
* not then throw.
*/
export function assertStrictEq(
actual: unknown,
expected: unknown,
msg?: string
): void {
if (actual !== expected) {
let actualString: string;
let expectedString: string;
try {
actualString = String(actual);
} catch (e) {
actualString = "[Cannot display]";
}
try {
expectedString = String(expected);
} catch (e) {
expectedString = "[Cannot display]";
}
console.error(
"strictEqual failed. actual =",
actualString,
"expected =",
expectedString
);
if (!msg) {
msg = `actual: ${actualString} expected: ${expectedString}`;
}
throw new Error(msg);
}
}

/**
* Make an assertion that actual contains expected. If not
* then thrown.
*/
export function assertStrContains(
actual: string,
expected: string,
msg?: string
): void {
if (!actual.includes(expected)) {
console.error(
"stringContains failed. actual =",
actual,
"not containing ",
expected
);
if (!msg) {
msg = `actual: "${actual}" expected to contains: "${expected}"`;
}
throw new Error(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)) {
console.error(
"stringMatching failed. actual =",
actual,
"not matching RegExp ",
expected
);
if (!msg) {
msg = `actual: "${actual}" expected to match: "${expected}"`;
}
throw new Error(msg);
}
}

/**
* 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(
fn: () => void,
ErrorClass?: Constructor,
msgIncludes = "",
msg?: string
): void {
let doesThrow = false;
try {
fn();
} catch (e) {
if (ErrorClass && !(Object.getPrototypeOf(e) === ErrorClass.prototype)) {
msg = `Expected error to be instance of "${ErrorClass.name}"${
msg ? `: ${msg}` : "."
}`;
throw new Error(msg);
}
if (msgIncludes) {
if (!e.message.includes(msgIncludes)) {
msg = `Expected error message to include "${msgIncludes}", but got "${
e.message
}"${msg ? `: ${msg}` : "."}`;
throw new Error(msg);
}
}
doesThrow = true;
}
if (!doesThrow) {
msg = `Expected function to throw${msg ? `: ${msg}` : "."}`;
throw new Error(msg);
}
}

export async function assertThrowsAsync(
fn: () => Promise<void>,
ErrorClass?: Constructor,
msgIncludes = "",
msg?: string
): Promise<void> {
let doesThrow = false;
try {
await fn();
} catch (e) {
if (ErrorClass && !(Object.getPrototypeOf(e) === ErrorClass.prototype)) {
msg = `Expected error to be instance of "${ErrorClass.name}"${
msg ? `: ${msg}` : "."
}`;
throw new Error(msg);
}
if (msgIncludes) {
if (!e.message.includes(msgIncludes)) {
msg = `Expected error message to include "${msgIncludes}", but got "${
e.message
}"${msg ? `: ${msg}` : "."}`;
throw new Error(msg);
}
}
doesThrow = true;
}
if (!doesThrow) {
msg = `Expected function to throw${msg ? `: ${msg}` : "."}`;
throw new Error(msg);
}
}
@@ -0,0 +1,46 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.

import { assertStrContains, assertMatch } from "./asserts.ts";
import { test, assert } from "./mod.ts";
// import { assertEqual as prettyAssertEqual } from "./pretty.ts";
// import "./format_test.ts";
// import "./diff_test.ts";
// import "./pretty_test.ts";

test(function testingAssertStringContains() {
assertStrContains("Denosaurus", "saur");
assertStrContains("Denosaurus", "Deno");
assertStrContains("Denosaurus", "rus");
});

test(function testingAssertStringContainsThrow() {
let didThrow = false;
try {
assertStrContains("Denosaurus from Jurassic", "Raptor");
} catch (e) {
assert(
e.message ===
`actual: "Denosaurus from Jurassic" expected to contains: "Raptor"`
);
didThrow = true;
}
assert(didThrow);
});

test(function testingAssertStringMatching() {
assertMatch("foobar@deno.com", RegExp(/[a-zA-Z]+@[a-zA-Z]+.com/));
});

test(function testingAssertStringMatchingThrows() {
let didThrow = false;
try {
assertMatch("Denosaurus from Jurassic", RegExp(/Raptor/));
} catch (e) {
assert(
e.message ===
`actual: "Denosaurus from Jurassic" expected to match: "/Raptor/"`
);
didThrow = true;
}
assert(didThrow);
});
@@ -1,8 +1,6 @@
import { bench, runBenchmarks } from "./../benching/mod.ts";
import { runTests } from "./mod.ts";

import "./test.ts";

bench(async function testingSerial(b) {
b.start();
await runTests();
@@ -4,7 +4,11 @@ interface FarthestPoint {
id: number;
}

export type DiffType = "removed" | "common" | "added";
export enum DiffType {
removed = "removed",
common = "common",
added = "added"
}

export interface DiffResult<T> {
type: DiffType;
@@ -50,12 +54,12 @@ export default function diff<T>(A: T[], B: T[]): Array<DiffResult<T>> {
if (!M && !N && !suffixCommon.length && !prefixCommon.length) return [];
if (!N) {
return [
...prefixCommon.map(c => ({ type: "common" as DiffType, value: c })),
...prefixCommon.map(c => ({ type: DiffType.common, value: c })),
...A.map(a => ({
type: (swapped ? "added" : "removed") as DiffType,
type: swapped ? DiffType.added : DiffType.removed,
value: a
})),
...suffixCommon.map(c => ({ type: "common" as DiffType, value: c }))
...suffixCommon.map(c => ({ type: DiffType.common, value: c }))
];
}
const offset = N;
@@ -91,18 +95,18 @@ export default function diff<T>(A: T[], B: T[]): Array<DiffResult<T>> {
const prev = j;
if (type === REMOVED) {
result.unshift({
type: (swapped ? "removed" : "added") as DiffType,
type: swapped ? DiffType.removed : DiffType.added,
value: B[b]
});
b -= 1;
} else if (type === ADDED) {
result.unshift({
type: (swapped ? "added" : "removed") as DiffType,
type: swapped ? DiffType.added : DiffType.removed,
value: A[a]
});
a -= 1;
} else {
result.unshift({ type: "common" as DiffType, value: A[a] });
result.unshift({ type: DiffType.common, value: A[a] });
a -= 1;
b -= 1;
}
@@ -194,8 +198,8 @@ export default function diff<T>(A: T[], B: T[]): Array<DiffResult<T>> {
);
}
return [
...prefixCommon.map(c => ({ type: "common" as DiffType, value: c })),
...prefixCommon.map(c => ({ type: DiffType.common, value: c })),
...backTrace(A, B, fp[delta + offset], swapped),
...suffixCommon.map(c => ({ type: "common" as DiffType, value: c }))
...suffixCommon.map(c => ({ type: DiffType.common, value: c }))
];
}
Oops, something went wrong.

0 comments on commit c734e32

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.