import { AssertionError, AssertionErrorConstructorOptions,} from "./assertion_error.ts";import * as asserts from "../testing/asserts.ts";import { inspect } from "./util.ts";import { ERR_AMBIGUOUS_ARGUMENT, ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, ERR_INVALID_RETURN_VALUE, ERR_MISSING_ARGS,} from "./internal/errors.ts";
interface ExtendedAssertionErrorConstructorOptions extends AssertionErrorConstructorOptions { generatedMessage?: boolean;}
function createAssertionError( options: ExtendedAssertionErrorConstructorOptions,): AssertionError { const error = new AssertionError(options); if (options.generatedMessage) { error.generatedMessage = true; } return error;}
function toNode( fn: () => void, opts?: { actual: unknown; expected: unknown; message?: string | Error; operator?: string; },) { const { operator, message, actual, expected } = opts || {}; try { fn(); } catch (e) { if (e instanceof asserts.AssertionError) { if (typeof message === "string") { throw new AssertionError({ operator, message, actual, expected, }); } else if (message instanceof Error) { throw message; } else { throw new AssertionError({ operator, message: e.message, actual, expected, }); } } throw e; }}
function assert(actual: unknown, message?: string | Error): asserts actual { if (arguments.length === 0) { throw new AssertionError({ message: "No value argument passed to `assert.ok()`", }); } toNode( () => asserts.assert(actual), { message, actual, expected: true }, );}const ok = assert;
function throws( fn: () => void, error?: RegExp | Function | Error, message?: string,): void { if (typeof fn !== "function") { throw new ERR_INVALID_ARG_TYPE("fn", "function", fn); } if ( typeof error === "object" && error !== null && Object.getPrototypeOf(error) === Object.prototype && Object.keys(error).length === 0 ) { throw new ERR_INVALID_ARG_VALUE( "error", error, "may not be an empty object", ); } if (typeof message === "string") { if ( !(error instanceof RegExp) && typeof error !== "function" && !(error instanceof Error) && typeof error !== "object" ) { throw new ERR_INVALID_ARG_TYPE("error", [ "Function", "Error", "RegExp", "Object", ], error); } } else { if ( typeof error !== "undefined" && typeof error !== "string" && !(error instanceof RegExp) && typeof error !== "function" && !(error instanceof Error) && typeof error !== "object" ) { throw new ERR_INVALID_ARG_TYPE("error", [ "Function", "Error", "RegExp", "Object", ], error); } }
try { fn(); } catch (e) { if ( validateThrownError(e, error, message, { operator: throws, }) ) { return; } } if (message) { let msg = `Missing expected exception: ${message}`; if (typeof error === "function" && error?.name) { msg = `Missing expected exception (${error.name}): ${message}`; } throw new AssertionError({ message: msg, operator: "throws", actual: undefined, expected: error, }); } else if (typeof error === "string") { throw new AssertionError({ message: `Missing expected exception: ${error}`, operator: "throws", actual: undefined, expected: undefined, }); } else if (typeof error === "function" && error?.prototype !== undefined) { throw new AssertionError({ message: `Missing expected exception (${error.name}).`, operator: "throws", actual: undefined, expected: error, }); } else { throw new AssertionError({ message: "Missing expected exception.", operator: "throws", actual: undefined, expected: error, }); }}
function doesNotThrow( fn: () => void, message?: string,): void;function doesNotThrow( fn: () => void, error?: Function, message?: string | Error,): void;function doesNotThrow( fn: () => void, error?: RegExp, message?: string,): void;function doesNotThrow( fn: () => void, expected?: Function | RegExp | string, message?: string | Error,): void { if (typeof fn !== "function") { throw new ERR_INVALID_ARG_TYPE("fn", "function", fn); } else if ( !(expected instanceof RegExp) && typeof expected !== "function" && typeof expected !== "string" && typeof expected !== "undefined" ) { throw new ERR_INVALID_ARG_TYPE("expected", ["Function", "RegExp"], fn); }
try { fn(); } catch (e) { gotUnwantedException(e, expected, message, doesNotThrow); } return;}
function equal( actual: unknown, expected: unknown, message?: string | Error,): void { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("actual", "expected"); }
if (actual == expected) { return; }
if (Number.isNaN(actual) && Number.isNaN(expected)) { return; }
if (typeof message === "string") { throw new AssertionError({ message, }); } else if (message instanceof Error) { throw message; }
toNode( () => asserts.assertStrictEquals(actual, expected), { message: message || `${actual} == ${expected}`, operator: "==", actual, expected, }, );}function notEqual( actual: unknown, expected: unknown, message?: string | Error,): void { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("actual", "expected"); }
if (Number.isNaN(actual) && Number.isNaN(expected)) { throw new AssertionError({ message: `${actual} != ${expected}`, operator: "!=", actual, expected, }); } if (actual != expected) { return; }
if (typeof message === "string") { throw new AssertionError({ message, }); } else if (message instanceof Error) { throw message; }
toNode( () => asserts.assertNotStrictEquals(actual, expected), { message: message || `${actual} != ${expected}`, operator: "!=", actual, expected, }, );}function strictEqual( actual: unknown, expected: unknown, message?: string | Error,): void { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("actual", "expected"); }
toNode( () => asserts.assertStrictEquals(actual, expected), { message, operator: "strictEqual", actual, expected }, );}function notStrictEqual( actual: unknown, expected: unknown, message?: string | Error,) { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("actual", "expected"); }
toNode( () => asserts.assertNotStrictEquals(actual, expected), { message, actual, expected, operator: "notStrictEqual" }, );}
function deepEqual() { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("actual", "expected"); }
throw new Error("Not implemented");}function notDeepEqual() { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("actual", "expected"); }
throw new Error("Not implemented");}function deepStrictEqual( actual: unknown, expected: unknown, message?: string | Error,) { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("actual", "expected"); }
toNode( () => asserts.assertEquals(actual, expected), { message, actual, expected, operator: "deepStrictEqual" }, );}function notDeepStrictEqual( actual: unknown, expected: unknown, message?: string | Error,) { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("actual", "expected"); }
toNode( () => asserts.assertNotEquals(actual, expected), { message, actual, expected, operator: "deepNotStrictEqual" }, );}
function fail(message?: string | Error): never { if (typeof message === "string" || message == null) { throw createAssertionError({ message: message ?? "Failed", operator: "fail", generatedMessage: message == null, }); } else { throw message; }}function match(actual: string, regexp: RegExp, message?: string | Error) { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("actual", "regexp"); } if (!(regexp instanceof RegExp)) { throw new ERR_INVALID_ARG_TYPE("regexp", "RegExp", regexp); }
toNode( () => asserts.assertMatch(actual, regexp), { message, actual, expected: regexp, operator: "match" }, );}
function doesNotMatch( string: string, regexp: RegExp, message?: string | Error,) { if (arguments.length < 2) { throw new ERR_MISSING_ARGS("string", "regexp"); } if (!(regexp instanceof RegExp)) { throw new ERR_INVALID_ARG_TYPE("regexp", "RegExp", regexp); } if (typeof string !== "string") { if (message instanceof Error) { throw message; } throw new AssertionError({ message: message || `The "string" argument must be of type string. Received type ${typeof string} (${ inspect(string) })`, actual: string, expected: regexp, operator: "doesNotMatch", }); }
toNode( () => asserts.assertNotMatch(string, regexp), { message, actual: string, expected: regexp, operator: "doesNotMatch" }, );}
function strict(actual: unknown, message?: string | Error): asserts actual { if (arguments.length === 0) { throw new AssertionError({ message: "No value argument passed to `assert.ok()`", }); } assert(actual, message);}
function rejects( asyncFn: Promise<any> | (() => Promise<any>), error?: RegExp | Function | Error,): Promise<void>;
function rejects( asyncFn: Promise<any> | (() => Promise<any>), message?: string,): Promise<void>;
function rejects( asyncFn: Promise<any> | (() => Promise<any>), error?: RegExp | Function | Error | string, message?: string,): Promise<void> { let promise: Promise<void>; if (typeof asyncFn === "function") { try { promise = asyncFn(); } catch (err) { return Promise.reject(err); }
if (!isValidThenable(promise)) { return Promise.reject( new ERR_INVALID_RETURN_VALUE( "instance of Promise", "promiseFn", promise, ), ); } } else if (!isValidThenable(asyncFn)) { return Promise.reject( new ERR_INVALID_ARG_TYPE("promiseFn", ["function", "Promise"], asyncFn), ); } else { promise = asyncFn; }
function onFulfilled(): Promise<void> { let message = "Missing expected rejection"; if (typeof error === "string") { message += `: ${error}`; } else if (typeof error === "function" && error.prototype !== undefined) { message += ` (${error.name}).`; } else { message += "."; } return Promise.reject(createAssertionError({ message, operator: "rejects", generatedMessage: true, })); }
function rejects_onRejected(e: Error): void { if ( validateThrownError(e, error, message, { operator: rejects, validationFunctionName: "validate", }) ) { return; } }
return promise.then(onFulfilled, rejects_onRejected);}
function doesNotReject( asyncFn: Promise<any> | (() => Promise<any>), error?: RegExp | Function,): Promise<void>;
function doesNotReject( asyncFn: Promise<any> | (() => Promise<any>), message?: string,): Promise<void>;
function doesNotReject( asyncFn: Promise<any> | (() => Promise<any>), error?: RegExp | Function | string, message?: string,): Promise<void> { let promise: Promise<any>; if (typeof asyncFn === "function") { try { const value = asyncFn(); if (!isValidThenable(value)) { return Promise.reject( new ERR_INVALID_RETURN_VALUE( "instance of Promise", "promiseFn", value, ), ); } promise = value; } catch (e) { return Promise.reject(e); } } else if (!isValidThenable(asyncFn)) { return Promise.reject( new ERR_INVALID_ARG_TYPE("promiseFn", ["function", "Promise"], asyncFn), ); } else { promise = asyncFn; }
return promise.then( () => {}, (e) => gotUnwantedException(e, error, message, doesNotReject), );}
function gotUnwantedException( e: any, expected: RegExp | Function | string | null | undefined, message: string | Error | null | undefined, operator: Function,): never { if (typeof expected === "string") { throw new AssertionError({ message: `Got unwanted exception: ${expected}\nActual message: "${e.message}"`, operator: operator.name, }); } else if ( typeof expected === "function" && expected.prototype !== undefined ) { if (e instanceof expected) { let msg = `Got unwanted exception: ${e.constructor?.name}`; if (message) { msg += ` ${String(message)}`; } throw new AssertionError({ message: msg, operator: operator.name, }); } else if (expected.prototype instanceof Error) { throw e; } else { const result = expected(e); if (result === true) { let msg = `Got unwanted rejection.\nActual message: "${e.message}"`; if (message) { msg += ` ${String(message)}`; } throw new AssertionError({ message: msg, operator: operator.name, }); } } throw e; } else { if (message) { throw new AssertionError({ message: `Got unwanted exception: ${message}\nActual message: "${ e ? e.message : String(e) }"`, operator: operator.name, }); } throw new AssertionError({ message: `Got unwanted exception.\nActual message: "${ e ? e.message : String(e) }"`, operator: operator.name, }); }}
function ifError(err: any) { if (err !== null && err !== undefined) { let message = "ifError got unwanted exception: ";
if (typeof err === "object" && typeof err.message === "string") { if (err.message.length === 0 && err.constructor) { message += err.constructor.name; } else { message += err.message; } } else { message += inspect(err); }
const newErr = new AssertionError({ actual: err, expected: null, operator: "ifError", message, stackStartFn: ifError, });
const origStack = err.stack;
if (typeof origStack === "string") { const tmp2 = origStack.split("\n"); tmp2.shift();
let tmp1 = newErr!.stack?.split("\n");
for (const errFrame of tmp2) { const pos = tmp1?.indexOf(errFrame);
if (pos !== -1) { tmp1 = tmp1?.slice(0, pos);
break; } }
newErr.stack = `${tmp1?.join("\n")}\n${tmp2.join("\n")}`; }
throw newErr; }}
interface ValidateThrownErrorOptions { operator: Function; validationFunctionName?: string;}
function validateThrownError( e: any, error: RegExp | Function | Error | string | null | undefined, message: string | undefined | null, options: ValidateThrownErrorOptions,): boolean { if (typeof error === "string") { if (message != null) { throw new ERR_INVALID_ARG_TYPE( "error", ["Object", "Error", "Function", "RegExp"], error, ); } else if (typeof e === "object" && e !== null) { if (e.message === error) { throw new ERR_AMBIGUOUS_ARGUMENT( "error/message", `The error message "${e.message}" is identical to the message.`, ); } } else if (e === error) { throw new ERR_AMBIGUOUS_ARGUMENT( "error/message", `The error "${e}" is identical to the message.`, ); } message = error; error = undefined; } if ( error instanceof Function && error.prototype !== undefined && error.prototype instanceof Error ) { if (e instanceof error) { return true; } throw createAssertionError({ message: `The error is expected to be an instance of "${error.name}". Received "${e ?.constructor?.name}"\n\nError message:\n\n${e?.message}`, actual: e, expected: error, operator: options.operator.name, generatedMessage: true, }); } if (error instanceof Function) { const received = error(e); if (received === true) { return true; } throw createAssertionError({ message: `The ${ options.validationFunctionName ? `"${options.validationFunctionName}" validation` : "validation" } function is expected to return "true". Received ${ inspect(received) }\n\nCaught error:\n\n${e}`, actual: e, expected: error, operator: options.operator.name, generatedMessage: true, }); } if (error instanceof RegExp) { if (error.test(String(e))) { return true; } throw createAssertionError({ message: `The input did not match the regular expression ${error.toString()}. Input:\n\n'${ String(e) }'\n`, actual: e, expected: error, operator: options.operator.name, generatedMessage: true, }); } if (typeof error === "object" && error !== null) { const keys = Object.keys(error); if (error instanceof Error) { keys.push("name", "message"); } for (const k of keys) { if (e == null) { throw createAssertionError({ message: message || "object is expected to thrown, but got null", actual: e, expected: error, operator: options.operator.name, generatedMessage: message == null, }); }
if (typeof e === "string") { throw createAssertionError({ message: message || `object is expected to thrown, but got string: ${e}`, actual: e, expected: error, operator: options.operator.name, generatedMessage: message == null, }); } if (typeof e === "number") { throw createAssertionError({ message: message || `object is expected to thrown, but got number: ${e}`, actual: e, expected: error, operator: options.operator.name, generatedMessage: message == null, }); } if (!(k in e)) { throw createAssertionError({ message: message || `A key in the expected object is missing: ${k}`, actual: e, expected: error, operator: options.operator.name, generatedMessage: message == null, }); } const actual = e[k]; const expected = (error as any)[k]; if (typeof actual === "string" && expected instanceof RegExp) { match(actual, expected); } else { deepStrictEqual(actual, expected); } } return true; } if (typeof error === "undefined") { return true; } throw createAssertionError({ message: `Invalid expectation: ${error}`, operator: options.operator.name, generatedMessage: true, });}
function isValidThenable(maybeThennable: any): boolean { if (!maybeThennable) { return false; }
if (maybeThennable instanceof Promise) { return true; }
const isThenable = typeof maybeThennable.then === "function" && typeof maybeThennable.catch === "function";
return isThenable && typeof maybeThennable !== "function";}
Object.assign(strict, { AssertionError, deepEqual: deepStrictEqual, deepStrictEqual, doesNotMatch, doesNotReject, doesNotThrow, equal: strictEqual, fail, ifError, match, notDeepEqual: notDeepStrictEqual, notDeepStrictEqual, notEqual: notStrictEqual, notStrictEqual, ok, rejects, strict, strictEqual, throws,});
export default Object.assign(assert, { AssertionError, deepEqual, deepStrictEqual, doesNotMatch, doesNotReject, doesNotThrow, equal, fail, ifError, match, notDeepEqual, notDeepStrictEqual, notEqual, notStrictEqual, ok, rejects, strict, strictEqual, throws,});
export { AssertionError, deepEqual, deepStrictEqual, doesNotMatch, doesNotReject, doesNotThrow, equal, fail, ifError, match, notDeepEqual, notDeepStrictEqual, notEqual, notStrictEqual, ok, rejects, strict, strictEqual, throws,};