Skip to content

Commit

Permalink
[Breaking] non-Date objects with different [[Prototypes]] are not equal
Browse files Browse the repository at this point in the history
Date objects are equal when:
 - the timestamp is the same
 - if strict, the [[Prototype]] is the same
 - own properties match, same as normal objects
  • Loading branch information
ljharb committed Jul 31, 2019
1 parent 99a7761 commit ec1cf9c
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 6 deletions.
14 changes: 9 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ var isArguments = require('is-arguments');
var is = require('object-is');
var isRegex = require('is-regex');
var flags = require('regexp.prototype.flags');

var isArray = require('isarray');
var isDate = require('is-date-object');

var getTime = Date.prototype.getTime;
var gPO = Object.getPrototypeOf;

function deepEqual(actual, expected, options) {
var opts = options || {};
Expand Down Expand Up @@ -52,7 +52,7 @@ function isBuffer(x) {
}

function objEquiv(a, b, opts) {
/* eslint max-statements: [2, 50] */
/* eslint max-statements: [2, 60] */
var i, key;
if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) { return false; }

Expand All @@ -72,9 +72,13 @@ function objEquiv(a, b, opts) {
return a.source === b.source && flags(a) === flags(b);
}

if (isDate(a) && isDate(b)) {
return getTime.call(a) === getTime.call(b);
}
var aIsDate = isDate(a);
var bIsDate = isDate(b);
if (aIsDate !== bIsDate) { return false; }
if (aIsDate || bIsDate) { // && would work too, because both are true or both false here
if (getTime.call(a) !== getTime.call(b)) { return false; }
if (opts.strict && gPO && gPO(a) !== gPO(b)) { return false; }
} else if (gPO && gPO(a) !== gPO(b)) { return false; } // non-Dates always compare [[Prototype]]s

var aIsBuffer = isBuffer(a);
var bIsBuffer = isBuffer(b);
Expand Down
47 changes: 46 additions & 1 deletion test/cmp.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,19 @@ test('arguments class', function (t) {
test('dates', function (t) {
var d0 = new Date(1387585278000);
var d1 = new Date('Fri Dec 20 2013 16:21:18 GMT-0800 (PST)');
t.ok(equal(d0, d1));

t.ok(equal(d0, d1), 'two dates with the same timestamp are equal');
t.ok(equal(d1, d0), 'two dates with the same timestamp are equal');
t.ok(equal(d0, d1, { strict: true }), 'strict: two dates with the same timestamp are equal');
t.ok(equal(d1, d0, { strict: true }), 'strict: two dates with the same timestamp are equal');

d1.a = true;

t.notOk(equal(d0, d1), 'two dates with the same timestamp but different own properties are not equal');
t.notOk(equal(d1, d0), 'two dates with the same timestamp but different own properties are not equal');
t.notOk(equal(d0, d1, { strict: true }), 'strict: two dates with the same timestamp but different own properties are not equal');
t.notOk(equal(d1, d0, { strict: true }), 'strict: two dates with the same timestamp but different own properties are not equal');

t.end();
});

Expand Down Expand Up @@ -316,3 +328,36 @@ test('arrays and objects', function (t) {

t.end();
});

test('[[Prototypes]]', { skip: !Object.getPrototypeOf }, function (t) {
function C() {}
var instance = new C();
delete instance.constructor;

t.notOk(equal({}, instance), 'two identical objects with different [[Prototypes]] are not equal');
t.notOk(equal({}, instance, { strict: true }), 'strict: two identical objects with different [[Prototypes]] are not equal');

t.test('Dates with different prototypes', { skip: !Object.setPrototypeOf }, function (st) {
var d1 = new Date(0);
var d2 = new Date(0);

st.ok(equal(d1, d2), 'two dates with the same timestamp are equal');
st.ok(equal(d2, d1), 'two dates with the same timestamp are equal');
st.ok(equal(d1, d2, { strict: true }), 'strict: two dates with the same timestamp are equal');
st.ok(equal(d1, d1, { strict: true }), 'strict: two dates with the same timestamp are equal');

var newProto = {};
Object.setPrototypeOf(newProto, Date.prototype);
Object.setPrototypeOf(d2, newProto);
st.ok(d2 instanceof Date, 'd2 is still a Date instance');

st.ok(equal(d1, d2), 'two dates with the same timestamp and different [[Prototype]] are equal');
st.ok(equal(d2, d1), 'two dates with the same timestamp and different [[Prototype]] are equal');
st.notOk(equal(d1, d2, { strict: true }), 'strict: two dates with the same timestamp and different [[Prototype]] are not equal');
st.notOk(equal(d2, d1, { strict: true }), 'strict: two dates with the same timestamp and different [[Prototype]] are not equal');

st.end();
});

t.end();
});

0 comments on commit ec1cf9c

Please sign in to comment.