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); });