Skip to content

Commit 26be82e

Browse files
committed
//base class to verify equality of two objects
1 parent a2037c3 commit 26be82e

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

javascript/base/equals.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2020 Las Venturas Playground. All rights reserved.
2+
// Use of this source code is governed by the MIT license, a copy of which can
3+
// be found in the LICENSE file.
4+
5+
// Returns whether the given |value| and |other| variables are equal to each other.
6+
export function equals(value, other) {
7+
const valueType = Object.prototype.toString.call(value);
8+
const otherType = Object.prototype.toString.call(other);
9+
10+
if (valueType !== otherType)
11+
return false; // the types are different
12+
13+
switch (valueType) {
14+
case '[object Array]':
15+
return arrayEquals(value, other);
16+
17+
case '[object Date]':
18+
return value.getTime() === other.getTime();
19+
20+
case '[object Function]':
21+
return value.toString() === other.toString();
22+
23+
case '[object Map]':
24+
return mapEquals(value, other);
25+
26+
case '[object Number]':
27+
if (Number.isNaN(value) && Number.isNaN(other))
28+
return true;
29+
30+
return value === other;
31+
32+
case '[object Object]':
33+
return objectEquals(value, other);
34+
35+
case '[object Set]':
36+
return setEquals(value, other);
37+
38+
default:
39+
return value === other;
40+
}
41+
}
42+
43+
// Returns whether the two arrays in |value| and |other| are equal to each other.
44+
function arrayEquals(value, other) {
45+
if (value.length !== other.length)
46+
return false; // the lengths are different
47+
48+
for (let index = 0; index < value.length; ++index) {
49+
if (!equals(value[index], other[index]))
50+
return false;
51+
}
52+
53+
return true;
54+
}
55+
56+
// Returns whether the two maps in |value| and |other| are equal to each other. Because keys in
57+
// maps are instance-based, we will do a strict comparison rather than a deep one.
58+
function mapEquals(value, other) {
59+
if (value.size !== other.size)
60+
return false; // different number of entries in the sets
61+
62+
for (const [ key, entry ] of value) {
63+
if (!other.has(key))
64+
return false;
65+
66+
if (!equals(entry, other.get(key)))
67+
return false;
68+
}
69+
70+
return true;
71+
}
72+
73+
// Returns whether the two objects in |value| and |other| are equal to each other.
74+
function objectEquals(value, other) {
75+
const valueKeys = Object.keys(value);
76+
const otherKeys = Object.keys(other);
77+
78+
if (valueKeys.length !== otherKeys.length)
79+
return false; // the objects have different numbers of keys
80+
81+
for (const key of valueKeys) {
82+
if (!other.hasOwnProperty(key))
83+
return false; // the |key| is not found on |other|
84+
85+
if (!equals(value[key], other[key]))
86+
return false;
87+
}
88+
89+
return true;
90+
}
91+
92+
// Returns whether the two sets in |value| and |other| are equal to each other.
93+
function setEquals(value, other) {
94+
if (value.size !== other.size)
95+
return false; // different number of entries in the sets
96+
97+
for (const key of value) {
98+
if (!other.has(key))
99+
return false;
100+
}
101+
102+
return true;
103+
}

javascript/base/equals.test.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright 2020 Las Venturas Playground. All rights reserved.
2+
// Use of this source code is governed by the MIT license, a copy of which can
3+
// be found in the LICENSE file.
4+
5+
import { equals } from 'base/equals.js';
6+
7+
describe('equals', it => {
8+
it('should be able to determine equality between given values', assert => {
9+
function multiply(a, b) { return a * b; }
10+
function add(a, b) { return a + b; }
11+
12+
assert.isTrue(equals('hello', 'hello'));
13+
assert.isTrue(equals(42, 42));
14+
assert.isTrue(equals(Math.PI, Math.PI));
15+
assert.isTrue(equals(true, true));
16+
assert.isTrue(equals(null, null));
17+
assert.isTrue(equals(undefined, undefined));
18+
assert.isTrue(equals(Number.NaN, Number.NaN));
19+
assert.isTrue(equals(NaN, NaN));
20+
21+
assert.isFalse(equals('hello', 'world'));
22+
assert.isFalse(equals(42, 44));
23+
assert.isFalse(equals(Math.PI, Math.SQRT2));
24+
assert.isFalse(equals(true, false));
25+
assert.isFalse(equals(null, undefined));
26+
assert.isFalse(equals(undefined, null));
27+
assert.isFalse(equals(NaN, Math.PI));
28+
29+
assert.isTrue(equals(new Date('2020-07-06 19:51:12'), new Date('2020-07-06 19:51:12')));
30+
assert.isFalse(equals(new Date('2020-07-06 19:51:12'), new Date('2020-07-07 19:51:12')));
31+
32+
assert.isTrue(equals(multiply, multiply));
33+
assert.isFalse(equals(multiply, add));
34+
35+
assert.isTrue(equals([ 1, 2, 3 ], [ 1, 2, 3 ]));
36+
assert.isFalse(equals([ 1, 2, 3 ], [ 3, 2, 1 ]));
37+
assert.isTrue(equals([ 1, 'hello', [ 1, 2 ] ], [ 1, 'hello', [ 1, 2 ] ]));
38+
39+
assert.isTrue(equals({ foo: 1 }, { foo: 1 }));
40+
assert.isTrue(equals({ foo: 1, bar: 2 }, { foo: 1, bar: 2 }));
41+
assert.isTrue(equals({ foo: 1, bar: 2 }, { bar: 2, foo: 1 }));
42+
assert.isFalse(equals({ foo: 1 }, { bar: 2 }));
43+
assert.isTrue(equals({ foo: { bar: 1 } }, { foo: { bar: 1 } }));
44+
45+
assert.isTrue(
46+
equals(new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
47+
new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ])));
48+
assert.isTrue(
49+
equals(new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
50+
new Map([ [ 'bar', 2 ], [ 'foo', 1 ] ])));
51+
assert.isFalse(
52+
equals(new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
53+
new Map([ [ 'bar', 1 ], [ 'foo', 2 ] ])));
54+
55+
assert.isTrue(equals(new Set([ 1, 2, 3 ]), new Set([ 1, 2, 3 ])));
56+
assert.isTrue(equals(new Set([ 1, 2, 3 ]), new Set([ 3, 2, 1 ])));
57+
assert.isFalse(equals(new Set([ 1, 2, 3 ]), new Set([ 1, 2, 3, 4 ])));
58+
59+
assert.isTrue(equals({
60+
value: true,
61+
options: {
62+
map: new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
63+
set: new Set([ 1, 2, 3 ]),
64+
},
65+
functions: [
66+
multiply,
67+
'Hello world!',
68+
Math.PI,
69+
]
70+
}, {
71+
value: true,
72+
options: {
73+
map: new Map([ [ 'foo', 1 ], [ 'bar', 2 ] ]),
74+
set: new Set([ 1, 2, 3 ]),
75+
},
76+
functions: [
77+
multiply,
78+
'Hello world!',
79+
Math.PI,
80+
]
81+
}));
82+
});
83+
});

0 commit comments

Comments
 (0)