Skip to content

Commit

Permalink
//base class to verify equality of two objects
Browse files Browse the repository at this point in the history
  • Loading branch information
RussellLVP committed Jul 6, 2020
1 parent a2037c3 commit 26be82e
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 0 deletions.
103 changes: 103 additions & 0 deletions javascript/base/equals.js
@@ -0,0 +1,103 @@
// Copyright 2020 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

// Returns whether the given |value| and |other| variables are equal to each other.
export function equals(value, other) {
const valueType = Object.prototype.toString.call(value);
const otherType = Object.prototype.toString.call(other);

if (valueType !== otherType)
return false; // the types are different

switch (valueType) {
case '[object Array]':
return arrayEquals(value, other);

case '[object Date]':
return value.getTime() === other.getTime();

case '[object Function]':
return value.toString() === other.toString();

case '[object Map]':
return mapEquals(value, other);

case '[object Number]':
if (Number.isNaN(value) && Number.isNaN(other))
return true;

return value === other;

case '[object Object]':
return objectEquals(value, other);

case '[object Set]':
return setEquals(value, other);

default:
return value === other;
}
}

// Returns whether the two arrays in |value| and |other| are equal to each other.
function arrayEquals(value, other) {
if (value.length !== other.length)
return false; // the lengths are different

for (let index = 0; index < value.length; ++index) {
if (!equals(value[index], other[index]))
return false;
}

return true;
}

// Returns whether the two maps in |value| and |other| are equal to each other. Because keys in
// maps are instance-based, we will do a strict comparison rather than a deep one.
function mapEquals(value, other) {
if (value.size !== other.size)
return false; // different number of entries in the sets

for (const [ key, entry ] of value) {
if (!other.has(key))
return false;

if (!equals(entry, other.get(key)))
return false;
}

return true;
}

// Returns whether the two objects in |value| and |other| are equal to each other.
function objectEquals(value, other) {
const valueKeys = Object.keys(value);
const otherKeys = Object.keys(other);

if (valueKeys.length !== otherKeys.length)
return false; // the objects have different numbers of keys

for (const key of valueKeys) {
if (!other.hasOwnProperty(key))
return false; // the |key| is not found on |other|

if (!equals(value[key], other[key]))
return false;
}

return true;
}

// Returns whether the two sets in |value| and |other| are equal to each other.
function setEquals(value, other) {
if (value.size !== other.size)
return false; // different number of entries in the sets

for (const key of value) {
if (!other.has(key))
return false;
}

return true;
}
83 changes: 83 additions & 0 deletions javascript/base/equals.test.js
@@ -0,0 +1,83 @@
// Copyright 2020 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

import { equals } from 'base/equals.js';

describe('equals', it => {
it('should be able to determine equality between given values', assert => {
function multiply(a, b) { return a * b; }
function add(a, b) { return a + b; }

assert.isTrue(equals('hello', 'hello'));
assert.isTrue(equals(42, 42));
assert.isTrue(equals(Math.PI, Math.PI));
assert.isTrue(equals(true, true));
assert.isTrue(equals(null, null));
assert.isTrue(equals(undefined, undefined));
assert.isTrue(equals(Number.NaN, Number.NaN));
assert.isTrue(equals(NaN, NaN));

assert.isFalse(equals('hello', 'world'));
assert.isFalse(equals(42, 44));
assert.isFalse(equals(Math.PI, Math.SQRT2));
assert.isFalse(equals(true, false));
assert.isFalse(equals(null, undefined));
assert.isFalse(equals(undefined, null));
assert.isFalse(equals(NaN, Math.PI));

assert.isTrue(equals(new Date('2020-07-06 19:51:12'), new Date('2020-07-06 19:51:12')));
assert.isFalse(equals(new Date('2020-07-06 19:51:12'), new Date('2020-07-07 19:51:12')));

assert.isTrue(equals(multiply, multiply));
assert.isFalse(equals(multiply, add));

assert.isTrue(equals([ 1, 2, 3 ], [ 1, 2, 3 ]));
assert.isFalse(equals([ 1, 2, 3 ], [ 3, 2, 1 ]));
assert.isTrue(equals([ 1, 'hello', [ 1, 2 ] ], [ 1, 'hello', [ 1, 2 ] ]));

assert.isTrue(equals({ foo: 1 }, { foo: 1 }));
assert.isTrue(equals({ foo: 1, bar: 2 }, { foo: 1, bar: 2 }));
assert.isTrue(equals({ foo: 1, bar: 2 }, { bar: 2, foo: 1 }));
assert.isFalse(equals({ foo: 1 }, { bar: 2 }));
assert.isTrue(equals({ foo: { bar: 1 } }, { foo: { bar: 1 } }));

assert.isTrue(
equals(new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ])));
assert.isTrue(
equals(new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
new Map([ [ 'bar', 2 ], [ 'foo', 1 ] ])));
assert.isFalse(
equals(new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
new Map([ [ 'bar', 1 ], [ 'foo', 2 ] ])));

assert.isTrue(equals(new Set([ 1, 2, 3 ]), new Set([ 1, 2, 3 ])));
assert.isTrue(equals(new Set([ 1, 2, 3 ]), new Set([ 3, 2, 1 ])));
assert.isFalse(equals(new Set([ 1, 2, 3 ]), new Set([ 1, 2, 3, 4 ])));

assert.isTrue(equals({
value: true,
options: {
map: new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
set: new Set([ 1, 2, 3 ]),
},
functions: [
multiply,
'Hello world!',
Math.PI,
]
}, {
value: true,
options: {
map: new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
set: new Set([ 1, 2, 3 ]),
},
functions: [
multiply,
'Hello world!',
Math.PI,
]
}));
});
});

0 comments on commit 26be82e

Please sign in to comment.