From 78c5763c2e71e1667ba5af5b87a4d40bfcaa5a7f Mon Sep 17 00:00:00 2001 From: Lucas Vieira Date: Sat, 30 Apr 2016 17:46:33 -0300 Subject: [PATCH 1/2] Verify types on within and related assertions --- lib/chai/core/assertions.js | 80 ++++++++++++++++++++++---- test/assert.js | 15 +++++ test/expect.js | 112 +++++++++++++++++++++++++++++++++++- test/should.js | 104 +++++++++++++++++++++++++++++++++ 4 files changed, 299 insertions(+), 12 deletions(-) diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index ff5a8ca5c..5fb19a02c 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -521,14 +521,26 @@ module.exports = function (chai, _) { * @alias greaterThan * @param {Number} value * @param {String} message _optional_ + * @namespace BDD * @api public */ function assertAbove (n, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { + var obj = flag(this, 'object') + , doLength = flag(this, 'doLength'); + + if (doLength) { new Assertion(obj, msg).to.have.property('length'); + } else { + new Assertion(obj, msg).is.a('number'); + } + + if (_.type(n) !== 'number') { + throw new Error('the argument to above must be a number'); + } + + if (doLength) { var len = obj.length; this.assert( len > n @@ -569,14 +581,26 @@ module.exports = function (chai, _) { * @alias gte * @param {Number} value * @param {String} message _optional_ + * @namespace BDD * @api public */ function assertLeast (n, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { + var obj = flag(this, 'object') + , doLength = flag(this, 'doLength'); + + if (doLength) { new Assertion(obj, msg).to.have.property('length'); + } else { + new Assertion(obj, msg).is.a('number'); + } + + if (_.type(n) !== 'number') { + throw new Error('the argument to least must be a number'); + } + + if (doLength) { var len = obj.length; this.assert( len >= n @@ -617,14 +641,26 @@ module.exports = function (chai, _) { * @alias lessThan * @param {Number} value * @param {String} message _optional_ + * @namespace BDD * @api public */ function assertBelow (n, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { + var obj = flag(this, 'object') + , doLength = flag(this, 'doLength'); + + if (doLength) { new Assertion(obj, msg).to.have.property('length'); + } else { + new Assertion(obj, msg).is.a('number'); + } + + if (_.type(n) !== 'number') { + throw new Error('the argument to below must be a number'); + } + + if (doLength) { var len = obj.length; this.assert( len < n @@ -665,14 +701,26 @@ module.exports = function (chai, _) { * @alias lte * @param {Number} value * @param {String} message _optional_ + * @namespace BDD * @api public */ function assertMost (n, msg) { if (msg) flag(this, 'message', msg); - var obj = flag(this, 'object'); - if (flag(this, 'doLength')) { + var obj = flag(this, 'object') + , doLength = flag(this, 'doLength'); + + if (doLength) { new Assertion(obj, msg).to.have.property('length'); + } else { + new Assertion(obj, msg).is.a('number'); + } + + if (_.type(n) !== 'number') { + throw new Error('the argument to most must be a number'); + } + + if (doLength) { var len = obj.length; this.assert( len <= n @@ -712,15 +760,27 @@ module.exports = function (chai, _) { * @param {Number} start lowerbound inclusive * @param {Number} finish upperbound inclusive * @param {String} message _optional_ + * @namespace BDD * @api public */ Assertion.addMethod('within', function (start, finish, msg) { if (msg) flag(this, 'message', msg); var obj = flag(this, 'object') - , range = start + '..' + finish; - if (flag(this, 'doLength')) { + , range = start + '..' + finish + , doLength = flag(this, 'doLength'); + + if (doLength) { new Assertion(obj, msg).to.have.property('length'); + } else { + new Assertion(obj, msg).is.a('number'); + } + + if (_.type(start) !== 'number' || _.type(finish) !== 'number') { + throw new Error('the arguments to within must be numbers'); + } + + if (doLength) { var len = obj.length; this.assert( len >= start && len <= finish diff --git a/test/assert.js b/test/assert.js index 25cae2e1f..304eaa858 100644 --- a/test/assert.js +++ b/test/assert.js @@ -789,6 +789,14 @@ describe('assert', function () { err(function() { assert.isAbove(1, 1); }, 'expected 1 to be above 1'); + + err(function() { + assert.isAbove(null, 1); + }, 'expected null to be a number'); + + err(function() { + assert.isAbove(1, null); + }, 'the argument to above must be a number'); }); it('below', function() { @@ -802,6 +810,13 @@ describe('assert', function () { assert.isBelow(1, 1); }, 'expected 1 to be below 1'); + err(function() { + assert.isBelow(null, 1); + }, 'expected null to be a number'); + + err(function() { + assert.isBelow(1, null); + }, 'the argument to below must be a number'); }); it('memberDeepEquals', function() { diff --git a/test/expect.js b/test/expect.js index de3ff2e5e..b1cb0ad55 100644 --- a/test/expect.js +++ b/test/expect.js @@ -153,6 +153,34 @@ describe('expect', function () { err(function () { expect([ 1, 2, 3 ]).to.have.length.within(5,7, 'blah'); }, "blah: expected [ 1, 2, 3 ] to have a length within 5..7"); + + err(function () { + expect(null).to.be.within(0, 1, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.be.within(null, 1, 'blah'); + }, "the arguments to within must be numbers"); + + err(function () { + expect(1).to.be.within(0, null, 'blah'); + }, "the arguments to within must be numbers"); + + err(function () { + expect(null).to.not.be.within(0, 1, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.not.be.within(null, 1, 'blah'); + }, "the arguments to within must be numbers"); + + err(function () { + expect(1).to.not.be.within(0, null, 'blah'); + }, "the arguments to within must be numbers"); + + err(function () { + expect(1).to.have.length.within(5,7, 'blah'); + }, "blah: expected 1 to have a property 'length'"); }); it('above(n)', function(){ @@ -165,7 +193,7 @@ describe('expect', function () { err(function(){ expect(5).to.be.above(6, 'blah'); - }, "blah: expected 5 to be above 6", 'blah'); + }, "blah: expected 5 to be above 6"); err(function(){ expect(10).to.not.be.above(6, 'blah'); @@ -178,6 +206,26 @@ describe('expect', function () { err(function () { expect([ 1, 2, 3 ]).to.have.length.above(4, 'blah'); }, "blah: expected [ 1, 2, 3 ] to have a length above 4 but got 3"); + + err(function () { + expect(null).to.be.above(0, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.be.above(null, 'blah'); + }, "the argument to above must be a number"); + + err(function () { + expect(null).to.not.be.above(0, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.not.be.above(null, 'blah'); + }, "the argument to above must be a number"); + + err(function () { + expect(1).to.have.length.above(0, 'blah'); + }, "blah: expected 1 to have a property 'length'"); }); it('least(n)', function(){ @@ -189,7 +237,7 @@ describe('expect', function () { err(function(){ expect(5).to.be.at.least(6, 'blah'); - }, "blah: expected 5 to be at least 6", 'blah'); + }, "blah: expected 5 to be at least 6"); err(function(){ expect(10).to.not.be.at.least(6, 'blah'); @@ -206,6 +254,26 @@ describe('expect', function () { err(function () { expect([ 1, 2, 3, 4 ]).to.not.have.length.of.at.least(4, 'blah'); }, "blah: expected [ 1, 2, 3, 4 ] to have a length below 4"); + + err(function () { + expect(null).to.be.at.least(0, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.be.at.least(null, 'blah'); + }, "the argument to least must be a number"); + + err(function () { + expect(null).to.not.be.at.least(0, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.not.be.at.least(null, 'blah'); + }, "the argument to least must be a number"); + + err(function () { + expect(1).to.have.length.at.least(0, 'blah'); + }, "blah: expected 1 to have a property 'length'"); }); it('below(n)', function(){ @@ -231,6 +299,26 @@ describe('expect', function () { err(function () { expect([ 1, 2, 3 ]).to.have.length.below(2, 'blah'); }, "blah: expected [ 1, 2, 3 ] to have a length below 2 but got 3"); + + err(function () { + expect(null).to.be.below(0, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.be.below(null, 'blah'); + }, "the argument to below must be a number"); + + err(function () { + expect(null).to.not.be.below(0, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.not.be.below(null, 'blah'); + }, "the argument to below must be a number"); + + err(function () { + expect(1).to.have.length.below(0, 'blah'); + }, "blah: expected 1 to have a property 'length'"); }); it('most(n)', function(){ @@ -260,6 +348,26 @@ describe('expect', function () { err(function () { expect([ 1, 2 ]).to.not.have.length.of.at.most(2, 'blah'); }, "blah: expected [ 1, 2 ] to have a length above 2"); + + err(function () { + expect(null).to.be.at.most(0, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.be.at.most(null, 'blah'); + }, "the argument to most must be a number"); + + err(function () { + expect(null).to.not.be.at.most(0, 'blah'); + }, "blah: expected null to be a number"); + + err(function () { + expect(1).to.not.be.at.most(null, 'blah'); + }, "the argument to most must be a number"); + + err(function () { + expect(1).to.have.length.of.at.most(0, 'blah'); + }, "blah: expected 1 to have a property 'length'"); }); it('match(regexp)', function(){ diff --git a/test/should.js b/test/should.js index d335d0edf..ead74a4f6 100644 --- a/test/should.js +++ b/test/should.js @@ -205,6 +205,34 @@ describe('should', function() { err(function(){ ({ foo: 1 }).should.have.length.within(50,100, 'blah'); }, "blah: expected { foo: 1 } to have a property 'length'"); + + err(function () { + ('string').should.be.within(0, 1, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.be.within(null, 1, 'blah'); + }, "the arguments to within must be numbers"); + + err(function () { + (1).should.be.within(0, null, 'blah'); + }, "the arguments to within must be numbers"); + + err(function () { + ('string').should.not.be.within(0, 1, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.not.be.within(null, 1, 'blah'); + }, "the arguments to within must be numbers"); + + err(function () { + (1).should.not.be.within(0, null, 'blah'); + }, "the arguments to within must be numbers"); + + err(function () { + (1).should.have.length.within(5,7, 'blah'); + }, "blah: expected 1 to have a property 'length'"); }); it('above(n)', function(){ @@ -224,6 +252,26 @@ describe('should', function() { err(function(){ ({foo: 1}).should.have.length.above(3, 'blah'); }, "blah: expected { foo: 1 } to have a property 'length'"); + + err(function () { + ('string').should.be.above(0, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.be.above(null, 'blah'); + }, "the argument to above must be a number"); + + err(function () { + ('string').should.not.be.above(0, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.not.be.above(null, 'blah'); + }, "the argument to above must be a number"); + + err(function () { + (1).should.have.length.above(0, 'blah'); + }, "blah: expected 1 to have a property 'length'"); }); it('least(n)', function(){ @@ -241,6 +289,22 @@ describe('should', function() { err(function(){ ({foo: 1}).should.have.length.of.at.least(3, 'blah'); }, "blah: expected { foo: 1 } to have a property 'length'"); + + err(function () { + ('string').should.be.at.least(0, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.be.at.least(null, 'blah'); + }, "the argument to least must be a number"); + + err(function () { + ('string').should.not.be.at.least(0, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.not.be.at.least(null, 'blah'); + }, "the argument to least must be a number"); }); it('below(n)', function(){ @@ -260,6 +324,26 @@ describe('should', function() { err(function(){ ({foo: 1}).should.have.length.below(3, 'blah'); }, "blah: expected { foo: 1 } to have a property 'length'"); + + err(function () { + ('string').should.be.below(0, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.be.below(null, 'blah'); + }, "the argument to below must be a number"); + + err(function () { + ('string').should.not.be.below(0, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.not.be.below(null, 'blah'); + }, "the argument to below must be a number"); + + err(function () { + (1).should.have.length.below(0, 'blah'); + }, "blah: expected 1 to have a property 'length'"); }); it('most(n)', function(){ @@ -277,6 +361,26 @@ describe('should', function() { err(function(){ ({foo: 1}).should.have.length.of.at.most(3, 'blah'); }, "blah: expected { foo: 1 } to have a property 'length'"); + + err(function () { + ('string').should.be.at.most(0, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.be.at.most(null, 'blah'); + }, "the argument to most must be a number"); + + err(function () { + ('string').should.not.be.at.most(0, 'blah'); + }, "blah: expected 'string' to be a number"); + + err(function () { + (1).should.not.be.at.most(null, 'blah'); + }, "the argument to most must be a number"); + + err(function () { + (1).should.have.length.of.at.most(0, 'blah'); + }, "blah: expected 1 to have a property 'length'"); }); it('match(regexp)', function(){ From de8659044ffea729e55a278ffc1dcb1960045991 Mon Sep 17 00:00:00 2001 From: Lucas Vieira Date: Sun, 1 May 2016 13:16:54 -0300 Subject: [PATCH 2/2] Documentation update to indicate type requirements --- lib/chai/core/assertions.js | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index 5fb19a02c..addab8c88 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -504,14 +504,15 @@ module.exports = function (chai, _) { /** * ### .above(value) * - * Asserts that the target is greater than `value`. + * Asserts that the number target is greater than `value`. * * expect(10).to.be.above(5); * * Can also be used in conjunction with `length` to * assert a minimum length. The benefit being a * more informative error message than if the length - * was supplied directly. + * was supplied directly. In this case the target must + * have a length property. * * expect('foo').to.have.length.above(2); * expect([ 1, 2, 3 ]).to.have.length.above(2); @@ -565,14 +566,15 @@ module.exports = function (chai, _) { /** * ### .least(value) * - * Asserts that the target is greater than or equal to `value`. + * Asserts that the number target is greater than or equal to `value`. * * expect(10).to.be.at.least(10); * * Can also be used in conjunction with `length` to * assert a minimum length. The benefit being a * more informative error message than if the length - * was supplied directly. + * was supplied directly. In this case the target must + * have a length property. * * expect('foo').to.have.length.of.at.least(2); * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); @@ -624,14 +626,15 @@ module.exports = function (chai, _) { /** * ### .below(value) * - * Asserts that the target is less than `value`. + * Asserts that the number target is less than `value`. * * expect(5).to.be.below(10); * * Can also be used in conjunction with `length` to * assert a maximum length. The benefit being a * more informative error message than if the length - * was supplied directly. + * was supplied directly. In this case the target must + * have a length property. * * expect('foo').to.have.length.below(4); * expect([ 1, 2, 3 ]).to.have.length.below(4); @@ -685,14 +688,15 @@ module.exports = function (chai, _) { /** * ### .most(value) * - * Asserts that the target is less than or equal to `value`. + * Asserts that the number target is less than or equal to `value`. * * expect(5).to.be.at.most(5); * * Can also be used in conjunction with `length` to * assert a maximum length. The benefit being a * more informative error message than if the length - * was supplied directly. + * was supplied directly. In this case the target must + * have a length property. * * expect('foo').to.have.length.of.at.most(4); * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); @@ -744,14 +748,15 @@ module.exports = function (chai, _) { /** * ### .within(start, finish) * - * Asserts that the target is within a range. + * Asserts that the number target is within a range of numbers. * * expect(7).to.be.within(5,10); * * Can also be used in conjunction with `length` to * assert a length range. The benefit being a * more informative error message than if the length - * was supplied directly. + * was supplied directly. In this case the target must + * have a length property. * * expect('foo').to.have.length.within(2,4); * expect([ 1, 2, 3 ]).to.have.length.within(2,4);