summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRuben Bridgewater <ruben@bridgewater.de>2018-12-13 07:33:31 +0100
committerRuben Bridgewater <ruben@bridgewater.de>2019-01-27 03:34:25 +0100
commit7493db21b667ed746d39c9b54357eac4287232e3 (patch)
treee6ae60900e43b5fa3d5dcdc8171782ae60192bb1 /lib
parent5cb196441a6df0fc3fa62e042ce108347f49814c (diff)
downloadandroid-node-v8-7493db21b667ed746d39c9b54357eac4287232e3.tar.gz
android-node-v8-7493db21b667ed746d39c9b54357eac4287232e3.tar.bz2
android-node-v8-7493db21b667ed746d39c9b54357eac4287232e3.zip
assert: adjust loose assertions
This changes the loose deep equal comparison by using the same logic as done in the strict deep equal comparison besides comparing primitives loosely, not comparing symbol properties and not comparing the prototype. `assert.deepEqual` is still commenly used and this is likely the biggest pitfall. Most changes are only minor and won't have a big impact besides likely fixing user expectations. PR-URL: https://github.com/nodejs/node/pull/25008 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/internal/util/comparisons.js153
1 files changed, 47 insertions, 106 deletions
diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js
index d072608906..3470f20666 100644
--- a/lib/internal/util/comparisons.js
+++ b/lib/internal/util/comparisons.js
@@ -14,7 +14,9 @@ const {
isStringObject,
isBooleanObject,
isBigIntObject,
- isSymbolObject
+ isSymbolObject,
+ isFloat32Array,
+ isFloat64Array
} = require('internal/util/types');
const {
getOwnNonIndexProperties,
@@ -84,18 +86,6 @@ function areEqualArrayBuffers(buf1, buf2) {
compare(new Uint8Array(buf1), new Uint8Array(buf2)) === 0;
}
-function isFloatTypedArrayTag(tag) {
- return tag === '[object Float32Array]' || tag === '[object Float64Array]';
-}
-
-function isArguments(tag) {
- return tag === '[object Arguments]';
-}
-
-function isObjectOrArrayTag(tag) {
- return tag === '[object Array]' || tag === '[object Object]';
-}
-
function isEqualBoxedPrimitive(val1, val2) {
if (isNumberObject(val1)) {
return isNumberObject(val2) &&
@@ -132,13 +122,38 @@ function isEqualBoxedPrimitive(val1, val2) {
// For strict comparison, objects should have
// a) The same built-in type tags
// b) The same prototypes.
-function strictDeepEqual(val1, val2, memos) {
- if (typeof val1 !== 'object') {
- return typeof val1 === 'number' && numberIsNaN(val1) &&
- numberIsNaN(val2);
+
+function innerDeepEqual(val1, val2, strict, memos) {
+ // All identical values are equivalent, as determined by ===.
+ if (val1 === val2) {
+ if (val1 !== 0)
+ return true;
+ return strict ? objectIs(val1, val2) : true;
}
- if (typeof val2 !== 'object' || val1 === null || val2 === null) {
- return false;
+
+ // Check more closely if val1 and val2 are equal.
+ if (strict) {
+ if (typeof val1 !== 'object') {
+ return typeof val1 === 'number' && numberIsNaN(val1) &&
+ numberIsNaN(val2);
+ }
+ if (typeof val2 !== 'object' || val1 === null || val2 === null) {
+ return false;
+ }
+ if (getPrototypeOf(val1) !== getPrototypeOf(val2)) {
+ return false;
+ }
+ } else {
+ if (val1 === null || typeof val1 !== 'object') {
+ if (val2 === null || typeof val2 !== 'object') {
+ // eslint-disable-next-line eqeqeq
+ return val1 == val2;
+ }
+ return false;
+ }
+ if (val2 === null || typeof val2 !== 'object') {
+ return false;
+ }
}
const val1Tag = objectToString(val1);
const val2Tag = objectToString(val2);
@@ -146,9 +161,6 @@ function strictDeepEqual(val1, val2, memos) {
if (val1Tag !== val2Tag) {
return false;
}
- if (getPrototypeOf(val1) !== getPrototypeOf(val2)) {
- return false;
- }
if (Array.isArray(val1)) {
// Check for sparse arrays and general fast path
if (val1.length !== val2.length) {
@@ -159,10 +171,10 @@ function strictDeepEqual(val1, val2, memos) {
if (keys1.length !== keys2.length) {
return false;
}
- return keyCheck(val1, val2, kStrict, memos, kIsArray, keys1);
+ return keyCheck(val1, val2, strict, memos, kIsArray, keys1);
}
if (val1Tag === '[object Object]') {
- return keyCheck(val1, val2, kStrict, memos, kNoIterator);
+ return keyCheck(val1, val2, strict, memos, kNoIterator);
}
if (isDate(val1)) {
if (dateGetTime(val1) !== dateGetTime(val2)) {
@@ -174,13 +186,16 @@ function strictDeepEqual(val1, val2, memos) {
}
} else if (isNativeError(val1) || val1 instanceof Error) {
// Do not compare the stack as it might differ even though the error itself
- // is otherwise identical. The non-enumerable name should be identical as
- // the prototype is also identical. Otherwise this is caught later on.
- if (val1.message !== val2.message) {
+ // is otherwise identical.
+ if (val1.message !== val2.message || val1.name !== val2.name) {
return false;
}
} else if (isArrayBufferView(val1)) {
- if (!areSimilarTypedArrays(val1, val2)) {
+ if (!strict && (isFloat32Array(val1) || isFloat64Array(val1))) {
+ if (!areSimilarFloatArrays(val1, val2)) {
+ return false;
+ }
+ } else if (!areSimilarTypedArrays(val1, val2)) {
return false;
}
// Buffer.compare returns true, so val1.length === val2.length. If they both
@@ -191,17 +206,17 @@ function strictDeepEqual(val1, val2, memos) {
if (keys1.length !== keys2.length) {
return false;
}
- return keyCheck(val1, val2, kStrict, memos, kNoIterator, keys1);
+ return keyCheck(val1, val2, strict, memos, kNoIterator, keys1);
} else if (isSet(val1)) {
if (!isSet(val2) || val1.size !== val2.size) {
return false;
}
- return keyCheck(val1, val2, kStrict, memos, kIsSet);
+ return keyCheck(val1, val2, strict, memos, kIsSet);
} else if (isMap(val1)) {
if (!isMap(val2) || val1.size !== val2.size) {
return false;
}
- return keyCheck(val1, val2, kStrict, memos, kIsMap);
+ return keyCheck(val1, val2, strict, memos, kIsMap);
} else if (isAnyArrayBuffer(val1)) {
if (!areEqualArrayBuffers(val1, val2)) {
return false;
@@ -209,66 +224,7 @@ function strictDeepEqual(val1, val2, memos) {
} else if (isBoxedPrimitive(val1) && !isEqualBoxedPrimitive(val1, val2)) {
return false;
}
- return keyCheck(val1, val2, kStrict, memos, kNoIterator);
-}
-
-function looseDeepEqual(val1, val2, memos) {
- if (val1 === null || typeof val1 !== 'object') {
- if (val2 === null || typeof val2 !== 'object') {
- // eslint-disable-next-line eqeqeq
- return val1 == val2;
- }
- return false;
- }
- if (val2 === null || typeof val2 !== 'object') {
- return false;
- }
- const val1Tag = objectToString(val1);
- const val2Tag = objectToString(val2);
- if (val1Tag === val2Tag) {
- if (isObjectOrArrayTag(val1Tag)) {
- return keyCheck(val1, val2, kLoose, memos, kNoIterator);
- }
- if (isArrayBufferView(val1)) {
- if (isFloatTypedArrayTag(val1Tag)) {
- return areSimilarFloatArrays(val1, val2);
- }
- return areSimilarTypedArrays(val1, val2);
- }
- if (isDate(val1) && isDate(val2)) {
- return val1.getTime() === val2.getTime();
- }
- if (isRegExp(val1) && isRegExp(val2)) {
- return areSimilarRegExps(val1, val2);
- }
- if (val1 instanceof Error && val2 instanceof Error) {
- if (val1.message !== val2.message || val1.name !== val2.name)
- return false;
- }
- // Ensure reflexivity of deepEqual with `arguments` objects.
- // See https://github.com/nodejs/node-v0.x-archive/pull/7178
- } else if (isArguments(val1Tag) || isArguments(val2Tag)) {
- return false;
- }
- if (isSet(val1)) {
- if (!isSet(val2) || val1.size !== val2.size) {
- return false;
- }
- return keyCheck(val1, val2, kLoose, memos, kIsSet);
- } else if (isMap(val1)) {
- if (!isMap(val2) || val1.size !== val2.size) {
- return false;
- }
- return keyCheck(val1, val2, kLoose, memos, kIsMap);
- } else if (isSet(val2) || isMap(val2)) {
- return false;
- }
- if (isAnyArrayBuffer(val1) && isAnyArrayBuffer(val2)) {
- if (!areEqualArrayBuffers(val1, val2)) {
- return false;
- }
- }
- return keyCheck(val1, val2, kLoose, memos, kNoIterator);
+ return keyCheck(val1, val2, strict, memos, kNoIterator);
}
function getEnumerables(val, keys) {
@@ -370,21 +326,6 @@ function keyCheck(val1, val2, strict, memos, iterationType, aKeys) {
return areEq;
}
-function innerDeepEqual(val1, val2, strict, memos) {
- // All identical values are equivalent, as determined by ===.
- if (val1 === val2) {
- if (val1 !== 0)
- return true;
- return strict ? objectIs(val1, val2) : true;
- }
-
- // Check more closely if val1 and val2 are equal.
- if (strict === true)
- return strictDeepEqual(val1, val2, memos);
-
- return looseDeepEqual(val1, val2, memos);
-}
-
function setHasEqualElement(set, val1, strict, memo) {
// Go looking.
for (const val2 of set) {