diff --git a/lib/assert.js b/lib/assert.js index 7fc9e0c342646a..c351b461a1abbf 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -143,7 +143,7 @@ assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { } }; -function _deepEqual(actual, expected, strict) { +function _deepEqual(actual, expected, strict, actualVisitedObjects) { // 7.1. All identical values are equivalent, as determined by ===. if (actual === expected) { return true; @@ -191,7 +191,14 @@ function _deepEqual(actual, expected, strict) { // corresponding key, and an identical 'prototype' property. Note: this // accounts for both named and indexed properties on Arrays. } else { - return objEquiv(actual, expected, strict); + actualVisitedObjects = actualVisitedObjects || []; + + if (actualVisitedObjects.includes(actual)) + return true; + + actualVisitedObjects.push(actual); + + return objEquiv(actual, expected, strict, actualVisitedObjects); } } @@ -199,7 +206,7 @@ function isArguments(object) { return Object.prototype.toString.call(object) == '[object Arguments]'; } -function objEquiv(a, b, strict) { +function objEquiv(a, b, strict, actualVisitedObjects) { if (a === null || a === undefined || b === null || b === undefined) return false; // if one is a primitive, the other must be same @@ -235,7 +242,8 @@ function objEquiv(a, b, strict) { //~~~possibly expensive deep test for (i = ka.length - 1; i >= 0; i--) { key = ka[i]; - if (!_deepEqual(a[key], b[key], strict)) return false; + if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects)) + return false; } return true; } diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index cf5b7d4c9933f6..e1756c093aea05 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -381,25 +381,22 @@ try { assert.ok(threw); -// GH-207. Make sure deepEqual doesn't loop forever on circular refs +// https://github.com/nodejs/node/issues/6416 +// Make sure circular refs don't throw. var b = {}; b.b = b; var c = {}; c.b = c; -var gotError = false; -try { - assert.deepEqual(b, c); -} catch (e) { - gotError = true; -} +a.doesNotThrow(makeBlock(a.deepEqual, b, c)); +a.doesNotThrow(makeBlock(a.deepStrictEqual, b, c)); + // GH-7178. Ensure reflexivity of deepEqual with `arguments` objects. var args = (function() { return arguments; })(); a.throws(makeBlock(a.deepEqual, [], args)); a.throws(makeBlock(a.deepEqual, args, [])); -assert.ok(gotError); var circular = {y: 1};