// https://github.com/nodejs/node/commit/c1d82ac2ff15594840e2a1b9531b506ae067ed27; // http://wiki.commonjs.org/wiki/Unit_Testing/1.0 // // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! // // Originally from narwhal.js (http://narwhaljs.org) // Copyright (c) 2009 Thomas Robinson <280north.com> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the 'Software'), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /** @todo replace this ridiculous choice of deepStrictEqual */ // eslint-disable-next-line complexity export function deepStrictEqual(actual: unknown, expected: unknown, strict?: boolean) { // 7.1. All identical values are equivalent, as determined by ===. if (actual === expected) { return true; // } else if (actual instanceof Buffer && expected instanceof Buffer) { // return compare(actual, expected) === 0; // // 7.2. If the expected value is a Date object, the actual value is // // equivalent if it is also a Date object that refers to the same time. } else if (actual instanceof Date && expected instanceof Date) { return actual.getTime() === expected.getTime(); // 7.3 If the expected value is a RegExp object, the actual value is // equivalent if it is also a RegExp object with the same source and // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). } else if (actual instanceof RegExp && expected instanceof RegExp) { return ( actual.source === expected.source && actual.global === expected.global && actual.multiline === expected.multiline && actual.lastIndex === expected.lastIndex && actual.ignoreCase === expected.ignoreCase ); // 7.4. Other pairs that do not both pass typeof value == 'object', // equivalence is determined by ==. } else if ( (actual === null || typeof actual !== 'object') && (expected === null || typeof expected !== 'object') ) { // eslint-disable-next-line eqeqeq return strict ? actual === expected : actual == expected; // 7.5 For all other Object pairs, including Array objects, equivalence is // determined by having the same number of owned properties (as verified // with Object.prototype.hasOwnProperty.call), the same set of keys // (although not necessarily the same order), equivalent values for every // corresponding key, and an identical 'prototype' property. Note: this // accounts for both named and indexed properties on Arrays. } return objEquiv(actual, expected, strict); } // eslint-disable-next-line @typescript-eslint/unbound-method const pSlice = Array.prototype.slice; function isPrimitive(arg) { return arg === null || (typeof arg !== 'object' && typeof arg !== 'function'); } function isArguments(object) { // eslint-disable-next-line eqeqeq return Object.prototype.toString.call(object) == '[object Arguments]'; } // eslint-disable-next-line complexity function objEquiv(a: unknown, b: unknown, strict) { if (a === null || a === undefined || b === null || b === undefined) return false; // if one is a primitive, the other must be same if (isPrimitive(a) || isPrimitive(b)) return a === b; if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false; const aIsArgs = isArguments(a); const bIsArgs = isArguments(b); if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) return false; if (aIsArgs) { a = pSlice.call(a); b = pSlice.call(b); return deepStrictEqual(a, b, strict); } const ka = Object.keys(a as object); const kb = Object.keys(b as object); let key; let i; // having the same number of owned properties (keys incorporates // hasOwnProperty) if (ka.length !== kb.length) return false; // the same set of keys (although not necessarily the same order), ka.sort(); kb.sort(); // ~~~cheap key test for (i = ka.length - 1; i >= 0; i--) { if (ka[i] !== kb[i]) return false; } // equivalent values for every corresponding key, and // ~~~possibly expensive deep test for (i = ka.length - 1; i >= 0; i--) { key = ka[i]; // @ts-ignore if (!deepStrictEqual(a[key], b[key], strict)) return false; } return true; }