├── .gitignore ├── CHANGELOG.md ├── .travis.yml ├── .eslintrc.json ├── LICENSE ├── chai-bn.d.ts ├── package.json ├── README.md ├── chai-bn.js └── test └── chai-bn.test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.3.1 4 | 5 | - Fix typing of boolean properties. 6 | 7 | ## 0.3.0 8 | 9 | - Update bn.js to 5.x 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | 5 | jobs: 6 | include: 7 | - stage: tests 8 | name: "Linter" 9 | script: npm run lint 10 | 11 | - stage: tests 12 | name: "Unit tests" 13 | script: npm run test 14 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "mocha": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "plugins": [ 9 | "mocha-no-only" 10 | ], 11 | "rules": { 12 | "array-bracket-spacing": ["error"], 13 | "camelcase": ["error"], 14 | "computed-property-spacing": ["error"], 15 | "curly": ["error"], 16 | "eqeqeq": ["error"], 17 | "indent": ["error", 2, {"SwitchCase": 1}], 18 | "key-spacing": ["error"], 19 | "linebreak-style": ["error", "unix"], 20 | "no-console": "off", 21 | "no-var": ["error"], 22 | "no-whitespace-before-property": ["error"], 23 | "object-curly-spacing": ["error"], 24 | "quotes": ["error", "single"], 25 | "semi": ["error", "always"], 26 | "space-before-blocks": ["error"], 27 | "space-before-function-paren": ["error", "always"], 28 | "space-in-parens": ["error"], 29 | "space-infix-ops": ["error", {"int32Hint": true}], 30 | "space-unary-ops": ["error", {"words": true, "nonwords": false}], 31 | 32 | "mocha-no-only/mocha-no-only": ["error"] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 António Marques 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /chai-bn.d.ts: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import BN from "bn.js"; 3 | 4 | export default function (BNModule: any): any; 5 | declare global { 6 | export namespace Chai { 7 | export interface BNComparer extends NumberComparer { 8 | (value: BN | string, message?: string): BNAssertion; 9 | } 10 | export interface BNCloseTo extends CloseTo { 11 | (value: BN | string, delta: BN | string, message?: string): BNAssertion; 12 | } 13 | export interface BNAssertion extends Assertion { 14 | equal: BNComparer; 15 | equals: BNComparer; 16 | eq: BNComparer; 17 | above: BNComparer; 18 | greaterThan: BNComparer; 19 | gt: BNComparer; 20 | gte: BNComparer; 21 | below: BNComparer; 22 | lessThan: BNComparer; 23 | lt: BNComparer; 24 | lte: BNComparer; 25 | least: BNComparer; 26 | most: BNComparer; 27 | closeTo: BNCloseTo; 28 | negative: Assertion; 29 | zero: Assertion; 30 | } 31 | export interface Assertion { 32 | bignumber: BNAssertion; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chai-bn", 3 | "version": "0.3.1", 4 | "description": "Chai assertions for comparing arbitrary-precision integers using the bignumber.js library", 5 | "main": "chai-bn.js", 6 | "types": "chai-bn.d.ts", 7 | "scripts": { 8 | "lint": "eslint .", 9 | "test": "mocha test/*.js" 10 | }, 11 | "devDependencies": { 12 | "bn.js": "^5.2.0", 13 | "chai": "^4.3.4", 14 | "eslint": "^7.31.0", 15 | "eslint-plugin-mocha-no-only": "^1.1.1", 16 | "mocha": "^9.0.2" 17 | }, 18 | "author": "Nicolas Venturo ", 19 | "license": "MIT", 20 | "homepage": "https://github.com/ZeppelinSolutions/chai-bn#readme", 21 | "repository": { 22 | "type": "git", 23 | "url": "git://github.com/ZeppelinSolutions/chai-bn" 24 | }, 25 | "keywords": [ 26 | "chai", 27 | "chai-plugin", 28 | "math", 29 | "test", 30 | "arbitrary", 31 | "precision", 32 | "arithmetic", 33 | "big", 34 | "number", 35 | "decimal", 36 | "float", 37 | "bignumber", 38 | "bn" 39 | ], 40 | "files": [ 41 | "chai-bn.js", 42 | "chai-bn.d.ts" 43 | ], 44 | "dependencies": {}, 45 | "peerDependencies": { 46 | "bn.js": "^5.0.0", 47 | "chai": "^4.0.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chai-bn 2 | 3 | [![NPM Package](https://img.shields.io/npm/v/chai-bn.svg?style=flat-square)](https://www.npmjs.org/package/chai-bn) 4 | [![Build Status](https://travis-ci.com/OpenZeppelin/chai-bn.svg?branch=master)](https://travis-ci.com/OpenZeppelin/chai-bn) 5 | 6 | [`Chai`](https://www.chaijs.com/) assertions for comparing arbitrary-precision integers using the [bn.js](https://github.com/indutny/bn.js) library. Forked from [chai-bignumber](https://github.com/asmarques/chai-bignumber), which uses the [bignumber.js](https://github.com/MikeMcl/bignumber.js) library. 7 | 8 | ## Installation 9 | 10 | ```bash 11 | npm install --save-dev chai-bn 12 | ``` 13 | 14 | ## Usage 15 | 16 | ```javascript 17 | const chai = require('chai'); 18 | const BN = require('bn.js'); 19 | 20 | // Enable and inject BN dependency 21 | chai.use(require('chai-bn')(BN)); 22 | ``` 23 | 24 | ## Assertions 25 | 26 | The following assertion methods are provided and will override the existing builtin assertions if the `bignumber` property is set as part of the assertion chain: 27 | - equal/equals/eq 28 | - above/gt/greaterThan 29 | - least/gte 30 | - below/lt/lessThan 31 | - most/lte 32 | - closeTo 33 | 34 | A set of additional assertion properties is also provided: 35 | - negative 36 | - zero 37 | 38 | Both actual values (the values being asserted) and expected values (the values the actual value is expected to match) can be either instances of `BN`, or strings which can be converted into a valid number. This is a key difference with [chai-bignumber](https://github.com/asmarques/chai-bignumber), which automatically converts JavaScript numbers to `BigNumber` instances for both actual and expected values. 39 | 40 | Only BDD style (`expect` or `should`) assertions are supported. 41 | 42 | ## Examples 43 | 44 | Methods: 45 | 46 | ```javascript 47 | const actual = new BN('100000000000000000').plus(new BN('1')); 48 | const expected = '100000000000000001'; 49 | 50 | actual.should.be.a.bignumber.that.equals(expected); 51 | expect(actual).to.be.a.bignumber.that.is.at.most(expected); 52 | (new BN('1000')).should.be.a.bignumber.that.is.lessThan('2000'); 53 | ``` 54 | 55 | Properties: 56 | 57 | ```javascript 58 | (new BN('-100')).should.be.a.bignumber.that.is.negative; 59 | expect(new BN('1').sub(new BN('1'))).to.be.a.bignumber.that.is.zero; 60 | ``` 61 | 62 | Some `Chai` properties (e.g. the `that.is` chain) have no effect other than increasing readability, and can be dropped if less verbosity is desired. 63 | 64 | ## License 65 | 66 | [MIT](LICENSE) 67 | -------------------------------------------------------------------------------- /chai-bn.js: -------------------------------------------------------------------------------- 1 | module.exports = function (BN) { 2 | const isEqualTo = BN.prototype.eq; 3 | const isGreaterThan = BN.prototype.gt; 4 | const isGreaterThanOrEqualTo = BN.prototype.gte; 5 | const isLessThan = BN.prototype.lt; 6 | const isLessThanOrEqualTo = BN.prototype.lte; 7 | const isNegative = BN.prototype.isNeg; 8 | const isZero = BN.prototype.isZero; 9 | 10 | return function (chai, utils) { 11 | const flag = utils.flag; 12 | // The 'bignumber' property sets the 'bignumber' flag, enabling the custom overrides 13 | chai.Assertion.addProperty('bignumber', function () { 14 | utils.flag(this, 'bignumber', true); 15 | }); 16 | 17 | // BN objects created using different (compatible) instances of BN can be used via BN.isBN() 18 | const isBN = function (object) { 19 | return object instanceof BN || BN.isBN(object); 20 | }; 21 | 22 | const convert = function (value) { 23 | if (isBN(value)) { 24 | return value; 25 | } else if (typeof value === 'string') { 26 | return new BN(value); 27 | // BN also supports conversion from e.g. JavaScript numbers, but only for small values. We disable that entirely 28 | } else { 29 | new chai.Assertion(value).assert(false, 30 | 'expected #{act} to be an instance of BN or string'); 31 | } 32 | }; 33 | 34 | // Overwrites the assertion performed by multiple methods (which should be aliases) with a new function. Prior to 35 | // calling said function, we assert that the actual value is a BN, and attempt to convert all other arguments to BN. 36 | const overwriteMethods = function (messageIndex, methodNames, newAssertion) { 37 | function overwriteMethod (originalAssertion) { 38 | return function () { 39 | if (utils.flag(this, 'bignumber')) { 40 | const actual = convert(this._obj); 41 | const args = [actual].concat( 42 | [].slice 43 | .call(arguments) 44 | .slice(0, messageIndex) 45 | .map(convert)) 46 | .concat(arguments[messageIndex]); 47 | newAssertion.apply(this, args); 48 | } else { 49 | originalAssertion.apply(this, arguments); 50 | } 51 | }; 52 | } 53 | 54 | methodNames.forEach(methodName => 55 | chai.Assertion.overwriteMethod(methodName, overwriteMethod) 56 | ); 57 | }; 58 | 59 | // Overwrites the assertion performed by multiple properties (which should be aliases) with a new function. Prior to 60 | // calling said function, we assert that the actual value is a BN. 61 | const overwriteProperties = function (propertyNames, newAssertion) { 62 | function overwriteProperty (originalAssertion) { 63 | return function () { 64 | if (utils.flag(this, 'bignumber')) { 65 | const actual = convert(this._obj); 66 | 67 | newAssertion.apply(this, [actual]); 68 | } else { 69 | originalAssertion.call(this); 70 | } 71 | }; 72 | } 73 | 74 | propertyNames.forEach(propertyName => 75 | chai.Assertion.overwriteProperty(propertyName, overwriteProperty) 76 | ); 77 | }; 78 | 79 | // BN.eq 80 | overwriteMethods(1, ['equal', 'equals', 'eq'], function (actual, expected, msg) { 81 | if (msg) { 82 | flag(this, 'message', msg); 83 | } 84 | this.assert( 85 | isEqualTo.bind(expected)(actual), 86 | 'expected #{act} to equal #{exp}', 87 | 'expected #{act} to be different from #{exp}', 88 | expected.toString(), 89 | actual.toString() 90 | ); 91 | }); 92 | 93 | // BN.gt 94 | overwriteMethods(1, ['above', 'gt', 'greaterThan'], function (actual, expected, msg) { 95 | if (msg) { 96 | flag(this, 'message', msg); 97 | } 98 | this.assert( 99 | isGreaterThan.bind(actual)(expected), 100 | 'expected #{act} to be greater than #{exp}', 101 | 'expected #{act} to be less than or equal to #{exp}', 102 | expected.toString(), 103 | actual.toString() 104 | ); 105 | }); 106 | 107 | // BN.gte 108 | overwriteMethods(1, ['least', 'gte'], function (actual, expected, msg) { 109 | if (msg) { 110 | flag(this, 'message', msg); 111 | } 112 | this.assert( 113 | isGreaterThanOrEqualTo.bind(actual)(expected), 114 | 'expected #{act} to be greater than or equal to #{exp}', 115 | 'expected #{act} to be less than #{exp}', 116 | expected.toString(), 117 | actual.toString() 118 | ); 119 | }); 120 | 121 | // BN.lt 122 | overwriteMethods(1, ['below', 'lt', 'lessThan'], function (actual, expected, msg) { 123 | if (msg) { 124 | flag(this, 'message', msg); 125 | } 126 | this.assert( 127 | isLessThan.bind(actual)(expected), 128 | 'expected #{act} to be less than #{exp}', 129 | 'expected #{act} to be greater than or equal to #{exp}', 130 | expected.toString(), 131 | actual.toString() 132 | ); 133 | }); 134 | 135 | // BN.lte 136 | overwriteMethods(1, ['most', 'lte'], function (actual, expected, msg) { 137 | if (msg) { 138 | flag(this, 'message', msg); 139 | } 140 | this.assert( 141 | isLessThanOrEqualTo.bind(actual)(expected), 142 | 'expected #{act} to be less than or equal to #{exp}', 143 | 'expected #{act} to be greater than #{exp}', 144 | expected.toString(), 145 | actual.toString() 146 | ); 147 | }); 148 | 149 | // Equality with tolerance, using gte and lte 150 | overwriteMethods(2, ['closeTo'], function (actual, expected, delta, msg) { 151 | if (msg) { 152 | flag(this, 'message', msg); 153 | } 154 | this.assert( 155 | isGreaterThanOrEqualTo.bind(actual)(expected.sub(delta)) && isLessThanOrEqualTo.bind(actual)(expected.add(delta)), 156 | `expected #{act} to be within '${delta}' of #{exp}`, 157 | `expected #{act} to be further than '${delta}' from #{exp}`, 158 | expected.toString(), 159 | actual.toString() 160 | ); 161 | }); 162 | 163 | // BN.isNeg 164 | overwriteProperties(['negative'], function (value) { 165 | this.assert( 166 | isNegative.bind(value)(), 167 | 'expected #{this} to be negative', 168 | 'expected #{this} to not be negative', 169 | value.toString() 170 | ); 171 | }); 172 | 173 | // BN.isZero 174 | overwriteProperties(['zero'], function (value) { 175 | this.assert( 176 | isZero.bind(value)(), 177 | 'expected #{this} to be zero', 178 | 'expected #{this} to not be zero', 179 | value.toString() 180 | ); 181 | }); 182 | }; 183 | }; 184 | -------------------------------------------------------------------------------- /test/chai-bn.test.js: -------------------------------------------------------------------------------- 1 | const BN = require('bn.js'); 2 | const chai = require('chai'); 3 | const expect = chai.expect; 4 | 5 | chai.should(); 6 | chai.use(require('../chai-bn')(BN)); 7 | chai.config.includeStack = true; 8 | 9 | describe('chai-bn', function () { 10 | const customMessage = 'Custom message'; 11 | const customMessageRegex = /^Custom message:/; 12 | const actualMatchInvalidError = /to be an instance of BN/; 13 | const expectedMatchInvalidError = /to be an instance of BN or string/; 14 | 15 | const testerGenerator = function (functionNames) { 16 | return [ 17 | function (a, b, msg) { 18 | functionNames.forEach(functionName => { 19 | if (msg) { 20 | a.should.be.a.bignumber.that[functionName](b, msg); 21 | expect(a).to.be.a.bignumber.that[functionName](b, msg); 22 | } else { 23 | a.should.be.a.bignumber.that[functionName](b); 24 | expect(a).to.be.a.bignumber.that[functionName](b); 25 | } 26 | }); 27 | }, 28 | 29 | function (a, b, msg) { 30 | functionNames.forEach(functionName => { 31 | if (msg) { 32 | a.should.not.be.a.bignumber.that[functionName](b, msg); 33 | expect(a).to.not.be.a.bignumber.that[functionName](b, msg); 34 | } else { 35 | a.should.not.be.a.bignumber.that[functionName](b); 36 | expect(a).to.not.be.a.bignumber.that[functionName](b); 37 | } 38 | }); 39 | } 40 | ]; 41 | }; 42 | 43 | const argTypeChecker = function (tester, notTester) { 44 | it('fails when first argument is not BN or string', function () { 45 | const testCases = [ 46 | [10, '10'], 47 | [-10, '-10'], 48 | [123456789123456789123456789, '123456789123456789123456789'], 49 | [-123456789123456789123456789, '-123456789123456789123456789'], 50 | ]; 51 | 52 | testCases.forEach(([a, b]) => { 53 | (() => tester(a, b)).should.throw(actualMatchInvalidError); 54 | (() => notTester(a, b)).should.throw(actualMatchInvalidError); 55 | }); 56 | }); 57 | 58 | it('fails when second argument is not BN or string', function () { 59 | const testCases = [ 60 | [new BN('10'), 10], 61 | [new BN('-10'), -10], 62 | [new BN('123456789123456789123456789'), 123456789123456789123456789], 63 | [new BN('-123456789123456789123456789'), -123456789123456789123456789], 64 | ]; 65 | 66 | testCases.forEach(([a, b]) => { 67 | (() => tester(a, b)).should.throw(expectedMatchInvalidError); 68 | (() => notTester(a, b)).should.throw(expectedMatchInvalidError); 69 | }); 70 | }); 71 | }; 72 | 73 | const toBNCombinations = function (a, b) { 74 | return [ 75 | [a, b], 76 | [new BN(a), b], 77 | [a, new BN(b)], 78 | [new BN(a), new BN(b)], 79 | ]; 80 | }; 81 | 82 | describe('equal/equals/eq', function () { 83 | const [tester, notTester] = testerGenerator(['equal', 'equals', 'eq']); 84 | const equalTestCases = [ 85 | ...toBNCombinations('10', '10'), 86 | ...toBNCombinations('-10', '-10'), 87 | ...toBNCombinations('123456789123456789123456789', '123456789123456789123456789'), 88 | ...toBNCombinations('-123456789123456789123456789', '-123456789123456789123456789'), 89 | ]; 90 | const notEqualTestCases = [ 91 | ...toBNCombinations('10', '9'), 92 | ...toBNCombinations('-10', '-9'), 93 | ...toBNCombinations('123456789123456789123456789', '123456789123456789123456788'), 94 | ...toBNCombinations('-123456789123456789123456789', '-123456789123456789123456788'), 95 | ]; 96 | it('asserts equality', function () { 97 | equalTestCases.forEach(([a, b]) => { 98 | tester(a, b); 99 | }); 100 | }); 101 | 102 | it('asserts inequality', function () { 103 | notEqualTestCases.forEach(([a, b]) => { 104 | notTester(a, b); 105 | }); 106 | }); 107 | 108 | it('equal fails on inequality', function () { 109 | notEqualTestCases.forEach(([a, b]) => { 110 | (() => tester(a, b)).should.throw(); 111 | (() => tester(a, b, customMessage)).should.throw(customMessageRegex); 112 | }); 113 | }); 114 | 115 | it('not equal fails on equality', function () { 116 | equalTestCases.forEach(([a, b]) => { 117 | (() => notTester(a, b)).should.throw(); 118 | (() => notTester(a, b, 'Custom message')).should.throw(customMessageRegex); 119 | }); 120 | }); 121 | 122 | argTypeChecker(tester, notTester); 123 | }); 124 | 125 | describe('above/gt/greaterThan', function () { 126 | const [tester, notTester] = testerGenerator(['above', 'gt', 'greaterThan']); 127 | const aboveTestCases = [ 128 | ...toBNCombinations('15', '10'), 129 | ...toBNCombinations('15', '-10'), 130 | ...toBNCombinations('-10', '-15'), 131 | 132 | ...toBNCombinations('123456789123456789', '123456789123'), 133 | ...toBNCombinations('123456789123456789', '-123456789123'), 134 | ...toBNCombinations('-123456789123', '-123456789123456789'), 135 | ]; 136 | 137 | const notAbovetestCases = [ 138 | ...toBNCombinations('10', '15'), 139 | ...toBNCombinations('-10', '15'), 140 | ...toBNCombinations('-15', '-10'), 141 | ...toBNCombinations('-15', '15'), 142 | ...toBNCombinations('-15', '-15'), 143 | 144 | ...toBNCombinations('123456789123', '123456789123456789'), 145 | ...toBNCombinations('-123456789123', '123456789123456789'), 146 | ...toBNCombinations('-123456789123456789', '-123456789123'), 147 | ]; 148 | 149 | it('asserts aboveness', function () { 150 | aboveTestCases.forEach(([a, b]) => { 151 | tester(a, b); 152 | }); 153 | }); 154 | 155 | it('asserts unaboveness', function () { 156 | notAbovetestCases.forEach(([a, b]) => { 157 | notTester(a, b); 158 | }); 159 | }); 160 | 161 | it('above fails on unaboveness', function () { 162 | notAbovetestCases.forEach(([a, b]) => { 163 | (() => tester(a, b)).should.throw(); 164 | (() => tester(a, b, customMessage)).should.throw(customMessageRegex); 165 | }); 166 | }); 167 | 168 | it('not above fails on aboveness', function () { 169 | aboveTestCases.forEach(([a, b]) => { 170 | (() => notTester(a, b)).should.throw(); 171 | (() => notTester(a, b, customMessage)).should.throw(customMessageRegex); 172 | }); 173 | }); 174 | 175 | argTypeChecker(tester, notTester); 176 | }); 177 | 178 | describe('least/gte', function () { 179 | const [tester, notTester] = testerGenerator(['gte']); 180 | const atLeastTestCases = [ 181 | ...toBNCombinations('15', '15'), 182 | ...toBNCombinations('15', '-10'), 183 | ...toBNCombinations('-10', '-15'), 184 | ...toBNCombinations('15', '15'), 185 | ...toBNCombinations('-15', '-15'), 186 | 187 | ...toBNCombinations('123456789123456789', '123456789123456789'), 188 | ...toBNCombinations('123456789123456789', '-123456789123'), 189 | ...toBNCombinations('-123456789123', '-123456789123456789'), 190 | ...toBNCombinations('123456789123456789', '123456789123456789'), 191 | ...toBNCombinations('-123456789123456789', '-123456789123456789'), 192 | ]; 193 | 194 | const notAtLeastTestCases = [ 195 | ...toBNCombinations('10', '15'), 196 | ...toBNCombinations('-10', '15'), 197 | ...toBNCombinations('-15', '-10'), 198 | 199 | ...toBNCombinations('123456789123', '123456789123456789'), 200 | ...toBNCombinations('-123456789123', '123456789123456789'), 201 | ...toBNCombinations('-123456789123456789', '-123456789123'), 202 | ]; 203 | 204 | it('asserts at least', function () { 205 | atLeastTestCases.forEach(([a, b]) => { 206 | tester(a, b); 207 | a.should.be.a.bignumber.that.is.at.least(b); 208 | expect(a).to.be.a.bignumber.that.is.at.least(b); 209 | }); 210 | }); 211 | 212 | it('asserts not at least', function () { 213 | notAtLeastTestCases.forEach(([a, b]) => { 214 | notTester(a, b); 215 | a.should.not.be.a.bignumber.that.is.at.least(b); 216 | expect(a).to.not.be.a.bignumber.that.is.at.least(b); 217 | }); 218 | }); 219 | 220 | it('at least fails fails on unaboveness', function () { 221 | notAtLeastTestCases.forEach(([a, b]) => { 222 | (() => tester(a, b)).should.throw(); 223 | (() => tester(a, b, customMessage)).should.throw(customMessageRegex); 224 | }); 225 | }); 226 | 227 | it('at most fails on aboveness', function () { 228 | atLeastTestCases.forEach(([a, b]) => { 229 | (() => notTester(a, b)).should.throw(); 230 | (() => notTester(a, b, customMessage)).should.throw(customMessageRegex); 231 | }); 232 | }); 233 | 234 | argTypeChecker(tester, notTester); 235 | }); 236 | 237 | describe('below/lt/lessThan', function () { 238 | const [tester, notTester] = testerGenerator(['below', 'lt', 'lessThan']); 239 | const belowTestCases = [ 240 | ...toBNCombinations('10', '15'), 241 | ...toBNCombinations('-10', '15'), 242 | ...toBNCombinations('-15', '-10'), 243 | 244 | ...toBNCombinations('123456789123', '123456789123456789'), 245 | ...toBNCombinations('-123456789123', '123456789123456789'), 246 | ...toBNCombinations('-123456789123456789', '-123456789123'), 247 | ]; 248 | 249 | const notBelowTestCases = [ 250 | ...toBNCombinations('15', '10'), 251 | ...toBNCombinations('15', '-10'), 252 | ...toBNCombinations('-10', '-15'), 253 | ...toBNCombinations('15', '15'), 254 | ...toBNCombinations('-15', '-15'), 255 | 256 | ...toBNCombinations('123456789123456789', '123456789123'), 257 | ...toBNCombinations('123456789123456789', '-123456789123'), 258 | ...toBNCombinations('-123456789123', '-123456789123456789'), 259 | ...toBNCombinations('123456789123456789', '123456789123456789'), 260 | ...toBNCombinations('-123456789123456789', '-123456789123456789'), 261 | ]; 262 | 263 | it('asserts belowness', function () { 264 | belowTestCases.forEach(([a, b]) => { 265 | tester(a, b); 266 | }); 267 | }); 268 | 269 | it('asserts unbelowness', function () { 270 | notBelowTestCases.forEach(([a, b]) => { 271 | notTester(a, b); 272 | }); 273 | }); 274 | 275 | it('below fails on unbelowness', function () { 276 | notBelowTestCases.forEach(([a, b]) => { 277 | (() => tester(a, b)).should.throw(); 278 | (() => tester(a, b, customMessage)).should.throw(customMessageRegex); 279 | }); 280 | }); 281 | 282 | it('not below fails on belowness', function () { 283 | belowTestCases.forEach(([a, b]) => { 284 | (() => notTester(a, b)).should.throw(); 285 | (() => notTester(a, b, customMessage)).should.throw(customMessageRegex); 286 | }); 287 | }); 288 | 289 | argTypeChecker(tester, notTester); 290 | }); 291 | 292 | describe('most/lte', function () { 293 | const [tester, notTester] = testerGenerator(['lte']); 294 | const atMostTestCases = [ 295 | ...toBNCombinations('10', '15'), 296 | ...toBNCombinations('-10', '15'), 297 | ...toBNCombinations('-15', '-10'), 298 | ...toBNCombinations('15', '15'), 299 | ...toBNCombinations('-15', '-15'), 300 | 301 | ...toBNCombinations('123456789123', '123456789123456789'), 302 | ...toBNCombinations('-123456789123', '123456789123456789'), 303 | ...toBNCombinations('-123456789123456789', '-123456789123'), 304 | ...toBNCombinations('123456789123456789', '123456789123456789'), 305 | ...toBNCombinations('-123456789123456789', '-123456789123456789'), 306 | ]; 307 | const notAtMostTestCases = [ 308 | ...toBNCombinations('15', '10'), 309 | ...toBNCombinations('15', '-10'), 310 | ...toBNCombinations('-10', '-15'), 311 | 312 | ...toBNCombinations('123456789123456789', '123456789123'), 313 | ...toBNCombinations('123456789123456789', '-123456789123'), 314 | ...toBNCombinations('-123456789123', '-123456789123456789'), 315 | ]; 316 | 317 | it('asserts at most', function () { 318 | atMostTestCases.forEach(([a, b]) => { 319 | tester(a, b); 320 | a.should.be.a.bignumber.that.is.at.most(b); 321 | expect(a).to.be.a.bignumber.that.is.at.most(b); 322 | }); 323 | }); 324 | 325 | it('asserts not at most', function () { 326 | notAtMostTestCases.forEach(([a, b]) => { 327 | notTester(a, b); 328 | a.should.not.be.a.bignumber.at.most(b); 329 | expect(a).to.not.be.a.bignumber.at.most(b); 330 | }); 331 | }); 332 | 333 | it('at most fails on not at most input', function () { 334 | notAtMostTestCases.forEach(([a, b]) => { 335 | (() => tester(a, b)).should.throw(); 336 | (() => tester(a, b, customMessage)).should.throw(customMessageRegex); 337 | (() => a.should.be.a.bignumber.at.most(b, customMessage)).should.throw(customMessageRegex); 338 | (() => expect(a).to.be.a.bignumber.at.most(b, customMessage)).should.throw(customMessageRegex); 339 | }); 340 | }); 341 | 342 | it('not at most fails on at most input', function () { 343 | atMostTestCases.forEach(([a, b]) => { 344 | (() => notTester(a, b)).should.throw(); 345 | (() => notTester(a, b, customMessage)).should.throw(customMessageRegex); 346 | (() => a.should.not.be.a.bignumber.at.most(b, customMessage)).should.throw(customMessageRegex); 347 | (() => expect(a).to.not.be.a.bignumber.at.most(b, customMessage)).should.throw(customMessageRegex); 348 | }); 349 | }); 350 | 351 | argTypeChecker(tester, notTester); 352 | }); 353 | 354 | describe('closeTo', function () { 355 | const tester = function (a, b, delta, customMessage) { 356 | a.should.be.a.bignumber.closeTo(b, delta, customMessage); 357 | expect(a).to.be.a.bignumber.closeTo(b, delta, customMessage); 358 | }; 359 | 360 | const notTester = function (a, b, delta, customMessage) { 361 | a.should.be.a.bignumber.not.closeTo(b, delta, customMessage); 362 | expect(a).to.be.a.bignumber.not.closeTo(b, delta, customMessage); 363 | }; 364 | const closeTestCases = [ 365 | [new BN('15'), '15', '0'], 366 | [new BN('15'), '10', '5'], 367 | [new BN('15'), '20', '5'], 368 | [new BN('-15'), '-15', '0'], 369 | [new BN('-15'), '-10', '5'], 370 | [new BN('-15'), '-20', '5'], 371 | [new BN('123456789123456789'), '123456789123456789', '0'], 372 | [new BN('123456789123456789'), '123456789123456780', '9'], 373 | [new BN('123456789123456789'), '123456789123456798', '9'], 374 | [new BN('-123456789123456789'), '-123456789123456789', '0'], 375 | [new BN('-123456789123456789'), '-123456789123456780', '9'], 376 | [new BN('-123456789123456789'), '-123456789123456798', '9'], 377 | ]; 378 | const notCloseTestCases = [ 379 | [new BN('15'), '14', '0'], 380 | [new BN('15'), '9', '5'], 381 | [new BN('15'), '21', '5'], 382 | [new BN('-15'), '-16', '0'], 383 | [new BN('-15'), '-9', '5'], 384 | [new BN('-15'), '-21', '5'], 385 | [new BN('123456789123456789'), '123456789123456788', '0'], 386 | [new BN('123456789123456789'), '123456789123456779', '9'], 387 | [new BN('123456789123456789'), '123456789123456799', '9'], 388 | [new BN('-123456789123456789'), '-123456789123456788', '0'], 389 | [new BN('-123456789123456789'), '-123456789123456779', '9'], 390 | [new BN('-123456789123456789'), '-123456789123456799', '9'], 391 | ]; 392 | 393 | it('asserts closeness', function () { 394 | closeTestCases.forEach(([a, b, delta]) => { 395 | tester(a, b, delta); 396 | (() => notTester(a, b, delta)).should.throw; 397 | }); 398 | }); 399 | 400 | it('asserts not closeness', function () { 401 | notCloseTestCases.forEach(([a, b, delta]) => { 402 | notTester(a, b, delta); 403 | (() => tester(a, b, delta)).should.throw; 404 | }); 405 | }); 406 | 407 | it('close fails on not closeness', function () { 408 | notCloseTestCases.forEach(([a, b, delta]) => { 409 | (() => tester(a, b, delta)).should.throw(); 410 | (() => tester(a, b, delta, customMessage)).should.throw(customMessageRegex); 411 | }); 412 | }); 413 | 414 | it('not close fails on closeness', function () { 415 | closeTestCases.forEach(([a, b, delta]) => { 416 | (() => notTester(a, b, delta)).should.throw(); 417 | (() => notTester(a, b, delta, customMessage)).should.throw(customMessageRegex); 418 | }); 419 | }); 420 | }); 421 | 422 | describe('negative', function () { 423 | const tester = function (a) { 424 | a.should.be.a.bignumber.that.is.negative; 425 | expect(a).to.be.a.bignumber.that.is.negative; 426 | }; 427 | 428 | const notTester = function (a) { 429 | a.should.not.be.a.bignumber.that.is.negative; 430 | expect(a).to.not.be.a.bignumber.that.is.negative; 431 | }; 432 | 433 | it('asserts negativity', function () { 434 | const testCases = [ 435 | new BN('-1'), 436 | new BN('-1234856789123456789'), 437 | ]; 438 | 439 | testCases.forEach((a) => { 440 | tester(a); 441 | }); 442 | }); 443 | 444 | it('asserts unnegativity', function () { 445 | const testCases = [ 446 | new BN('0'), 447 | new BN('1'), 448 | new BN('1234856789123456789'), 449 | ]; 450 | 451 | testCases.forEach((a) => { 452 | notTester(a); 453 | }); 454 | }); 455 | 456 | it('fails when argument is not BN or string', function () { 457 | const testCases = [ 458 | -5, 459 | 0, 460 | 5, 461 | ]; 462 | 463 | testCases.forEach((a) => { 464 | (() => tester(a)).should.throw(actualMatchInvalidError); 465 | (() => notTester(a)).should.throw(actualMatchInvalidError); 466 | }); 467 | }); 468 | }); 469 | 470 | describe('zero', function () { 471 | const tester = function (a) { 472 | a.should.be.a.bignumber.that.is.zero; 473 | expect(a).to.be.a.bignumber.that.is.zero; 474 | }; 475 | 476 | const notTester = function (a) { 477 | a.should.not.be.a.bignumber.that.is.zero; 478 | expect(a).to.not.be.a.bignumber.that.is.zero; 479 | }; 480 | 481 | it('asserts zeroness', function () { 482 | const testCases = [ 483 | new BN('0'), 484 | ]; 485 | 486 | testCases.forEach((a) => { 487 | tester(a); 488 | }); 489 | }); 490 | 491 | it('asserts unzeroness', function () { 492 | const testCases = [ 493 | new BN('1'), 494 | new BN('-1'), 495 | new BN('123456789123456789'), 496 | new BN('-123456789123456789'), 497 | ]; 498 | 499 | testCases.forEach((a) => { 500 | notTester(a); 501 | }); 502 | }); 503 | 504 | it('fails when argument is not BN or string', function () { 505 | const testCases = [ 506 | -5, 507 | 0, 508 | 5, 509 | ]; 510 | 511 | testCases.forEach((a) => { 512 | (() => tester(a)).should.throw(actualMatchInvalidError); 513 | (() => notTester(a)).should.throw(actualMatchInvalidError); 514 | }); 515 | }); 516 | }); 517 | }); 518 | --------------------------------------------------------------------------------