Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deep equality checks for arrays, objects, etc. containing big numbers #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 48 additions & 11 deletions chai-bn.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
Expand All @@ -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}',
Expand All @@ -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}',
Expand All @@ -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}',
Expand All @@ -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}',
Expand All @@ -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}`,
Expand Down
77 changes: 72 additions & 5 deletions test/chai-bn.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -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 = [
Expand Down Expand Up @@ -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);
});

Expand Down