47 lines
1.4 KiB
JavaScript
47 lines
1.4 KiB
JavaScript
|
import assert from 'assert'
|
||
|
|
||
|
export const epsilon = 1e-12
|
||
|
|
||
|
const isNumber = entity => (typeof entity === 'number')
|
||
|
|
||
|
export function equal(a, b) {
|
||
|
if (isNumber(a) && isNumber(b)) {
|
||
|
if (a === b) return true
|
||
|
if (isNaN(a)) return assert.strictEqual(a.toString(), b.toString())
|
||
|
const message = `${a} ~= ${b} (to ${epsilon})`
|
||
|
if (a === 0) return assert.ok(Math.abs(b) < epsilon, message)
|
||
|
if (b === 0) return assert.ok(Math.abs(a) < epsilon, message)
|
||
|
const diff = Math.abs(a - b)
|
||
|
const maxDiff = Math.abs(epsilon * Math.max(Math.abs(a), Math.abs(b)))
|
||
|
return assert.ok(diff <= maxDiff, message)
|
||
|
}
|
||
|
return assert.strictEqual(a, b)
|
||
|
}
|
||
|
|
||
|
export function deepEqual(a, b) {
|
||
|
if (Array.isArray(a) && Array.isArray(b)) {
|
||
|
const alen = a.length
|
||
|
assert.strictEqual(alen, b.length, `${a} ~= ${b}`)
|
||
|
for (let i = 0; i < alen; ++i) deepEqual(a[i], b[i])
|
||
|
return true
|
||
|
}
|
||
|
if (typeof a === 'object' && typeof b === 'object') {
|
||
|
for (const prop in a) {
|
||
|
if (a.hasOwnProperty(prop)) {
|
||
|
assert.ok(
|
||
|
b.hasOwnProperty(prop), `a[${prop}] = ${a[prop]} ~= ${b[prop]}`)
|
||
|
deepEqual(a[prop], b[prop])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (const prop in b) {
|
||
|
if (b.hasOwnProperty(prop)) {
|
||
|
assert.ok(
|
||
|
a.hasOwnProperty(prop), `${a[prop]} ~= ${b[prop]} = b[${prop}]`)
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
return equal(a, b)
|
||
|
}
|