From 703cf7d8431d4c7a89c29829872da8d8190392dd Mon Sep 17 00:00:00 2001
From: Philipp Frauenthaler
Date: Fri, 20 Sep 2019 15:16:17 +0200
Subject: [PATCH] add functionality to check deep equality between
arrays/objects containing BNs
---
chai-bn.js | 59 ++++++++++++++++++++++++++-------
test/chai-bn.test.js | 77 +++++++++++++++++++++++++++++++++++++++++---
2 files changed, 120 insertions(+), 16 deletions(-)
diff --git a/chai-bn.js b/chai-bn.js
index 0816268..dae9b05 100644
--- a/chai-bn.js
+++ b/chai-bn.js
@@ -36,9 +36,8 @@ module.exports = function (BN) {
function overwriteMethod (originalAssertion) {
return function () {
if (utils.flag(this, 'bignumber')) {
- const actual = convert(this._obj);
-
- newAssertion.apply(this, [actual].concat([].slice.call(arguments).map(convert)));
+ const args = [this._obj].concat([].slice.call(arguments));
+ newAssertion.apply(this, args);
} else {
originalAssertion.apply(this, arguments);
}
@@ -57,7 +56,6 @@ module.exports = function (BN) {
return function () {
if (utils.flag(this, 'bignumber')) {
const actual = convert(this._obj);
-
newAssertion.apply(this, [actual]);
} else {
originalAssertion.call(this);
@@ -72,17 +70,47 @@ module.exports = function (BN) {
// BN.eq
overwriteMethods(['equal', 'equals', 'eq'], function (actual, expected) {
- this.assert(
- isEqualTo.bind(expected)(actual),
- 'expected #{act} to equal #{exp}',
- 'expected #{act} to be different from #{exp}',
- expected.toString(),
- actual.toString()
- );
+ if (utils.flag(this, 'deep')) {
+ // objects that contain BNs should be deeply compared with each other, e.g., if two arrays containing BNs are equal
+ this.assert(
+ utils.eql(actual, expected, {
+ comparator: function (val1, val2) {
+ if ((!isBN(val1) && (typeof val1 !== 'string')) || (!isBN(val2) && (typeof val2 !== 'string'))) {
+ // at least on of the two parameters cannot be converted to a BN
+ // return null to cause the function extensiveDeepEqual (see deep-eql) to ignore the comparator result on objects other than BN
+ // this is useful since the first invocation of extensiveDeepEqual may also call comparator on collections (e.g., array of BN) and objects
+ return null;
+ }
+
+ val1 = convert(val1);
+ val2 = convert(val2);
+
+ return val1.eq(val2);
+ }
+ }),
+ 'expected #{this} to deeply equal #{exp}',
+ 'expected #{this} to not deeply equal #{exp}',
+ expected,
+ actual
+ );
+ } else {
+ // two BN objects should be compared with each other
+ actual = convert(actual);
+ expected = convert(expected);
+ this.assert(
+ isEqualTo.bind(expected)(actual),
+ 'expected #{act} to equal #{exp}',
+ 'expected #{act} to be different from #{exp}',
+ expected.toString(),
+ actual.toString()
+ );
+ }
});
// BN.gt
overwriteMethods(['above', 'gt', 'greaterThan'], function (actual, expected) {
+ actual = convert(actual);
+ expected = convert(expected);
this.assert(
isGreaterThan.bind(actual)(expected),
'expected #{act} to be greater than #{exp}',
@@ -94,6 +122,8 @@ module.exports = function (BN) {
// BN.gte
overwriteMethods(['least', 'gte'], function (actual, expected) {
+ actual = convert(actual);
+ expected = convert(expected);
this.assert(
isGreaterThanOrEqualTo.bind(actual)(expected),
'expected #{act} to be greater than or equal to #{exp}',
@@ -105,6 +135,8 @@ module.exports = function (BN) {
// BN.lt
overwriteMethods(['below', 'lt', 'lessThan'], function (actual, expected) {
+ actual = convert(actual);
+ expected = convert(expected);
this.assert(
isLessThan.bind(actual)(expected),
'expected #{act} to be less than #{exp}',
@@ -116,6 +148,8 @@ module.exports = function (BN) {
// BN.lte
overwriteMethods(['most', 'lte'], function (actual, expected) {
+ actual = convert(actual);
+ expected = convert(expected);
this.assert(
isLessThanOrEqualTo.bind(actual)(expected),
'expected #{act} to be less than or equal to #{exp}',
@@ -127,6 +161,9 @@ module.exports = function (BN) {
// Equality with tolerance, using gte and lte
overwriteMethods(['closeTo'], function (actual, expected, delta) {
+ actual = convert(actual);
+ expected = convert(expected);
+ delta = convert(delta);
this.assert(
isGreaterThanOrEqualTo.bind(actual)(expected.sub(delta)) && isLessThanOrEqualTo.bind(actual)(expected.add(delta)),
`expected #{act} to be within '${delta}' of #{exp}`,
diff --git a/test/chai-bn.test.js b/test/chai-bn.test.js
index a6e316e..4b9ddff 100644
--- a/test/chai-bn.test.js
+++ b/test/chai-bn.test.js
@@ -28,6 +28,24 @@ describe('chai-bn', function () {
];
};
+ const deepTesterGenerator = function (functionNames) {
+ return [
+ function (a, b) {
+ functionNames.forEach(functionName => {
+ a.should.have.a.bignumber.and.to.deep[functionName](b);
+ expect(a).to.have.a.bignumber.and.to.deep[functionName](b);
+ });
+ },
+
+ function (a, b) {
+ functionNames.forEach(functionName => {
+ a.should.have.a.bignumber.and.not.to.deep[functionName](b);
+ expect(a).to.have.a.bignumber.and.not.to.deep[functionName](b);
+ });
+ }
+ ];
+ };
+
const argTypeChecker = function (tester, notTester) {
it('fails when first argument is not BN or string', function () {
const testCases = [
@@ -60,15 +78,16 @@ describe('chai-bn', function () {
const toBNCombinations = function (a, b) {
return [
- [ a, b ],
- [ new BN(a), b],
- [ a, new BN(b) ],
- [ new BN(a), new BN(b) ],
+ [a, b],
+ [new BN(a), b],
+ [a, new BN(b)],
+ [new BN(a), new BN(b)],
];
};
- describe('equal/equals/eq', function () {
+ describe('equal/equals/eq and .deep equal/equals/eq', function () {
const [tester, notTester] = testerGenerator(['equal', 'equals', 'eq']);
+ const [deepTester, deepNotTester] = deepTesterGenerator(['equal', 'equals', 'eq']);
it('asserts equality', function () {
const testCases = [
@@ -96,6 +115,54 @@ describe('chai-bn', function () {
});
});
+ it('asserts deep equality of arrays', function () {
+ deepTester(
+ [new BN(1), '2', new BN(-10), '123456789123456789123456789', '-123456789123456789123456789'],
+ [new BN(1), '2', '-10', '123456789123456789123456789', '-123456789123456789123456789']
+ );
+
+ deepTester(
+ [],
+ []
+ );
+ });
+
+ it('asserts deep inequality of arrays', function () {
+ deepNotTester(
+ [new BN(1), '2', new BN(-10), '-123456789123456789123456789', '123456789123456789123456789'],
+ [new BN(1), '2', '-10', '-123456789123456789123456789', '-123456789123456789123456789']
+ );
+
+ deepNotTester(
+ [],
+ ['-10']
+ );
+ });
+
+ it('asserts deep equality of objects', function () {
+ deepTester(
+ {a: '-10', b: '-123456789123456789123456789', c: '123456789123456789123456789', d: new BN(10)},
+ {a: new BN(-10), b: '-123456789123456789123456789', c: '123456789123456789123456789', d: new BN(10)}
+ );
+
+ deepTester(
+ {},
+ {}
+ );
+ });
+
+ it('asserts deep inequality of objects', function () {
+ deepNotTester(
+ {a: '-10', b: '-123456789123456789123456789', c: '123456789123456789123456789', d: new BN(10)},
+ {a: new BN(-10), b: '-123456789123456789123456789', c: '123456789123456789123456789', d: new BN(11)}
+ );
+
+ deepNotTester(
+ {},
+ {a: '-10'}
+ );
+ });
+
argTypeChecker(tester, notTester);
});