From 43b22c8facd43f347f0a9704dc8382f678fb5350 Mon Sep 17 00:00:00 2001 From: Lucas Vieira Date: Sat, 10 Sep 2016 17:00:13 -0300 Subject: [PATCH 1/3] Verify types on increase | decrease --- lib/chai/core/assertions.js | 16 +++++++++++----- lib/chai/interface/assert.js | 18 +++++++++--------- test/assert.js | 27 +++++++++++++++++---------- test/expect.js | 25 ++++++++++++++++--------- test/should.js | 21 ++++++++++++++------- 5 files changed, 67 insertions(+), 40 deletions(-) diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index ab6a9f648..8af77e280 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -224,7 +224,7 @@ module.exports = function (chai, _) { * expect([1,2,3]).to.include(2); * expect('foobar').to.contain('foo'); * expect({ foo: 'bar', hello: 'universe' }).to.include({ foo: 'bar' }); - * + * * By default, strict equality (===) is used. When asserting the inclusion of * a value in an array, the array is searched for an element that's strictly * equal to the given value. When asserting a subset of properties in an @@ -319,7 +319,7 @@ module.exports = function (chai, _) { return; } - + // Assert inclusion in an array or substring in a string. this.assert( typeof obj === 'string' || !isDeep ? ~obj.indexOf(val) @@ -1764,7 +1764,7 @@ module.exports = function (chai, _) { if (!cmp) { var matchIdx = superset.indexOf(elem); if (matchIdx === -1) return false; - + // Remove match from superset so not counted twice if duplicate in subset. if (!contains) superset.splice(matchIdx, 1); return true; @@ -1961,7 +1961,7 @@ module.exports = function (chai, _) { /** * ### .increase(function) * - * Asserts that a function increases an object property + * Asserts that a function increases a numeric object property * * var obj = { val: 10 }; * var fn = function() { obj.val = 15 }; @@ -1991,6 +1991,9 @@ module.exports = function (chai, _) { initial = target[prop]; } + // Make sure that the target is a number + new Assertion(initial).is.a('number'); + fn(); var final = prop === undefined || prop === null ? target() : target[prop]; @@ -2015,7 +2018,7 @@ module.exports = function (chai, _) { /** * ### .decrease(function) * - * Asserts that a function decreases an object property + * Asserts that a function decreases a numeric object property * * var obj = { val: 10 }; * var fn = function() { obj.val = 5 }; @@ -2045,6 +2048,9 @@ module.exports = function (chai, _) { initial = target[prop]; } + // Make sure that the target is a number + new Assertion(initial).is.a('number'); + fn(); var final = prop === undefined || prop === null ? target() : target[prop]; diff --git a/lib/chai/interface/assert.js b/lib/chai/interface/assert.js index fa9a3b9d0..9b0901758 100644 --- a/lib/chai/interface/assert.js +++ b/lib/chai/interface/assert.js @@ -2182,7 +2182,7 @@ module.exports = function (chai, util) { /** * ### .increases(function, object, property, [message]) * - * Asserts that a function increases an object property + * Asserts that a function increases a numeric object property * * var obj = { val: 10 }; * var fn = function() { obj.val = 13 }; @@ -2209,7 +2209,7 @@ module.exports = function (chai, util) { /** * ### .increasesBy(function, object, property, delta, [message]) * - * Asserts that a function increases an object property or a function's return value by an amount (delta) + * Asserts that a function increases a numeric object property or a function's return value by an amount (delta) * * var obj = { val: 10 }; * var fn = function() { obj.val += 10 }; @@ -2241,7 +2241,7 @@ module.exports = function (chai, util) { /** * ### .doesNotIncrease(function, object, property, [message]) * - * Asserts that a function does not increase object property + * Asserts that a function does not increase a numeric object property * * var obj = { val: 10 }; * var fn = function() { obj.val = 8 }; @@ -2268,7 +2268,7 @@ module.exports = function (chai, util) { /** * ### .increasesButNotBy(function, object, property, [message]) * - * Asserts that a function does not increase object property or function's return value by an amount (delta) + * Asserts that a function does not increase a numeric object property or function's return value by an amount (delta) * * var obj = { val: 10 }; * var fn = function() { obj.val = 15 }; @@ -2300,7 +2300,7 @@ module.exports = function (chai, util) { /** * ### .decreases(function, object, property, [message]) * - * Asserts that a function decreases an object property + * Asserts that a function decreases a numeric object property * * var obj = { val: 10 }; * var fn = function() { obj.val = 5 }; @@ -2327,7 +2327,7 @@ module.exports = function (chai, util) { /** * ### .decreasesBy(function, object, property, delta, [message]) * - * Asserts that a function decreases an object property or a function's return value by an amount (delta) + * Asserts that a function decreases a numeric object property or a function's return value by an amount (delta) * * var obj = { val: 10 }; * var fn = function() { obj.val -= 5 }; @@ -2359,7 +2359,7 @@ module.exports = function (chai, util) { /** * ### .doesNotDecrease(function, object, property, [message]) * - * Asserts that a function does not decreases an object property + * Asserts that a function does not decreases a numeric object property * * var obj = { val: 10 }; * var fn = function() { obj.val = 15 }; @@ -2386,7 +2386,7 @@ module.exports = function (chai, util) { /** * ### .doesNotDecreaseBy(function, object, property, delta, [message]) * - * Asserts that a function does not decreases an object property or a function's return value by an amount (delta) + * Asserts that a function does not decreases a numeric object property or a function's return value by an amount (delta) * * var obj = { val: 10 }; * var fn = function() { obj.val = 5 }; @@ -2418,7 +2418,7 @@ module.exports = function (chai, util) { /** * ### .decreasesButNotBy(function, object, property, delta, [message]) * - * Asserts that a function does not decreases an object property or a function's return value by an amount (delta) + * Asserts that a function does not decreases a numeric object property or a function's return value by an amount (delta) * * var obj = { val: 10 }; * var fn = function() { obj.val = 5 }; diff --git a/test/assert.js b/test/assert.js index 449a1789c..c7f3f42a1 100644 --- a/test/assert.js +++ b/test/assert.js @@ -365,7 +365,7 @@ describe('assert', function () { it('exists', function() { var meeber = 'awesome'; var iDoNotExist; - + assert.exists(meeber); assert.exists(0); assert.exists(false); @@ -379,7 +379,7 @@ describe('assert', function () { it('notExists', function() { var meeber = 'awesome'; var iDoNotExist; - + assert.notExists(iDoNotExist); err(function (){ @@ -728,7 +728,7 @@ describe('assert', function () { var aKey = {thisIs: 'anExampleObject'} , anotherKey = {doingThisBecauseOf: 'referential equality'} , testMap = new Map(); - + testMap.set(aKey, 'aValue'); testMap.set(anotherKey, 'anotherValue'); @@ -751,7 +751,7 @@ describe('assert', function () { , weirdMapKey2 = {toString: NaN} , weirdMapKey3 = [] , weirdMap = new Map(); - + weirdMap.set(weirdMapKey1, 'val1'); weirdMap.set(weirdMapKey2, 'val2'); @@ -763,7 +763,7 @@ describe('assert', function () { , symMapKey2 = Symbol() , symMapKey3 = Symbol() , symMap = new Map(); - + symMap.set(symMapKey1, 'val1'); symMap.set(symMapKey2, 'val2'); @@ -825,7 +825,7 @@ describe('assert', function () { var aKey = {thisIs: 'anExampleObject'} , anotherKey = {doingThisBecauseOf: 'referential equality'} , testSet = new Set(); - + testSet.add(aKey); testSet.add(anotherKey); @@ -848,7 +848,7 @@ describe('assert', function () { , weirdSetKey2 = {toString: NaN} , weirdSetKey3 = [] , weirdSet = new Set(); - + weirdSet.add(weirdSetKey1); weirdSet.add(weirdSetKey2); @@ -860,7 +860,7 @@ describe('assert', function () { , symSetKey2 = Symbol() , symSetKey3 = Symbol() , symSet = new Set(); - + symSet.add(symSetKey1); symSet.add(symSetKey2); @@ -873,7 +873,7 @@ describe('assert', function () { } var errSet = new Set(); - + errSet.add({1: 20}); errSet.add('number'); @@ -1749,7 +1749,7 @@ describe('assert', function () { }); it('increase, decrease', function() { - var obj = { value: 10 }, + var obj = { value: 10, noop: null }, arr = ['one', 'two'], pFn = function() { arr.push('three') }, popFn = function() { arr.pop() }, @@ -1777,6 +1777,13 @@ describe('assert', function () { assert.doesNotIncrease(popFn, lenFn); assert.increasesBy(pFn, lenFn, 1); assert.increasesButNotBy(pFn, lenFn, 2); + + err(function() { + assert.increases(incFn, obj, 'noop'); + }, 'expected null to be a number'); + err(function() { + assert.decreases(incFn, obj, 'noop'); + }, 'expected null to be a number'); }); it('isExtensible / extensible', function() { diff --git a/test/expect.js b/test/expect.js index 14e6ec2f7..f6eaedd32 100644 --- a/test/expect.js +++ b/test/expect.js @@ -603,7 +603,7 @@ describe('expect', function () { err(function(){ expect().to.not.be.empty; }, "expected undefined to exist"); - + }); it('NaN', function() { @@ -797,7 +797,7 @@ describe('expect', function () { expect(obj).to.not.have.deep.property('a', {b: 1}, 'blah'); }, "blah: expected { a: { b: 1 } } to not have a deep property 'a' of { b: 1 }"); }); - + it('nested.property(name, val)', function(){ expect({ foo: { bar: 'baz' } }) .to.have.nested.property('foo.bar', 'baz'); @@ -1182,7 +1182,7 @@ describe('expect', function () { var aKey = {thisIs: 'anExampleObject'} , anotherKey = {doingThisBecauseOf: 'referential equality'} , testMap = new Map(); - + testMap.set(aKey, 'aValue'); testMap.set(anotherKey, 'anotherValue'); @@ -1209,7 +1209,7 @@ describe('expect', function () { , weirdMapKey2 = {toString: NaN} , weirdMapKey3 = [] , weirdMap = new Map(); - + weirdMap.set(weirdMapKey1, 'val1'); weirdMap.set(weirdMapKey2, 'val2'); @@ -1221,7 +1221,7 @@ describe('expect', function () { , symMapKey2 = Symbol() , symMapKey3 = Symbol() , symMap = new Map(); - + symMap.set(symMapKey1, 'val1'); symMap.set(symMapKey2, 'val2'); @@ -1262,7 +1262,7 @@ describe('expect', function () { var aKey = {thisIs: 'anExampleObject'} , anotherKey = {doingThisBecauseOf: 'referential equality'} , testSet = new Set(); - + testSet.add(aKey); testSet.add(anotherKey); @@ -1289,7 +1289,7 @@ describe('expect', function () { , weirdSetKey2 = {toString: NaN} , weirdSetKey3 = [] , weirdSet = new Set(); - + weirdSet.add(weirdSetKey1); weirdSet.add(weirdSetKey2); @@ -1301,7 +1301,7 @@ describe('expect', function () { , symSetKey2 = Symbol() , symSetKey3 = Symbol() , symSet = new Set(); - + symSet.add(symSetKey1); symSet.add(symSetKey2); @@ -1898,7 +1898,7 @@ describe('expect', function () { }); it('increase, decrease', function() { - var obj = { value: 10 }, + var obj = { value: 10, noop: null }, arr = ['one', 'two'], pFn = function() { arr.push('three') }, popFn = function() { arr.pop() }, @@ -1931,6 +1931,13 @@ describe('expect', function () { expect(popFn).to.decrease(lenFn).but.not.by(2); expect(nFn).to.not.decrease(lenFn); expect(pFn).to.not.decrease(lenFn); + + err(function() { + expect(incFn).to.increase(obj, 'noop'); + }, 'expected null to be a number'); + err(function() { + expect(incFn).to.decrease(obj, 'noop'); + }, 'expected null to be a number'); }); it('extensible', function() { diff --git a/test/should.js b/test/should.js index 4995264f9..e89055cac 100644 --- a/test/should.js +++ b/test/should.js @@ -1030,7 +1030,7 @@ describe('should', function() { var aKey = {thisIs: 'anExampleObject'} , anotherKey = {doingThisBecauseOf: 'referential equality'} , testMap = new Map(); - + testMap.set(aKey, 'aValue'); testMap.set(anotherKey, 'anotherValue'); @@ -1055,7 +1055,7 @@ describe('should', function() { , weirdMapKey2 = {toString: NaN} , weirdMapKey3 = [] , weirdMap = new Map(); - + weirdMap.set(weirdMapKey1, 'val1'); weirdMap.set(weirdMapKey2, 'val2'); @@ -1067,7 +1067,7 @@ describe('should', function() { , symMapKey2 = Symbol() , symMapKey3 = Symbol() , symMap = new Map(); - + symMap.set(symMapKey1, 'val1'); symMap.set(symMapKey2, 'val2'); @@ -1108,7 +1108,7 @@ describe('should', function() { var aKey = {thisIs: 'anExampleObject'} , anotherKey = {doingThisBecauseOf: 'referential equality'} , testSet = new Set(); - + testSet.add(aKey); testSet.add(anotherKey); @@ -1135,7 +1135,7 @@ describe('should', function() { , weirdSetKey2 = {toString: NaN} , weirdSetKey3 = [] , weirdSet = new Set(); - + weirdSet.add(weirdSetKey1); weirdSet.add(weirdSetKey2); @@ -1147,7 +1147,7 @@ describe('should', function() { , symSetKey2 = Symbol() , symSetKey3 = Symbol() , symSet = new Set(); - + symSet.add(symSetKey1); symSet.add(symSetKey2); @@ -1742,7 +1742,7 @@ describe('should', function() { }); it('increase, decrease', function() { - var obj = { value: 10 }, + var obj = { value: 10, noop: null }, arr = ['one', 'two'], pFn = function() { arr.push('three') }, popFn = function() { arr.pop() }, @@ -1778,6 +1778,13 @@ describe('should', function() { popFn.should.decrease(lenFn).by(1); popFn.should.decrease(lenFn).but.not.by(2); + + err(function() { + incFn.should.increase(obj, 'noop'); + }, 'expected null to be a number'); + err(function() { + incFn.should.decrease(obj, 'noop'); + }, 'expected null to be a number'); }); it('extensible', function() { From c802d38dbe9ea63a97b9fb517ebdc05289019736 Mon Sep 17 00:00:00 2001 From: Lucas Vieira Date: Sat, 10 Sep 2016 17:01:26 -0300 Subject: [PATCH 2/3] Add tests that ensure assert.atMost and assert.atLeast are checking type --- test/assert.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/assert.js b/test/assert.js index c7f3f42a1..e8219c65b 100644 --- a/test/assert.js +++ b/test/assert.js @@ -1693,6 +1693,13 @@ describe('assert', function () { err(function() { assert.isAtLeast(1, 3); }, 'expected 1 to be at least 3'); + + err(function() { + assert.isAtLeast(null, 1); + }, 'expected null to be a number'); + err(function() { + assert.isAtLeast(1, null); + }, 'the argument to least must be a number'); }); it('below', function() { @@ -1722,6 +1729,13 @@ describe('assert', function () { err(function() { assert.isAtMost(3, 1); }, 'expected 3 to be at most 1'); + + err(function() { + assert.isAtMost(null, 1); + }, 'expected null to be a number'); + err(function() { + assert.isAtMost(1, null); + }, 'the argument to most must be a number'); }); it('change', function() { From 5f3c4ae166a13cdb318911f01fcb61eb83efb9e2 Mon Sep 17 00:00:00 2001 From: Lucas Vieira Date: Mon, 12 Sep 2016 01:59:11 -0300 Subject: [PATCH 3/3] Improve docs for "increase | decrease" Indicate that 'property' and 'message' are optional. Indicate that 'increase' and 'decrease' can receive a function which returns the property to be checked. --- lib/chai/core/assertions.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index 8af77e280..12f167410 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -1959,7 +1959,7 @@ module.exports = function (chai, _) { Assertion.addChainableMethod('changes', assertChanges); /** - * ### .increase(function) + * ### .increase(target[, property[, message]]) * * Asserts that a function increases a numeric object property * @@ -1967,11 +1967,18 @@ module.exports = function (chai, _) { * var fn = function() { obj.val = 15 }; * expect(fn).to.increase(obj, 'val'); * + * It can also receive a function which returns the property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * var getVal = function() { return obj.val }; + * expect(fn).to.increase(getVal); + * * @name increase * @alias increases * @alias Increase - * @param {String} target - * @param {String} property name + * @param {String|Function} target + * @param {String} property name _optional_ * @param {String} message _optional_ * @namespace BDD * @api public @@ -2016,7 +2023,7 @@ module.exports = function (chai, _) { Assertion.addChainableMethod('increases', assertIncreases); /** - * ### .decrease(function) + * ### .decrease(target[, property[, message]]) * * Asserts that a function decreases a numeric object property * @@ -2024,11 +2031,18 @@ module.exports = function (chai, _) { * var fn = function() { obj.val = 5 }; * expect(fn).to.decrease(obj, 'val'); * + * It can also receive a function which returns the property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * var getVal = function() { return obj.val }; + * expect(fn).to.decrease(getVal); + * * @name decrease * @alias decreases * @alias Decrease - * @param {String} target - * @param {String} property name + * @param {String|Function} target + * @param {String} property name _optional_ * @param {String} message _optional_ * @namespace BDD * @api public