UNPKG

@itwin/core-backend

Version:
67 lines 3.76 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { Assertion, util } from "chai"; import { Geometry } from "@itwin/core-geometry"; export const defaultOpts = { tolerance: 1e-10, considerNonExistingAndUndefinedEqual: false, }; /** get whether two numbers are almost equal within a tolerance */ const isAlmostEqualNumber = (a, b, tol) => Geometry.isSameCoordinate(a, b, tol); /** normalize a classname for comparisons */ const normalizeClassName = (name) => name.toLowerCase().replace(/:/, "."); /** * The diff shown on failure will show undefined fields as part of the diff even if * consideringNonExistingAndUndefinedEqual is true. You can ignore that. * We would have to mutate the object to clean the diff, although it is worth considering. */ export function advancedDeepEqual(e, a, options = {}) { const normalizedClassNameProps = options.normalizeClassNameProps === true ? ["classFullName", "relClassName"] : options.normalizeClassNameProps || []; if (options.tolerance === undefined) options.tolerance = defaultOpts.tolerance; if (e === a) return true; if (typeof e !== typeof a) return false; switch (typeof e) { case "number": return isAlmostEqualNumber(e, a, options.tolerance); case "string": case "boolean": case "function": case "symbol": case "undefined": return false; // these objects can only be strict equal which was already tested case "object": if ((e === null) !== (a === null)) return false; const eSize = Object.keys(e).filter((k) => options.considerNonExistingAndUndefinedEqual && e[k] !== undefined).length; const aSize = Object.keys(a).filter((k) => options.considerNonExistingAndUndefinedEqual && a[k] !== undefined).length; return (eSize === aSize || !!options.useSubsetEquality) && Object.keys(e).every((keyOfE) => (keyOfE in a || options.considerNonExistingAndUndefinedEqual) && normalizedClassNameProps.includes(keyOfE) ? advancedDeepEqual(normalizeClassName(e[keyOfE]), normalizeClassName(a[keyOfE])) : advancedDeepEqual(e[keyOfE], a[keyOfE], options)); default: // bigint unhandled throw Error(`unhandled deep compare type code returned from typeof, "${typeof e}"`); } } Assertion.addMethod("advancedEqual", function advancedEqual(expected, options = {}) { if (options.tolerance === undefined) options.tolerance = 1e-10; const actual = this._obj; const isDeep = util.flag(this, "deep"); this.assert(isDeep ? advancedDeepEqual(expected, actual, options) : isAlmostEqualNumber(expected, actual, options.tolerance), `expected ${isDeep ? "deep equality of " : " "}#{exp} and #{act} with a tolerance of ${options.tolerance}`, `expected ${isDeep ? "deep inequality of " : " "}#{exp} and #{act} with a tolerance of ${options.tolerance}`, expected, actual); }); Assertion.addMethod("subsetEqual", function subsetEqual(expected, options = {}) { if (options.tolerance === undefined) options.tolerance = 1e-10; const actual = this._obj; this.assert(advancedDeepEqual(expected, actual, { ...options, useSubsetEquality: true }), `expected #{act} to contain as a subset #{exp}`, `expected #{act} not to contain as a subset #{exp}`, expected, actual); }); //# sourceMappingURL=AdvancedEqual.js.map