From 6c18935dc379ca5e0599c63b341b7994820ac659 Mon Sep 17 00:00:00 2001
From: Graeme Yeates Function (uh, ahem) Functions
- Pass true for the immediate parameter to cause
+ Pass true for the immediate argument to cause
debounce to trigger the function on the leading instead of the
trailing edge of the wait interval. Useful in circumstances like
preventing accidental double-clicks on a "submit" button from firing a
From f087449a74418ef26deed0f3315cc1256d8143ae Mon Sep 17 00:00:00 2001
From: Graeme Array Functions
and so on. Use with apply to pass in an array of arrays.
-_.unzip(["moe", 30, true], ["larry", 40, false], ["curly", 50, false]); +_.unzip([["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]); => [['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]]From ed828f43f49ee96784cf3f1ef4d7bf9b0e499971 Mon Sep 17 00:00:00 2001 From: Carl Xiong
_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); @@ -967,12 +968,12 @@Array Functions
- unzip_.unzip(*arrays)
+ unzip_.unzip(array)
- The opposite of zip. Given a number of arrays, returns a
+ The opposite of zip. Given an array of arrays, returns a
series of new arrays, the first of which contains all of the first elements
in the input arrays, the second of which contains all of the second elements,
- and so on. Use with apply to pass in an array of arrays.
+ and so on.
_.unzip([["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]); From b10b2e6d72aebbff7961c65a9b9b1838812f9c73 Mon Sep 17 00:00:00 2001 From: Justin RidgewellDate: Mon, 27 Apr 2015 13:01:39 -0400 Subject: [PATCH 016/263] Cleanup _.mapObject --- underscore.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/underscore.js b/underscore.js index 7ecb85825..f54cffa47 100644 --- a/underscore.js +++ b/underscore.js @@ -961,14 +961,13 @@ _.mapObject = function(obj, iteratee, context) { iteratee = cb(iteratee, context); var keys = _.keys(obj), - length = keys.length, - results = {}, - currentKey; - for (var index = 0; index < length; index++) { - currentKey = keys[index]; - results[currentKey] = iteratee(obj[currentKey], currentKey, obj); - } - return results; + length = keys.length, + results = {}; + for (var index = 0; index < length; index++) { + var currentKey = keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; }; // Convert an object into a list of `[key, value]` pairs. From 9244d619ccfe277c98600efcf5aaa2f8026bb53e Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Tue, 28 Apr 2015 10:22:32 -0400 Subject: [PATCH 017/263] Merge pull request #2161 from smelnikov/result-doc-fix described correct behavior of _.result in docs --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 78eedd16a..cb64aa297 100644 --- a/index.html +++ b/index.html @@ -1931,8 +1931,8 @@ Utility Functions
If the value of the named property is a function then invoke it with the object as context; otherwise, return it. If a default value - is provided and the property doesn't exist than the default will be returned. - If defaultValue is a function its result will be returned. + is provided and the property doesn't exist or is undefined than the default + will be returned. If defaultValue is a function its result will be returned.var object = {cheese: 'crumpets', stuff: function(){ return 'nonsense'; }}; From 4c534babce217abb7e13bd47efcb399e47ef9cca Mon Sep 17 00:00:00 2001 From: Justin RidgewellFrom 8f3d0507e885f64a05424fdc09a07cf77e2f676b Mon Sep 17 00:00:00 2001 From: Paul FalgoutDate: Tue, 28 Apr 2015 10:25:24 -0400 Subject: [PATCH 018/263] Fix grammar --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index cb64aa297..952b9e285 100644 --- a/index.html +++ b/index.html @@ -1931,7 +1931,7 @@ Utility Functions
If the value of the named property is a function then invoke it with the object as context; otherwise, return it. If a default value - is provided and the property doesn't exist or is undefined than the default + is provided and the property doesn't exist or is undefined then the default will be returned. If defaultValue is a function its result will be returned.From 42b763e42873f630d1d0facd285ca7e9ad985110 Mon Sep 17 00:00:00 2001 From: Marek+ +Date: Tue, 21 Apr 2015 10:53:08 +0100 Subject: [PATCH 019/263] Make _.sample more efficient by exiting early, make _.shuffle call through to _.sample * Improves efficiency of _.sample for when n is significantly smaller than obj.length * Improves tests to make sure _.sample and _.shuffle actually change the order * Replace shuffle with call to _.sample to avoid duplicated logic --- test/.eslintrc | 1 + test/collections.js | 13 +++++++++---- underscore.js | 29 ++++++++++++++++------------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/test/.eslintrc b/test/.eslintrc index c48aeed6d..052484beb 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -12,6 +12,7 @@ "strictEqual": false, "notStrictEqual": false, "notEqual": false, + "notDeepEqual": false, "throws": false, "asyncTest": false, "start": false, diff --git a/test/collections.js b/test/collections.js index c95fb0e22..3b94d21a4 100644 --- a/test/collections.js +++ b/test/collections.js @@ -737,12 +737,12 @@ }); test('shuffle', function() { - var numbers = _.range(10); + deepEqual(_.shuffle([1]), [1], 'behaves correctly on size 1 arrays'); + var numbers = _.range(20); var shuffled = _.shuffle(numbers); + notDeepEqual(numbers, shuffled, 'does change the order'); // Chance of false negative: 1 in ~2.4*10^18 notStrictEqual(numbers, shuffled, 'original object is unmodified'); - ok(_.every(_.range(10), function() { //appears consistent? - return _.every(numbers, _.partial(_.contains, numbers)); - }), 'contains the same members before and after shuffle'); + deepEqual(numbers, _.sortBy(shuffled), 'contains the same members before and after shuffle'); shuffled = _.shuffle({a: 1, b: 2, c: 3, d: 4}); equal(shuffled.length, 4); @@ -750,6 +750,8 @@ }); test('sample', function() { + strictEqual(_.sample([1]), 1, 'behaves correctly when no second parameter is given'); + deepEqual(_.sample([1, 2, 3], -2), [], 'behaves correctly on negative n'); var numbers = _.range(10); var allSampled = _.sample(numbers, 10).sort(); deepEqual(allSampled, numbers, 'contains the same members before and after sample'); @@ -761,6 +763,9 @@ notStrictEqual(_.sample([1, 2, 3], 0), [], 'sampling an array with 0 picks returns an empty array'); deepEqual(_.sample([1, 2], -1), [], 'sampling a negative number of picks returns an empty array'); ok(_.contains([1, 2, 3], _.sample({a: 1, b: 2, c: 3})), 'sample one value from an object'); + var partialSample = _.sample(_.range(1000), 10); + var partialSampleSorted = partialSample.sort(); + notDeepEqual(partialSampleSorted, _.range(10), 'samples from the whole array, not just the beginning'); }); test('toArray', function() { diff --git a/underscore.js b/underscore.js index 7ecb85825..e21f76460 100644 --- a/underscore.js +++ b/underscore.js @@ -349,21 +349,13 @@ return result; }; - // Shuffle a collection, using the modern version of the - // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + // Shuffle a collection. _.shuffle = function(obj) { - var set = isArrayLike(obj) ? obj : _.values(obj); - var length = set.length; - var shuffled = Array(length); - for (var index = 0, rand; index < length; index++) { - rand = _.random(0, index); - if (rand !== index) shuffled[index] = shuffled[rand]; - shuffled[rand] = set[index]; - } - return shuffled; + return _.sample(obj, Infinity); }; - // Sample **n** random values from a collection. + // Sample **n** random values from a collection using the modern version of the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). // If **n** is not specified, returns a single random element. // The internal `guard` argument allows it to work with `map`. _.sample = function(obj, n, guard) { @@ -371,7 +363,18 @@ if (!isArrayLike(obj)) obj = _.values(obj); return obj[_.random(obj.length - 1)]; } - return _.shuffle(obj).slice(0, Math.max(0, n)); + + var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj); + var length = getLength(sample); + n = Math.max(Math.min(n, length), 0); + var rand, temp; + for (var index = length - 1; index > length - n - 1; index--) { + rand = _.random(0, index); + temp = sample[index]; + sample[index] = sample[rand]; + sample[rand] = temp; + } + return sample.slice(length - n); }; // Sort the object's values by a criterion produced by an iteratee. From 770bb76be323acbd829c519e6fc92922c1872e2c Mon Sep 17 00:00:00 2001 From: Andres Suarez Date: Thu, 7 May 2015 18:04:44 -0400 Subject: [PATCH 020/263] Reword comment to not use "require" --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index f54cffa47..038e2561d 100644 --- a/underscore.js +++ b/underscore.js @@ -42,7 +42,7 @@ }; // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in + // backwards-compatibility for their old module API. If we're in // the browser, add `_` as a global object. if (typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports) { From 450c21df094896703052556c715018f0501019ee Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 8 May 2015 11:17:50 -0400 Subject: [PATCH 021/263] _.restArgs cleanup Two points: - Use restArgs to cleanup `_.zip` method - Undo a performance regression @akre54 [mentioned](https://github.com/jashkenas/underscore/pull/2140/files#r28144086) --- underscore.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/underscore.js b/underscore.js index 038e2561d..adec86a10 100644 --- a/underscore.js +++ b/underscore.js @@ -19,6 +19,7 @@ // Create quick reference variables for speed access to core prototypes. var + push = ArrayProto.push, slice = ArrayProto.slice, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty; @@ -576,12 +577,6 @@ }); }; - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - return _.unzip(arguments); - }; - // Complement of _.zip. Unzip accepts an array of arrays and groups // each array's elements on shared indices _.unzip = function(array) { @@ -594,6 +589,10 @@ return result; }; + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = restArgs(_.unzip); + // Converts lists into objects. Pass either a single array of `[key, value]` // pairs, or two parallel arrays of the same length -- one of keys, and one of // the corresponding values. @@ -1507,10 +1506,11 @@ _.mixin = function(obj) { _.each(_.functions(obj), function(name) { var func = _[name] = obj[name]; - _.prototype[name] = restArgs(function(args) { - args.unshift(this._wrapped); + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); return result(this, func.apply(_, args)); - }); + }; }); }; From a7f4623dc280cbb252cc892671b0a34228ac904f Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Tue, 28 Apr 2015 00:44:35 -0400 Subject: [PATCH 022/263] Simplify reduce wrapper to just determine initial Well, and optimize `iteratee`, cause we don't really need context anywhere else. --- underscore.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/underscore.js b/underscore.js index 038e2561d..c427429ae 100644 --- a/underscore.js +++ b/underscore.js @@ -183,7 +183,14 @@ var createReduce = function(dir) { // Optimized iterator function as using arguments.length // in the main function will deoptimize the, see #1991. - var iterator = function(obj, iteratee, memo, keys, index, length) { + var reducer = function(obj, iteratee, memo, initial) { + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + index = dir > 0 ? 0 : length - 1; + if (!initial) { + memo = obj[keys ? keys[index] : index]; + index += dir; + } for (; index >= 0 && index < length; index += dir) { var currentKey = keys ? keys[index] : index; memo = iteratee(memo, obj[currentKey], currentKey, obj); @@ -192,16 +199,8 @@ }; return function(obj, iteratee, memo, context) { - iteratee = optimizeCb(iteratee, context, 4); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length, - index = dir > 0 ? 0 : length - 1; - // Determine the initial value if none is provided. - if (arguments.length < 3) { - memo = obj[keys ? keys[index] : index]; - index += dir; - } - return iterator(obj, iteratee, memo, keys, index, length); + var initial = arguments.length >= 3; + return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial); }; }; From 68bb747a1349b215752fdf8b1b2ad1667f1f8a0d Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Tue, 14 Apr 2015 12:00:04 -0400 Subject: [PATCH 023/263] Detect global in strict mode and WebWorkers; fixes #2152 --- underscore.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/underscore.js b/underscore.js index 7ecb85825..2a03f3012 100644 --- a/underscore.js +++ b/underscore.js @@ -8,8 +8,10 @@ // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `exports` on the server. - var root = this; + // Establish the root object, `window` (`self`) in the browser, or `global` on the server. + // We use `self` instead of `window` for `WebWorker` support. + var root = (typeof self == 'object' && self.self == self && self) || + (typeof global == 'object' && global.global == global && global); // Save the previous value of the `_` variable. var previousUnderscore = root._; @@ -1562,4 +1564,4 @@ return _; }); } -}.call(this)); +}()); From 481bff7ac433ef15bc63c93dad66a5787525fb3a Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 15 May 2015 01:26:37 -0400 Subject: [PATCH 024/263] Use restArgs in flattening functions --- underscore.js | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/underscore.js b/underscore.js index 1efa346b5..a4d4b84a3 100644 --- a/underscore.js +++ b/underscore.js @@ -549,9 +549,9 @@ // Produce an array that contains the union: each distinct element from all of // the passed-in arrays. - _.union = function() { - return _.uniq(flatten(arguments, true, true)); - }; + _.union = restArgs(function(arrays) { + return _.uniq(flatten(arrays, true, true)); + }); // Produce an array that contains every item shared between all the // passed-in arrays. @@ -571,12 +571,12 @@ // Take the difference between one array and a number of other arrays. // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = flatten(arguments, true, true, 1); + _.difference = restArgs(function(array, rest) { + rest = flatten(rest, true, true); return _.filter(array, function(value){ return !_.contains(rest, value); }); - }; + }); // Complement of _.zip. Unzip accepts an array of arrays and groups // each array's elements on shared indices @@ -1037,15 +1037,15 @@ }; // Return a copy of the object only containing the whitelisted properties. - _.pick = function(object, oiteratee, context) { - var result = {}, obj = object, iteratee, keys; + _.pick = restArgs(function(obj, keys) { + var result = {}, iteratee = keys[0]; if (obj == null) return result; - if (_.isFunction(oiteratee)) { + if (_.isFunction(iteratee)) { + if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]); keys = _.allKeys(obj); - iteratee = optimizeCb(oiteratee, context); } else { - keys = flatten(arguments, false, false, 1); iteratee = function(value, key, obj) { return key in obj; }; + keys = flatten(keys, false, false); obj = Object(obj); } for (var i = 0, length = keys.length; i < length; i++) { @@ -1054,20 +1054,22 @@ if (iteratee(value, key, obj)) result[key] = value; } return result; - }; + }); // Return a copy of the object without the blacklisted properties. - _.omit = function(obj, iteratee, context) { + _.omit = restArgs(function(obj, keys) { + var iteratee = keys[0], context; if (_.isFunction(iteratee)) { iteratee = _.negate(iteratee); + if (keys.length > 1) context = keys[1]; } else { - var keys = _.map(flatten(arguments, false, false, 1), String); + keys = _.map(flatten(keys, false, false), String); iteratee = function(value, key) { return !_.contains(keys, key); }; } return _.pick(obj, iteratee, context); - }; + }); // Fill in a given object with default properties. _.defaults = createAssigner(_.allKeys, true); From 8a7e8e68bdf98d32a6fcfe2ce8e0daf566d03c07 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 15 May 2015 01:31:43 -0400 Subject: [PATCH 025/263] Remove unused param `startIndex` from flatten() --- underscore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/underscore.js b/underscore.js index a4d4b84a3..4ef811af2 100644 --- a/underscore.js +++ b/underscore.js @@ -488,9 +488,9 @@ }; // Internal implementation of a recursive `flatten` function. - var flatten = function(input, shallow, strict, startIndex) { + var flatten = function(input, shallow, strict) { var output = [], idx = 0; - for (var i = startIndex || 0, length = getLength(input); i < length; i++) { + for (var i = 0, length = getLength(input); i < length; i++) { var value = input[i]; if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { //flatten current level of array or arguments object From 99fd23e9a35d64a0307352573793d8dd91e874fc Mon Sep 17 00:00:00 2001 From: Adam Krebs Date: Fri, 15 May 2015 10:57:19 -0400 Subject: [PATCH 026/263] document _.matches as alias of _.matcher --- index.html | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/index.html b/index.html index 952b9e285..f0624544c 100644 --- a/index.html +++ b/index.html @@ -623,7 +623,7 @@ Collection Functions (Arrays or Objects)
Alias: includes
Returns true if the value is present in the list. - Uses indexOf internally, if list is an Array. + Uses indexOf internally, if list is an Array. Use fromIndex to start your search at a given index.@@ -1409,7 +1409,7 @@Object Functions
create
@@ -1454,7 +1454,7 @@_.create(prototype, props)
- Creates a new object with the given prototype, optionally attaching + Creates a new object with the given prototype, optionally attaching props as own properties. Basically, Object.create, but without all of the property descriptor jazz.Object Functions
extendOwn_.extendOwn(destination, *sources)
Alias: assign
- Like extend, but only copies own properties over to the + Like extend, but only copies own properties over to the destination object. @@ -1505,7 +1505,7 @@Object Functions
clone
_.clone(object)
- Create a shallow-copied clone of the provided plain object. + Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.@@ -1567,6 +1567,7 @@Object Functions
matcher
_.matcher(attrs)
+ Alias: matches
Returns a predicate function that will tell you if a passed in object contains all of the key/value properties present in attrs. @@ -2210,7 +2211,7 @@Change Log
1.8.3 — April 2, 2015 — Diff — Docs
From 4e2d94d63ae8074da234af2258c1fae5106996ae Mon Sep 17 00:00:00 2001 From: Graeme Yeates
- - Adds an _.create method, as a slimmed down version of + Adds an _.create method, as a slimmed down version of Object.create.
- @@ -2224,7 +2225,7 @@
Change Log
1.8.2 — Feb. 22, 2015 — Diff — Docs
- - Restores the previous old-Internet-Explorer edge cases changed in + Restores the previous old-Internet-Explorer edge cases changed in 1.8.1.
- @@ -2237,7 +2238,7 @@
Change Log
1.8.1 — Feb. 19, 2015 — Diff — Docs
- - Fixes/changes some old-Internet Explorer and related edge case + Fixes/changes some old-Internet Explorer and related edge case behavior. Test your app with Underscore 1.8.1 in an old IE and let us know how it's doing...
@@ -2256,7 +2257,7 @@Change Log
names on an object.- - Reverted a 1.7.0 change where _.extend only copied "own" + Reverted a 1.7.0 change where _.extend only copied "own" properties. Hopefully this will un-break you — if it breaks you again, I apologize.
@@ -2270,7 +2271,7 @@Change Log
- Added an _.isMatch predicate function that tells you if an - object matches key-value properties. A kissing cousin of + object matches key-value properties. A kissing cousin of _.isEqual and _.matcher.
- @@ -2285,7 +2286,7 @@
Change Log
that provides the fallback value).- - Added the _.propertyOf function generator as a mirror-world + Added the _.propertyOf function generator as a mirror-world version of _.property.
- @@ -2293,7 +2294,7 @@
Change Log
name — _.matcher.- - Various and diverse code simplifications, changes for improved + Various and diverse code simplifications, changes for improved cross-platform compatibility, and edge case bug fixes.
Date: Fri, 15 May 2015 15:52:12 -0400 Subject: [PATCH 027/263] Test tricky object comparisions --- test/objects.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/objects.js b/test/objects.js index 9b4577408..0bc7cce02 100644 --- a/test/objects.js +++ b/test/objects.js @@ -554,6 +554,13 @@ var other = {a: 1}; strictEqual(_.isEqual(new Foo, other), false, 'Objects from different constructors are not equal'); + + + // Tricky object cases val comparisions + equal(_.isEqual([0], [-0]), false); + equal(_.isEqual({a: 0}, {a: -0}), false); + equal(_.isEqual([NaN], [NaN]), true); + equal(_.isEqual({a: NaN}, {a: NaN}), true); }); test('isEmpty', function() { From 20f1cc4750c1288a9784ed02c74b6f139c3da723 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Fri, 22 May 2015 14:22:20 -0400 Subject: [PATCH 028/263] style --- underscore.js | 1 - 1 file changed, 1 deletion(-) diff --git a/underscore.js b/underscore.js index 23bd1a408..5df26e053 100644 --- a/underscore.js +++ b/underscore.js @@ -365,7 +365,6 @@ if (!isArrayLike(obj)) obj = _.values(obj); return obj[_.random(obj.length - 1)]; } - var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj); var length = getLength(sample); n = Math.max(Math.min(n, length), 0); From 1673423ed988294e95df0af7da99928bf545590e Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 16 May 2015 20:14:04 -0400 Subject: [PATCH 029/263] Optimize _.isEqual for primatives --- underscore.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/underscore.js b/underscore.js index 1efa346b5..2a0cc9c0e 100644 --- a/underscore.js +++ b/underscore.js @@ -1115,6 +1115,15 @@ if (a === b) return a !== 0 || 1 / a === 1 / b; // A strict comparison is necessary because `null == undefined`. if (a == null || b == null) return a === b; + // `NaN`s are equivalent, but non-reflexive. + if (a !== a) return b !== b; + // Exhaust primitive checks + var type = typeof a; + if (type !== 'function' && type !== 'object' && typeof b !== 'object') return false; + return deepEq(a, b, aStack, bStack); + }; + + var deepEq = function(a, b, aStack, bStack) { // Unwrap any wrapped objects. if (a instanceof _) a = a._wrapped; if (b instanceof _) b = b._wrapped; From 3cd04870adff10304da1a5cbd19c9aa310f1ee2c Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 3 Apr 2015 11:22:25 -0400 Subject: [PATCH 030/263] Allow _.bindAll to take arrays Closes #1996, supercedes #2005. --- test/functions.js | 4 ++++ underscore.js | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/test/functions.js b/test/functions.js index e54ae945a..67d22d414 100644 --- a/test/functions.js +++ b/test/functions.js @@ -119,6 +119,10 @@ var sayLast = moe.sayLast; equal(sayLast(1, 2, 3, 4, 5, 6, 7, 'Tom'), 'hi: moe', 'createCallback works with any number of arguments'); + + _.bindAll(moe, ['getName']); + var getName = moe.getName; + equal(getName(), 'name: moe', 'flattens arguments into a single list'); }); test('memoize', function() { diff --git a/underscore.js b/underscore.js index 037b7e0b2..5168ba1c4 100644 --- a/underscore.js +++ b/underscore.js @@ -743,10 +743,13 @@ // are the method names to be bound. Useful for ensuring that all callbacks // defined on an object belong to it. _.bindAll = restArgs(function(obj, keys) { - if (keys.length < 1) throw new Error('bindAll must be passed function names'); - return _.each(keys, function(key) { + keys = flatten(keys, false, false); + var index = keys.length; + if (index < 1) throw new Error('bindAll must be passed function names'); + while (index--) { + var key = keys[index]; obj[key] = _.bind(obj[key], obj); - }); + }; }); // Memoize an expensive function by storing its results. From d55724239a87bf0b76d29810b43742595ba81dc3 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 24 May 2015 15:22:39 -0400 Subject: [PATCH 031/263] Fix eslint errors --- underscore.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/underscore.js b/underscore.js index 5168ba1c4..5d9e52bf2 100644 --- a/underscore.js +++ b/underscore.js @@ -10,8 +10,8 @@ // Establish the root object, `window` (`self`) in the browser, or `global` on the server. // We use `self` instead of `window` for `WebWorker` support. - var root = (typeof self == 'object' && self.self == self && self) || - (typeof global == 'object' && global.global == global && global); + var root = (typeof self === 'object' && self.self === self && self) || + (typeof global === 'object' && global.global === global && global); // Save the previous value of the `_` variable. var previousUnderscore = root._; @@ -749,7 +749,7 @@ while (index--) { var key = keys[index]; obj[key] = _.bind(obj[key], obj); - }; + } }); // Memoize an expensive function by storing its results. @@ -1041,6 +1041,11 @@ } }; + // Internal pick helper function to determine if `obj` has key `key. + var keyInObj = function(value, key, obj) { + return key in obj; + }; + // Return a copy of the object only containing the whitelisted properties. _.pick = restArgs(function(obj, keys) { var result = {}, iteratee = keys[0]; @@ -1049,7 +1054,7 @@ if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]); keys = _.allKeys(obj); } else { - iteratee = function(value, key, obj) { return key in obj; }; + iteratee = keyInObj; keys = flatten(keys, false, false); obj = Object(obj); } @@ -1116,7 +1121,8 @@ // Internal recursive comparison function for `isEqual`. - var eq = function(a, b, aStack, bStack) { + var eq, deepEq; + eq = function(a, b, aStack, bStack) { // Identical objects are equal. `0 === -0`, but they aren't identical. // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). if (a === b) return a !== 0 || 1 / a === 1 / b; @@ -1130,7 +1136,8 @@ return deepEq(a, b, aStack, bStack); }; - var deepEq = function(a, b, aStack, bStack) { + // Internal recursive comparison function for `isEqual`. + deepEq = function(a, b, aStack, bStack) { // Unwrap any wrapped objects. if (a instanceof _) a = a._wrapped; if (b instanceof _) b = b._wrapped; From a848bb5461b11fdbc89123c0b6c7d36583e3b5b4 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 24 May 2015 19:04:48 -0400 Subject: [PATCH 032/263] Sample from left to right --- underscore.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/underscore.js b/underscore.js index 5d9e52bf2..dffee52f8 100644 --- a/underscore.js +++ b/underscore.js @@ -368,14 +368,14 @@ var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj); var length = getLength(sample); n = Math.max(Math.min(n, length), 0); - var rand, temp; - for (var index = length - 1; index > length - n - 1; index--) { - rand = _.random(0, index); - temp = sample[index]; + var last = length - 1; + for (var index = 0; index < n; index++) { + var rand = _.random(index, last); + var temp = sample[index]; sample[index] = sample[rand]; sample[rand] = temp; } - return sample.slice(length - n); + return sample.slice(0, n); }; // Sort the object's values by a criterion produced by an iteratee. From 669330f654f38ffeae9662facb7076f8b15bf259 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 24 May 2015 23:36:59 -0400 Subject: [PATCH 033/263] Fix comment --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 5d9e52bf2..e7b382dbf 100644 --- a/underscore.js +++ b/underscore.js @@ -1041,7 +1041,7 @@ } }; - // Internal pick helper function to determine if `obj` has key `key. + // Internal pick helper function to determine if `obj` has key `key`. var keyInObj = function(value, key, obj) { return key in obj; }; From 0e326fdd1ca5e7981955af17dc65b09968648e2b Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Tue, 26 May 2015 02:15:30 -0700 Subject: [PATCH 034/263] upgrade eslint version and fix all current warnings/errors --- .eslintrc | 76 ++++++++++-- package.json | 4 +- test/arrays.js | 42 +++---- test/chaining.js | 3 +- test/collections.js | 124 ++++++++++---------- test/cross-document.js | 2 +- test/functions.js | 62 +++++----- test/objects.js | 260 ++++++++++++++++++++--------------------- test/utility.js | 93 +++++++-------- underscore.js | 85 +++++++------- 10 files changed, 406 insertions(+), 345 deletions(-) diff --git a/.eslintrc b/.eslintrc index 2c46d63de..e48ae1426 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,30 +6,86 @@ }, "rules": { + "block-scoped-var": 1, "brace-style": [1, "1tbs"], - "curly": [0, "multi"], - "eqeqeq": [1, "smart"], + "camelcase": 2, + "comma-dangle": [2, "never"], + "comma-spacing": 2, + "consistent-return": 1, + "dot-notation": [2, { "allowKeywords": false }], + "eol-last": 2, + "eqeqeq": [2, "smart"], + "indent": [2, 2, {"indentSwitchCase": true}], + "key-spacing": [1, { "align": "colon" }], + "linebreak-style": 2, "max-depth": [1, 4], "max-params": [1, 5], "new-cap": 2, - "new-parens": 0, - "no-constant-condition": 0, + "no-alert": 2, + "no-caller": 2, + "no-catch-shadow": 2, + "no-console": 2, + "no-debugger": 2, + "no-delete-var": 2, "no-div-regex": 1, + "no-dupe-args": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 2, "no-else-return": 1, + "no-empty-class": 2, + "no-empty-label": 2, + "no-eval": 2, + "no-ex-assign": 2, + "no-extend-native": 2, + "no-extra-boolean-cast": 2, "no-extra-parens": 1, + "no-extra-semi": 2, + "no-fallthrough": 2, "no-floating-decimal": 2, + "no-func-assign": 2, + "no-implied-eval": 2, "no-inner-declarations": 2, - "no-lonely-if": 1, + "no-irregular-whitespace": 2, + "no-label-var": 2, + "no-lone-blocks": 2, + "no-lonely-if": 2, + "no-multi-spaces": 1, + "no-multi-str": 2, + "no-native-reassign": 2, + "no-negated-in-lhs": 1, "no-nested-ternary": 2, - "no-new-object": 0, - "no-new-func": 0, - "no-underscore-dangle": 0, + "no-new-object": 2, + "no-new-wrappers": 2, + "no-obj-calls": 2, + "no-octal": 2, + "no-octal-escape": 2, + "no-proto": 2, + "no-redeclare": 2, + "no-reserved-keys": 2, + "no-shadow": 2, + "no-spaced-func": 2, + "no-throw-literal": 2, + "no-trailing-spaces": 2, + "no-undef-init": 2, + "no-undefined": 2, + "no-unneeded-ternary": 2, + "no-unreachable": 2, + "no-unused-expressions": 2, + "no-unused-vars": 2, + "no-use-before-define": [2, "nofunc"], + "no-with": 2, + "quote-props": [1, "as-needed"], "quotes": [2, "single", "avoid-escape"], "radix": 2, + "semi": 2, "space-after-keywords": [2, "always"], + "space-before-function-paren": [2, {"anonymous": "never", "named": "never"}], "space-in-brackets": [2, "never"], - "space-unary-word-ops": 2, - "strict": 0, + "space-infix-ops": 2, + "space-return-throw-case": 2, + "space-unary-ops": [2, { "words": true, "nonwords": false }], + "use-isnan": 2, + "valid-typeof": 2, "wrap-iife": 2 } } diff --git a/package.json b/package.json index 0a9126bf0..f1ad720da 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "version": "1.8.3", "devDependencies": { "docco": "*", - "eslint": "0.6.x", + "eslint": "0.21.x", "karma": "~0.12.31", "karma-qunit": "~0.1.4", "qunit-cli": "~0.2.0", @@ -26,7 +26,7 @@ }, "scripts": { "test": "npm run test-node && npm run lint", - "lint": "eslint underscore.js test/*.js", + "lint": "eslint --reset underscore.js test/*.js", "test-node": "qunit-cli test/*.js", "test-browser": "npm i karma-phantomjs-launcher && ./node_modules/karma/bin/karma start", "build": "uglifyjs underscore.js -c \"evaluate=false\" --comments \"/ .*/\" -m --source-map underscore-min.map -o underscore-min.js", diff --git a/test/arrays.js b/test/arrays.js index 3f39ed90a..b8903d3ea 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -16,7 +16,7 @@ result = (function() { return _.first([1, 2, 3], 2); }()); deepEqual(result, [1, 2]); - equal(_.first(null), undefined, 'handles nulls'); + equal(_.first(null), void 0, 'handles nulls'); strictEqual(_.first([1, 2, 3], -1).length, 0); }); @@ -69,7 +69,7 @@ result = _.map([[1, 2, 3], [1, 2, 3]], _.last); deepEqual(result, [3, 3], 'works well with _.map'); - equal(_.last(null), undefined, 'handles nulls'); + equal(_.last(null), void 0, 'handles nulls'); strictEqual(_.last([1, 2, 3], -1).length, 0); }); @@ -106,8 +106,8 @@ var result = (function(){ return _.without(arguments, 0, 1); }(1, 2, 1, 0, 3, 1, 4)); deepEqual(result, [2, 3, 4], 'works on an arguments object'); - list = [{one : 1}, {two : 2}]; - equal(_.without(list, {one : 1}).length, 2, 'uses real object identity for comparisons.'); + list = [{one: 1}, {two: 2}]; + equal(_.without(list, {one: 1}).length, 2, 'uses real object identity for comparisons.'); equal(_.without(list, list[0]).length, 1, 'ditto.'); }); @@ -242,8 +242,8 @@ var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true]; deepEqual(_.zip(names, ages, leaders), [ ['moe', 30, true], - ['larry', 40, undefined], - ['curly', 50, undefined] + ['larry', 40, void 0], + ['curly', 50, void 0] ], 'zipped together arrays of different lengths'); var stooges = _.zip(['moe', 30, 'stooge 1'], ['larry', 40, 'stooge 2'], ['curly', 50, 'stooge 3']); @@ -252,7 +252,7 @@ // In the case of difference lengths of the tuples undefineds // should be used as placeholder stooges = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); - deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [undefined, undefined, 'extra data']], 'zipped pairs with empties'); + deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [void 0, void 0, 'extra data']], 'zipped pairs with empties'); var empty = _.zip([]); deepEqual(empty, [], 'unzipped empty'); @@ -324,7 +324,7 @@ index = _.indexOf(numbers, 2, 5); equal(index, 7, 'supports the fromIndex argument'); - index = _.indexOf([,,,], undefined); + index = _.indexOf([,,, 0], void 0); equal(index, 0, 'treats sparse arrays as if they were dense'); var array = [1, 2, 3, 1, 2, 3]; @@ -336,7 +336,7 @@ }); strictEqual(_.indexOf([1, 2, 3], 1, true), 0); - index = _.indexOf([], undefined, true); + index = _.indexOf([], void 0, true); equal(index, -1, 'empty array with truthy `isSorted` returns -1'); }); @@ -361,7 +361,7 @@ test('lastIndexOf', function() { var numbers = [1, 0, 1]; - var falsey = [void 0, '', 0, false, NaN, null, undefined]; + var falsey = [void 0, '', 0, false, NaN, null, void 0]; equal(_.lastIndexOf(numbers, 1), 2); numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0]; @@ -392,7 +392,7 @@ strictEqual(_.lastIndexOf(array, 1, 2), 0, 'should work with a positive `fromIndex`'); _.each([6, 8, Math.pow(2, 32), Infinity], function(fromIndex) { - strictEqual(_.lastIndexOf(array, undefined, fromIndex), -1); + strictEqual(_.lastIndexOf(array, void 0, fromIndex), -1); strictEqual(_.lastIndexOf(array, 1, fromIndex), 3); strictEqual(_.lastIndexOf(array, '', fromIndex), -1); }); @@ -439,10 +439,10 @@ test('findIndex', function() { var objects = [ - {'a': 0, 'b': 0}, - {'a': 1, 'b': 1}, - {'a': 2, 'b': 2}, - {'a': 0, 'b': 0} + {a: 0, b: 0}, + {a: 1, b: 1}, + {a: 2, b: 2}, + {a: 0, b: 0} ]; equal(_.findIndex(objects, function(obj) { @@ -470,7 +470,7 @@ }, objects); var sparse = []; - sparse[20] = {'a': 2, 'b': 2}; + sparse[20] = {a: 2, b: 2}; equal(_.findIndex(sparse, function(obj) { return obj && obj.b * obj.a === 4; }), 20, 'Works with sparse arrays'); @@ -482,10 +482,10 @@ test('findLastIndex', function() { var objects = [ - {'a': 0, 'b': 0}, - {'a': 1, 'b': 1}, - {'a': 2, 'b': 2}, - {'a': 0, 'b': 0} + {a: 0, b: 0}, + {a: 1, b: 1}, + {a: 2, b: 2}, + {a: 0, b: 0} ]; equal(_.findLastIndex(objects, function(obj) { @@ -513,7 +513,7 @@ }, objects); var sparse = []; - sparse[20] = {'a': 2, 'b': 2}; + sparse[20] = {a: 2, b: 2}; equal(_.findLastIndex(sparse, function(obj) { return obj && obj.b * obj.a === 4; }), 20, 'Works with sparse arrays'); diff --git a/test/chaining.js b/test/chaining.js index 34fd73c36..c5830f36f 100644 --- a/test/chaining.js +++ b/test/chaining.js @@ -17,7 +17,8 @@ hash[l] = hash[l] || 0; hash[l]++; return hash; - }, {}).value(); + }, {}) + .value(); equal(counts.a, 16, 'counted all the letters in the song'); equal(counts.e, 10, 'counted all the letters in the song'); }); diff --git a/test/collections.js b/test/collections.js index 3b94d21a4..2faccbafc 100644 --- a/test/collections.js +++ b/test/collections.js @@ -9,7 +9,7 @@ }); var answers = []; - _.each([1, 2, 3], function(num){ answers.push(num * this.multiplier);}, {multiplier : 5}); + _.each([1, 2, 3], function(num){ answers.push(num * this.multiplier); }, {multiplier: 5}); deepEqual(answers, [5, 10, 15], 'context object property accessed'); answers = []; @@ -17,7 +17,7 @@ deepEqual(answers, [1, 2, 3], 'aliased as "forEach"'); answers = []; - var obj = {one : 1, two : 2, three : 3}; + var obj = {one: 1, two: 2, three: 3}; obj.constructor.prototype.four = 4; _.each(obj, function(value, key){ answers.push(key); }); deepEqual(answers, ['one', 'two', 'three'], 'iterating over objects works, and ignores the object prototype.'); @@ -26,8 +26,8 @@ // ensure the each function is JITed _(1000).times(function() { _.each([], function(){}); }); var count = 0; - obj = {1 : 'foo', 2 : 'bar', 3 : 'baz'}; - _.each(obj, function(value, key){ count++; }); + obj = {1: 'foo', 2: 'bar', 3: 'baz'}; + _.each(obj, function(){ count++; }); equal(count, 3, 'the fun should be called only 3 times'); var answer = null; @@ -149,7 +149,7 @@ var doubled = _.map([1, 2, 3], function(num){ return num * 2; }); deepEqual(doubled, [2, 4, 6], 'doubled numbers'); - var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier : 3}); + var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier: 3}); deepEqual(tripled, [3, 6, 9], 'tripled numbers with context'); doubled = _([1, 2, 3]).map(function(num){ return num * 2; }); @@ -167,7 +167,7 @@ }, [5]), [1], 'called with context'); // Passing a property name like _.pluck. - var people = [{name : 'moe', age : 30}, {name : 'curly', age : 50}]; + var people = [{name: 'moe', age: 30}, {name: 'curly', age: 50}]; deepEqual(_.map(people, 'name'), ['moe', 'curly'], 'predicate string map to object properties'); }); @@ -176,29 +176,29 @@ }); test('reduce', function() { - var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }, 0); + var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0); equal(sum, 6, 'can sum up an array'); - var context = {multiplier : 3}; - sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num * this.multiplier; }, 0, context); + var context = {multiplier: 3}; + sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num * this.multiplier; }, 0, context); equal(sum, 18, 'can reduce with a context object'); - sum = _.inject([1, 2, 3], function(sum, num){ return sum + num; }, 0); + sum = _.inject([1, 2, 3], function(memo, num){ return memo + num; }, 0); equal(sum, 6, 'aliased as "inject"'); - sum = _([1, 2, 3]).reduce(function(sum, num){ return sum + num; }, 0); + sum = _([1, 2, 3]).reduce(function(memo, num){ return memo + num; }, 0); equal(sum, 6, 'OO-style reduce'); - sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }); + sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }); equal(sum, 6, 'default initial value'); - var prod = _.reduce([1, 2, 3, 4], function(prod, num){ return prod * num; }); + var prod = _.reduce([1, 2, 3, 4], function(memo, num){ return memo * num; }); equal(prod, 24, 'can reduce via multiplication'); ok(_.reduce(null, _.noop, 138) === 138, 'handles a null (with initial value) properly'); - equal(_.reduce([], _.noop, undefined), undefined, 'undefined can be passed as a special case'); + equal(_.reduce([], _.noop, void 0), void 0, 'undefined can be passed as a special case'); equal(_.reduce([_], _.noop), _, 'collection of length one with no initial value returns the first item'); - equal(_.reduce([], _.noop), undefined, 'returns undefined when collection is empty and no initial value'); + equal(_.reduce([], _.noop), void 0, 'returns undefined when collection is empty and no initial value'); }); test('foldl', function() { @@ -212,45 +212,45 @@ list = _.reduceRight(['foo', 'bar', 'baz'], function(memo, str){ return memo + str; }); equal(list, 'bazbarfoo', 'default initial value'); - var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(sum, num){ return sum + num; }); + var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(memo, num){ return memo + num; }); equal(sum, 6, 'default initial value on object'); ok(_.reduceRight(null, _.noop, 138) === 138, 'handles a null (with initial value) properly'); equal(_.reduceRight([_], _.noop), _, 'collection of length one with no initial value returns the first item'); - equal(_.reduceRight([], _.noop, undefined), undefined, 'undefined can be passed as a special case'); - equal(_.reduceRight([], _.noop), undefined, 'returns undefined when collection is empty and no initial value'); + equal(_.reduceRight([], _.noop, void 0), void 0, 'undefined can be passed as a special case'); + equal(_.reduceRight([], _.noop), void 0, 'returns undefined when collection is empty and no initial value'); // Assert that the correct arguments are being passed. var args, - memo = {}, + init = {}, object = {a: 1, b: 2}, lastKey = _.keys(object).pop(); var expected = lastKey === 'a' - ? [memo, 1, 'a', object] - : [memo, 2, 'b', object]; + ? [init, 1, 'a', object] + : [init, 2, 'b', object]; _.reduceRight(object, function() { if (!args) args = _.toArray(arguments); - }, memo); + }, init); deepEqual(args, expected); // And again, with numeric keys. - object = {'2': 'a', '1': 'b'}; + object = {2: 'a', 1: 'b'}; lastKey = _.keys(object).pop(); args = null; expected = lastKey === '2' - ? [memo, 'a', '2', object] - : [memo, 'b', '1', object]; + ? [init, 'a', '2', object] + : [init, 'b', '1', object]; _.reduceRight(object, function() { if (!args) args = _.toArray(arguments); - }, memo); + }, init); deepEqual(args, expected); }); @@ -290,9 +290,9 @@ return x.x === 4; }), {x: 4, z: 1}); - _.findIndex([{a: 1}], function(a, key, obj) { + _.findIndex([{a: 1}], function(a, key, o) { equal(key, 0); - deepEqual(obj, [{a: 1}]); + deepEqual(o, [{a: 1}]); strictEqual(this, _, 'called with context'); }, _); }); @@ -356,7 +356,7 @@ ok(!_.every([0, 11, 28], function(num){ return num % 2 === 0; }), 'an odd number'); ok(_.every([1], _.identity) === true, 'cast to boolean - true'); ok(_.every([0], _.identity) === false, 'cast to boolean - false'); - ok(!_.every([undefined, undefined, undefined], _.identity), 'works with arrays of undefined'); + ok(!_.every([void 0, void 0, void 0], _.identity), 'works with arrays of undefined'); var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; ok(!_.every(list, {a: 1, b: 2}), 'Can be called with object'); @@ -493,13 +493,13 @@ deepEqual(result[0], [1, 5, 7], 'first array sorted'); deepEqual(result[1], [1, 2, 3], 'second array sorted'); delete String.prototype.call; - equal(s.call, undefined, 'call function removed'); + equal(s.call, void 0, 'call function removed'); }); test('pluck', function() { var people = [{name: 'moe', age: 30}, {name: 'curly', age: 50}]; deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'pulls names out of objects'); - deepEqual(_.pluck(people, 'address'), [undefined, undefined], 'missing properties are returned as undefined'); + deepEqual(_.pluck(people, 'address'), [void 0, void 0], 'missing properties are returned as undefined'); //compat: most flexible handling of edge cases deepEqual(_.pluck([{'[object Object]': 1}], {}), [1]); }); @@ -547,7 +547,7 @@ test('max', function() { equal(-Infinity, _.max(null), 'can handle null/undefined'); - equal(-Infinity, _.max(undefined), 'can handle null/undefined'); + equal(-Infinity, _.max(void 0), 'can handle null/undefined'); equal(-Infinity, _.max(null, _.identity), 'can handle null/undefined'); equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max'); @@ -557,7 +557,7 @@ equal(-Infinity, _.max({}), 'Maximum value of an empty object'); equal(-Infinity, _.max([]), 'Maximum value of an empty array'); - equal(_.max({'a': 'a'}), -Infinity, 'Maximum value of a non-numeric collection'); + equal(_.max({a: 'a'}), -Infinity, 'Maximum value of a non-numeric collection'); equal(299999, _.max(_.range(1, 300000)), 'Maximum value of a too-big array'); @@ -569,16 +569,16 @@ var iterator = function(o){ return o.x; }; equal(_.max([a, b], iterator), a, 'Respects iterator return value of -Infinity'); - deepEqual(_.max([{'a': 1}, {'a': 0, 'b': 3}, {'a': 4}, {'a': 2}], 'a'), {'a': 4}, 'String keys use property iterator'); + deepEqual(_.max([{a: 1}, {a: 0, b: 3}, {a: 4}, {a: 2}], 'a'), {a: 4}, 'String keys use property iterator'); - deepEqual(_.max([0, 2], function(a){ return a * this.x; }, {x: 1}), 2, 'Iterator context'); + deepEqual(_.max([0, 2], function(c){ return c * this.x; }, {x: 1}), 2, 'Iterator context'); deepEqual(_.max([[1], [2, 3], [-1, 4], [5]], 0), [5], 'Lookup falsy iterator'); deepEqual(_.max([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: 2}, 'Lookup falsy iterator'); }); test('min', function() { equal(Infinity, _.min(null), 'can handle null/undefined'); - equal(Infinity, _.min(undefined), 'can handle null/undefined'); + equal(Infinity, _.min(void 0), 'can handle null/undefined'); equal(Infinity, _.min(null, _.identity), 'can handle null/undefined'); equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min'); @@ -588,7 +588,7 @@ equal(Infinity, _.min({}), 'Minimum value of an empty object'); equal(Infinity, _.min([]), 'Minimum value of an empty array'); - equal(_.min({'a': 'a'}), Infinity, 'Minimum value of a non-numeric collection'); + equal(_.min({a: 'a'}), Infinity, 'Minimum value of a non-numeric collection'); var now = new Date(9999999999); var then = new Date(0); @@ -604,20 +604,20 @@ var iterator = function(o){ return o.x; }; equal(_.min([a, b], iterator), a, 'Respects iterator return value of Infinity'); - deepEqual(_.min([{'a': 1}, {'a': 0, 'b': 3}, {'a': 4}, {'a': 2}], 'a'), {'a': 0, 'b': 3}, 'String keys use property iterator'); + deepEqual(_.min([{a: 1}, {a: 0, b: 3}, {a: 4}, {a: 2}], 'a'), {a: 0, b: 3}, 'String keys use property iterator'); - deepEqual(_.min([0, 2], function(a){ return a * this.x; }, {x: -1}), 2, 'Iterator context'); + deepEqual(_.min([0, 2], function(c){ return c * this.x; }, {x: -1}), 2, 'Iterator context'); deepEqual(_.min([[1], [2, 3], [-1, 4], [5]], 0), [-1, 4], 'Lookup falsy iterator'); deepEqual(_.min([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: -1}, 'Lookup falsy iterator'); }); test('sortBy', function() { - var people = [{name : 'curly', age : 50}, {name : 'moe', age : 30}]; + var people = [{name: 'curly', age: 50}, {name: 'moe', age: 30}]; people = _.sortBy(people, function(person){ return person.age; }); deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'stooges sorted by age'); - var list = [undefined, 4, 1, undefined, 3, 2]; - deepEqual(_.sortBy(list, _.identity), [1, 2, 3, 4, undefined, undefined], 'sortBy with undefined values'); + var list = [void 0, 4, 1, void 0, 3, 2]; + deepEqual(_.sortBy(list, _.identity), [1, 2, 3, 4, void 0, void 0], 'sortBy with undefined values'); list = ['one', 'two', 'three', 'four', 'five']; var sorted = _.sortBy(list, 'length'); @@ -635,9 +635,9 @@ new Pair(2, 1), new Pair(2, 2), new Pair(2, 3), new Pair(2, 4), new Pair(2, 5), new Pair(2, 6), - new Pair(undefined, 1), new Pair(undefined, 2), - new Pair(undefined, 3), new Pair(undefined, 4), - new Pair(undefined, 5), new Pair(undefined, 6) + new Pair(void 0, 1), new Pair(void 0, 2), + new Pair(void 0, 3), new Pair(void 0, 4), + new Pair(void 0, 5), new Pair(void 0, 6) ]; var actual = _.sortBy(collection, function(pair) { @@ -758,7 +758,7 @@ allSampled = _.sample(numbers, 20).sort(); deepEqual(allSampled, numbers, 'also works when sampling more objects than are present'); ok(_.contains(numbers, _.sample(numbers)), 'sampling a single element returns something from the array'); - strictEqual(_.sample([]), undefined, 'sampling empty array with no number returns undefined'); + strictEqual(_.sample([]), void 0, 'sampling empty array with no number returns undefined'); notStrictEqual(_.sample([], 5), [], 'sampling empty array with a number returns an empty array'); notStrictEqual(_.sample([1, 2, 3], 0), [], 'sampling an array with 0 picks returns an empty array'); deepEqual(_.sample([1, 2], -1), [], 'sampling a negative number of picks returns an empty array'); @@ -775,7 +775,7 @@ ok(_.toArray(a) !== a, 'array is cloned'); deepEqual(_.toArray(a), [1, 2, 3], 'cloned array contains same elements'); - var numbers = _.toArray({one : 1, two : 2, three : 3}); + var numbers = _.toArray({one: 1, two: 2, three: 3}); deepEqual(numbers, [1, 2, 3], 'object flattened into array'); if (typeof document != 'undefined') { @@ -783,13 +783,13 @@ var actual; try { actual = _.toArray(document.childNodes); - } catch(ex) { } + } catch(e) { /* ignored */ } deepEqual(actual, _.map(document.childNodes, _.identity), 'works on NodeList'); } }); test('size', function() { - equal(_.size({one : 1, two : 2, three : 3}), 3, 'can compute the size of an object'); + equal(_.size({one: 1, two: 2, three: 3}), 3, 'can compute the size of an object'); equal(_.size([1, 2, 3]), 3, 'can compute the size of an array'); equal(_.size({length: 3, 0: 0, 1: 0, 2: 0}), 3, 'can compute the size of Array-likes'); @@ -839,23 +839,23 @@ if (typeof document != 'undefined') { test('Can use various collection methods on NodeLists', function() { - var parent = document.createElement('div'); - parent.innerHTML = 'textnode'; + var parent = document.createElement('div'); + parent.innerHTML = 'textnode'; - var elementChildren = _.filter(parent.childNodes, _.isElement); - equal(elementChildren.length, 2); + var elementChildren = _.filter(parent.childNodes, _.isElement); + equal(elementChildren.length, 2); - deepEqual(_.map(elementChildren, 'id'), ['id1', 'id2']); - deepEqual(_.map(parent.childNodes, 'nodeType'), [1, 3, 1]); + deepEqual(_.map(elementChildren, 'id'), ['id1', 'id2']); + deepEqual(_.map(parent.childNodes, 'nodeType'), [1, 3, 1]); - ok(!_.every(parent.childNodes, _.isElement)); - ok(_.some(parent.childNodes, _.isElement)); + ok(!_.every(parent.childNodes, _.isElement)); + ok(_.some(parent.childNodes, _.isElement)); - function compareNode(node) { - return _.isElement(node) ? node.id.charAt(2) : void 0; - } - equal(_.max(parent.childNodes, compareNode), _.last(parent.childNodes)); - equal(_.min(parent.childNodes, compareNode), _.first(parent.childNodes)); + function compareNode(node) { + return _.isElement(node) ? node.id.charAt(2) : void 0; + } + equal(_.max(parent.childNodes, compareNode), _.last(parent.childNodes)); + equal(_.min(parent.childNodes, compareNode), _.first(parent.childNodes)); }); } diff --git a/test/cross-document.js b/test/cross-document.js index 735a8d7ec..215d78e85 100644 --- a/test/cross-document.js +++ b/test/cross-document.js @@ -138,4 +138,4 @@ }); } -}()); \ No newline at end of file +}()); diff --git a/test/functions.js b/test/functions.js index 67d22d414..8c4541110 100644 --- a/test/functions.js +++ b/test/functions.js @@ -5,7 +5,7 @@ QUnit.config.asyncRetries = 3; test('bind', function() { - var context = {name : 'moe'}; + var context = {name: 'moe'}; var func = function(arg) { return 'name: ' + (this.name || arg); }; var bound = _.bind(func, context); equal(bound(), 'name: moe', 'can bind a function to a context'); @@ -29,18 +29,18 @@ func = _.bind(func, this, 'hello', 'moe', 'curly'); equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments'); - func = function(context, message) { equal(this, context, message); }; + func = function(ctx, message) { equal(this, ctx, message); }; _.bind(func, 0, 0, 'can bind a function to `0`')(); _.bind(func, '', '', 'can bind a function to an empty string')(); _.bind(func, false, false, 'can bind a function to `false`')(); // These tests are only meaningful when using a browser without a native bind function // To test this with a modern browser, set underscore's nativeBind to undefined - var F = function () { return this; }; + var F = function() { return this; }; var boundf = _.bind(F, {hello: 'moe curly'}); var Boundf = boundf; // make eslint happy. var newBoundf = new Boundf(); - equal(newBoundf.hello, undefined, 'function should not be bound to the context, to comply with ECMAScript 5'); + equal(newBoundf.hello, void 0, 'function should not be bound to the context, to comply with ECMAScript 5'); equal(boundf().hello, 'moe curly', "When called without the new operator, it's OK to be bound to the context"); ok(newBoundf instanceof F, 'a bound instance is an instance of the original function'); @@ -90,10 +90,10 @@ }); test('bindAll', function() { - var curly = {name : 'curly'}, moe = { - name : 'moe', - getName : function() { return 'name: ' + this.name; }, - sayHi : function() { return 'hi: ' + this.name; } + var curly = {name: 'curly'}, moe = { + name : 'moe', + getName: function() { return 'name: ' + this.name; }, + sayHi : function() { return 'hi: ' + this.name; } }; curly.getName = moe.getName; _.bindAll(moe, 'getName', 'sayHi'); @@ -101,12 +101,12 @@ equal(curly.getName(), 'name: curly', 'unbound function is bound to current object'); equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object'); - curly = {name : 'curly'}; + curly = {name: 'curly'}; moe = { - name : 'moe', - getName : function() { return 'name: ' + this.name; }, - sayHi : function() { return 'hi: ' + this.name; }, - sayLast : function() { return this.sayHi(_.last(arguments)); } + name : 'moe', + getName: function() { return 'name: ' + this.name; }, + sayHi : function() { return 'hi: ' + this.name; }, + sayLast: function() { return this.sayHi(_.last(arguments)); } }; throws(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named'); @@ -159,7 +159,7 @@ return key.toUpperCase(); }); hashed('yep'); - deepEqual(hashed.cache, {'YEP': 'yep'}, 'takes a hasher'); + deepEqual(hashed.cache, {YEP: 'yep'}, 'takes a hasher'); // Test that the hash function can be used to swizzle the key. var objCacher = _.memoize(function(value, key) { @@ -169,7 +169,7 @@ }); var myObj = objCacher('a', 'alpha'); var myObjAlias = objCacher('b', 'alpha'); - notStrictEqual(myObj, undefined, 'object is created if second argument used as key'); + notStrictEqual(myObj, void 0, 'object is created if second argument used as key'); strictEqual(myObj, myObjAlias, 'object is cached if second argument used as key'); strictEqual(myObj.value, 'a', 'object is not modified if second argument used as key'); }); @@ -360,7 +360,7 @@ throttledIncr(); equal(counter, 1); - _.now = function () { + _.now = function() { return new Date(2013, 0, 1, 1, 1, 1); }; @@ -441,7 +441,7 @@ debouncedIncr(); equal(counter, 1, 'incr was called immediately'); - _.now = function () { + _.now = function() { return new Date(2013, 0, 1, 1, 1, 1); }; @@ -499,13 +499,13 @@ equal(backwards('moe'), 'hi: moe eom', 'wrapped the salutation function'); var inner = function(){ return 'Hello '; }; - var obj = {name : 'Moe'}; - obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; }); + var obj = {name: 'Moe'}; + obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; }); equal(obj.hi(), 'Hello Moe'); - var noop = function(){}; + var noop = function(){}; var wrapped = _.wrap(noop, function(){ return Array.prototype.slice.call(arguments, 0); }); - var ret = wrapped(['whats', 'your'], 'vector', 'victor'); + var ret = wrapped(['whats', 'your'], 'vector', 'victor'); deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']); }); @@ -594,29 +594,29 @@ test('restArgs', 10, function() { _.restArgs(function(a, args) { - strictEqual(a, 1); - deepEqual(args, [2, 3], 'collects rest arguments into an array'); + strictEqual(a, 1); + deepEqual(args, [2, 3], 'collects rest arguments into an array'); })(1, 2, 3); _.restArgs(function(a, args) { - strictEqual(a, undefined); - deepEqual(args, [], 'passes empty array if there are not enough arguments'); + strictEqual(a, void 0); + deepEqual(args, [], 'passes empty array if there are not enough arguments'); })(); _.restArgs(function(a, b, c, args) { - strictEqual(arguments.length, 4); - deepEqual(args, [4, 5], 'works on functions with many named parameters'); + strictEqual(arguments.length, 4); + deepEqual(args, [4, 5], 'works on functions with many named parameters'); })(1, 2, 3, 4, 5); var obj = {}; _.restArgs(function() { - strictEqual(this, obj, 'invokes function with this context'); + strictEqual(this, obj, 'invokes function with this context'); }).call(obj); _.restArgs(function(array, iteratee, context) { - deepEqual(array, [1, 2, 3, 4], 'startIndex can be used manually specify index of rest parameter'); - strictEqual(iteratee, undefined); - strictEqual(context, undefined); + deepEqual(array, [1, 2, 3, 4], 'startIndex can be used manually specify index of rest parameter'); + strictEqual(iteratee, void 0); + strictEqual(context, void 0); }, 0)(1, 2, 3, 4); }); diff --git a/test/objects.js b/test/objects.js index 0bc7cce02..af8a1f1ea 100644 --- a/test/objects.js +++ b/test/objects.js @@ -6,7 +6,7 @@ var testElement = typeof document === 'object' ? document.createElement('div') : void 0; test('keys', function() { - deepEqual(_.keys({one : 1, two : 2}), ['one', 'two'], 'can extract the keys from an object'); + deepEqual(_.keys({one: 1, two: 2}), ['one', 'two'], 'can extract the keys from an object'); // the test above is not safe because it relies on for-in enumeration order var a = []; a[1] = 0; deepEqual(_.keys(a), ['1'], 'is not fooled by sparse arrays; see issue #95'); @@ -18,17 +18,17 @@ // keys that may be missed if the implementation isn't careful var trouble = { - 'constructor': Object, - 'valueOf': _.noop, - 'hasOwnProperty': null, - 'toString': 5, - 'toLocaleString': undefined, - 'propertyIsEnumerable': /a/, - 'isPrototypeOf': this, - '__defineGetter__': Boolean, - '__defineSetter__': {}, - '__lookupSetter__': false, - '__lookupGetter__': [] + constructor : Object, + valueOf : _.noop, + hasOwnProperty : null, + toString : 5, + toLocaleString : void 0, + propertyIsEnumerable: /a/, + isPrototypeOf : this, + __defineGetter__ : Boolean, + __defineSetter__ : {}, + __lookupSetter__ : false, + __lookupGetter__ : [] }; var troubleKeys = ['constructor', 'valueOf', 'hasOwnProperty', 'toString', 'toLocaleString', 'propertyIsEnumerable', 'isPrototypeOf', '__defineGetter__', '__defineSetter__', '__lookupSetter__', '__lookupGetter__'].sort(); @@ -36,7 +36,7 @@ }); test('allKeys', function() { - deepEqual(_.allKeys({one : 1, two : 2}), ['one', 'two'], 'can extract the allKeys from an object'); + deepEqual(_.allKeys({one: 1, two: 2}), ['one', 'two'], 'can extract the allKeys from an object'); // the test above is not safe because it relies on for-in enumeration order var a = []; a[1] = 0; deepEqual(_.allKeys(a), ['1'], 'is not fooled by sparse arrays; see issue #95'); @@ -50,13 +50,13 @@ // allKeys that may be missed if the implementation isn't careful var trouble = { - constructor: Object, - valueOf: _.noop, - hasOwnProperty: null, - toString: 5, - toLocaleString: undefined, + constructor : Object, + valueOf : _.noop, + hasOwnProperty : null, + toString : 5, + toLocaleString : void 0, propertyIsEnumerable: /a/, - isPrototypeOf: this + isPrototypeOf : this }; var troubleKeys = ['constructor', 'valueOf', 'hasOwnProperty', 'toString', 'toLocaleString', 'propertyIsEnumerable', 'isPrototypeOf'].sort(); @@ -93,7 +93,7 @@ }); test('functions', function() { - var obj = {a : 'dash', b : _.map, c : /yo/, d : _.reduce}; + var obj = {a: 'dash', b: _.map, c: /yo/, d: _.reduce}; deepEqual(['b', 'd'], _.functions(obj), 'can grab the function names of any passed-in object'); var Animal = function(){}; @@ -127,13 +127,13 @@ try { result = {}; - _.extend(result, null, undefined, {a: 1}); - } catch(ex) {} + _.extend(result, null, void 0, {a: 1}); + } catch(e) { /* ignored */ } equal(result.a, 1, 'should not error on `null` or `undefined` sources'); strictEqual(_.extend(null, {a: 1}), null, 'extending null results in null'); - strictEqual(_.extend(undefined, {a: 1}), undefined, 'extending undefined results in undefined'); + strictEqual(_.extend(void 0, {a: 1}), void 0, 'extending undefined results in undefined'); }); test('extendOwn', function() { @@ -154,13 +154,13 @@ deepEqual(_.extendOwn({}, subObj), {c: 'd'}, 'assign copies own properties from source'); result = {}; - deepEqual(_.assign(result, null, undefined, {a: 1}), {a: 1}, 'should not error on `null` or `undefined` sources'); + deepEqual(_.assign(result, null, void 0, {a: 1}), {a: 1}, 'should not error on `null` or `undefined` sources'); _.each(['a', 5, null, false], function(val) { strictEqual(_.assign(val, {a: 1}), val, 'assigning non-objects results in returning the non-object value'); }); - strictEqual(_.extendOwn(undefined, {a: 1}), undefined, 'assigning undefined results in undefined'); + strictEqual(_.extendOwn(void 0, {a: 1}), void 0, 'assigning undefined results in undefined'); result = _.extendOwn({a: 1, 0: 2, 1: '5', length: 6}, {0: 1, 1: 2, length: 2}); deepEqual(result, {a: 1, 0: 1, 1: 2, length: 2}, 'assign should treat array-like objects like normal objects'); @@ -219,7 +219,7 @@ deepEqual(result, {1: 'b'}, 'can omit numeric properties'); deepEqual(_.omit(null, 'a', 'b'), {}, 'non objects return empty object'); - deepEqual(_.omit(undefined, 'toString'), {}, 'null/undefined return empty object'); + deepEqual(_.omit(void 0, 'toString'), {}, 'null/undefined return empty object'); deepEqual(_.omit(5, 'toString', 'b'), {}, 'returns empty object for primitives'); var data = {a: 1, b: 2, c: 3}; @@ -257,17 +257,17 @@ try { options = {}; - _.defaults(options, null, undefined, {a: 1}); - } catch(ex) {} + _.defaults(options, null, void 0, {a: 1}); + } catch(e) { /* ignored */ } equal(options.a, 1, 'should not error on `null` or `undefined` sources'); strictEqual(_.defaults(null, {a: 1}), null, 'result is null if destination is null'); - strictEqual(_.defaults(undefined, {a: 1}), undefined, 'result is undefined if destination is undefined'); + strictEqual(_.defaults(void 0, {a: 1}), void 0, 'result is undefined if destination is undefined'); }); test('clone', function() { - var moe = {name : 'moe', lucky : [13, 27, 34]}; + var moe = {name: 'moe', lucky: [13, 27, 34]}; var clone = _.clone(moe); equal(clone.name, 'moe', 'the clone as the attributes of the original'); @@ -277,7 +277,7 @@ clone.lucky.push(101); equal(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original'); - equal(_.clone(undefined), void 0, 'non objects should not be changed by clone'); + equal(_.clone(void 0), void 0, 'non objects should not be changed by clone'); equal(_.clone(1), 1, 'non objects should not be changed by clone'); equal(_.clone(null), null, 'non objects should not be changed by clone'); }); @@ -286,7 +286,7 @@ var Parent = function() {}; Parent.prototype = {foo: function() {}, bar: 2}; - _.each(['foo', null, undefined, 1], function(val) { + _.each(['foo', null, void 0, 1], function(val) { deepEqual(_.create(val), {}, 'should return empty object when a non-object is provided'); }); @@ -324,8 +324,8 @@ ok(!_.isEqual(0, -0), '`0` is not equal to `-0`'); ok(!_.isEqual(-0, 0), 'Commutative equality is implemented for `0` and `-0`'); - ok(!_.isEqual(null, undefined), '`null` is not equal to `undefined`'); - ok(!_.isEqual(undefined, null), 'Commutative equality is implemented for `null` and `undefined`'); + ok(!_.isEqual(null, void 0), '`null` is not equal to `undefined`'); + ok(!_.isEqual(void 0, null), 'Commutative equality is implemented for `null` and `undefined`'); // String object and primitive comparisons. ok(_.isEqual('Curly', 'Curly'), 'Identical string primitives are equal'); @@ -350,7 +350,7 @@ // Comparisons involving `NaN`. ok(_.isEqual(NaN, NaN), '`NaN` is equal to `NaN`'); - ok(_.isEqual(new Object(NaN), NaN), 'Object(`NaN`) is equal to `NaN`'); + ok(_.isEqual(new Number(NaN), NaN), 'Object(`NaN`) is equal to `NaN`'); ok(!_.isEqual(61, NaN), 'A number primitive is not equal to `NaN`'); ok(!_.isEqual(new Number(79), NaN), 'A number object is not equal to `NaN`'); ok(!_.isEqual(Infinity, NaN), '`Infinity` is not equal to `NaN`'); @@ -431,7 +431,7 @@ var sparse = []; sparse[1] = 5; - ok(_.isEqual(sparse, [undefined, 5]), 'Handles sparse arrays as dense'); + ok(_.isEqual(sparse, [void 0, 5]), 'Handles sparse arrays as dense'); // Simple objects. ok(_.isEqual({a: 'Curly', b: 1, c: true}, {a: 'Curly', b: 1, c: true}), 'Objects containing identical primitives are equal'); @@ -440,18 +440,18 @@ ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), 'Objects of identical sizes with different property names are not equal'); ok(!_.isEqual({a: 1, b: 2}, {a: 1}), 'Objects of different sizes are not equal'); ok(!_.isEqual({a: 1}, {a: 1, b: 2}), 'Commutative equality is implemented for objects'); - ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), 'Objects with identical keys and different values are not equivalent'); + ok(!_.isEqual({x: 1, y: void 0}, {x: 1, z: 2}), 'Objects with identical keys and different values are not equivalent'); // `A` contains nested objects and arrays. a = { - name: new String('Moe Howard'), - age: new Number(77), - stooge: true, + name : new String('Moe Howard'), + age : new Number(77), + stooge : true, hobbies: ['acting'], - film: { - name: 'Sing a Song of Six Pants', + film : { + name : 'Sing a Song of Six Pants', release: new Date(1947, 9, 30), - stars: [new String('Larry Fine'), 'Shemp Howard'], + stars : [new String('Larry Fine'), 'Shemp Howard'], minutes: new Number(16), seconds: 54 } @@ -459,14 +459,14 @@ // `B` contains equivalent nested objects and arrays. b = { - name: new String('Moe Howard'), - age: new Number(77), - stooge: true, + name : new String('Moe Howard'), + age : new Number(77), + stooge : true, hobbies: ['acting'], - film: { - name: 'Sing a Song of Six Pants', + film : { + name : 'Sing a Song of Six Pants', release: new Date(1947, 9, 30), - stars: [new String('Larry Fine'), 'Shemp Howard'], + stars : [new String('Larry Fine'), 'Shemp Howard'], minutes: new Number(16), seconds: 54 } @@ -536,7 +536,7 @@ ok(_.isEqual(a, b), 'Cyclic structures with nested and identically-named properties are equal'); // Chaining. - ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal'); + ok(!_.isEqual(_({x: 1, y: void 0}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal'); a = _({x: 1, y: 2}).chain(); b = _({x: 1, y: 2}).chain(); @@ -544,9 +544,9 @@ // Objects without a `constructor` property if (Object.create) { - a = Object.create(null, {x: {value: 1, enumerable: true}}); - b = {x: 1}; - ok(_.isEqual(a, b), 'Handles objects without a constructor (e.g. from Object.create'); + a = Object.create(null, {x: {value: 1, enumerable: true}}); + b = {x: 1}; + ok(_.isEqual(a, b), 'Handles objects without a constructor (e.g. from Object.create'); } function Foo() { this.a = 1; } @@ -566,7 +566,7 @@ test('isEmpty', function() { ok(!_([1]).isEmpty(), '[1] is not empty'); ok(_.isEmpty([]), '[] is empty'); - ok(!_.isEmpty({one : 1}), '{one : 1} is not empty'); + ok(!_.isEmpty({one: 1}), '{one: 1} is not empty'); ok(_.isEmpty({}), '{} is empty'); ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty'); ok(_.isEmpty(null), 'null is empty'); @@ -574,7 +574,7 @@ ok(_.isEmpty(''), 'the empty string is empty'); ok(!_.isEmpty('moe'), 'but other strings are not'); - var obj = {one : 1}; + var obj = {one: 1}; delete obj.one; ok(_.isEmpty(obj), 'deleting all the keys from an object empties it'); @@ -583,7 +583,7 @@ ok(!_.isEmpty(args('')), 'non-empty arguments object is not empty'); // covers collecting non-enumerable properties in IE < 9 - var nonEnumProp = {'toString': 5}; + var nonEnumProp = {toString: 5}; ok(!_.isEmpty(nonEnumProp), 'non-enumerable property is not empty'); }); @@ -609,9 +609,9 @@ if (testElement) { ok(_.isObject(testElement), 'and DOM element'); } - ok(_.isObject(function () {}), 'and functions'); + ok(_.isObject(function() {}), 'and functions'); ok(!_.isObject(null), 'but not null'); - ok(!_.isObject(undefined), 'and not undefined'); + ok(!_.isObject(void 0), 'and not undefined'); ok(!_.isObject('string'), 'and not string'); ok(!_.isObject(12), 'and not number'); ok(!_.isObject(true), 'and not boolean'); @@ -619,7 +619,7 @@ }); test('isArray', function() { - ok(!_.isArray(undefined), 'undefined vars are not arrays'); + ok(!_.isArray(void 0), 'undefined vars are not arrays'); ok(!_.isArray(arguments), 'the arguments object is not an array'); ok(_.isArray([1, 2, 3]), 'but arrays are'); }); @@ -638,7 +638,7 @@ test('isNumber', function() { ok(!_.isNumber('string'), 'a string is not a number'); ok(!_.isNumber(arguments), 'the arguments object is not a number'); - ok(!_.isNumber(undefined), 'undefined is not a number'); + ok(!_.isNumber(void 0), 'undefined is not a number'); ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are'); ok(_.isNumber(NaN), 'NaN *is* a number'); ok(_.isNumber(Infinity), 'Infinity is a number'); @@ -651,7 +651,7 @@ ok(!_.isBoolean('false'), 'the string "false" is not a boolean'); ok(!_.isBoolean('true'), 'the string "true" is not a boolean'); ok(!_.isBoolean(arguments), 'the arguments object is not a boolean'); - ok(!_.isBoolean(undefined), 'undefined is not a boolean'); + ok(!_.isBoolean(void 0), 'undefined is not a boolean'); ok(!_.isBoolean(NaN), 'NaN is not a boolean'); ok(!_.isBoolean(null), 'null is not a boolean'); ok(_.isBoolean(true), 'but true is'); @@ -659,7 +659,7 @@ }); test('isFunction', function() { - ok(!_.isFunction(undefined), 'undefined vars are not functions'); + ok(!_.isFunction(void 0), 'undefined vars are not functions'); ok(!_.isFunction([1, 2, 3]), 'arrays are not functions'); ok(!_.isFunction('moe'), 'strings are not functions'); ok(_.isFunction(_.isFunction), 'but functions are'); @@ -676,9 +676,9 @@ .map(_.propertyOf(typeof GLOBAL != 'undefined' ? GLOBAL : window)) .compact() .each(function(TypedArray) { - // PhantomJS reports `typeof UInt8Array == 'object'` and doesn't report toString TypeArray - // as a function - strictEqual(_.isFunction(TypedArray), Object.prototype.toString.call(TypedArray) === '[object Function]'); + // PhantomJS reports `typeof UInt8Array == 'object'` and doesn't report toString TypeArray + // as a function + strictEqual(_.isFunction(TypedArray), Object.prototype.toString.call(TypedArray) === '[object Function]'); }); }); } @@ -695,7 +695,7 @@ }); test('isFinite', function() { - ok(!_.isFinite(undefined), 'undefined is not finite'); + ok(!_.isFinite(void 0), 'undefined is not finite'); ok(!_.isFinite(null), 'null is not finite'); ok(!_.isFinite(NaN), 'NaN is not finite'); ok(!_.isFinite(Infinity), 'Infinity is not finite'); @@ -711,7 +711,7 @@ }); test('isNaN', function() { - ok(!_.isNaN(undefined), 'undefined is not NaN'); + ok(!_.isNaN(void 0), 'undefined is not NaN'); ok(!_.isNaN(null), 'null is not NaN'); ok(!_.isNaN(0), '0 is not NaN'); ok(_.isNaN(NaN), 'but NaN is'); @@ -719,7 +719,7 @@ }); test('isNull', function() { - ok(!_.isNull(undefined), 'undefined is not null'); + ok(!_.isNull(void 0), 'undefined is not null'); ok(!_.isNull(NaN), 'NaN is not null'); ok(_.isNull(null), 'but null is'); }); @@ -730,7 +730,7 @@ ok(!_.isUndefined(false), 'false is defined'); ok(!_.isUndefined(NaN), 'NaN is defined'); ok(_.isUndefined(), 'nothing is undefined'); - ok(_.isUndefined(undefined), 'undefined is undefined'); + ok(_.isUndefined(void 0), 'undefined is undefined'); }); test('isError', function() { @@ -762,7 +762,7 @@ equal(intercepted, returned, 'can use tapped objects in a chain'); }); - test('has', function () { + test('has', function() { var obj = {foo: 'bar', func: function(){}}; ok(_.has(obj, 'foo'), 'has() checks that the object has a property.'); ok(!_.has(obj, 'baz'), "has() returns false if the object doesn't have the property."); @@ -773,7 +773,7 @@ child.prototype = obj; ok(!_.has(child, 'foo'), 'has() does not check the prototype chain for a property.'); strictEqual(_.has(null, 'foo'), false, 'has() returns false for null'); - strictEqual(_.has(undefined, 'foo'), false, 'has() returns false for undefined'); + strictEqual(_.has(void 0, 'foo'), false, 'has() returns false for undefined'); }); test('isMatch', function() { @@ -783,17 +783,17 @@ equal(_.isMatch(moe, {hair: true}), true, 'Returns a boolean'); equal(_.isMatch(curly, {hair: true}), false, 'Returns a boolean'); - equal(_.isMatch(5, {__x__: undefined}), false, 'can match undefined props on primitives'); - equal(_.isMatch({__x__: undefined}, {__x__: undefined}), true, 'can match undefined props'); + equal(_.isMatch(5, {__x__: void 0}), false, 'can match undefined props on primitives'); + equal(_.isMatch({__x__: void 0}, {__x__: void 0}), true, 'can match undefined props'); equal(_.isMatch(null, {}), true, 'Empty spec called with null object returns true'); equal(_.isMatch(null, {a: 1}), false, 'Non-empty spec called with null object returns false'); - _.each([null, undefined], function(item) { strictEqual(_.isMatch(item, null), true, 'null matches null'); }); - _.each([null, undefined], function(item) { strictEqual(_.isMatch(item, null), true, 'null matches {}'); }); - strictEqual(_.isMatch({b: 1}, {a: undefined}), false, 'handles undefined values (1683)'); + _.each([null, void 0], function(item) { strictEqual(_.isMatch(item, null), true, 'null matches null'); }); + _.each([null, void 0], function(item) { strictEqual(_.isMatch(item, null), true, 'null matches {}'); }); + strictEqual(_.isMatch({b: 1}, {a: void 0}), false, 'handles undefined values (1683)'); - _.each([true, 5, NaN, null, undefined], function(item) { + _.each([true, 5, NaN, null, void 0], function(item) { strictEqual(_.isMatch({a: 1}, item), true, 'treats primitives as empty'); }); @@ -812,8 +812,8 @@ ok(_.isMatch({x: 5, y: 1}, Prototest), 'spec can be a function'); //null edge cases - var oCon = {'constructor': Object}; - deepEqual(_.map([null, undefined, 5, {}], _.partial(_.isMatch, _, oCon)), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); + var oCon = {constructor: Object}; + deepEqual(_.map([null, void 0, 5, {}], _.partial(_.isMatch, _, oCon)), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); }); test('matcher', function() { @@ -824,21 +824,21 @@ equal(_.matcher({hair: true})(moe), true, 'Returns a boolean'); equal(_.matcher({hair: true})(curly), false, 'Returns a boolean'); - equal(_.matcher({__x__: undefined})(5), false, 'can match undefined props on primitives'); - equal(_.matcher({__x__: undefined})({__x__: undefined}), true, 'can match undefined props'); + equal(_.matcher({__x__: void 0})(5), false, 'can match undefined props on primitives'); + equal(_.matcher({__x__: void 0})({__x__: void 0}), true, 'can match undefined props'); equal(_.matcher({})(null), true, 'Empty spec called with null object returns true'); equal(_.matcher({a: 1})(null), false, 'Non-empty spec called with null object returns false'); ok(_.find(stooges, _.matcher({hair: false})) === curly, 'returns a predicate that can be used by finding functions.'); ok(_.find(stooges, _.matcher(moe)) === moe, 'can be used to locate an object exists in a collection.'); - deepEqual(_.where([null, undefined], {a: 1}), [], 'Do not throw on null values.'); + deepEqual(_.where([null, void 0], {a: 1}), [], 'Do not throw on null values.'); - deepEqual(_.where([null, undefined], null), [null, undefined], 'null matches null'); - deepEqual(_.where([null, undefined], {}), [null, undefined], 'null matches {}'); - deepEqual(_.where([{b: 1}], {a: undefined}), [], 'handles undefined values (1683)'); + deepEqual(_.where([null, void 0], null), [null, void 0], 'null matches null'); + deepEqual(_.where([null, void 0], {}), [null, void 0], 'null matches {}'); + deepEqual(_.where([{b: 1}], {a: void 0}), [], 'handles undefined values (1683)'); - _.each([true, 5, NaN, null, undefined], function(item) { + _.each([true, 5, NaN, null, void 0], function(item) { deepEqual(_.where([{a: 1}], item), [{a: 1}], 'treats primitives as empty'); }); @@ -859,18 +859,18 @@ ok(_.matcher(Prototest)({x: 5, y: 1}), 'spec can be a function'); // #1729 - var o = {'b': 1}; + var o = {b: 1}; var m = _.matcher(o); - equal(m({'b': 1}), true); + equal(m({b: 1}), true); o.b = 2; o.a = 1; - equal(m({'b': 1}), true, 'changing spec object doesnt change matches result'); + equal(m({b: 1}), true, 'changing spec object doesnt change matches result'); //null edge cases - var oCon = _.matcher({'constructor': Object}); - deepEqual(_.map([null, undefined, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); + var oCon = _.matcher({constructor: Object}); + deepEqual(_.map([null, void 0, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); }); test('matcher', function() { @@ -881,21 +881,21 @@ equal(_.matcher({hair: true})(moe), true, 'Returns a boolean'); equal(_.matcher({hair: true})(curly), false, 'Returns a boolean'); - equal(_.matcher({__x__: undefined})(5), false, 'can match undefined props on primitives'); - equal(_.matcher({__x__: undefined})({__x__: undefined}), true, 'can match undefined props'); + equal(_.matcher({__x__: void 0})(5), false, 'can match undefined props on primitives'); + equal(_.matcher({__x__: void 0})({__x__: void 0}), true, 'can match undefined props'); equal(_.matcher({})(null), true, 'Empty spec called with null object returns true'); equal(_.matcher({a: 1})(null), false, 'Non-empty spec called with null object returns false'); ok(_.find(stooges, _.matcher({hair: false})) === curly, 'returns a predicate that can be used by finding functions.'); ok(_.find(stooges, _.matcher(moe)) === moe, 'can be used to locate an object exists in a collection.'); - deepEqual(_.where([null, undefined], {a: 1}), [], 'Do not throw on null values.'); + deepEqual(_.where([null, void 0], {a: 1}), [], 'Do not throw on null values.'); - deepEqual(_.where([null, undefined], null), [null, undefined], 'null matches null'); - deepEqual(_.where([null, undefined], {}), [null, undefined], 'null matches {}'); - deepEqual(_.where([{b: 1}], {a: undefined}), [], 'handles undefined values (1683)'); + deepEqual(_.where([null, void 0], null), [null, void 0], 'null matches null'); + deepEqual(_.where([null, void 0], {}), [null, void 0], 'null matches {}'); + deepEqual(_.where([{b: 1}], {a: void 0}), [], 'handles undefined values (1683)'); - _.each([true, 5, NaN, null, undefined], function(item) { + _.each([true, 5, NaN, null, void 0], function(item) { deepEqual(_.where([{a: 1}], item), [{a: 1}], 'treats primitives as empty'); }); @@ -916,25 +916,25 @@ ok(_.matcher(Prototest)({x: 5, y: 1}), 'spec can be a function'); // #1729 - var o = {'b': 1}; + var o = {b: 1}; var m = _.matcher(o); - equal(m({'b': 1}), true); + equal(m({b: 1}), true); o.b = 2; o.a = 1; - equal(m({'b': 1}), true, 'changing spec object doesnt change matches result'); + equal(m({b: 1}), true, 'changing spec object doesnt change matches result'); //null edge cases - var oCon = _.matcher({'constructor': Object}); - deepEqual(_.map([null, undefined, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); + var oCon = _.matcher({constructor: Object}); + deepEqual(_.map([null, void 0, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); }); test('findKey', function() { var objects = { - a: {'a': 0, 'b': 0}, - b: {'a': 1, 'b': 1}, - c: {'a': 2, 'b': 2} + a: {a: 0, b: 0}, + b: {a: 1, b: 1}, + c: {a: 2, b: 2} }; equal(_.findKey(objects, function(obj) { @@ -949,7 +949,7 @@ equal(_.findKey(objects, function(obj) { return obj.b * obj.a === 5; - }), undefined); + }), void 0); strictEqual(_.findKey([1, 2, 3, 4, 5, 6], function(obj) { return obj === 3; @@ -957,7 +957,7 @@ strictEqual(_.findKey(objects, function(a) { return a.foo === null; - }), undefined); + }), void 0); _.findKey({a: {a: 1}}, function(a, key, obj) { equal(key, 'a'); @@ -972,53 +972,53 @@ test('mapObject', function() { - var obj = {'a': 1, 'b': 2}; - var objects = { - a: {'a': 0, 'b': 0}, - b: {'a': 1, 'b': 1}, - c: {'a': 2, 'b': 2} + var obj = {a: 1, b: 2}; + var objects = { + a: {a: 0, b: 0}, + b: {a: 1, b: 1}, + c: {a: 2, b: 2} }; deepEqual(_.mapObject(obj, function(val) { return val * 2; - }), {'a': 2, 'b': 4}, 'simple objects'); + }), {a: 2, b: 4}, 'simple objects'); deepEqual(_.mapObject(objects, function(val) { - return _.reduce(val, function(memo,v){ - return memo + v; - },0); - }), {'a': 0, 'b': 2, 'c': 4}, 'nested objects'); + return _.reduce(val, function(memo, v){ + return memo + v; + }, 0); + }), {a: 0, b: 2, c: 4}, 'nested objects'); - deepEqual(_.mapObject(obj, function(val,key,obj) { - return obj[key] * 2; - }), {'a': 2, 'b': 4}, 'correct keys'); + deepEqual(_.mapObject(obj, function(val, key, o) { + return o[key] * 2; + }), {a: 2, b: 4}, 'correct keys'); - deepEqual(_.mapObject([1,2], function(val) { + deepEqual(_.mapObject([1, 2], function(val) { return val * 2; - }), {'0': 2, '1': 4}, 'check behavior for arrays'); + }), {0: 2, 1: 4}, 'check behavior for arrays'); deepEqual(_.mapObject(obj, function(val) { return val * this.multiplier; - }, {multiplier : 3}), {'a': 3, 'b': 6}, 'keep context'); + }, {multiplier: 3}), {a: 3, b: 6}, 'keep context'); deepEqual(_.mapObject({a: 1}, function() { return this.length; - }, [1,2]), {'a': 2}, 'called with context'); + }, [1, 2]), {a: 2}, 'called with context'); var ids = _.mapObject({length: 2, 0: {id: '1'}, 1: {id: '2'}}, function(n){ return n.id; }); - deepEqual(ids, {'length': undefined, '0': '1', '1': '2'}, 'Check with array-like objects'); + deepEqual(ids, {length: void 0, 0: '1', 1: '2'}, 'Check with array-like objects'); // Passing a property name like _.pluck. - var people = {'a': {name : 'moe', age : 30}, 'b': {name : 'curly', age : 50}}; - deepEqual(_.mapObject(people, 'name'), {'a': 'moe', 'b': 'curly'}, 'predicate string map to object properties'); + var people = {a: {name: 'moe', age: 30}, b: {name: 'curly', age: 50}}; + deepEqual(_.mapObject(people, 'name'), {a: 'moe', b: 'curly'}, 'predicate string map to object properties'); - _.each([null, void 0, 1, 'abc', [], {}, undefined], function(val){ + _.each([null, void 0, 1, 'abc', [], {}, void 0], function(val){ deepEqual(_.mapObject(val, _.identity), {}, 'mapValue identity'); }); - var Proto = function(){this.a = 1;}; + var Proto = function(){ this.a = 1; }; Proto.prototype.b = 1; var protoObj = new Proto(); deepEqual(_.mapObject(protoObj, _.identity), {a: 1}, 'ignore inherited values from prototypes'); diff --git a/test/utility.js b/test/utility.js index 83b76a0e3..31746cc08 100644 --- a/test/utility.js +++ b/test/utility.js @@ -21,42 +21,42 @@ }); test('identity', function() { - var stooge = {name : 'moe'}; + var stooge = {name: 'moe'}; equal(_.identity(stooge), stooge, 'stooge is the same as his identity'); }); test('constant', function() { - var stooge = {name : 'moe'}; + var stooge = {name: 'moe'}; equal(_.constant(stooge)(), stooge, 'should create a function that returns stooge'); }); test('noop', function() { - strictEqual(_.noop('curly', 'larry', 'moe'), undefined, 'should always return undefined'); + strictEqual(_.noop('curly', 'larry', 'moe'), void 0, 'should always return undefined'); }); test('property', function() { - var stooge = {name : 'moe'}; + var stooge = {name: 'moe'}; equal(_.property('name')(stooge), 'moe', 'should return the property with the given name'); - equal(_.property('name')(null), undefined, 'should return undefined for null values'); - equal(_.property('name')(undefined), undefined, 'should return undefined for undefined values'); + equal(_.property('name')(null), void 0, 'should return undefined for null values'); + equal(_.property('name')(void 0), void 0, 'should return undefined for undefined values'); }); - + test('propertyOf', function() { var stoogeRanks = _.propertyOf({curly: 2, moe: 1, larry: 3}); equal(stoogeRanks('curly'), 2, 'should return the property with the given name'); - equal(stoogeRanks(null), undefined, 'should return undefined for null values'); - equal(stoogeRanks(undefined), undefined, 'should return undefined for undefined values'); - + equal(stoogeRanks(null), void 0, 'should return undefined for null values'); + equal(stoogeRanks(void 0), void 0, 'should return undefined for undefined values'); + function MoreStooges() { this.shemp = 87; } MoreStooges.prototype = {curly: 2, moe: 1, larry: 3}; var moreStoogeRanks = _.propertyOf(new MoreStooges()); equal(moreStoogeRanks('curly'), 2, 'should return properties from further up the prototype chain'); - + var nullPropertyOf = _.propertyOf(null); - equal(nullPropertyOf('curly'), undefined, 'should return undefined when obj is null'); - - var undefPropertyOf = _.propertyOf(undefined); - equal(undefPropertyOf('curly'), undefined, 'should return undefined when obj is undefined'); + equal(nullPropertyOf('curly'), void 0, 'should return undefined when obj is null'); + + var undefPropertyOf = _.propertyOf(void 0); + equal(undefPropertyOf('curly'), void 0, 'should return undefined when obj is undefined'); }); test('random', function() { @@ -86,7 +86,7 @@ test('times', function() { var vals = []; - _.times(3, function (i) { vals.push(i); }); + _.times(3, function(i) { vals.push(i); }); deepEqual(vals, [0, 1, 2], 'is 0 indexed'); // vals = []; @@ -127,16 +127,16 @@ var escapeCharacters = ['<', '>', '"', '\'', '`']; _.each(escapeCharacters, function(escapeChar) { - var str = 'a ' + escapeChar + ' string escaped'; - var escaped = _.escape(str); - notEqual(str, escaped, escapeChar + ' is escaped'); - equal(str, _.unescape(escaped), escapeChar + ' can be unescaped'); + var s = 'a ' + escapeChar + ' string escaped'; + var e = _.escape(s); + notEqual(s, e, escapeChar + ' is escaped'); + equal(s, _.unescape(e), escapeChar + ' can be unescaped'); - str = 'a ' + escapeChar + escapeChar + escapeChar + 'some more string' + escapeChar; - escaped = _.escape(str); + s = 'a ' + escapeChar + escapeChar + escapeChar + 'some more string' + escapeChar; + e = _.escape(s); - equal(escaped.indexOf(escapeChar), -1, 'can escape multiple occurances of ' + escapeChar); - equal(_.unescape(escaped), str, 'multiple occurrences of ' + escapeChar + ' can be unescaped'); + equal(e.indexOf(escapeChar), -1, 'can escape multiple occurances of ' + escapeChar); + equal(_.unescape(e), s, 'multiple occurrences of ' + escapeChar + ' can be unescaped'); }); // handles multiple escape characters at once @@ -158,7 +158,7 @@ test('template', function() { var basicTemplate = _.template("<%= thing %> is gettin' on my noives!"); - var result = basicTemplate({thing : 'This'}); + var result = basicTemplate({thing: 'This'}); equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation'); var sansSemicolonTemplate = _.template('A <% this %> B'); @@ -173,7 +173,7 @@ var fancyTemplate = _.template(' <% ' + ' for (var key in people) { ' + '%>
'); - result = fancyTemplate({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}}); + result = fancyTemplate({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}}); equal(result, '- <%= people[key] %>
<% } %>', 'can run arbitrary javascript in templates'); var escapedCharsInJavascriptTemplate = _.template('
- Moe
- Larry
- Curly
<% _.each(numbers.split("\\n"), function(item) { %>
'); @@ -182,7 +182,7 @@ var namespaceCollisionTemplate = _.template('<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %><% }); %>'); result = namespaceCollisionTemplate({ - pageCount: 3, + pageCount : 3, thumbnails: { 1: 'p1-thumbnail.gif', 2: 'p2-thumbnail.gif', @@ -211,7 +211,7 @@ equal(result, '<script>'); var stooge = { - name: 'Moe', + name : 'Moe', template: _.template("I'm <%= this.name %>") }; equal(stooge.template(), "I'm Moe"); @@ -222,15 +222,15 @@ ' if (data) { data += 12345; }; %>\n ' + '- <%= item %>
<% }) %><%= data %> \n ' ); - equal(template({data : 12345}).replace(/\s/g, ''), '24690 '); + equal(template({data: 12345}).replace(/\s/g, ''), '24690 '); _.templateSettings = { - evaluate : /\{\{([\s\S]+?)\}\}/g, - interpolate : /\{\{=([\s\S]+?)\}\}/g + evaluate : /\{\{([\s\S]+?)\}\}/g, + interpolate: /\{\{=([\s\S]+?)\}\}/g }; var custom = _.template('{{ for (var key in people) { }}
'); - result = custom({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}}); + result = custom({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}}); equal(result, '- {{= people[key] }}
{{ } }}', 'can run arbitrary javascript in templates'); var customQuote = _.template("It's its, not it's"); @@ -240,12 +240,12 @@ equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'."); _.templateSettings = { - evaluate : /<\?([\s\S]+?)\?>/g, - interpolate : /<\?=([\s\S]+?)\?>/g + evaluate : /<\?([\s\S]+?)\?>/g, + interpolate: /<\?=([\s\S]+?)\?>/g }; var customWithSpecialChars = _.template('
- Moe
- Larry
- Curly
for (var key in people) { ?>
'); - result = customWithSpecialChars({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}}); + result = customWithSpecialChars({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}}); equal(result, '- = people[key] ?>
} ?>', 'can run arbitrary javascript in templates'); var customWithSpecialCharsQuote = _.template("It's its, not it's"); @@ -255,21 +255,22 @@ equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'."); _.templateSettings = { - interpolate : /\{\{(.+?)\}\}/g + interpolate: /\{\{(.+?)\}\}/g }; var mustache = _.template('Hello {{planet}}!'); - equal(mustache({planet : 'World'}), 'Hello World!', 'can mimic mustache.js'); + equal(mustache({planet: 'World'}), 'Hello World!', 'can mimic mustache.js'); var templateWithNull = _.template('a null undefined {{planet}}'); - equal(templateWithNull({planet : 'world'}), 'a null undefined world', 'can handle missing escape and evaluate settings'); + equal(templateWithNull({planet: 'world'}), 'a null undefined world', 'can handle missing escape and evaluate settings'); }); test('_.template provides the generated function source, when a SyntaxError occurs', function() { + var source; try { _.template('<%= if x %>'); } catch (ex) { - var source = ex.source; + source = ex.source; } ok(/__p/.test(source)); }); @@ -284,13 +285,13 @@ strictEqual(_.result(obj, 'w'), ''); strictEqual(_.result(obj, 'x'), 'x'); strictEqual(_.result(obj, 'y'), 'x'); - strictEqual(_.result(obj, 'z'), undefined); - strictEqual(_.result(null, 'x'), undefined); + strictEqual(_.result(obj, 'z'), void 0); + strictEqual(_.result(null, 'x'), void 0); }); test('result returns a default value if object is null or undefined', function() { strictEqual(_.result(null, 'b', 'default'), 'default'); - strictEqual(_.result(undefined, 'c', 'default'), 'default'); + strictEqual(_.result(void 0, 'c', 'default'), 'default'); strictEqual(_.result(''.match('missing'), 1, 'default'), 'default'); }); @@ -301,7 +302,7 @@ test('result only returns the default value if the object does not have the property or is undefined', function() { strictEqual(_.result({}, 'b', 'default'), 'default'); - strictEqual(_.result({d: undefined}, 'd', 'default'), 'default'); + strictEqual(_.result({d: void 0}, 'd', 'default'), 'default'); }); test('result does not return the default if the property of an object is found in the prototype', function() { @@ -312,7 +313,7 @@ test('result does use the fallback when the result of invoking the property is undefined', function() { var obj = {a: function() {}}; - strictEqual(_.result(obj, 'a', 'failed'), undefined); + strictEqual(_.result(obj, 'a', 'failed'), void 0); }); test('result fallback can use a function', function() { @@ -341,11 +342,11 @@ test('#556 - undefined template variables.', function() { var template = _.template('<%=x%>'); strictEqual(template({x: null}), ''); - strictEqual(template({x: undefined}), ''); + strictEqual(template({x: void 0}), ''); var templateEscaped = _.template('<%-x%>'); strictEqual(templateEscaped({x: null}), ''); - strictEqual(templateEscaped({x: undefined}), ''); + strictEqual(templateEscaped({x: void 0}), ''); var templateWithProperty = _.template('<%=x.foo%>'); strictEqual(templateWithProperty({x: {}}), ''); diff --git a/underscore.js b/underscore.js index e7b382dbf..08b3ed589 100644 --- a/underscore.js +++ b/underscore.js @@ -10,8 +10,8 @@ // Establish the root object, `window` (`self`) in the browser, or `global` on the server. // We use `self` instead of `window` for `WebWorker` support. - var root = (typeof self === 'object' && self.self === self && self) || - (typeof global === 'object' && global.global === global && global); + var root = typeof self === 'object' && self.self === self && self || + typeof global === 'object' && global.global === global && global; // Save the previous value of the `_` variable. var previousUnderscore = root._; @@ -21,18 +21,18 @@ // Create quick reference variables for speed access to core prototypes. var - push = ArrayProto.push, - slice = ArrayProto.slice, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; + push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; // All **ECMAScript 5** native function implementations that we hope to use // are declared here. var - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind, - nativeCreate = Object.create; + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind, + nativeCreate = Object.create; // Naked function reference for surrogate-prototype-swapping. var Ctor = function(){}; @@ -103,7 +103,8 @@ return function() { var length = Math.max(arguments.length - startIndex, 0); var rest = Array(length); - for (var index = 0; index < length; index++) { + var index; + for (index = 0; index < length; index++) { rest[index] = arguments[index + startIndex]; } switch (startIndex) { @@ -315,10 +316,10 @@ } } else { iteratee = cb(iteratee, context); - _.each(obj, function(value, index, list) { - computed = iteratee(value, index, list); + _.each(obj, function(v, index, list) { + computed = iteratee(v, index, list); if (computed > lastComputed || computed === -Infinity && result === -Infinity) { - result = value; + result = v; lastComputed = computed; } }); @@ -340,10 +341,10 @@ } } else { iteratee = cb(iteratee, context); - _.each(obj, function(value, index, list) { - computed = iteratee(value, index, list); + _.each(obj, function(v, index, list) { + computed = iteratee(v, index, list); if (computed < lastComputed || computed === Infinity && result === Infinity) { - result = value; + result = v; lastComputed = computed; } }); @@ -383,8 +384,8 @@ iteratee = cb(iteratee, context); return _.pluck(_.map(obj, function(value, index, list) { return { - value: value, - index: index, + value : value, + index : index, criteria: iteratee(value, index, list) }; }).sort(function(left, right) { @@ -563,7 +564,8 @@ for (var i = 0, length = getLength(array); i < length; i++) { var item = array[i]; if (_.contains(result, item)) continue; - for (var j = 1; j < argsLength; j++) { + var j; + for (j = 1; j < argsLength; j++) { if (!_.contains(arguments[j], item)) break; } if (j === argsLength) result.push(item); @@ -647,9 +649,9 @@ var i = 0, length = getLength(array); if (typeof idx == 'number') { if (dir > 0) { - i = idx >= 0 ? idx : Math.max(idx + length, i); + i = idx >= 0 ? idx : Math.max(idx + length, i); } else { - length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; } } else if (sortedIndex && idx && length) { idx = sortedIndex(array, item); @@ -914,7 +916,7 @@ var collectNonEnumProps = function(obj, keys) { var nonEnumIdx = nonEnumerableProps.length; var constructor = obj.constructor; - var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; + var proto = _.isFunction(constructor) && constructor.prototype || ObjProto; // Constructor is a special case. var prop = 'constructor'; @@ -965,7 +967,7 @@ // In contrast to _.map it returns an object _.mapObject = function(obj, iteratee, context) { iteratee = cb(iteratee, context); - var keys = _.keys(obj), + var keys = _.keys(obj), length = keys.length, results = {}; for (var index = 0; index < length; index++) { @@ -1043,7 +1045,7 @@ // Internal pick helper function to determine if `obj` has key `key`. var keyInObj = function(value, key, obj) { - return key in obj; + return key in obj; }; // Return a copy of the object only containing the whitelisted properties. @@ -1402,8 +1404,8 @@ // If the value of the named `property` is a function then invoke it with the // `object` as context; otherwise, return it. - _.result = function(object, property, fallback) { - var value = object == null ? void 0 : object[property]; + _.result = function(object, prop, fallback) { + var value = object == null ? void 0 : object[prop]; if (value === void 0) { value = fallback; } @@ -1421,9 +1423,9 @@ // By default, Underscore uses ERB-style template delimiters, change the // following template settings to use alternative delimiters. _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g + evaluate : /<%([\s\S]+?)%>/g, + interpolate: /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g }; // When customizing `templateSettings`, if you don't want to define an @@ -1434,15 +1436,15 @@ // Certain characters need to be escaped so that they can be put into a // string literal. var escapes = { - "'": "'", - '\\': '\\', - '\r': 'r', - '\n': 'n', + "'" : "'", + '\\' : '\\', + '\r' : 'r', + '\n' : 'n', '\u2028': 'u2028', '\u2029': 'u2029' }; - var escaper = /\\|'|\r|\n|\u2028|\u2029/g; + var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g; var escapeChar = function(match) { return '\\' + escapes[match]; @@ -1467,7 +1469,7 @@ var index = 0; var source = "__p+='"; text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { - source += text.slice(index, offset).replace(escaper, escapeChar); + source += text.slice(index, offset).replace(escapeRegExp, escapeChar); index = offset + match.length; if (escape) { @@ -1490,8 +1492,9 @@ "print=function(){__p+=__j.call(arguments,'');};\n" + source + 'return __p;\n'; + var render; try { - var render = new Function(settings.variable || 'obj', '_', source); + render = new Function(settings.variable || 'obj', '_', source); } catch (e) { e.source = source; throw e; @@ -1522,7 +1525,7 @@ // underscore functions. Wrapped objects may be chained. // Helper function to continue chaining intermediate results. - var result = function(instance, obj) { + var chainResult = function(instance, obj) { return instance._chain ? _(obj).chain() : obj; }; @@ -1533,7 +1536,7 @@ _.prototype[name] = function() { var args = [this._wrapped]; push.apply(args, arguments); - return result(this, func.apply(_, args)); + return chainResult(this, func.apply(_, args)); }; }); }; @@ -1548,7 +1551,7 @@ var obj = this._wrapped; method.apply(obj, arguments); if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; - return result(this, obj); + return chainResult(this, obj); }; }); @@ -1556,7 +1559,7 @@ _.each(['concat', 'join', 'slice'], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { - return result(this, method.apply(this._wrapped, arguments)); + return chainResult(this, method.apply(this._wrapped, arguments)); }; }); From de320a16237f0a2cdd55a04a5ca2cf1efb62c8b3 Mon Sep 17 00:00:00 2001 From: Michael Ficarra
- Moe
- Larry
- Curly
Date: Tue, 26 May 2015 11:31:30 -0700 Subject: [PATCH 035/263] change key-spacing linting rule to not require colon alignment --- .eslintrc | 2 +- test/functions.js | 8 +++---- test/objects.js | 56 +++++++++++++++++++++++------------------------ test/utility.js | 8 +++---- underscore.js | 16 +++++++------- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/.eslintrc b/.eslintrc index e48ae1426..0e88b37eb 100644 --- a/.eslintrc +++ b/.eslintrc @@ -16,7 +16,7 @@ "eol-last": 2, "eqeqeq": [2, "smart"], "indent": [2, 2, {"indentSwitchCase": true}], - "key-spacing": [1, { "align": "colon" }], + "key-spacing": 1, "linebreak-style": 2, "max-depth": [1, 4], "max-params": [1, 5], diff --git a/test/functions.js b/test/functions.js index 8c4541110..7ceb49dfe 100644 --- a/test/functions.js +++ b/test/functions.js @@ -91,9 +91,9 @@ test('bindAll', function() { var curly = {name: 'curly'}, moe = { - name : 'moe', + name: 'moe', getName: function() { return 'name: ' + this.name; }, - sayHi : function() { return 'hi: ' + this.name; } + sayHi: function() { return 'hi: ' + this.name; } }; curly.getName = moe.getName; _.bindAll(moe, 'getName', 'sayHi'); @@ -103,9 +103,9 @@ curly = {name: 'curly'}; moe = { - name : 'moe', + name: 'moe', getName: function() { return 'name: ' + this.name; }, - sayHi : function() { return 'hi: ' + this.name; }, + sayHi: function() { return 'hi: ' + this.name; }, sayLast: function() { return this.sayHi(_.last(arguments)); } }; diff --git a/test/objects.js b/test/objects.js index af8a1f1ea..2aa19db76 100644 --- a/test/objects.js +++ b/test/objects.js @@ -18,17 +18,17 @@ // keys that may be missed if the implementation isn't careful var trouble = { - constructor : Object, - valueOf : _.noop, - hasOwnProperty : null, - toString : 5, - toLocaleString : void 0, + constructor: Object, + valueOf: _.noop, + hasOwnProperty: null, + toString: 5, + toLocaleString: void 0, propertyIsEnumerable: /a/, - isPrototypeOf : this, - __defineGetter__ : Boolean, - __defineSetter__ : {}, - __lookupSetter__ : false, - __lookupGetter__ : [] + isPrototypeOf: this, + __defineGetter__: Boolean, + __defineSetter__: {}, + __lookupSetter__: false, + __lookupGetter__: [] }; var troubleKeys = ['constructor', 'valueOf', 'hasOwnProperty', 'toString', 'toLocaleString', 'propertyIsEnumerable', 'isPrototypeOf', '__defineGetter__', '__defineSetter__', '__lookupSetter__', '__lookupGetter__'].sort(); @@ -50,13 +50,13 @@ // allKeys that may be missed if the implementation isn't careful var trouble = { - constructor : Object, - valueOf : _.noop, - hasOwnProperty : null, - toString : 5, - toLocaleString : void 0, + constructor: Object, + valueOf: _.noop, + hasOwnProperty: null, + toString: 5, + toLocaleString: void 0, propertyIsEnumerable: /a/, - isPrototypeOf : this + isPrototypeOf: this }; var troubleKeys = ['constructor', 'valueOf', 'hasOwnProperty', 'toString', 'toLocaleString', 'propertyIsEnumerable', 'isPrototypeOf'].sort(); @@ -444,14 +444,14 @@ // `A` contains nested objects and arrays. a = { - name : new String('Moe Howard'), - age : new Number(77), - stooge : true, + name: new String('Moe Howard'), + age: new Number(77), + stooge: true, hobbies: ['acting'], - film : { - name : 'Sing a Song of Six Pants', + film: { + name: 'Sing a Song of Six Pants', release: new Date(1947, 9, 30), - stars : [new String('Larry Fine'), 'Shemp Howard'], + stars: [new String('Larry Fine'), 'Shemp Howard'], minutes: new Number(16), seconds: 54 } @@ -459,14 +459,14 @@ // `B` contains equivalent nested objects and arrays. b = { - name : new String('Moe Howard'), - age : new Number(77), - stooge : true, + name: new String('Moe Howard'), + age: new Number(77), + stooge: true, hobbies: ['acting'], - film : { - name : 'Sing a Song of Six Pants', + film: { + name: 'Sing a Song of Six Pants', release: new Date(1947, 9, 30), - stars : [new String('Larry Fine'), 'Shemp Howard'], + stars: [new String('Larry Fine'), 'Shemp Howard'], minutes: new Number(16), seconds: 54 } diff --git a/test/utility.js b/test/utility.js index 31746cc08..c20f33a24 100644 --- a/test/utility.js +++ b/test/utility.js @@ -182,7 +182,7 @@ var namespaceCollisionTemplate = _.template('<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %><% }); %>'); result = namespaceCollisionTemplate({ - pageCount : 3, + pageCount: 3, thumbnails: { 1: 'p1-thumbnail.gif', 2: 'p2-thumbnail.gif', @@ -211,7 +211,7 @@ equal(result, '<script>'); var stooge = { - name : 'Moe', + name: 'Moe', template: _.template("I'm <%= this.name %>") }; equal(stooge.template(), "I'm Moe"); @@ -225,7 +225,7 @@ equal(template({data: 12345}).replace(/\s/g, ''), ' 24690 '); _.templateSettings = { - evaluate : /\{\{([\s\S]+?)\}\}/g, + evaluate: /\{\{([\s\S]+?)\}\}/g, interpolate: /\{\{=([\s\S]+?)\}\}/g }; @@ -240,7 +240,7 @@ equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'."); _.templateSettings = { - evaluate : /<\?([\s\S]+?)\?>/g, + evaluate: /<\?([\s\S]+?)\?>/g, interpolate: /<\?=([\s\S]+?)\?>/g }; diff --git a/underscore.js b/underscore.js index cbf33c45f..30365ab02 100644 --- a/underscore.js +++ b/underscore.js @@ -384,8 +384,8 @@ iteratee = cb(iteratee, context); return _.pluck(_.map(obj, function(value, index, list) { return { - value : value, - index : index, + value: value, + index: index, criteria: iteratee(value, index, list) }; }).sort(function(left, right) { @@ -1423,9 +1423,9 @@ // By default, Underscore uses ERB-style template delimiters, change the // following template settings to use alternative delimiters. _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, + evaluate: /<%([\s\S]+?)%>/g, interpolate: /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g + escape: /<%-([\s\S]+?)%>/g }; // When customizing `templateSettings`, if you don't want to define an @@ -1436,10 +1436,10 @@ // Certain characters need to be escaped so that they can be put into a // string literal. var escapes = { - "'" : "'", - '\\' : '\\', - '\r' : 'r', - '\n' : 'n', + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', '\u2028': 'u2028', '\u2029': 'u2029' }; From d36d0da4988c5125aa5c293775951ee3490a7e1e Mon Sep 17 00:00:00 2001 From: Justin RidgewellDate: Wed, 27 May 2015 13:10:06 -0400 Subject: [PATCH 036/263] Remove nativeBind usage We cover almost all of nativeBind's cases: - Binding function to context - Binding function to context with args - Binding constructor with args The only downside is supported environments will no longer get the correct `length` property of the bound method. Usually, you subtract the number of bound args from `func`'s length. But, now Underscore is consistent between all environments. --- underscore.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/underscore.js b/underscore.js index 30365ab02..0f680e47b 100644 --- a/underscore.js +++ b/underscore.js @@ -17,7 +17,7 @@ var previousUnderscore = root._; // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + var ArrayProto = Array.prototype, ObjProto = Object.prototype; // Create quick reference variables for speed access to core prototypes. var @@ -31,7 +31,6 @@ var nativeIsArray = Array.isArray, nativeKeys = Object.keys, - nativeBind = FuncProto.bind, nativeCreate = Object.create; // Naked function reference for surrogate-prototype-swapping. @@ -711,15 +710,13 @@ // Create a function bound to a given object (assigning `this`, and arguments, // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if // available. - _.bind = function(func, context) { - if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + _.bind = restArgs(function(func, context, args) { if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); - var args = slice.call(arguments, 2); var bound = restArgs(function(callArgs) { return executeBound(func, bound, context, this, args.concat(callArgs)); }); return bound; - }; + }); // Partially apply a function by creating a version that has had some of its // arguments pre-filled, without changing its dynamic `this` context. _ acts From 66d61e8a5b82a5daa61f07fb3da240b0f194abc8 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 29 May 2015 16:56:02 -0400 Subject: [PATCH 037/263] Remove native #reduceRight reference --- index.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.html b/index.html index f0624544c..b3b80bd2c 100644 --- a/index.html +++ b/index.html @@ -514,8 +514,7 @@ Collection Functions (Arrays or Objects)
reduceRight_.reduceRight(list, iteratee, memo, [context])
Alias: foldr
- The right-associative version of reduce. Delegates to the - JavaScript 1.8 version of reduceRight, if it exists. Foldr + The right-associative version of reduce. Foldr is not as useful in JavaScript as it would be in a language with lazy evaluation. From 427fa965f8f322b43433079fb3578f30c7f7305e Mon Sep 17 00:00:00 2001 From: Erik BernhardssonDate: Fri, 29 May 2015 10:29:47 -0400 Subject: [PATCH 038/263] Avoid array creation in recursive flatten fixes #2202 If you have a n=1000 deeply nested array with k=1000 elements in the leaf node then it would be copied n times leading to O(n*k). After this fix, it will take O(n+k) --- test/arrays.js | 5 +++++ underscore.js | 16 +++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index b8903d3ea..d41a019e3 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -98,6 +98,11 @@ equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23); equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'Flatten can handle massive collections'); equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'Flatten can handle massive collections'); + + var x = _.range(100000); + for (var i = 0; i < 1000; i++) x = [x]; + deepEqual(_.flatten(x), _.range(100000), 'Flatten can handle very deep arrays'); + deepEqual(_.flatten(x, true), x[0], 'Flatten can handle very deep arrays with shallow'); }); test('without', function() { diff --git a/underscore.js b/underscore.js index 0f680e47b..c8d534b10 100644 --- a/underscore.js +++ b/underscore.js @@ -490,17 +490,19 @@ }; // Internal implementation of a recursive `flatten` function. - var flatten = function(input, shallow, strict) { - var output = [], idx = 0; + var flatten = function(input, shallow, strict, output) { + output = output || []; + var idx = output.length; for (var i = 0, length = getLength(input); i < length; i++) { var value = input[i]; if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { //flatten current level of array or arguments object - if (!shallow) value = flatten(value, shallow, strict); - var j = 0, len = value.length; - output.length += len; - while (j < len) { - output[idx++] = value[j++]; + if (shallow) { + var j = 0, len = value.length; + while (j < len) output[idx++] = value[j++]; + } else { + flatten(value, shallow, strict, output); + idx = output.length; } } else if (!strict) { output[idx++] = value; From d04b7e9cf10c6909ee5e74eaef8cc1177c80d1c3 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Sun, 24 May 2015 23:42:51 -0700 Subject: [PATCH 039/263] Addes coverage with nyc and coveralls Closes #2191 --- .gitignore | 2 ++ .travis.yml | 3 ++- package.json | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2c7f8be2f..ab5b5c583 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ node_modules *.log *.idea *.swp +nyc_output +coverage diff --git a/.travis.yml b/.travis.yml index 07d33cc8a..d19cf6e8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,4 +29,5 @@ env: global: - secure: bDZSBQfqr21hCayjcZ20IxrV6+XGhxQPFIfwWqEKLrF93Gu8LLVjZRxXE/mE8I8N4Z5WtDNb4ZHrm/TTzmcPa5MuHgIxEdknQCncobH8oimwc83SHwEPk6okeNKl39VlCjvvnmoe/V/KpnknuYn3Rqghtl/Uv9KLpCwskwjTtcw= - secure: SRECgXuwcZTcD3GVxTS2bYNgRyye4vq6BLrV2PH9FyNenowsKQR2EwlC/dppc1Q8NWMgv79J/R96q9JOFh+mEH9L5dlBb2yhnGH8amVeM/ChAJHT/F8YktKM453uVpz5fR00QcCQDDUOx6Pvx374ID0OKNpWKAkQBWA9mPTsLnE= - matrix: BROWSER=false \ No newline at end of file + matrix: BROWSER=false +after_success: npm run coveralls diff --git a/package.json b/package.json index f1ad720da..9bcfb0fc0 100644 --- a/package.json +++ b/package.json @@ -17,15 +17,19 @@ "main": "underscore.js", "version": "1.8.3", "devDependencies": { + "coveralls": "^2.11.2", "docco": "*", "eslint": "0.21.x", "karma": "~0.12.31", "karma-qunit": "~0.1.4", + "nyc": "^2.1.3", "qunit-cli": "~0.2.0", "uglify-js": "2.4.x" }, "scripts": { "test": "npm run test-node && npm run lint", + "coverage": "nyc npm run test-node && nyc report", + "coveralls": "nyc npm run test-node && nyc report --reporter=text-lcov | coveralls", "lint": "eslint --reset underscore.js test/*.js", "test-node": "qunit-cli test/*.js", "test-browser": "npm i karma-phantomjs-launcher && ./node_modules/karma/bin/karma start", From 4a4a94a4f9b85dd384e339af0c5f2741147882e2 Mon Sep 17 00:00:00 2001 From: Kevin Kirsche Date: Wed, 10 Jun 2015 18:25:49 -0400 Subject: [PATCH 040/263] Remove moot `version` property from bower.json Per bower/bower.json-spec@a325da3 --- bower.json | 1 - 1 file changed, 1 deletion(-) diff --git a/bower.json b/bower.json index c7b885334..951eabb18 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,5 @@ { "name": "underscore", - "version": "1.8.3", "main": "underscore.js", "keywords": ["util", "functional", "server", "client", "browser"], "ignore" : ["docs", "test", "*.yml", "CNAME", "index.html", "favicon.ico", "CONTRIBUTING.md", ".*", "component.json", "package.json", "karma.*"] From 1f19b943d3c868a7996b72e4c6f5cd80f3bc6dd6 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Fri, 12 Jun 2015 00:04:47 +0100 Subject: [PATCH 041/263] Extend max, min to return max/min of multple arrays --- test/collections.js | 4 ++++ underscore.js | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/collections.js b/test/collections.js index 2faccbafc..d25e9d0fa 100644 --- a/test/collections.js +++ b/test/collections.js @@ -564,6 +564,8 @@ equal(3, _.max([1, 2, 3, 'test']), 'Finds correct max in array starting with num and containing a NaN'); equal(3, _.max(['test', 1, 2, 3]), 'Finds correct max in array starting with NaN'); + deepEqual([3, 6], _.map([[1, 2, 3], [4, 5, 6]], _.max), 'Finds correct max in array when mapping through multiple arrays'); + var a = {x: -Infinity}; var b = {x: -Infinity}; var iterator = function(o){ return o.x; }; @@ -590,6 +592,8 @@ equal(Infinity, _.min([]), 'Minimum value of an empty array'); equal(_.min({a: 'a'}), Infinity, 'Minimum value of a non-numeric collection'); + deepEqual([1, 4], _.map([[1, 2, 3], [4, 5, 6]], _.min), 'Finds correct min in array when mapping through multiple arrays'); + var now = new Date(9999999999); var then = new Date(0); equal(_.min([now, then]), then); diff --git a/underscore.js b/underscore.js index c8d534b10..1f5f47050 100644 --- a/underscore.js +++ b/underscore.js @@ -305,7 +305,7 @@ _.max = function(obj, iteratee, context) { var result = -Infinity, lastComputed = -Infinity, value, computed; - if (iteratee == null && obj != null) { + if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) { obj = isArrayLike(obj) ? obj : _.values(obj); for (var i = 0, length = obj.length; i < length; i++) { value = obj[i]; @@ -330,7 +330,7 @@ _.min = function(obj, iteratee, context) { var result = Infinity, lastComputed = Infinity, value, computed; - if (iteratee == null && obj != null) { + if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) { obj = isArrayLike(obj) ? obj : _.values(obj); for (var i = 0, length = obj.length; i < length; i++) { value = obj[i]; From 094edb7ce5192306a90f24dbb74dd4d165aa586a Mon Sep 17 00:00:00 2001 From: Jeff Long Date: Fri, 26 Jun 2015 14:47:23 -0500 Subject: [PATCH 042/263] Fix typo in comment Noticed a small typo while checking something in the source. s/offest/offset --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index c8d534b10..5d96f46b8 100644 --- a/underscore.js +++ b/underscore.js @@ -1479,7 +1479,7 @@ source += "';\n" + evaluate + "\n__p+='"; } - // Adobe VMs need the match returned to produce the correct offest. + // Adobe VMs need the match returned to produce the correct offset. return match; }); source += "';\n"; From 6567011ea1f3d7c0bf26571744020e39d4072a60 Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Wed, 1 Jul 2015 11:47:13 -0400 Subject: [PATCH 043/263] Minor restArgs style tweak --- underscore.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/underscore.js b/underscore.js index 5d96f46b8..695153aa6 100644 --- a/underscore.js +++ b/underscore.js @@ -102,8 +102,7 @@ return function() { var length = Math.max(arguments.length - startIndex, 0); var rest = Array(length); - var index; - for (index = 0; index < length; index++) { + for (var index = 0; index < length; index++) { rest[index] = arguments[index + startIndex]; } switch (startIndex) { From 7fc15e5816dc02371517c4cb16a28e35f5b9a857 Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Wed, 24 Jun 2015 11:59:22 -0400 Subject: [PATCH 044/263] Ensure underscore can be run in a Node VM --- test/utility.js | 31 +++++++++++++++++++++++++++++++ underscore.js | 8 +++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/test/utility.js b/test/utility.js index c20f33a24..61c0347a4 100644 --- a/test/utility.js +++ b/test/utility.js @@ -14,6 +14,37 @@ }); + if (typeof this == 'object') { + test('noConflict', function() { + var underscore = _.noConflict(); + equal(underscore.identity(1), 1); + if (typeof require != 'function') { + equal(this._, void 0, 'global underscore is removed'); + this._ = underscore; + } + }); + } + + if (typeof require == 'function') { + asyncTest('noConflict (node vm)', 2, function() { + var fs = require('fs'); + var vm = require('vm'); + var filename = __dirname + '/../underscore.js'; + fs.readFile(filename, function(err, content){ + var sandbox = vm.createScript( + content + 'this.underscore = this._.noConflict();', + filename + ); + var context = {_: 'oldvalue'}; + sandbox.runInNewContext(context); + equal(context._, 'oldvalue'); + equal(context.underscore.VERSION, _.VERSION); + + start(); + }); + }); + } + test('#750 - Return _ instance.', 2, function() { var instance = _([]); ok(_(instance) === instance); diff --git a/underscore.js b/underscore.js index c8d534b10..387b196c6 100644 --- a/underscore.js +++ b/underscore.js @@ -8,10 +8,12 @@ // Baseline setup // -------------- - // Establish the root object, `window` (`self`) in the browser, or `global` on the server. - // We use `self` instead of `window` for `WebWorker` support. + // Establish the root object, `window` (`self`) in the browser, `global` + // on the server, or `this` in some virtual machines. We use `self` + // instead of `window` for `WebWorker` support. var root = typeof self === 'object' && self.self === self && self || - typeof global === 'object' && global.global === global && global; + typeof global === 'object' && global.global === global && global || + this; // Save the previous value of the `_` variable. var previousUnderscore = root._; From 95068507c3930f53cf828477c53fd8a3469f3307 Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Sun, 5 Jul 2015 20:56:10 -0400 Subject: [PATCH 045/263] Remove unused optimizeCb case --- underscore.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/underscore.js b/underscore.js index 1413d1421..bd237ce3c 100644 --- a/underscore.js +++ b/underscore.js @@ -69,9 +69,6 @@ case 1: return function(value) { return func.call(context, value); }; - case 2: return function(value, other) { - return func.call(context, value, other); - }; case 3: return function(value, index, collection) { return func.call(context, value, index, collection); }; From acf826fa42ba65d42c7e5cccd78ea3a7876c8032 Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Mon, 6 Jul 2015 07:58:55 -0700 Subject: [PATCH 046/263] add comment about 2-parameter case omission in optimizeCb function --- underscore.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/underscore.js b/underscore.js index bd237ce3c..7eefdb340 100644 --- a/underscore.js +++ b/underscore.js @@ -69,6 +69,8 @@ case 1: return function(value) { return func.call(context, value); }; + // The 2-parameter case has been omitted only because no current consumers + // made use of it. case 3: return function(value, index, collection) { return func.call(context, value, index, collection); }; From 1d65f77a8beff2eb8ae673bd9da47768acf2b796 Mon Sep 17 00:00:00 2001 From: Andrew Lewis Date: Thu, 9 Jul 2015 20:18:34 -0400 Subject: [PATCH 047/263] _.defaults() does not initialize for undefined/null --- test/objects.js | 4 ++-- underscore.js | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/objects.js b/test/objects.js index 2aa19db76..92e66df80 100644 --- a/test/objects.js +++ b/test/objects.js @@ -262,8 +262,8 @@ equal(options.a, 1, 'should not error on `null` or `undefined` sources'); - strictEqual(_.defaults(null, {a: 1}), null, 'result is null if destination is null'); - strictEqual(_.defaults(void 0, {a: 1}), void 0, 'result is undefined if destination is undefined'); + deepEqual(_.defaults(null, {a: 1}), {a: 1}, 'defaults skips nulls'); + deepEqual(_.defaults(void 0, {a: 1}), {a: 1}, 'defaults skips undefined'); }); test('clone', function() { diff --git a/underscore.js b/underscore.js index bea6d0ac5..188f20968 100644 --- a/underscore.js +++ b/underscore.js @@ -1008,9 +1008,10 @@ }; // An internal function for creating assigner functions. - var createAssigner = function(keysFunc, undefinedOnly) { + var createAssigner = function(keysFunc, defaults) { return function(obj) { var length = arguments.length; + if (defaults) obj = Object(obj); if (length < 2 || obj == null) return obj; for (var index = 1; index < length; index++) { var source = arguments[index], @@ -1018,7 +1019,7 @@ l = keys.length; for (var i = 0; i < l; i++) { var key = keys[i]; - if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; + if (!defaults || obj[key] === void 0) obj[key] = source[key]; } } return obj; From 10026ebb7eb71db62c89cd76eb5054ce56240958 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 12 Jul 2015 20:37:32 -0400 Subject: [PATCH 048/263] Fix isFunction for PhantomJS's NodeLists https://github.com/jashkenas/underscore/pull/2233#issuecomment-120677098 --- test/objects.js | 5 +++++ underscore.js | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/objects.js b/test/objects.js index 2aa19db76..f7f71cbbe 100644 --- a/test/objects.js +++ b/test/objects.js @@ -668,6 +668,11 @@ if (testElement) { ok(!_.isFunction(testElement), 'elements are not functions'); } + + var nodelist = typeof document != 'undefined' && document.childNodes; + if (nodelist) { + ok(!_.isFunction(nodelist)); + } }); if (typeof Int8Array !== 'undefined') { diff --git a/underscore.js b/underscore.js index bea6d0ac5..35d2e05d8 100644 --- a/underscore.js +++ b/underscore.js @@ -1271,8 +1271,9 @@ } // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, - // IE 11 (#1621), and in Safari 8 (#1929). - if (typeof /./ != 'function' && typeof Int8Array != 'object') { + // IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236). + var nodelist = root.document && root.document.childNodes; + if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') { _.isFunction = function(obj) { return typeof obj == 'function' || false; }; From 30bc324a272197e92c5f47e68adade55f9739914 Mon Sep 17 00:00:00 2001 From: Adam Krebs Date: Wed, 15 Jul 2015 16:41:20 -0400 Subject: [PATCH 049/263] Fix _.unzip example. Closes #2238 --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index b3b80bd2c..08ee8e7b9 100644 --- a/index.html +++ b/index.html @@ -975,8 +975,8 @@ Array Functions
and so on.-_.unzip([["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]); -=> [['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]] +_.unzip([['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]]) +=> ["moe", 30, true], ["larry", 40, false], ["curly", 50, false]From 533ecbca5b9250c6b37f8b7b098cb4dff549e9bc Mon Sep 17 00:00:00 2001 From: John-David Dalton
Date: Wed, 22 Jul 2015 11:06:44 -0700 Subject: [PATCH 050/263] Fix #2242; add qunit dependency. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 9bcfb0fc0..b2bc6eda1 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "karma-qunit": "~0.1.4", "nyc": "^2.1.3", "qunit-cli": "~0.2.0", + "qunitjs": "^1.18.0", "uglify-js": "2.4.x" }, "scripts": { From 90a49f3407487fde518ce18eb6986bd20eab5fdf Mon Sep 17 00:00:00 2001 From: Xue Hu Date: Fri, 24 Jul 2015 16:25:11 -0700 Subject: [PATCH 051/263] Clarify _.every documentation --- index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 08ee8e7b9..cd1725aa0 100644 --- a/index.html +++ b/index.html @@ -597,7 +597,8 @@ Collection Functions (Arrays or Objects)
Alias: all
Returns true if all of the values in the list pass the - predicate truth test. + predicate truth test. Short-circuits and stops traversing the list + if a false element is found._.every([true, 1, null, 'yes'], _.identity); From 4d9582350a7490db3fef5fa6bc0c889d6c9da7b3 Mon Sep 17 00:00:00 2001 From: Petr Archakov" + "Date: Wed, 5 Nov 2014 11:48:08 +0100 Subject: [PATCH 052/263] Add _.chunk to Array functions. fix _.chunk function fix _.chunk function Do not return original array if chunkin in more then array size parts Do not return original array if chunkin in more then array size parts spaces clean up --- test/arrays.js | 16 +++++++++++++++- underscore.js | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/test/arrays.js b/test/arrays.js index d41a019e3..01b6f9a6d 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -538,5 +538,19 @@ deepEqual(_.range(12, 7, -2), [12, 10, 8], 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b'); deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs'); }); - + + test('chunk', function() { + deepEqual(_.chunk([], 2), [], 'chunk for empty array returns an empty array'); + deepEqual(_.chunk(null, 2), [], 'chunk for null returns an empty array'); + + deepEqual(_.chunk([1, 2, 3], 0), [], 'chunk into parts of 0 elements returns an empty array'); + deepEqual(_.chunk([1, 2, 3], -1), [], 'chunk into parts of negative amount of elements returns an empty array'); + + deepEqual(_.chunk([1, 2, 3], 3), [[1, 2, 3]], 'chunk into parts of current array length elements returns the original array'); + deepEqual(_.chunk([1, 2, 3], 5), [[1, 2, 3]], 'chunk into parts of more then current array length elements returns the original array'); + + deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 2), [[10, 20], [30, 40], [50, 60], [70]], 'chunk into parts of less then current array length elements'); + deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 3), [[10, 20, 30], [40, 50, 60], [70]], 'chunk into parts of less then current array length elements'); + }); + }()); diff --git a/underscore.js b/underscore.js index 35d2e05d8..03a0c7037 100644 --- a/underscore.js +++ b/underscore.js @@ -696,6 +696,20 @@ return range; }; + // Split an **array** into several arrays containing **count** or less elements + // of initial array + _.chunk = function(array, count) { + var result = []; + + if (array == null || count <= 0) return []; + + for (var i = 0, length = array.length; i < length;) { + result.push(array.slice(i, i += count)); + } + + return result; + }; + // Function (ahem) Functions // ------------------ From b221fe734e18a26163726c9f3bc27340e1e8f864 Mon Sep 17 00:00:00 2001 From: Petr Archakov Date: Mon, 13 Apr 2015 11:36:26 +0200 Subject: [PATCH 053/263] chunk(): set default parts to 1 --- test/arrays.js | 18 ++++++++++-------- underscore.js | 11 ++++++----- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 01b6f9a6d..95190daf5 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -538,19 +538,21 @@ deepEqual(_.range(12, 7, -2), [12, 10, 8], 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b'); deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs'); }); - + test('chunk', function() { deepEqual(_.chunk([], 2), [], 'chunk for empty array returns an empty array'); - deepEqual(_.chunk(null, 2), [], 'chunk for null returns an empty array'); - - deepEqual(_.chunk([1, 2, 3], 0), [], 'chunk into parts of 0 elements returns an empty array'); - deepEqual(_.chunk([1, 2, 3], -1), [], 'chunk into parts of negative amount of elements returns an empty array'); - + + deepEqual(_.chunk([1, 2, 3], 0), [1, 2, 3], 'chunk into parts of 0 elements returns original array'); + + deepEqual(_.chunk([1, 2, 3], 1), [1, 2, 3], 'chunk into parts of 1 elements returns original array'); + deepEqual(_.chunk([1, 2, 3]), [1, 2, 3], 'chunk into parts of 1 elements is default value and returns original array'); + + deepEqual(_.chunk([1, 2, 3], -1), [1, 2, 3], 'chunk into parts of negative amount of elements returns an empty array'); + deepEqual(_.chunk([1, 2, 3], 3), [[1, 2, 3]], 'chunk into parts of current array length elements returns the original array'); deepEqual(_.chunk([1, 2, 3], 5), [[1, 2, 3]], 'chunk into parts of more then current array length elements returns the original array'); - + deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 2), [[10, 20], [30, 40], [50, 60], [70]], 'chunk into parts of less then current array length elements'); deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 3), [[10, 20, 30], [40, 50, 60], [70]], 'chunk into parts of less then current array length elements'); }); - }()); diff --git a/underscore.js b/underscore.js index 03a0c7037..2cf5ceef8 100644 --- a/underscore.js +++ b/underscore.js @@ -699,12 +699,13 @@ // Split an **array** into several arrays containing **count** or less elements // of initial array _.chunk = function(array, count) { - var result = []; - - if (array == null || count <= 0) return []; + count = +count || 1; + if (count <= 1) return slice.call(array); - for (var i = 0, length = array.length; i < length;) { - result.push(array.slice(i, i += count)); + var result = []; + var i = 0, length = array.length; + while (i < length) { + result.push(slice.call(array, i, i += count)); } return result; From 4415d62d6b0fa34af1f3da0b0ebd708da8f93977 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 28 Jul 2015 08:16:13 -0700 Subject: [PATCH 054/263] Ensure `_.sortBy` stable sorts when iterating an object. --- test/collections.js | 15 +++++++++++---- underscore.js | 7 ++++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/test/collections.js b/test/collections.js index d25e9d0fa..485eb0ce8 100644 --- a/test/collections.js +++ b/test/collections.js @@ -632,7 +632,7 @@ this.y = y; } - var collection = [ + var stableArray = [ new Pair(1, 1), new Pair(1, 2), new Pair(1, 3), new Pair(1, 4), new Pair(1, 5), new Pair(1, 6), @@ -644,13 +644,20 @@ new Pair(void 0, 5), new Pair(void 0, 6) ]; - var actual = _.sortBy(collection, function(pair) { + var stableObject = _.object('abcdefghijklmnopqr'.split(''), stableArray); + + var actual = _.sortBy(stableArray, function(pair) { return pair.x; }); - deepEqual(actual, collection, 'sortBy should be stable'); + deepEqual(actual, stableArray, 'sortBy should be stable for arrays'); + deepEqual(_.sortBy(stableArray, 'x'), stableArray, 'sortBy accepts property string'); + + actual = _.sortBy(stableObject, function(pair) { + return pair.x; + }); - deepEqual(_.sortBy(collection, 'x'), collection, 'sortBy accepts property string'); + deepEqual(actual, stableArray, 'sortBy should be stable for objects'); list = ['q', 'w', 'e', 'r', 't', 'y']; deepEqual(_.sortBy(list), ['e', 'q', 'r', 't', 'w', 'y'], 'uses _.identity if iterator is not specified'); diff --git a/underscore.js b/underscore.js index 35d2e05d8..8ef56d251 100644 --- a/underscore.js +++ b/underscore.js @@ -380,12 +380,13 @@ // Sort the object's values by a criterion produced by an iteratee. _.sortBy = function(obj, iteratee, context) { + var index = 0; iteratee = cb(iteratee, context); - return _.pluck(_.map(obj, function(value, index, list) { + return _.pluck(_.map(obj, function(value, key, list) { return { value: value, - index: index, - criteria: iteratee(value, index, list) + index: index++, + criteria: iteratee(value, key, list) }; }).sort(function(left, right) { var a = left.criteria; From 97dee1323b34ba6a0a1aa672241e13603458a2bb Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Tue, 28 Jul 2015 12:21:15 -0400 Subject: [PATCH 055/263] Enforce 1 being the minimal chunk size #1919 --- test/arrays.js | 9 ++++----- underscore.js | 4 +--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 95190daf5..5b52ad433 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -542,12 +542,11 @@ test('chunk', function() { deepEqual(_.chunk([], 2), [], 'chunk for empty array returns an empty array'); - deepEqual(_.chunk([1, 2, 3], 0), [1, 2, 3], 'chunk into parts of 0 elements returns original array'); + deepEqual(_.chunk([1, 2, 3], 0), [], 'chunk into parts of 0 elements returns empty array'); + deepEqual(_.chunk([1, 2, 3], -1), [], 'chunk into parts of negative amount of elements returns an empty array'); + deepEqual(_.chunk([1, 2, 3]), [], 'defaults to empty array (chunk size 0)'); - deepEqual(_.chunk([1, 2, 3], 1), [1, 2, 3], 'chunk into parts of 1 elements returns original array'); - deepEqual(_.chunk([1, 2, 3]), [1, 2, 3], 'chunk into parts of 1 elements is default value and returns original array'); - - deepEqual(_.chunk([1, 2, 3], -1), [1, 2, 3], 'chunk into parts of negative amount of elements returns an empty array'); + deepEqual(_.chunk([1, 2, 3], 1), [[1], [2], [3]], 'chunk into parts of 1 elements returns original array'); deepEqual(_.chunk([1, 2, 3], 3), [[1, 2, 3]], 'chunk into parts of current array length elements returns the original array'); deepEqual(_.chunk([1, 2, 3], 5), [[1, 2, 3]], 'chunk into parts of more then current array length elements returns the original array'); diff --git a/underscore.js b/underscore.js index 2cf5ceef8..4ff6a4811 100644 --- a/underscore.js +++ b/underscore.js @@ -699,15 +699,13 @@ // Split an **array** into several arrays containing **count** or less elements // of initial array _.chunk = function(array, count) { - count = +count || 1; - if (count <= 1) return slice.call(array); + if (count == null || count < 1) return []; var result = []; var i = 0, length = array.length; while (i < length) { result.push(slice.call(array, i, i += count)); } - return result; }; From 72caece9eef35149b1dee0478198703307bfd881 Mon Sep 17 00:00:00 2001 From: Damon Hunt Date: Mon, 3 Aug 2015 17:28:24 +0800 Subject: [PATCH 056/263] Fixes _.isNaN for wrapped numbers --- test/objects.js | 1 + underscore.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/objects.js b/test/objects.js index 1788ae4e1..850b328cf 100644 --- a/test/objects.js +++ b/test/objects.js @@ -719,6 +719,7 @@ ok(!_.isNaN(void 0), 'undefined is not NaN'); ok(!_.isNaN(null), 'null is not NaN'); ok(!_.isNaN(0), '0 is not NaN'); + ok(!_.isNaN(new Number(0)), 'wrapped 0 is not NaN'); ok(_.isNaN(NaN), 'but NaN is'); ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN'); }); diff --git a/underscore.js b/underscore.js index e9cdbde23..2db4b6179 100644 --- a/underscore.js +++ b/underscore.js @@ -1301,7 +1301,7 @@ // Is the given value `NaN`? (NaN is the only number which does not equal itself). _.isNaN = function(obj) { - return _.isNumber(obj) && obj !== +obj; + return _.isNumber(obj) && obj != +obj; }; // Is a given value a boolean? From de6f16527f5f85e864b53f013e1cd0ddb13e263e Mon Sep 17 00:00:00 2001 From: Damon Hunt Date: Mon, 3 Aug 2015 20:52:23 +0800 Subject: [PATCH 057/263] Fixes _.isNaN for wrapped numbers with isNaN --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 2db4b6179..92debf96d 100644 --- a/underscore.js +++ b/underscore.js @@ -1301,7 +1301,7 @@ // Is the given value `NaN`? (NaN is the only number which does not equal itself). _.isNaN = function(obj) { - return _.isNumber(obj) && obj != +obj; + return _.isNumber(obj) && isNaN(obj); }; // Is a given value a boolean? From 0baa80709370e507d2c3d8a8724864788cec96d3 Mon Sep 17 00:00:00 2001 From: Jon Abrams Date: Mon, 3 Aug 2015 22:41:52 -0700 Subject: [PATCH 058/263] Fixes out of date comment on _.isNaN --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 92debf96d..d513b47b6 100644 --- a/underscore.js +++ b/underscore.js @@ -1299,7 +1299,7 @@ return isFinite(obj) && !isNaN(parseFloat(obj)); }; - // Is the given value `NaN`? (NaN is the only number which does not equal itself). + // Is the given value `NaN`? _.isNaN = function(obj) { return _.isNumber(obj) && isNaN(obj); }; From 7ee7064eb27b7cd7b247345e20031db53d71be3c Mon Sep 17 00:00:00 2001 From: Matthew Hasbach Date: Thu, 6 Aug 2015 06:06:30 -0400 Subject: [PATCH 059/263] Remove LICENSE from package.json files array. NPM includes LICENSE automatically. https://docs.npmjs.com/files/package.json#files --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index b2bc6eda1..2c39f4339 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "files": [ "underscore.js", "underscore-min.js", - "underscore-min.map", - "LICENSE" + "underscore-min.map" ] } From 5edc6b288eaedf9a40d32044de55014304fcd188 Mon Sep 17 00:00:00 2001 From: Dennis Lin Date: Fri, 7 Aug 2015 13:27:19 -0700 Subject: [PATCH 060/263] Add a navigational link to the sidebar for _.isError `_.isError` is documented but not in the sidebar. --- index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/index.html b/index.html index cd1725aa0..a657cab36 100644 --- a/index.html +++ b/index.html @@ -307,6 +307,7 @@ - isBoolean - isDate - isRegExp +- isError - isNaN - isNull - isUndefined From 327e9812a592b5f5dcad7ffbee455c126d15aa84 Mon Sep 17 00:00:00 2001 From: John-David DaltonDate: Sat, 8 Aug 2015 14:45:58 -0700 Subject: [PATCH 061/263] Remove duplicated test block. --- test/objects.js | 57 ------------------------------------------------- 1 file changed, 57 deletions(-) diff --git a/test/objects.js b/test/objects.js index 850b328cf..066264c2b 100644 --- a/test/objects.js +++ b/test/objects.js @@ -879,63 +879,6 @@ deepEqual(_.map([null, void 0, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); }); - test('matcher', function() { - var moe = {name: 'Moe Howard', hair: true}; - var curly = {name: 'Curly Howard', hair: false}; - var stooges = [moe, curly]; - - equal(_.matcher({hair: true})(moe), true, 'Returns a boolean'); - equal(_.matcher({hair: true})(curly), false, 'Returns a boolean'); - - equal(_.matcher({__x__: void 0})(5), false, 'can match undefined props on primitives'); - equal(_.matcher({__x__: void 0})({__x__: void 0}), true, 'can match undefined props'); - - equal(_.matcher({})(null), true, 'Empty spec called with null object returns true'); - equal(_.matcher({a: 1})(null), false, 'Non-empty spec called with null object returns false'); - - ok(_.find(stooges, _.matcher({hair: false})) === curly, 'returns a predicate that can be used by finding functions.'); - ok(_.find(stooges, _.matcher(moe)) === moe, 'can be used to locate an object exists in a collection.'); - deepEqual(_.where([null, void 0], {a: 1}), [], 'Do not throw on null values.'); - - deepEqual(_.where([null, void 0], null), [null, void 0], 'null matches null'); - deepEqual(_.where([null, void 0], {}), [null, void 0], 'null matches {}'); - deepEqual(_.where([{b: 1}], {a: void 0}), [], 'handles undefined values (1683)'); - - _.each([true, 5, NaN, null, void 0], function(item) { - deepEqual(_.where([{a: 1}], item), [{a: 1}], 'treats primitives as empty'); - }); - - function Prototest() {} - Prototest.prototype.x = 1; - var specObj = new Prototest; - var protospec = _.matcher(specObj); - equal(protospec({x: 2}), true, 'spec is restricted to own properties'); - - specObj.y = 5; - protospec = _.matcher(specObj); - equal(protospec({x: 1, y: 5}), true); - equal(protospec({x: 1, y: 4}), false); - - ok(_.matcher({x: 1, y: 5})(specObj), 'inherited and own properties are checked on the test object'); - - Prototest.x = 5; - ok(_.matcher(Prototest)({x: 5, y: 1}), 'spec can be a function'); - - // #1729 - var o = {b: 1}; - var m = _.matcher(o); - - equal(m({b: 1}), true); - o.b = 2; - o.a = 1; - equal(m({b: 1}), true, 'changing spec object doesnt change matches result'); - - - //null edge cases - var oCon = _.matcher({constructor: Object}); - deepEqual(_.map([null, void 0, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); - }); - test('findKey', function() { var objects = { a: {a: 0, b: 0}, From cabbb384728f3590167fdca199c6e177d0bb4b34 Mon Sep 17 00:00:00 2001 From: Benjamin Delespierre Date: Fri, 19 Jun 2015 16:43:18 +0200 Subject: [PATCH 062/263] Adds paragraph for bdelespierre/underscore.php lib in #links --- index.html | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index a657cab36..43469e5cc 100644 --- a/index.html +++ b/index.html @@ -2145,10 +2145,9 @@ Links & Suggested Reading
- Underscore.php, - a PHP port of the functions that are applicable in both languages. - Includes OOP-wrapping and chaining. - (source) + Underscore.php, + a PHP port of the functions that are applicable in both languages. Tailored for PHP 5.4 and made with data-type tolerance in mind. + (source)
From b352144a0fa2d59a27dde6b3a47f989989f0e6c6 Mon Sep 17 00:00:00 2001 From: John-David Dalton
+Date: Tue, 18 Aug 2015 13:15:25 -0700 Subject: [PATCH 063/263] Remove source map url in Uglify options of the package.json [closes #2145] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2c39f4339..2cb4cc47c 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "lint": "eslint --reset underscore.js test/*.js", "test-node": "qunit-cli test/*.js", "test-browser": "npm i karma-phantomjs-launcher && ./node_modules/karma/bin/karma start", - "build": "uglifyjs underscore.js -c \"evaluate=false\" --comments \"/ .*/\" -m --source-map underscore-min.map -o underscore-min.js", + "build": "uglifyjs underscore.js -c \"evaluate=false\" --comments \"/ .*/\" -m --source-map underscore-min.map --source-map-url \" \" -o underscore-min.js", "doc": "docco underscore.js" }, "license": "MIT", From b10c0203e445685133c24f9bca6609455f08da71 Mon Sep 17 00:00:00 2001 From: Adam Krebs Date: Tue, 18 Aug 2015 22:39:38 -0400 Subject: [PATCH 064/263] Mark _.identity as code using backticks. Closes #2278 --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index d513b47b6..e00c04273 100644 --- a/underscore.js +++ b/underscore.js @@ -85,7 +85,7 @@ // A mostly-internal function to generate callbacks that can be applied // to each element in a collection, returning the desired result — either - // identity, an arbitrary callback, a property matcher, or a property accessor. + // `identity`, an arbitrary callback, a property matcher, or a property accessor. var cb = function(value, context, argCount) { if (value == null) return _.identity; if (_.isFunction(value)) return optimizeCb(value, context, argCount); From 37f62d39c2880ebabb05bcd8d90151cf289e5d88 Mon Sep 17 00:00:00 2001 From: Adam Krebs Date: Tue, 18 Aug 2015 22:41:21 -0400 Subject: [PATCH 065/263] grammar tweaks --- underscore.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index e00c04273..b5ac00fd3 100644 --- a/underscore.js +++ b/underscore.js @@ -92,6 +92,7 @@ if (_.isObject(value)) return _.matcher(value); return _.property(value); }; + _.iteratee = function(value, context) { return cb(value, context, Infinity); }; @@ -137,7 +138,7 @@ }; // Helper for collection methods to determine whether a collection - // should be iterated as an array or as an object + // should be iterated as an array or as an object. // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; From 8b0c68267395132fa1133fa1aef1291e2a121438 Mon Sep 17 00:00:00 2001 From: wgpsutherland Date: Wed, 26 Aug 2015 17:26:55 +0100 Subject: [PATCH 066/263] Change equality comparisons of definite strings and numbers --- underscore.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/underscore.js b/underscore.js index b5ac00fd3..a8079d9e3 100644 --- a/underscore.js +++ b/underscore.js @@ -11,8 +11,8 @@ // Establish the root object, `window` (`self`) in the browser, `global` // on the server, or `this` in some virtual machines. We use `self` // instead of `window` for `WebWorker` support. - var root = typeof self === 'object' && self.self === self && self || - typeof global === 'object' && global.global === global && global || + var root = typeof self == 'object' && self.self === self && self || + typeof global == 'object' && global.global === global && global || this; // Save the previous value of the `_` variable. @@ -571,7 +571,7 @@ for (j = 1; j < argsLength; j++) { if (!_.contains(arguments[j], item)) break; } - if (j === argsLength) result.push(item); + if (j == argsLength) result.push(item); } return result; }; @@ -1149,7 +1149,7 @@ if (a !== a) return b !== b; // Exhaust primitive checks var type = typeof a; - if (type !== 'function' && type !== 'object' && typeof b !== 'object') return false; + if (type != 'function' && type != 'object' && typeof b != 'object') return false; return deepEq(a, b, aStack, bStack); }; @@ -1183,7 +1183,7 @@ return +a === +b; } - var areArrays = className === '[object Array]'; + var areArrays = className == '[object Array]'; if (!areArrays) { if (typeof a != 'object' || typeof b != 'object') return false; @@ -1251,7 +1251,7 @@ _.isEmpty = function(obj) { if (obj == null) return true; if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; - return _.keys(obj).length === 0; + return _.keys(obj).length == 0; }; // Is a given value a DOM element? @@ -1262,19 +1262,19 @@ // Is a given value an array? // Delegates to ECMA5's native Array.isArray _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) === '[object Array]'; + return toString.call(obj) == '[object Array]'; }; // Is a given variable an object? _.isObject = function(obj) { var type = typeof obj; - return type === 'function' || type === 'object' && !!obj; + return type == 'function' || type == 'object' && !!obj; }; // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { _['is' + name] = function(obj) { - return toString.call(obj) === '[object ' + name + ']'; + return toString.call(obj) == '[object ' + name + ']'; }; }); @@ -1307,7 +1307,7 @@ // Is a given value a boolean? _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; }; // Is a given value equal to null? @@ -1566,7 +1566,7 @@ _.prototype[name] = function() { var obj = this._wrapped; method.apply(obj, arguments); - if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; + if ((name == 'shift' || name == 'splice') && obj.length == 0) delete obj[0]; return chainResult(this, obj); }; }); @@ -1599,7 +1599,7 @@ // popular enough to be bundled in a third party lib, but not be part of // an AMD load request. Those cases could generate an error when an // anonymous define() is called outside of a loader request. - if (typeof define === 'function' && define.amd) { + if (typeof define == 'function' && define.amd) { define('underscore', [], function() { return _; }); From 97c3f0f90590cfe257df4d844990d5c36947803f Mon Sep 17 00:00:00 2001 From: wgpsutherland Date: Wed, 26 Aug 2015 17:29:51 +0100 Subject: [PATCH 067/263] Change inequality comparisons of numbers and strings --- underscore.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/underscore.js b/underscore.js index a8079d9e3..bca2c1055 100644 --- a/underscore.js +++ b/underscore.js @@ -48,8 +48,8 @@ // Export the Underscore object for **Node.js**, with // backwards-compatibility for their old module API. If we're in // the browser, add `_` as a global object. - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { + if (typeof exports != 'undefined') { + if (typeof module != 'undefined' && module.exports) { exports = module.exports = _; } exports._ = _; @@ -1160,7 +1160,7 @@ if (b instanceof _) b = b._wrapped; // Compare `[[Class]]` names. var className = toString.call(a); - if (className !== toString.call(b)) return false; + if (className != toString.call(b)) return false; switch (className) { // Strings, numbers, regular expressions, dates, and booleans are compared by value. case '[object RegExp]': @@ -1218,7 +1218,7 @@ if (areArrays) { // Compare array lengths to determine if a deep comparison is necessary. length = a.length; - if (length !== b.length) return false; + if (length != b.length) return false; // Deep compare the contents, ignoring non-numeric properties. while (length--) { if (!eq(a[length], b[length], aStack, bStack)) return false; @@ -1228,7 +1228,7 @@ var keys = _.keys(a), key; length = keys.length; // Ensure that both objects contain the same number of properties before comparing deep equality. - if (_.keys(b).length !== length) return false; + if (_.keys(b).length != length) return false; while (length--) { // Deep compare each member key = keys[length]; From 660938d320f6c20a460316e3da40eafdb1a17df6 Mon Sep 17 00:00:00 2001 From: wgpsutherland Date: Wed, 26 Aug 2015 17:50:28 +0100 Subject: [PATCH 068/263] Change back equality comparisons that were failing in the linter --- underscore.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/underscore.js b/underscore.js index bca2c1055..7926dc293 100644 --- a/underscore.js +++ b/underscore.js @@ -571,7 +571,7 @@ for (j = 1; j < argsLength; j++) { if (!_.contains(arguments[j], item)) break; } - if (j == argsLength) result.push(item); + if (j === argsLength) result.push(item); } return result; }; @@ -1149,7 +1149,7 @@ if (a !== a) return b !== b; // Exhaust primitive checks var type = typeof a; - if (type != 'function' && type != 'object' && typeof b != 'object') return false; + if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; return deepEq(a, b, aStack, bStack); }; @@ -1160,7 +1160,7 @@ if (b instanceof _) b = b._wrapped; // Compare `[[Class]]` names. var className = toString.call(a); - if (className != toString.call(b)) return false; + if (className !== toString.call(b)) return false; switch (className) { // Strings, numbers, regular expressions, dates, and booleans are compared by value. case '[object RegExp]': @@ -1183,7 +1183,7 @@ return +a === +b; } - var areArrays = className == '[object Array]'; + var areArrays = className === '[object Array]'; if (!areArrays) { if (typeof a != 'object' || typeof b != 'object') return false; @@ -1218,7 +1218,7 @@ if (areArrays) { // Compare array lengths to determine if a deep comparison is necessary. length = a.length; - if (length != b.length) return false; + if (length !== b.length) return false; // Deep compare the contents, ignoring non-numeric properties. while (length--) { if (!eq(a[length], b[length], aStack, bStack)) return false; @@ -1228,7 +1228,7 @@ var keys = _.keys(a), key; length = keys.length; // Ensure that both objects contain the same number of properties before comparing deep equality. - if (_.keys(b).length != length) return false; + if (_.keys(b).length !== length) return false; while (length--) { // Deep compare each member key = keys[length]; @@ -1251,7 +1251,7 @@ _.isEmpty = function(obj) { if (obj == null) return true; if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; - return _.keys(obj).length == 0; + return _.keys(obj).length === 0; }; // Is a given value a DOM element? @@ -1262,19 +1262,19 @@ // Is a given value an array? // Delegates to ECMA5's native Array.isArray _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) == '[object Array]'; + return toString.call(obj) === '[object Array]'; }; // Is a given variable an object? _.isObject = function(obj) { var type = typeof obj; - return type == 'function' || type == 'object' && !!obj; + return type === 'function' || type === 'object' && !!obj; }; // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { _['is' + name] = function(obj) { - return toString.call(obj) == '[object ' + name + ']'; + return toString.call(obj) === '[object ' + name + ']'; }; }); @@ -1307,7 +1307,7 @@ // Is a given value a boolean? _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; }; // Is a given value equal to null? @@ -1566,7 +1566,7 @@ _.prototype[name] = function() { var obj = this._wrapped; method.apply(obj, arguments); - if ((name == 'shift' || name == 'splice') && obj.length == 0) delete obj[0]; + if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; return chainResult(this, obj); }; }); From ac5f82639c8ee082468433eff226315e5d19f02c Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Tue, 8 Sep 2015 16:37:58 -0700 Subject: [PATCH 069/263] fix tests for qunit 1.19.0 --- test/arrays.js | 462 +++++++++++----------- test/chaining.js | 62 +-- test/collections.js | 676 ++++++++++++++++---------------- test/cross-document.js | 102 ++--- test/functions.js | 322 ++++++++-------- test/objects.js | 846 ++++++++++++++++++++--------------------- test/utility.js | 260 ++++++------- 7 files changed, 1365 insertions(+), 1365 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 5b52ad433..0de58e07e 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -3,135 +3,135 @@ QUnit.module('Arrays'); - test('first', function() { - equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array'); - equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"'); - deepEqual(_.first([1, 2, 3], 0), [], 'can pass an index to first'); - deepEqual(_.first([1, 2, 3], 2), [1, 2], 'can pass an index to first'); - deepEqual(_.first([1, 2, 3], 5), [1, 2, 3], 'can pass an index to first'); + test('first', function(assert) { + assert.equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array'); + assert.equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"'); + assert.deepEqual(_.first([1, 2, 3], 0), [], 'can pass an index to first'); + assert.deepEqual(_.first([1, 2, 3], 2), [1, 2], 'can pass an index to first'); + assert.deepEqual(_.first([1, 2, 3], 5), [1, 2, 3], 'can pass an index to first'); var result = (function(){ return _.first(arguments); }(4, 3, 2, 1)); - equal(result, 4, 'works on an arguments object.'); + assert.equal(result, 4, 'works on an arguments object.'); result = _.map([[1, 2, 3], [1, 2, 3]], _.first); - deepEqual(result, [1, 1], 'works well with _.map'); + assert.deepEqual(result, [1, 1], 'works well with _.map'); result = (function() { return _.first([1, 2, 3], 2); }()); - deepEqual(result, [1, 2]); + assert.deepEqual(result, [1, 2]); - equal(_.first(null), void 0, 'handles nulls'); - strictEqual(_.first([1, 2, 3], -1).length, 0); + assert.equal(_.first(null), void 0, 'handles nulls'); + assert.strictEqual(_.first([1, 2, 3], -1).length, 0); }); - test('head', function() { - strictEqual(_.first, _.head, 'alias for first'); + test('head', function(assert) { + assert.strictEqual(_.first, _.head, 'alias for first'); }); - test('take', function() { - strictEqual(_.first, _.take, 'alias for first'); + test('take', function(assert) { + assert.strictEqual(_.first, _.take, 'alias for first'); }); - test('rest', function() { + test('rest', function(assert) { var numbers = [1, 2, 3, 4]; - deepEqual(_.rest(numbers), [2, 3, 4], 'working rest()'); - deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'working rest(0)'); - deepEqual(_.rest(numbers, 2), [3, 4], 'rest can take an index'); + assert.deepEqual(_.rest(numbers), [2, 3, 4], 'working rest()'); + assert.deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'working rest(0)'); + assert.deepEqual(_.rest(numbers, 2), [3, 4], 'rest can take an index'); var result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4)); - deepEqual(result, [2, 3, 4], 'works on arguments object'); + assert.deepEqual(result, [2, 3, 4], 'works on arguments object'); result = _.map([[1, 2, 3], [1, 2, 3]], _.rest); - deepEqual(_.flatten(result), [2, 3, 2, 3], 'works well with _.map'); + assert.deepEqual(_.flatten(result), [2, 3, 2, 3], 'works well with _.map'); result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4)); - deepEqual(result, [2, 3, 4], 'works on arguments object'); + assert.deepEqual(result, [2, 3, 4], 'works on arguments object'); }); - test('tail', function() { - strictEqual(_.rest, _.tail, 'alias for rest'); + test('tail', function(assert) { + assert.strictEqual(_.rest, _.tail, 'alias for rest'); }); - test('drop', function() { - strictEqual(_.rest, _.drop, 'alias for rest'); + test('drop', function(assert) { + assert.strictEqual(_.rest, _.drop, 'alias for rest'); }); - test('initial', function() { - deepEqual(_.initial([1, 2, 3, 4, 5]), [1, 2, 3, 4], 'working initial()'); - deepEqual(_.initial([1, 2, 3, 4], 2), [1, 2], 'initial can take an index'); - deepEqual(_.initial([1, 2, 3, 4], 6), [], 'initial can take a large index'); + test('initial', function(assert) { + assert.deepEqual(_.initial([1, 2, 3, 4, 5]), [1, 2, 3, 4], 'working initial()'); + assert.deepEqual(_.initial([1, 2, 3, 4], 2), [1, 2], 'initial can take an index'); + assert.deepEqual(_.initial([1, 2, 3, 4], 6), [], 'initial can take a large index'); var result = (function(){ return _(arguments).initial(); }(1, 2, 3, 4)); - deepEqual(result, [1, 2, 3], 'initial works on arguments object'); + assert.deepEqual(result, [1, 2, 3], 'initial works on arguments object'); result = _.map([[1, 2, 3], [1, 2, 3]], _.initial); - deepEqual(_.flatten(result), [1, 2, 1, 2], 'initial works with _.map'); + assert.deepEqual(_.flatten(result), [1, 2, 1, 2], 'initial works with _.map'); }); - test('last', function() { - equal(_.last([1, 2, 3]), 3, 'can pull out the last element of an array'); - deepEqual(_.last([1, 2, 3], 0), [], 'can pass an index to last'); - deepEqual(_.last([1, 2, 3], 2), [2, 3], 'can pass an index to last'); - deepEqual(_.last([1, 2, 3], 5), [1, 2, 3], 'can pass an index to last'); + test('last', function(assert) { + assert.equal(_.last([1, 2, 3]), 3, 'can pull out the last element of an array'); + assert.deepEqual(_.last([1, 2, 3], 0), [], 'can pass an index to last'); + assert.deepEqual(_.last([1, 2, 3], 2), [2, 3], 'can pass an index to last'); + assert.deepEqual(_.last([1, 2, 3], 5), [1, 2, 3], 'can pass an index to last'); var result = (function(){ return _(arguments).last(); }(1, 2, 3, 4)); - equal(result, 4, 'works on an arguments object'); + assert.equal(result, 4, 'works on an arguments object'); result = _.map([[1, 2, 3], [1, 2, 3]], _.last); - deepEqual(result, [3, 3], 'works well with _.map'); + assert.deepEqual(result, [3, 3], 'works well with _.map'); - equal(_.last(null), void 0, 'handles nulls'); - strictEqual(_.last([1, 2, 3], -1).length, 0); + assert.equal(_.last(null), void 0, 'handles nulls'); + assert.strictEqual(_.last([1, 2, 3], -1).length, 0); }); - test('compact', function() { - equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values'); + test('compact', function(assert) { + assert.equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values'); var result = (function(){ return _.compact(arguments).length; }(0, 1, false, 2, false, 3)); - equal(result, 3, 'works on an arguments object'); + assert.equal(result, 3, 'works on an arguments object'); }); - test('flatten', function() { - deepEqual(_.flatten(null), [], 'Flattens supports null'); - deepEqual(_.flatten(void 0), [], 'Flattens supports undefined'); + test('flatten', function(assert) { + assert.deepEqual(_.flatten(null), [], 'Flattens supports null'); + assert.deepEqual(_.flatten(void 0), [], 'Flattens supports undefined'); - deepEqual(_.flatten([[], [[]], []]), [], 'Flattens empty arrays'); - deepEqual(_.flatten([[], [[]], []], true), [[]], 'Flattens empty arrays'); + assert.deepEqual(_.flatten([[], [[]], []]), [], 'Flattens empty arrays'); + assert.deepEqual(_.flatten([[], [[]], []], true), [[]], 'Flattens empty arrays'); var list = [1, [2], [3, [[[4]]]]]; - deepEqual(_.flatten(list), [1, 2, 3, 4], 'can flatten nested arrays'); - deepEqual(_.flatten(list, true), [1, 2, 3, [[[4]]]], 'can shallowly flatten nested arrays'); + assert.deepEqual(_.flatten(list), [1, 2, 3, 4], 'can flatten nested arrays'); + assert.deepEqual(_.flatten(list, true), [1, 2, 3, [[[4]]]], 'can shallowly flatten nested arrays'); var result = (function(){ return _.flatten(arguments); }(1, [2], [3, [[[4]]]])); - deepEqual(result, [1, 2, 3, 4], 'works on an arguments object'); + assert.deepEqual(result, [1, 2, 3, 4], 'works on an arguments object'); list = [[1], [2], [3], [[4]]]; - deepEqual(_.flatten(list, true), [1, 2, 3, [4]], 'can shallowly flatten arrays containing only other arrays'); + assert.deepEqual(_.flatten(list, true), [1, 2, 3, [4]], 'can shallowly flatten arrays containing only other arrays'); - equal(_.flatten([_.range(10), _.range(10), 5, 1, 3], true).length, 23); - equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23); - equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'Flatten can handle massive collections'); - equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'Flatten can handle massive collections'); + assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3], true).length, 23); + assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23); + assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'Flatten can handle massive collections'); + assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'Flatten can handle massive collections'); var x = _.range(100000); for (var i = 0; i < 1000; i++) x = [x]; - deepEqual(_.flatten(x), _.range(100000), 'Flatten can handle very deep arrays'); - deepEqual(_.flatten(x, true), x[0], 'Flatten can handle very deep arrays with shallow'); + assert.deepEqual(_.flatten(x), _.range(100000), 'Flatten can handle very deep arrays'); + assert.deepEqual(_.flatten(x, true), x[0], 'Flatten can handle very deep arrays with shallow'); }); - test('without', function() { + test('without', function(assert) { var list = [1, 2, 1, 0, 3, 1, 4]; - deepEqual(_.without(list, 0, 1), [2, 3, 4], 'can remove all instances of an object'); + assert.deepEqual(_.without(list, 0, 1), [2, 3, 4], 'can remove all instances of an object'); var result = (function(){ return _.without(arguments, 0, 1); }(1, 2, 1, 0, 3, 1, 4)); - deepEqual(result, [2, 3, 4], 'works on an arguments object'); + assert.deepEqual(result, [2, 3, 4], 'works on an arguments object'); list = [{one: 1}, {two: 2}]; - equal(_.without(list, {one: 1}).length, 2, 'uses real object identity for comparisons.'); - equal(_.without(list, list[0]).length, 1, 'ditto.'); + assert.equal(_.without(list, {one: 1}).length, 2, 'uses real object identity for comparisons.'); + assert.equal(_.without(list, list[0]).length, 1, 'ditto.'); }); - test('sortedIndex', function() { + test('sortedIndex', function(assert) { var numbers = [10, 20, 30, 40, 50], num = 35; var indexForNum = _.sortedIndex(numbers, num); - equal(indexForNum, 3, '35 should be inserted at index 3'); + assert.equal(indexForNum, 3, '35 should be inserted at index 3'); var indexFor30 = _.sortedIndex(numbers, 30); - equal(indexFor30, 2, '30 should be inserted at index 2'); + assert.equal(indexFor30, 2, '30 should be inserted at index 2'); var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}]; var iterator = function(obj){ return obj.x; }; - strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2); - strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3); + assert.strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2); + assert.strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3); var context = {1: 2, 2: 3, 3: 4}; iterator = function(obj){ return this[obj]; }; - strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1); + assert.strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1); var values = [0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647]; var array = Array(Math.pow(2, 32) - 1); @@ -139,25 +139,25 @@ while (length--) { array[values[length]] = values[length]; } - equal(_.sortedIndex(array, 2147483648), 2147483648, 'should work with large indexes'); + assert.equal(_.sortedIndex(array, 2147483648), 2147483648, 'should work with large indexes'); }); - test('uniq', function() { + test('uniq', function(assert) { var list = [1, 2, 1, 3, 1, 4]; - deepEqual(_.uniq(list), [1, 2, 3, 4], 'can find the unique values of an unsorted array'); + assert.deepEqual(_.uniq(list), [1, 2, 3, 4], 'can find the unique values of an unsorted array'); list = [1, 1, 1, 2, 2, 3]; - deepEqual(_.uniq(list, true), [1, 2, 3], 'can find the unique values of a sorted array faster'); + assert.deepEqual(_.uniq(list, true), [1, 2, 3], 'can find the unique values of a sorted array faster'); list = [{name: 'moe'}, {name: 'curly'}, {name: 'larry'}, {name: 'curly'}]; var iterator = function(value) { return value.name; }; - deepEqual(_.map(_.uniq(list, false, iterator), iterator), ['moe', 'curly', 'larry'], 'can find the unique values of an array using a custom iterator'); + assert.deepEqual(_.map(_.uniq(list, false, iterator), iterator), ['moe', 'curly', 'larry'], 'can find the unique values of an array using a custom iterator'); - deepEqual(_.map(_.uniq(list, iterator), iterator), ['moe', 'curly', 'larry'], 'can find the unique values of an array using a custom iterator without specifying whether array is sorted'); + assert.deepEqual(_.map(_.uniq(list, iterator), iterator), ['moe', 'curly', 'larry'], 'can find the unique values of an array using a custom iterator without specifying whether array is sorted'); iterator = function(value) { return value + 1; }; list = [1, 2, 2, 3, 4, 4]; - deepEqual(_.uniq(list, true, iterator), [1, 2, 3, 4], 'iterator works with sorted array'); + assert.deepEqual(_.uniq(list, true, iterator), [1, 2, 3, 4], 'iterator works with sorted array'); var kittens = [ {kitten: 'Celery', cuteness: 8}, @@ -170,236 +170,236 @@ {kitten: 'Juniper', cuteness: 10} ]; - deepEqual(_.uniq(kittens, true, 'cuteness'), expected, 'string iterator works with sorted array'); + assert.deepEqual(_.uniq(kittens, true, 'cuteness'), expected, 'string iterator works with sorted array'); var result = (function(){ return _.uniq(arguments); }(1, 2, 1, 3, 1, 4)); - deepEqual(result, [1, 2, 3, 4], 'works on an arguments object'); + assert.deepEqual(result, [1, 2, 3, 4], 'works on an arguments object'); var a = {}, b = {}, c = {}; - deepEqual(_.uniq([a, b, a, b, c]), [a, b, c], 'works on values that can be tested for equivalency but not ordered'); + assert.deepEqual(_.uniq([a, b, a, b, c]), [a, b, c], 'works on values that can be tested for equivalency but not ordered'); - deepEqual(_.uniq(null), []); + assert.deepEqual(_.uniq(null), []); var context = {}; list = [3]; _.uniq(list, function(value, index, array) { - strictEqual(this, context); - strictEqual(value, 3); - strictEqual(index, 0); - strictEqual(array, list); + assert.strictEqual(this, context); + assert.strictEqual(value, 3); + assert.strictEqual(index, 0); + assert.strictEqual(array, list); }, context); - deepEqual(_.uniq([{a: 1, b: 1}, {a: 1, b: 2}, {a: 1, b: 3}, {a: 2, b: 1}], 'a'), [{a: 1, b: 1}, {a: 2, b: 1}], 'can use pluck like iterator'); - deepEqual(_.uniq([{0: 1, b: 1}, {0: 1, b: 2}, {0: 1, b: 3}, {0: 2, b: 1}], 0), [{0: 1, b: 1}, {0: 2, b: 1}], 'can use falsey pluck like iterator'); + assert.deepEqual(_.uniq([{a: 1, b: 1}, {a: 1, b: 2}, {a: 1, b: 3}, {a: 2, b: 1}], 'a'), [{a: 1, b: 1}, {a: 2, b: 1}], 'can use pluck like iterator'); + assert.deepEqual(_.uniq([{0: 1, b: 1}, {0: 1, b: 2}, {0: 1, b: 3}, {0: 2, b: 1}], 0), [{0: 1, b: 1}, {0: 2, b: 1}], 'can use falsey pluck like iterator'); }); - test('unique', function() { - strictEqual(_.uniq, _.unique, 'alias for uniq'); + test('unique', function(assert) { + assert.strictEqual(_.uniq, _.unique, 'alias for uniq'); }); - test('intersection', function() { + test('intersection', function(assert) { var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho']; - deepEqual(_.intersection(stooges, leaders), ['moe'], 'can take the set intersection of two arrays'); - deepEqual(_(stooges).intersection(leaders), ['moe'], 'can perform an OO-style intersection'); + assert.deepEqual(_.intersection(stooges, leaders), ['moe'], 'can take the set intersection of two arrays'); + assert.deepEqual(_(stooges).intersection(leaders), ['moe'], 'can perform an OO-style intersection'); var result = (function(){ return _.intersection(arguments, leaders); }('moe', 'curly', 'larry')); - deepEqual(result, ['moe'], 'works on an arguments object'); + assert.deepEqual(result, ['moe'], 'works on an arguments object'); var theSixStooges = ['moe', 'moe', 'curly', 'curly', 'larry', 'larry']; - deepEqual(_.intersection(theSixStooges, leaders), ['moe'], 'returns a duplicate-free array'); + assert.deepEqual(_.intersection(theSixStooges, leaders), ['moe'], 'returns a duplicate-free array'); result = _.intersection([2, 4, 3, 1], [1, 2, 3]); - deepEqual(result, [2, 3, 1], 'preserves order of first array'); + assert.deepEqual(result, [2, 3, 1], 'preserves order of first array'); result = _.intersection(null, [1, 2, 3]); - equal(Object.prototype.toString.call(result), '[object Array]', 'returns an empty array when passed null as first argument'); - equal(result.length, 0, 'returns an empty array when passed null as first argument'); + assert.equal(Object.prototype.toString.call(result), '[object Array]', 'returns an empty array when passed null as first argument'); + assert.equal(result.length, 0, 'returns an empty array when passed null as first argument'); result = _.intersection([1, 2, 3], null); - equal(Object.prototype.toString.call(result), '[object Array]', 'returns an empty array when passed null as argument beyond the first'); - equal(result.length, 0, 'returns an empty array when passed null as argument beyond the first'); + assert.equal(Object.prototype.toString.call(result), '[object Array]', 'returns an empty array when passed null as argument beyond the first'); + assert.equal(result.length, 0, 'returns an empty array when passed null as argument beyond the first'); }); - test('union', function() { + test('union', function(assert) { var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]); - deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays'); + assert.deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays'); result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]); - deepEqual(result, [1, 2, 3, 30, 40, [1]], 'takes the union of a list of nested arrays'); + assert.deepEqual(result, [1, 2, 3, 30, 40, [1]], 'takes the union of a list of nested arrays'); var args = null; (function(){ args = arguments; }(1, 2, 3)); result = _.union(args, [2, 30, 1], [1, 40]); - deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays'); + assert.deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays'); result = _.union([1, 2, 3], 4); - deepEqual(result, [1, 2, 3], 'restrict the union to arrays only'); + assert.deepEqual(result, [1, 2, 3], 'restrict the union to arrays only'); }); - test('difference', function() { + test('difference', function(assert) { var result = _.difference([1, 2, 3], [2, 30, 40]); - deepEqual(result, [1, 3], 'takes the difference of two arrays'); + assert.deepEqual(result, [1, 3], 'takes the difference of two arrays'); result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]); - deepEqual(result, [3, 4], 'takes the difference of three arrays'); + assert.deepEqual(result, [3, 4], 'takes the difference of three arrays'); result = _.difference([1, 2, 3], 1); - deepEqual(result, [1, 2, 3], 'restrict the difference to arrays only'); + assert.deepEqual(result, [1, 2, 3], 'restrict the difference to arrays only'); }); - test('zip', function() { + test('zip', function(assert) { var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true]; - deepEqual(_.zip(names, ages, leaders), [ + assert.deepEqual(_.zip(names, ages, leaders), [ ['moe', 30, true], ['larry', 40, void 0], ['curly', 50, void 0] ], 'zipped together arrays of different lengths'); var stooges = _.zip(['moe', 30, 'stooge 1'], ['larry', 40, 'stooge 2'], ['curly', 50, 'stooge 3']); - deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs'); + assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs'); // In the case of difference lengths of the tuples undefineds // should be used as placeholder stooges = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); - deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [void 0, void 0, 'extra data']], 'zipped pairs with empties'); + assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [void 0, void 0, 'extra data']], 'zipped pairs with empties'); var empty = _.zip([]); - deepEqual(empty, [], 'unzipped empty'); + assert.deepEqual(empty, [], 'unzipped empty'); - deepEqual(_.zip(null), [], 'handles null'); - deepEqual(_.zip(), [], '_.zip() returns []'); + assert.deepEqual(_.zip(null), [], 'handles null'); + assert.deepEqual(_.zip(), [], '_.zip() returns []'); }); - test('unzip', function() { - deepEqual(_.unzip(null), [], 'handles null'); + test('unzip', function(assert) { + assert.deepEqual(_.unzip(null), [], 'handles null'); - deepEqual(_.unzip([['a', 'b'], [1, 2]]), [['a', 1], ['b', 2]]); + assert.deepEqual(_.unzip([['a', 'b'], [1, 2]]), [['a', 1], ['b', 2]]); // complements zip var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); - deepEqual(_.unzip(zipped), [['fred', 'barney'], [30, 40], [true, false]]); + assert.deepEqual(_.unzip(zipped), [['fred', 'barney'], [30, 40], [true, false]]); zipped = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); - deepEqual(_.unzip(zipped), [['moe', 30, void 0], ['larry', 40, void 0], ['curly', 50, 'extra data']], 'Uses length of largest array'); + assert.deepEqual(_.unzip(zipped), [['moe', 30, void 0], ['larry', 40, void 0], ['curly', 50, 'extra data']], 'Uses length of largest array'); }); - test('object', function() { + test('object', function(assert) { var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]); var shouldBe = {moe: 30, larry: 40, curly: 50}; - deepEqual(result, shouldBe, 'two arrays zipped together into an object'); + assert.deepEqual(result, shouldBe, 'two arrays zipped together into an object'); result = _.object([['one', 1], ['two', 2], ['three', 3]]); shouldBe = {one: 1, two: 2, three: 3}; - deepEqual(result, shouldBe, 'an array of pairs zipped together into an object'); + assert.deepEqual(result, shouldBe, 'an array of pairs zipped together into an object'); var stooges = {moe: 30, larry: 40, curly: 50}; - deepEqual(_.object(_.pairs(stooges)), stooges, 'an object converted to pairs and back to an object'); + assert.deepEqual(_.object(_.pairs(stooges)), stooges, 'an object converted to pairs and back to an object'); - deepEqual(_.object(null), {}, 'handles nulls'); + assert.deepEqual(_.object(null), {}, 'handles nulls'); }); - test('indexOf', function() { + test('indexOf', function(assert) { var numbers = [1, 2, 3]; - equal(_.indexOf(numbers, 2), 1, 'can compute indexOf'); + assert.equal(_.indexOf(numbers, 2), 1, 'can compute indexOf'); var result = (function(){ return _.indexOf(arguments, 2); }(1, 2, 3)); - equal(result, 1, 'works on an arguments object'); + assert.equal(result, 1, 'works on an arguments object'); _.each([null, void 0, [], false], function(val) { var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val); - equal(_.indexOf(val, 2), -1, msg); - equal(_.indexOf(val, 2, -1), -1, msg); - equal(_.indexOf(val, 2, -20), -1, msg); - equal(_.indexOf(val, 2, 15), -1, msg); + assert.equal(_.indexOf(val, 2), -1, msg); + assert.equal(_.indexOf(val, 2, -1), -1, msg); + assert.equal(_.indexOf(val, 2, -20), -1, msg); + assert.equal(_.indexOf(val, 2, 15), -1, msg); }); var num = 35; numbers = [10, 20, 30, 40, 50]; var index = _.indexOf(numbers, num, true); - equal(index, -1, '35 is not in the list'); + assert.equal(index, -1, '35 is not in the list'); numbers = [10, 20, 30, 40, 50]; num = 40; index = _.indexOf(numbers, num, true); - equal(index, 3, '40 is in the list'); + assert.equal(index, 3, '40 is in the list'); numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40; - equal(_.indexOf(numbers, num, true), 1, '40 is in the list'); - equal(_.indexOf(numbers, 6, true), -1, '6 isnt in the list'); - equal(_.indexOf([1, 2, 5, 4, 6, 7], 5, true), -1, 'sorted indexOf doesn\'t uses binary search'); - ok(_.every(['1', [], {}, null], function() { + assert.equal(_.indexOf(numbers, num, true), 1, '40 is in the list'); + assert.equal(_.indexOf(numbers, 6, true), -1, '6 isnt in the list'); + assert.equal(_.indexOf([1, 2, 5, 4, 6, 7], 5, true), -1, 'sorted indexOf doesn\'t uses binary search'); + assert.ok(_.every(['1', [], {}, null], function() { return _.indexOf(numbers, num, {}) === 1; }), 'non-nums as fromIndex make indexOf assume sorted'); numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; index = _.indexOf(numbers, 2, 5); - equal(index, 7, 'supports the fromIndex argument'); + assert.equal(index, 7, 'supports the fromIndex argument'); index = _.indexOf([,,, 0], void 0); - equal(index, 0, 'treats sparse arrays as if they were dense'); + assert.equal(index, 0, 'treats sparse arrays as if they were dense'); var array = [1, 2, 3, 1, 2, 3]; - strictEqual(_.indexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index'); - strictEqual(_.indexOf(array, 1, -2), -1, 'neg `fromIndex` starts at the right index'); - strictEqual(_.indexOf(array, 2, -3), 4); + assert.strictEqual(_.indexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index'); + assert.strictEqual(_.indexOf(array, 1, -2), -1, 'neg `fromIndex` starts at the right index'); + assert.strictEqual(_.indexOf(array, 2, -3), 4); _.each([-6, -8, -Infinity], function(fromIndex) { - strictEqual(_.indexOf(array, 1, fromIndex), 0); + assert.strictEqual(_.indexOf(array, 1, fromIndex), 0); }); - strictEqual(_.indexOf([1, 2, 3], 1, true), 0); + assert.strictEqual(_.indexOf([1, 2, 3], 1, true), 0); index = _.indexOf([], void 0, true); - equal(index, -1, 'empty array with truthy `isSorted` returns -1'); + assert.equal(index, -1, 'empty array with truthy `isSorted` returns -1'); }); - test('indexOf with NaN', function() { - strictEqual(_.indexOf([1, 2, NaN, NaN], NaN), 2, 'Expected [1, 2, NaN] to contain NaN'); - strictEqual(_.indexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); + test('indexOf with NaN', function(assert) { + assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN), 2, 'Expected [1, 2, NaN] to contain NaN'); + assert.strictEqual(_.indexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); - strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, 1), 2, 'startIndex does not affect result'); - strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, -2), 2, 'startIndex does not affect result'); + assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, 1), 2, 'startIndex does not affect result'); + assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, -2), 2, 'startIndex does not affect result'); (function() { - strictEqual(_.indexOf(arguments, NaN), 2, 'Expected arguments [1, 2, NaN] to contain NaN'); + assert.strictEqual(_.indexOf(arguments, NaN), 2, 'Expected arguments [1, 2, NaN] to contain NaN'); }(1, 2, NaN, NaN)); }); - test('indexOf with +- 0', function() { + test('indexOf with +- 0', function(assert) { _.each([-0, +0], function(val) { - strictEqual(_.indexOf([1, 2, val, val], val), 2); - strictEqual(_.indexOf([1, 2, val, val], -val), 2); + assert.strictEqual(_.indexOf([1, 2, val, val], val), 2); + assert.strictEqual(_.indexOf([1, 2, val, val], -val), 2); }); }); - test('lastIndexOf', function() { + test('lastIndexOf', function(assert) { var numbers = [1, 0, 1]; var falsey = [void 0, '', 0, false, NaN, null, void 0]; - equal(_.lastIndexOf(numbers, 1), 2); + assert.equal(_.lastIndexOf(numbers, 1), 2); numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0]; numbers.lastIndexOf = null; - equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function'); - equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element'); + assert.equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function'); + assert.equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element'); var result = (function(){ return _.lastIndexOf(arguments, 1); }(1, 0, 1, 0, 0, 1, 0, 0, 0)); - equal(result, 5, 'works on an arguments object'); + assert.equal(result, 5, 'works on an arguments object'); _.each([null, void 0, [], false], function(val) { var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val); - equal(_.lastIndexOf(val, 2), -1, msg); - equal(_.lastIndexOf(val, 2, -1), -1, msg); - equal(_.lastIndexOf(val, 2, -20), -1, msg); - equal(_.lastIndexOf(val, 2, 15), -1, msg); + assert.equal(_.lastIndexOf(val, 2), -1, msg); + assert.equal(_.lastIndexOf(val, 2, -1), -1, msg); + assert.equal(_.lastIndexOf(val, 2, -20), -1, msg); + assert.equal(_.lastIndexOf(val, 2, 15), -1, msg); }); numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; var index = _.lastIndexOf(numbers, 2, 2); - equal(index, 1, 'supports the fromIndex argument'); + assert.equal(index, 1, 'supports the fromIndex argument'); var array = [1, 2, 3, 1, 2, 3]; - strictEqual(_.lastIndexOf(array, 1, 0), 0, 'starts at the correct from idx'); - strictEqual(_.lastIndexOf(array, 3), 5, 'should return the index of the last matched value'); - strictEqual(_.lastIndexOf(array, 4), -1, 'should return `-1` for an unmatched value'); + assert.strictEqual(_.lastIndexOf(array, 1, 0), 0, 'starts at the correct from idx'); + assert.strictEqual(_.lastIndexOf(array, 3), 5, 'should return the index of the last matched value'); + assert.strictEqual(_.lastIndexOf(array, 4), -1, 'should return `-1` for an unmatched value'); - strictEqual(_.lastIndexOf(array, 1, 2), 0, 'should work with a positive `fromIndex`'); + assert.strictEqual(_.lastIndexOf(array, 1, 2), 0, 'should work with a positive `fromIndex`'); _.each([6, 8, Math.pow(2, 32), Infinity], function(fromIndex) { - strictEqual(_.lastIndexOf(array, void 0, fromIndex), -1); - strictEqual(_.lastIndexOf(array, 1, fromIndex), 3); - strictEqual(_.lastIndexOf(array, '', fromIndex), -1); + assert.strictEqual(_.lastIndexOf(array, void 0, fromIndex), -1); + assert.strictEqual(_.lastIndexOf(array, 1, fromIndex), 3); + assert.strictEqual(_.lastIndexOf(array, '', fromIndex), -1); }); var expected = _.map(falsey, function(value) { @@ -410,39 +410,39 @@ return _.lastIndexOf(array, 3, fromIndex); }); - deepEqual(actual, expected, 'should treat falsey `fromIndex` values, except `0` and `NaN`, as `array.length`'); - strictEqual(_.lastIndexOf(array, 3, '1'), 5, 'should treat non-number `fromIndex` values as `array.length`'); - strictEqual(_.lastIndexOf(array, 3, true), 5, 'should treat non-number `fromIndex` values as `array.length`'); + assert.deepEqual(actual, expected, 'should treat falsey `fromIndex` values, except `0` and `NaN`, as `array.length`'); + assert.strictEqual(_.lastIndexOf(array, 3, '1'), 5, 'should treat non-number `fromIndex` values as `array.length`'); + assert.strictEqual(_.lastIndexOf(array, 3, true), 5, 'should treat non-number `fromIndex` values as `array.length`'); - strictEqual(_.lastIndexOf(array, 2, -3), 1, 'should work with a negative `fromIndex`'); - strictEqual(_.lastIndexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index'); + assert.strictEqual(_.lastIndexOf(array, 2, -3), 1, 'should work with a negative `fromIndex`'); + assert.strictEqual(_.lastIndexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index'); - deepEqual(_.map([-6, -8, -Infinity], function(fromIndex) { + assert.deepEqual(_.map([-6, -8, -Infinity], function(fromIndex) { return _.lastIndexOf(array, 1, fromIndex); }), [0, -1, -1]); }); - test('lastIndexOf with NaN', function() { - strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN), 3, 'Expected [1, 2, NaN] to contain NaN'); - strictEqual(_.lastIndexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); + test('lastIndexOf with NaN', function(assert) { + assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN), 3, 'Expected [1, 2, NaN] to contain NaN'); + assert.strictEqual(_.lastIndexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); - strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, 2), 2, 'fromIndex does not affect result'); - strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, -2), 2, 'fromIndex does not affect result'); + assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, 2), 2, 'fromIndex does not affect result'); + assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, -2), 2, 'fromIndex does not affect result'); (function() { - strictEqual(_.lastIndexOf(arguments, NaN), 3, 'Expected arguments [1, 2, NaN] to contain NaN'); + assert.strictEqual(_.lastIndexOf(arguments, NaN), 3, 'Expected arguments [1, 2, NaN] to contain NaN'); }(1, 2, NaN, NaN)); }); - test('lastIndexOf with +- 0', function() { + test('lastIndexOf with +- 0', function(assert) { _.each([-0, +0], function(val) { - strictEqual(_.lastIndexOf([1, 2, val, val], val), 3); - strictEqual(_.lastIndexOf([1, 2, val, val], -val), 3); - strictEqual(_.lastIndexOf([-1, 1, 2], -val), -1); + assert.strictEqual(_.lastIndexOf([1, 2, val, val], val), 3); + assert.strictEqual(_.lastIndexOf([1, 2, val, val], -val), 3); + assert.strictEqual(_.lastIndexOf([-1, 1, 2], -val), -1); }); }); - test('findIndex', function() { + test('findIndex', function(assert) { var objects = [ {a: 0, b: 0}, {a: 1, b: 1}, @@ -450,42 +450,42 @@ {a: 0, b: 0} ]; - equal(_.findIndex(objects, function(obj) { + assert.equal(_.findIndex(objects, function(obj) { return obj.a === 0; }), 0); - equal(_.findIndex(objects, function(obj) { + assert.equal(_.findIndex(objects, function(obj) { return obj.b * obj.a === 4; }), 2); - equal(_.findIndex(objects, 'a'), 1, 'Uses lookupIterator'); + assert.equal(_.findIndex(objects, 'a'), 1, 'Uses lookupIterator'); - equal(_.findIndex(objects, function(obj) { + assert.equal(_.findIndex(objects, function(obj) { return obj.b * obj.a === 5; }), -1); - equal(_.findIndex(null, _.noop), -1); - strictEqual(_.findIndex(objects, function(a) { + assert.equal(_.findIndex(null, _.noop), -1); + assert.strictEqual(_.findIndex(objects, function(a) { return a.foo === null; }), -1); _.findIndex([{a: 1}], function(a, key, obj) { - equal(key, 0); - deepEqual(obj, [{a: 1}]); - strictEqual(this, objects, 'called with context'); + assert.equal(key, 0); + assert.deepEqual(obj, [{a: 1}]); + assert.strictEqual(this, objects, 'called with context'); }, objects); var sparse = []; sparse[20] = {a: 2, b: 2}; - equal(_.findIndex(sparse, function(obj) { + assert.equal(_.findIndex(sparse, function(obj) { return obj && obj.b * obj.a === 4; }), 20, 'Works with sparse arrays'); var array = [1, 2, 3, 4]; array.match = 55; - strictEqual(_.findIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); + assert.strictEqual(_.findIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); }); - test('findLastIndex', function() { + test('findLastIndex', function(assert) { var objects = [ {a: 0, b: 0}, {a: 1, b: 1}, @@ -493,65 +493,65 @@ {a: 0, b: 0} ]; - equal(_.findLastIndex(objects, function(obj) { + assert.equal(_.findLastIndex(objects, function(obj) { return obj.a === 0; }), 3); - equal(_.findLastIndex(objects, function(obj) { + assert.equal(_.findLastIndex(objects, function(obj) { return obj.b * obj.a === 4; }), 2); - equal(_.findLastIndex(objects, 'a'), 2, 'Uses lookupIterator'); + assert.equal(_.findLastIndex(objects, 'a'), 2, 'Uses lookupIterator'); - equal(_.findLastIndex(objects, function(obj) { + assert.equal(_.findLastIndex(objects, function(obj) { return obj.b * obj.a === 5; }), -1); - equal(_.findLastIndex(null, _.noop), -1); - strictEqual(_.findLastIndex(objects, function(a) { + assert.equal(_.findLastIndex(null, _.noop), -1); + assert.strictEqual(_.findLastIndex(objects, function(a) { return a.foo === null; }), -1); _.findLastIndex([{a: 1}], function(a, key, obj) { - equal(key, 0); - deepEqual(obj, [{a: 1}]); - strictEqual(this, objects, 'called with context'); + assert.equal(key, 0); + assert.deepEqual(obj, [{a: 1}]); + assert.strictEqual(this, objects, 'called with context'); }, objects); var sparse = []; sparse[20] = {a: 2, b: 2}; - equal(_.findLastIndex(sparse, function(obj) { + assert.equal(_.findLastIndex(sparse, function(obj) { return obj && obj.b * obj.a === 4; }), 20, 'Works with sparse arrays'); var array = [1, 2, 3, 4]; array.match = 55; - strictEqual(_.findLastIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); + assert.strictEqual(_.findLastIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); }); - test('range', function() { - deepEqual(_.range(0), [], 'range with 0 as a first argument generates an empty array'); - deepEqual(_.range(4), [0, 1, 2, 3], 'range with a single positive argument generates an array of elements 0,1,2,...,n-1'); - deepEqual(_.range(5, 8), [5, 6, 7], 'range with two arguments a & b, a<b generates an array of elements a,a+1,a+2,...,b-2,b-1'); - deepEqual(_.range(8, 5), [], 'range with two arguments a & b, b<a generates an empty array'); - deepEqual(_.range(3, 10, 3), [3, 6, 9], 'range with three arguments a & b & c, c < b-a, a < b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) < c'); - deepEqual(_.range(3, 10, 15), [3], 'range with three arguments a & b & c, c > b-a, a < b generates an array with a single element, equal to a'); - deepEqual(_.range(12, 7, -2), [12, 10, 8], 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b'); - deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs'); + test('range', function(assert) { + assert.deepEqual(_.range(0), [], 'range with 0 as a first argument generates an empty array'); + assert.deepEqual(_.range(4), [0, 1, 2, 3], 'range with a single positive argument generates an array of elements 0,1,2,...,n-1'); + assert.deepEqual(_.range(5, 8), [5, 6, 7], 'range with two arguments a & b, a<b generates an array of elements a,a+1,a+2,...,b-2,b-1'); + assert.deepEqual(_.range(8, 5), [], 'range with two arguments a & b, b<a generates an empty array'); + assert.deepEqual(_.range(3, 10, 3), [3, 6, 9], 'range with three arguments a & b & c, c < b-a, a < b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) < c'); + assert.deepEqual(_.range(3, 10, 15), [3], 'range with three arguments a & b & c, c > b-a, a < b generates an array with a single element, equal to a'); + assert.deepEqual(_.range(12, 7, -2), [12, 10, 8], 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b'); + assert.deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs'); }); - test('chunk', function() { - deepEqual(_.chunk([], 2), [], 'chunk for empty array returns an empty array'); + test('chunk', function(assert) { + assert.deepEqual(_.chunk([], 2), [], 'chunk for empty array returns an empty array'); - deepEqual(_.chunk([1, 2, 3], 0), [], 'chunk into parts of 0 elements returns empty array'); - deepEqual(_.chunk([1, 2, 3], -1), [], 'chunk into parts of negative amount of elements returns an empty array'); - deepEqual(_.chunk([1, 2, 3]), [], 'defaults to empty array (chunk size 0)'); + assert.deepEqual(_.chunk([1, 2, 3], 0), [], 'chunk into parts of 0 elements returns empty array'); + assert.deepEqual(_.chunk([1, 2, 3], -1), [], 'chunk into parts of negative amount of elements returns an empty array'); + assert.deepEqual(_.chunk([1, 2, 3]), [], 'defaults to empty array (chunk size 0)'); - deepEqual(_.chunk([1, 2, 3], 1), [[1], [2], [3]], 'chunk into parts of 1 elements returns original array'); + assert.deepEqual(_.chunk([1, 2, 3], 1), [[1], [2], [3]], 'chunk into parts of 1 elements returns original array'); - deepEqual(_.chunk([1, 2, 3], 3), [[1, 2, 3]], 'chunk into parts of current array length elements returns the original array'); - deepEqual(_.chunk([1, 2, 3], 5), [[1, 2, 3]], 'chunk into parts of more then current array length elements returns the original array'); + assert.deepEqual(_.chunk([1, 2, 3], 3), [[1, 2, 3]], 'chunk into parts of current array length elements returns the original array'); + assert.deepEqual(_.chunk([1, 2, 3], 5), [[1, 2, 3]], 'chunk into parts of more then current array length elements returns the original array'); - deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 2), [[10, 20], [30, 40], [50, 60], [70]], 'chunk into parts of less then current array length elements'); - deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 3), [[10, 20, 30], [40, 50, 60], [70]], 'chunk into parts of less then current array length elements'); + assert.deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 2), [[10, 20], [30, 40], [50, 60], [70]], 'chunk into parts of less then current array length elements'); + assert.deepEqual(_.chunk([10, 20, 30, 40, 50, 60, 70], 3), [[10, 20, 30], [40, 50, 60], [70]], 'chunk into parts of less then current array length elements'); }); }()); diff --git a/test/chaining.js b/test/chaining.js index c5830f36f..1e708b90b 100644 --- a/test/chaining.js +++ b/test/chaining.js @@ -3,7 +3,7 @@ QUnit.module('Chaining'); - test('map/flatten/reduce', function() { + test('map/flatten/reduce', function(assert) { var lyrics = [ 'I\'m a lumberjack and I\'m okay', 'I sleep all night and I work all day', @@ -19,11 +19,11 @@ return hash; }, {}) .value(); - equal(counts.a, 16, 'counted all the letters in the song'); - equal(counts.e, 10, 'counted all the letters in the song'); + assert.equal(counts.a, 16, 'counted all the letters in the song'); + assert.equal(counts.e, 10, 'counted all the letters in the song'); }); - test('select/reject/sortBy', function() { + test('select/reject/sortBy', function(assert) { var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; numbers = _(numbers).chain().select(function(n) { return n % 2 === 0; @@ -32,10 +32,10 @@ }).sortBy(function(n) { return -n; }).value(); - deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); + assert.deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); }); - test('select/reject/sortBy in functional style', function() { + test('select/reject/sortBy in functional style', function(assert) { var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; numbers = _.chain(numbers).select(function(n) { return n % 2 === 0; @@ -44,10 +44,10 @@ }).sortBy(function(n) { return -n; }).value(); - deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); + assert.deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); }); - test('reverse/concat/unshift/pop/map', function() { + test('reverse/concat/unshift/pop/map', function(assert) { var numbers = [1, 2, 3, 4, 5]; numbers = _(numbers).chain() .reverse() @@ -56,44 +56,44 @@ .pop() .map(function(n){ return n * 2; }) .value(); - deepEqual(numbers, [34, 10, 8, 6, 4, 2, 10, 10], 'can chain together array functions.'); + assert.deepEqual(numbers, [34, 10, 8, 6, 4, 2, 10, 10], 'can chain together array functions.'); }); - test('splice', function() { + test('splice', function(assert) { var instance = _([1, 2, 3, 4, 5]).chain(); - deepEqual(instance.splice(1, 3).value(), [1, 5]); - deepEqual(instance.splice(1, 0).value(), [1, 5]); - deepEqual(instance.splice(1, 1).value(), [1]); - deepEqual(instance.splice(0, 1).value(), [], '#397 Can create empty array'); + assert.deepEqual(instance.splice(1, 3).value(), [1, 5]); + assert.deepEqual(instance.splice(1, 0).value(), [1, 5]); + assert.deepEqual(instance.splice(1, 1).value(), [1]); + assert.deepEqual(instance.splice(0, 1).value(), [], '#397 Can create empty array'); }); - test('shift', function() { + test('shift', function(assert) { var instance = _([1, 2, 3]).chain(); - deepEqual(instance.shift().value(), [2, 3]); - deepEqual(instance.shift().value(), [3]); - deepEqual(instance.shift().value(), [], '#397 Can create empty array'); + assert.deepEqual(instance.shift().value(), [2, 3]); + assert.deepEqual(instance.shift().value(), [3]); + assert.deepEqual(instance.shift().value(), [], '#397 Can create empty array'); }); - test('pop', function() { + test('pop', function(assert) { var instance = _([1, 2, 3]).chain(); - deepEqual(instance.pop().value(), [1, 2]); - deepEqual(instance.pop().value(), [1]); - deepEqual(instance.pop().value(), [], '#397 Can create empty array'); + assert.deepEqual(instance.pop().value(), [1, 2]); + assert.deepEqual(instance.pop().value(), [1]); + assert.deepEqual(instance.pop().value(), [], '#397 Can create empty array'); }); - test('chaining works in small stages', function() { + test('chaining works in small stages', function(assert) { var o = _([1, 2, 3, 4]).chain(); - deepEqual(o.filter(function(i) { return i < 3; }).value(), [1, 2]); - deepEqual(o.filter(function(i) { return i > 2; }).value(), [3, 4]); + assert.deepEqual(o.filter(function(i) { return i < 3; }).value(), [1, 2]); + assert.deepEqual(o.filter(function(i) { return i > 2; }).value(), [3, 4]); }); - test('#1562: Engine proxies for chained functions', function() { + test('#1562: Engine proxies for chained functions', function(assert) { var wrapped = _(512); - strictEqual(wrapped.toJSON(), 512); - strictEqual(wrapped.valueOf(), 512); - strictEqual(+wrapped, 512); - strictEqual(wrapped.toString(), '512'); - strictEqual('' + wrapped, '512'); + assert.strictEqual(wrapped.toJSON(), 512); + assert.strictEqual(wrapped.valueOf(), 512); + assert.strictEqual(+wrapped, 512); + assert.strictEqual(wrapped.toString(), '512'); + assert.strictEqual('' + wrapped, '512'); }); }()); diff --git a/test/collections.js b/test/collections.js index 485eb0ce8..c718bab80 100644 --- a/test/collections.js +++ b/test/collections.js @@ -3,24 +3,24 @@ QUnit.module('Collections'); - test('each', function() { + test('each', function(assert) { _.each([1, 2, 3], function(num, i) { - equal(num, i + 1, 'each iterators provide value and iteration count'); + assert.equal(num, i + 1, 'each iterators provide value and iteration count'); }); var answers = []; _.each([1, 2, 3], function(num){ answers.push(num * this.multiplier); }, {multiplier: 5}); - deepEqual(answers, [5, 10, 15], 'context object property accessed'); + assert.deepEqual(answers, [5, 10, 15], 'context object property accessed'); answers = []; _.each([1, 2, 3], function(num){ answers.push(num); }); - deepEqual(answers, [1, 2, 3], 'aliased as "forEach"'); + assert.deepEqual(answers, [1, 2, 3], 'aliased as "forEach"'); answers = []; var obj = {one: 1, two: 2, three: 3}; obj.constructor.prototype.four = 4; _.each(obj, function(value, key){ answers.push(key); }); - deepEqual(answers, ['one', 'two', 'three'], 'iterating over objects works, and ignores the object prototype.'); + assert.deepEqual(answers, ['one', 'two', 'three'], 'iterating over objects works, and ignores the object prototype.'); delete obj.constructor.prototype.four; // ensure the each function is JITed @@ -28,36 +28,36 @@ var count = 0; obj = {1: 'foo', 2: 'bar', 3: 'baz'}; _.each(obj, function(){ count++; }); - equal(count, 3, 'the fun should be called only 3 times'); + assert.equal(count, 3, 'the fun should be called only 3 times'); var answer = null; _.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; }); - ok(answer, 'can reference the original collection from inside the iterator'); + assert.ok(answer, 'can reference the original collection from inside the iterator'); answers = 0; _.each(null, function(){ ++answers; }); - equal(answers, 0, 'handles a null properly'); + assert.equal(answers, 0, 'handles a null properly'); _.each(false, function(){}); var a = [1, 2, 3]; - strictEqual(_.each(a, function(){}), a); - strictEqual(_.each(null, function(){}), null); + assert.strictEqual(_.each(a, function(){}), a); + assert.strictEqual(_.each(null, function(){}), null); }); - test('forEach', function() { - strictEqual(_.each, _.forEach, 'alias for each'); + test('forEach', function(assert) { + assert.strictEqual(_.each, _.forEach, 'alias for each'); }); - test('lookupIterator with contexts', function() { + test('lookupIterator with contexts', function(assert) { _.each([true, false, 'yes', '', 0, 1, {}], function(context) { _.each([1], function() { - equal(this, context); + assert.equal(this, context); }, context); }); }); - test('Iterating objects with sketchy length properties', function() { + test('Iterating objects with sketchy length properties', function(assert) { var functions = [ 'each', 'map', 'filter', 'find', 'some', 'every', 'max', 'min', @@ -79,29 +79,29 @@ {length: new Number(15)} ]; - expect(tricks.length * (functions.length + reducers.length + 4)); + assert.expect(tricks.length * (functions.length + reducers.length + 4)); _.each(tricks, function(trick) { var length = trick.length; - strictEqual(_.size(trick), 1, 'size on obj with length: ' + length); - deepEqual(_.toArray(trick), [length], 'toArray on obj with length: ' + length); - deepEqual(_.shuffle(trick), [length], 'shuffle on obj with length: ' + length); - deepEqual(_.sample(trick), length, 'sample on obj with length: ' + length); + assert.strictEqual(_.size(trick), 1, 'size on obj with length: ' + length); + assert.deepEqual(_.toArray(trick), [length], 'toArray on obj with length: ' + length); + assert.deepEqual(_.shuffle(trick), [length], 'shuffle on obj with length: ' + length); + assert.deepEqual(_.sample(trick), length, 'sample on obj with length: ' + length); _.each(functions, function(method) { _[method](trick, function(val, key) { - strictEqual(key, 'length', method + ': ran with length = ' + val); + assert.strictEqual(key, 'length', method + ': ran with length = ' + val); }); }); _.each(reducers, function(method) { - strictEqual(_[method](trick), trick.length, method); + assert.strictEqual(_[method](trick), trick.length, method); }); }); }); - test('Resistant to collection length and properties changing while iterating', function() { + test('Resistant to collection length and properties changing while iterating', function(assert) { var collection = [ 'each', 'map', 'filter', 'find', @@ -124,14 +124,14 @@ ++answers; return method === 'every' ? true : null; }, {}); - equal(answers, 100, method + ' enumerates [0, length)'); + assert.equal(answers, 100, method + ' enumerates [0, length)'); var growingCollection = [1, 2, 3], count = 0; _[method](growingCollection, function() { if (count < 10) growingCollection.push(count++); return method === 'every' ? true : null; }, {}); - equal(count, 3, method + ' is resistant to length changes'); + assert.equal(count, 3, method + ' is resistant to length changes'); }); _.each(collection.concat(object), function(method) { @@ -141,85 +141,85 @@ return method === 'every' ? true : null; }, {}); - equal(count, 2, method + ' is resistant to property changes'); + assert.equal(count, 2, method + ' is resistant to property changes'); }); }); - test('map', function() { + test('map', function(assert) { var doubled = _.map([1, 2, 3], function(num){ return num * 2; }); - deepEqual(doubled, [2, 4, 6], 'doubled numbers'); + assert.deepEqual(doubled, [2, 4, 6], 'doubled numbers'); var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier: 3}); - deepEqual(tripled, [3, 6, 9], 'tripled numbers with context'); + assert.deepEqual(tripled, [3, 6, 9], 'tripled numbers with context'); doubled = _([1, 2, 3]).map(function(num){ return num * 2; }); - deepEqual(doubled, [2, 4, 6], 'OO-style doubled numbers'); + assert.deepEqual(doubled, [2, 4, 6], 'OO-style doubled numbers'); var ids = _.map({length: 2, 0: {id: '1'}, 1: {id: '2'}}, function(n){ return n.id; }); - deepEqual(ids, ['1', '2'], 'Can use collection methods on Array-likes.'); + assert.deepEqual(ids, ['1', '2'], 'Can use collection methods on Array-likes.'); - deepEqual(_.map(null, _.noop), [], 'handles a null properly'); + assert.deepEqual(_.map(null, _.noop), [], 'handles a null properly'); - deepEqual(_.map([1], function() { + assert.deepEqual(_.map([1], function() { return this.length; }, [5]), [1], 'called with context'); // Passing a property name like _.pluck. var people = [{name: 'moe', age: 30}, {name: 'curly', age: 50}]; - deepEqual(_.map(people, 'name'), ['moe', 'curly'], 'predicate string map to object properties'); + assert.deepEqual(_.map(people, 'name'), ['moe', 'curly'], 'predicate string map to object properties'); }); - test('collect', function() { - strictEqual(_.map, _.collect, 'alias for map'); + test('collect', function(assert) { + assert.strictEqual(_.map, _.collect, 'alias for map'); }); - test('reduce', function() { + test('reduce', function(assert) { var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0); - equal(sum, 6, 'can sum up an array'); + assert.equal(sum, 6, 'can sum up an array'); var context = {multiplier: 3}; sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num * this.multiplier; }, 0, context); - equal(sum, 18, 'can reduce with a context object'); + assert.equal(sum, 18, 'can reduce with a context object'); sum = _.inject([1, 2, 3], function(memo, num){ return memo + num; }, 0); - equal(sum, 6, 'aliased as "inject"'); + assert.equal(sum, 6, 'aliased as "inject"'); sum = _([1, 2, 3]).reduce(function(memo, num){ return memo + num; }, 0); - equal(sum, 6, 'OO-style reduce'); + assert.equal(sum, 6, 'OO-style reduce'); sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }); - equal(sum, 6, 'default initial value'); + assert.equal(sum, 6, 'default initial value'); var prod = _.reduce([1, 2, 3, 4], function(memo, num){ return memo * num; }); - equal(prod, 24, 'can reduce via multiplication'); + assert.equal(prod, 24, 'can reduce via multiplication'); - ok(_.reduce(null, _.noop, 138) === 138, 'handles a null (with initial value) properly'); - equal(_.reduce([], _.noop, void 0), void 0, 'undefined can be passed as a special case'); - equal(_.reduce([_], _.noop), _, 'collection of length one with no initial value returns the first item'); - equal(_.reduce([], _.noop), void 0, 'returns undefined when collection is empty and no initial value'); + assert.ok(_.reduce(null, _.noop, 138) === 138, 'handles a null (with initial value) properly'); + assert.equal(_.reduce([], _.noop, void 0), void 0, 'undefined can be passed as a special case'); + assert.equal(_.reduce([_], _.noop), _, 'collection of length one with no initial value returns the first item'); + assert.equal(_.reduce([], _.noop), void 0, 'returns undefined when collection is empty and no initial value'); }); - test('foldl', function() { - strictEqual(_.reduce, _.foldl, 'alias for reduce'); + test('foldl', function(assert) { + assert.strictEqual(_.reduce, _.foldl, 'alias for reduce'); }); - test('reduceRight', function() { + test('reduceRight', function(assert) { var list = _.reduceRight(['foo', 'bar', 'baz'], function(memo, str){ return memo + str; }, ''); - equal(list, 'bazbarfoo', 'can perform right folds'); + assert.equal(list, 'bazbarfoo', 'can perform right folds'); list = _.reduceRight(['foo', 'bar', 'baz'], function(memo, str){ return memo + str; }); - equal(list, 'bazbarfoo', 'default initial value'); + assert.equal(list, 'bazbarfoo', 'default initial value'); var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(memo, num){ return memo + num; }); - equal(sum, 6, 'default initial value on object'); + assert.equal(sum, 6, 'default initial value on object'); - ok(_.reduceRight(null, _.noop, 138) === 138, 'handles a null (with initial value) properly'); - equal(_.reduceRight([_], _.noop), _, 'collection of length one with no initial value returns the first item'); + assert.ok(_.reduceRight(null, _.noop, 138) === 138, 'handles a null (with initial value) properly'); + assert.equal(_.reduceRight([_], _.noop), _, 'collection of length one with no initial value returns the first item'); - equal(_.reduceRight([], _.noop, void 0), void 0, 'undefined can be passed as a special case'); - equal(_.reduceRight([], _.noop), void 0, 'returns undefined when collection is empty and no initial value'); + assert.equal(_.reduceRight([], _.noop, void 0), void 0, 'undefined can be passed as a special case'); + assert.equal(_.reduceRight([], _.noop), void 0, 'returns undefined when collection is empty and no initial value'); // Assert that the correct arguments are being passed. @@ -236,7 +236,7 @@ if (!args) args = _.toArray(arguments); }, init); - deepEqual(args, expected); + assert.deepEqual(args, expected); // And again, with numeric keys. @@ -252,30 +252,30 @@ if (!args) args = _.toArray(arguments); }, init); - deepEqual(args, expected); + assert.deepEqual(args, expected); }); - test('foldr', function() { - strictEqual(_.reduceRight, _.foldr, 'alias for reduceRight'); + test('foldr', function(assert) { + assert.strictEqual(_.reduceRight, _.foldr, 'alias for reduceRight'); }); - test('find', function() { + test('find', function(assert) { var array = [1, 2, 3, 4]; - strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found `value`'); - strictEqual(_.find(array, function() { return false; }), void 0, 'should return `undefined` if `value` is not found'); + assert.strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found `value`'); + assert.strictEqual(_.find(array, function() { return false; }), void 0, 'should return `undefined` if `value` is not found'); array.dontmatch = 55; - strictEqual(_.find(array, function(x) { return x === 55; }), void 0, 'iterates array-likes correctly'); + assert.strictEqual(_.find(array, function(x) { return x === 55; }), void 0, 'iterates array-likes correctly'); // Matching an object like _.findWhere. var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}]; - deepEqual(_.find(list, {a: 1}), {a: 1, b: 2}, 'can be used as findWhere'); - deepEqual(_.find(list, {b: 4}), {a: 1, b: 4}); - ok(!_.find(list, {c: 1}), 'undefined when not found'); - ok(!_.find([], {c: 1}), 'undefined when searching empty list'); + assert.deepEqual(_.find(list, {a: 1}), {a: 1, b: 2}, 'can be used as findWhere'); + assert.deepEqual(_.find(list, {b: 4}), {a: 1, b: 4}); + assert.ok(!_.find(list, {c: 1}), 'undefined when not found'); + assert.ok(!_.find([], {c: 1}), 'undefined when searching empty list'); var result = _.find([1, 2, 3], function(num){ return num * 2 === 4; }); - equal(result, 2, 'found the first "2" and broke the loop'); + assert.equal(result, 2, 'found the first "2" and broke the loop'); var obj = { a: {x: 1, z: 3}, @@ -284,348 +284,348 @@ d: {x: 4, z: 1} }; - deepEqual(_.find(obj, {x: 2}), {x: 2, z: 2}, 'works on objects'); - deepEqual(_.find(obj, {x: 2, z: 1}), void 0); - deepEqual(_.find(obj, function(x) { + assert.deepEqual(_.find(obj, {x: 2}), {x: 2, z: 2}, 'works on objects'); + assert.deepEqual(_.find(obj, {x: 2, z: 1}), void 0); + assert.deepEqual(_.find(obj, function(x) { return x.x === 4; }), {x: 4, z: 1}); _.findIndex([{a: 1}], function(a, key, o) { - equal(key, 0); - deepEqual(o, [{a: 1}]); - strictEqual(this, _, 'called with context'); + assert.equal(key, 0); + assert.deepEqual(o, [{a: 1}]); + assert.strictEqual(this, _, 'called with context'); }, _); }); - test('detect', function() { - strictEqual(_.detect, _.find, 'alias for detect'); + test('detect', function(assert) { + assert.strictEqual(_.detect, _.find, 'alias for detect'); }); - test('filter', function() { + test('filter', function(assert) { var evenArray = [1, 2, 3, 4, 5, 6]; var evenObject = {one: 1, two: 2, three: 3}; var isEven = function(num){ return num % 2 === 0; }; - deepEqual(_.filter(evenArray, isEven), [2, 4, 6]); - deepEqual(_.filter(evenObject, isEven), [2], 'can filter objects'); - deepEqual(_.filter([{}, evenObject, []], 'two'), [evenObject], 'predicate string map to object properties'); + assert.deepEqual(_.filter(evenArray, isEven), [2, 4, 6]); + assert.deepEqual(_.filter(evenObject, isEven), [2], 'can filter objects'); + assert.deepEqual(_.filter([{}, evenObject, []], 'two'), [evenObject], 'predicate string map to object properties'); _.filter([1], function() { - equal(this, evenObject, 'given context'); + assert.equal(this, evenObject, 'given context'); }, evenObject); // Can be used like _.where. var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; - deepEqual(_.filter(list, {a: 1}), [{a: 1, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]); - deepEqual(_.filter(list, {b: 2}), [{a: 1, b: 2}, {a: 2, b: 2}]); - deepEqual(_.filter(list, {}), list, 'Empty object accepts all items'); - deepEqual(_(list).filter({}), list, 'OO-filter'); + assert.deepEqual(_.filter(list, {a: 1}), [{a: 1, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]); + assert.deepEqual(_.filter(list, {b: 2}), [{a: 1, b: 2}, {a: 2, b: 2}]); + assert.deepEqual(_.filter(list, {}), list, 'Empty object accepts all items'); + assert.deepEqual(_(list).filter({}), list, 'OO-filter'); }); - test('select', function() { - strictEqual(_.filter, _.select, 'alias for filter'); + test('select', function(assert) { + assert.strictEqual(_.filter, _.select, 'alias for filter'); }); - test('reject', function() { + test('reject', function(assert) { var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 === 0; }); - deepEqual(odds, [1, 3, 5], 'rejected each even number'); + assert.deepEqual(odds, [1, 3, 5], 'rejected each even number'); var context = 'obj'; var evens = _.reject([1, 2, 3, 4, 5, 6], function(num){ - equal(context, 'obj'); + assert.equal(context, 'obj'); return num % 2 !== 0; }, context); - deepEqual(evens, [2, 4, 6], 'rejected each odd number'); + assert.deepEqual(evens, [2, 4, 6], 'rejected each odd number'); - deepEqual(_.reject([odds, {one: 1, two: 2, three: 3}], 'two'), [odds], 'predicate string map to object properties'); + assert.deepEqual(_.reject([odds, {one: 1, two: 2, three: 3}], 'two'), [odds], 'predicate string map to object properties'); // Can be used like _.where. var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; - deepEqual(_.reject(list, {a: 1}), [{a: 2, b: 2}]); - deepEqual(_.reject(list, {b: 2}), [{a: 1, b: 3}, {a: 1, b: 4}]); - deepEqual(_.reject(list, {}), [], 'Returns empty list given empty object'); - deepEqual(_.reject(list, []), [], 'Returns empty list given empty array'); - }); - - test('every', function() { - ok(_.every([], _.identity), 'the empty set'); - ok(_.every([true, true, true], _.identity), 'every true values'); - ok(!_.every([true, false, true], _.identity), 'one false value'); - ok(_.every([0, 10, 28], function(num){ return num % 2 === 0; }), 'even numbers'); - ok(!_.every([0, 11, 28], function(num){ return num % 2 === 0; }), 'an odd number'); - ok(_.every([1], _.identity) === true, 'cast to boolean - true'); - ok(_.every([0], _.identity) === false, 'cast to boolean - false'); - ok(!_.every([void 0, void 0, void 0], _.identity), 'works with arrays of undefined'); + assert.deepEqual(_.reject(list, {a: 1}), [{a: 2, b: 2}]); + assert.deepEqual(_.reject(list, {b: 2}), [{a: 1, b: 3}, {a: 1, b: 4}]); + assert.deepEqual(_.reject(list, {}), [], 'Returns empty list given empty object'); + assert.deepEqual(_.reject(list, []), [], 'Returns empty list given empty array'); + }); + + test('every', function(assert) { + assert.ok(_.every([], _.identity), 'the empty set'); + assert.ok(_.every([true, true, true], _.identity), 'every true values'); + assert.ok(!_.every([true, false, true], _.identity), 'one false value'); + assert.ok(_.every([0, 10, 28], function(num){ return num % 2 === 0; }), 'even numbers'); + assert.ok(!_.every([0, 11, 28], function(num){ return num % 2 === 0; }), 'an odd number'); + assert.ok(_.every([1], _.identity) === true, 'cast to boolean - true'); + assert.ok(_.every([0], _.identity) === false, 'cast to boolean - false'); + assert.ok(!_.every([void 0, void 0, void 0], _.identity), 'works with arrays of undefined'); var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; - ok(!_.every(list, {a: 1, b: 2}), 'Can be called with object'); - ok(_.every(list, 'a'), 'String mapped to object property'); + assert.ok(!_.every(list, {a: 1, b: 2}), 'Can be called with object'); + assert.ok(_.every(list, 'a'), 'String mapped to object property'); list = [{a: 1, b: 2}, {a: 2, b: 2, c: true}]; - ok(_.every(list, {b: 2}), 'Can be called with object'); - ok(!_.every(list, 'c'), 'String mapped to object property'); + assert.ok(_.every(list, {b: 2}), 'Can be called with object'); + assert.ok(!_.every(list, 'c'), 'String mapped to object property'); - ok(_.every({a: 1, b: 2, c: 3, d: 4}, _.isNumber), 'takes objects'); - ok(!_.every({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects'); - ok(_.every(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); - ok(!_.every(['a', 'b', 'c', 'd', 'f'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); + assert.ok(_.every({a: 1, b: 2, c: 3, d: 4}, _.isNumber), 'takes objects'); + assert.ok(!_.every({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects'); + assert.ok(_.every(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); + assert.ok(!_.every(['a', 'b', 'c', 'd', 'f'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); }); - test('all', function() { - strictEqual(_.all, _.every, 'alias for all'); + test('all', function(assert) { + assert.strictEqual(_.all, _.every, 'alias for all'); }); - test('some', function() { - ok(!_.some([]), 'the empty set'); - ok(!_.some([false, false, false]), 'all false values'); - ok(_.some([false, false, true]), 'one true value'); - ok(_.some([null, 0, 'yes', false]), 'a string'); - ok(!_.some([null, 0, '', false]), 'falsy values'); - ok(!_.some([1, 11, 29], function(num){ return num % 2 === 0; }), 'all odd numbers'); - ok(_.some([1, 10, 29], function(num){ return num % 2 === 0; }), 'an even number'); - ok(_.some([1], _.identity) === true, 'cast to boolean - true'); - ok(_.some([0], _.identity) === false, 'cast to boolean - false'); - ok(_.some([false, false, true])); + test('some', function(assert) { + assert.ok(!_.some([]), 'the empty set'); + assert.ok(!_.some([false, false, false]), 'all false values'); + assert.ok(_.some([false, false, true]), 'one true value'); + assert.ok(_.some([null, 0, 'yes', false]), 'a string'); + assert.ok(!_.some([null, 0, '', false]), 'falsy values'); + assert.ok(!_.some([1, 11, 29], function(num){ return num % 2 === 0; }), 'all odd numbers'); + assert.ok(_.some([1, 10, 29], function(num){ return num % 2 === 0; }), 'an even number'); + assert.ok(_.some([1], _.identity) === true, 'cast to boolean - true'); + assert.ok(_.some([0], _.identity) === false, 'cast to boolean - false'); + assert.ok(_.some([false, false, true])); var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; - ok(!_.some(list, {a: 5, b: 2}), 'Can be called with object'); - ok(_.some(list, 'a'), 'String mapped to object property'); + assert.ok(!_.some(list, {a: 5, b: 2}), 'Can be called with object'); + assert.ok(_.some(list, 'a'), 'String mapped to object property'); list = [{a: 1, b: 2}, {a: 2, b: 2, c: true}]; - ok(_.some(list, {b: 2}), 'Can be called with object'); - ok(!_.some(list, 'd'), 'String mapped to object property'); + assert.ok(_.some(list, {b: 2}), 'Can be called with object'); + assert.ok(!_.some(list, 'd'), 'String mapped to object property'); - ok(_.some({a: '1', b: '2', c: '3', d: '4', e: 6}, _.isNumber), 'takes objects'); - ok(!_.some({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects'); - ok(_.some(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); - ok(!_.some(['x', 'y', 'z'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); + assert.ok(_.some({a: '1', b: '2', c: '3', d: '4', e: 6}, _.isNumber), 'takes objects'); + assert.ok(!_.some({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects'); + assert.ok(_.some(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); + assert.ok(!_.some(['x', 'y', 'z'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); }); - test('any', function() { - strictEqual(_.any, _.some, 'alias for any'); + test('any', function(assert) { + assert.strictEqual(_.any, _.some, 'alias for any'); }); - test('includes', function() { + test('includes', function(assert) { _.each([null, void 0, 0, 1, NaN, {}, []], function(val) { - strictEqual(_.includes(val, 'hasOwnProperty'), false); + assert.strictEqual(_.includes(val, 'hasOwnProperty'), false); }); - strictEqual(_.includes([1, 2, 3], 2), true, 'two is in the array'); - ok(!_.includes([1, 3, 9], 2), 'two is not in the array'); + assert.strictEqual(_.includes([1, 2, 3], 2), true, 'two is in the array'); + assert.ok(!_.includes([1, 3, 9], 2), 'two is not in the array'); - strictEqual(_.includes([5, 4, 3, 2, 1], 5, true), true, 'doesn\'t delegate to binary search'); + assert.strictEqual(_.includes([5, 4, 3, 2, 1], 5, true), true, 'doesn\'t delegate to binary search'); - ok(_.includes({moe: 1, larry: 3, curly: 9}, 3) === true, '_.includes on objects checks their values'); - ok(_([1, 2, 3]).includes(2), 'OO-style includes'); + assert.ok(_.includes({moe: 1, larry: 3, curly: 9}, 3) === true, '_.includes on objects checks their values'); + assert.ok(_([1, 2, 3]).includes(2), 'OO-style includes'); }); - test('include', function() { - strictEqual(_.includes, _.include, 'alias for includes'); + test('include', function(assert) { + assert.strictEqual(_.includes, _.include, 'alias for includes'); }); - test('contains', function() { - strictEqual(_.includes, _.contains, 'alias for includes'); + test('contains', function(assert) { + assert.strictEqual(_.includes, _.contains, 'alias for includes'); var numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; - strictEqual(_.includes(numbers, 1, 1), true, 'contains takes a fromIndex'); - strictEqual(_.includes(numbers, 1, -1), false, 'contains takes a fromIndex'); - strictEqual(_.includes(numbers, 1, -2), false, 'contains takes a fromIndex'); - strictEqual(_.includes(numbers, 1, -3), true, 'contains takes a fromIndex'); - strictEqual(_.includes(numbers, 1, 6), true, 'contains takes a fromIndex'); - strictEqual(_.includes(numbers, 1, 7), false, 'contains takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, 1), true, 'contains takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, -1), false, 'contains takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, -2), false, 'contains takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, -3), true, 'contains takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, 6), true, 'contains takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, 7), false, 'contains takes a fromIndex'); - ok(_.every([1, 2, 3], _.partial(_.contains, numbers)), 'fromIndex is guarded'); + assert.ok(_.every([1, 2, 3], _.partial(_.contains, numbers)), 'fromIndex is guarded'); }); - test('includes with NaN', function() { - strictEqual(_.includes([1, 2, NaN, NaN], NaN), true, 'Expected [1, 2, NaN] to contain NaN'); - strictEqual(_.includes([1, 2, Infinity], NaN), false, 'Expected [1, 2, NaN] to contain NaN'); + test('includes with NaN', function(assert) { + assert.strictEqual(_.includes([1, 2, NaN, NaN], NaN), true, 'Expected [1, 2, NaN] to contain NaN'); + assert.strictEqual(_.includes([1, 2, Infinity], NaN), false, 'Expected [1, 2, NaN] to contain NaN'); }); - test('includes with +- 0', function() { + test('includes with +- 0', function(assert) { _.each([-0, +0], function(val) { - strictEqual(_.includes([1, 2, val, val], val), true); - strictEqual(_.includes([1, 2, val, val], -val), true); - strictEqual(_.includes([-1, 1, 2], -val), false); + assert.strictEqual(_.includes([1, 2, val, val], val), true); + assert.strictEqual(_.includes([1, 2, val, val], -val), true); + assert.strictEqual(_.includes([-1, 1, 2], -val), false); }); }); - test('invoke', 5, function() { + test('invoke', 5, function(assert) { var list = [[5, 1, 7], [3, 2, 1]]; var result = _.invoke(list, 'sort'); - deepEqual(result[0], [1, 5, 7], 'first array sorted'); - deepEqual(result[1], [1, 2, 3], 'second array sorted'); + assert.deepEqual(result[0], [1, 5, 7], 'first array sorted'); + assert.deepEqual(result[1], [1, 2, 3], 'second array sorted'); _.invoke([{ method: function() { - deepEqual(_.toArray(arguments), [1, 2, 3], 'called with arguments'); + assert.deepEqual(_.toArray(arguments), [1, 2, 3], 'called with arguments'); } }], 'method', 1, 2, 3); - deepEqual(_.invoke([{a: null}, {}, {a: _.constant(1)}], 'a'), [null, void 0, 1], 'handles null & undefined'); + assert.deepEqual(_.invoke([{a: null}, {}, {a: _.constant(1)}], 'a'), [null, void 0, 1], 'handles null & undefined'); - throws(function() { + assert.throws(function() { _.invoke([{a: 1}], 'a'); }, TypeError, 'throws for non-functions'); }); - test('invoke w/ function reference', function() { + test('invoke w/ function reference', function(assert) { var list = [[5, 1, 7], [3, 2, 1]]; var result = _.invoke(list, Array.prototype.sort); - deepEqual(result[0], [1, 5, 7], 'first array sorted'); - deepEqual(result[1], [1, 2, 3], 'second array sorted'); + assert.deepEqual(result[0], [1, 5, 7], 'first array sorted'); + assert.deepEqual(result[1], [1, 2, 3], 'second array sorted'); - deepEqual(_.invoke([1, 2, 3], function(a) { + assert.deepEqual(_.invoke([1, 2, 3], function(a) { return a + this; }, 5), [6, 7, 8], 'receives params from invoke'); }); // Relevant when using ClojureScript - test('invoke when strings have a call method', function() { + test('invoke when strings have a call method', function(assert) { String.prototype.call = function() { return 42; }; var list = [[5, 1, 7], [3, 2, 1]]; var s = 'foo'; - equal(s.call(), 42, 'call function exists'); + assert.equal(s.call(), 42, 'call function exists'); var result = _.invoke(list, 'sort'); - deepEqual(result[0], [1, 5, 7], 'first array sorted'); - deepEqual(result[1], [1, 2, 3], 'second array sorted'); + assert.deepEqual(result[0], [1, 5, 7], 'first array sorted'); + assert.deepEqual(result[1], [1, 2, 3], 'second array sorted'); delete String.prototype.call; - equal(s.call, void 0, 'call function removed'); + assert.equal(s.call, void 0, 'call function removed'); }); - test('pluck', function() { + test('pluck', function(assert) { var people = [{name: 'moe', age: 30}, {name: 'curly', age: 50}]; - deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'pulls names out of objects'); - deepEqual(_.pluck(people, 'address'), [void 0, void 0], 'missing properties are returned as undefined'); + assert.deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'pulls names out of objects'); + assert.deepEqual(_.pluck(people, 'address'), [void 0, void 0], 'missing properties are returned as undefined'); //compat: most flexible handling of edge cases - deepEqual(_.pluck([{'[object Object]': 1}], {}), [1]); + assert.deepEqual(_.pluck([{'[object Object]': 1}], {}), [1]); }); - test('where', function() { + test('where', function(assert) { var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; var result = _.where(list, {a: 1}); - equal(result.length, 3); - equal(result[result.length - 1].b, 4); + assert.equal(result.length, 3); + assert.equal(result[result.length - 1].b, 4); result = _.where(list, {b: 2}); - equal(result.length, 2); - equal(result[0].a, 1); + assert.equal(result.length, 2); + assert.equal(result[0].a, 1); result = _.where(list, {}); - equal(result.length, list.length); + assert.equal(result.length, list.length); function test() {} test.map = _.map; - deepEqual(_.where([_, {a: 1, b: 2}, _], test), [_, _], 'checks properties given function'); + assert.deepEqual(_.where([_, {a: 1, b: 2}, _], test), [_, _], 'checks properties given function'); }); - test('findWhere', function() { + test('findWhere', function(assert) { var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}]; var result = _.findWhere(list, {a: 1}); - deepEqual(result, {a: 1, b: 2}); + assert.deepEqual(result, {a: 1, b: 2}); result = _.findWhere(list, {b: 4}); - deepEqual(result, {a: 1, b: 4}); + assert.deepEqual(result, {a: 1, b: 4}); result = _.findWhere(list, {c: 1}); - ok(_.isUndefined(result), 'undefined when not found'); + assert.ok(_.isUndefined(result), 'undefined when not found'); result = _.findWhere([], {c: 1}); - ok(_.isUndefined(result), 'undefined when searching empty list'); + assert.ok(_.isUndefined(result), 'undefined when searching empty list'); function test() {} test.map = _.map; - equal(_.findWhere([_, {a: 1, b: 2}, _], test), _, 'checks properties given function'); + assert.equal(_.findWhere([_, {a: 1, b: 2}, _], test), _, 'checks properties given function'); function TestClass() { this.y = 5; this.x = 'foo'; } var expect = {c: 1, x: 'foo', y: 5}; - deepEqual(_.findWhere([{y: 5, b: 6}, expect], new TestClass()), expect, 'uses class instance properties'); + assert.deepEqual(_.findWhere([{y: 5, b: 6}, expect], new TestClass()), expect, 'uses class instance properties'); }); - test('max', function() { - equal(-Infinity, _.max(null), 'can handle null/undefined'); - equal(-Infinity, _.max(void 0), 'can handle null/undefined'); - equal(-Infinity, _.max(null, _.identity), 'can handle null/undefined'); + test('max', function(assert) { + assert.equal(-Infinity, _.max(null), 'can handle null/undefined'); + assert.equal(-Infinity, _.max(void 0), 'can handle null/undefined'); + assert.equal(-Infinity, _.max(null, _.identity), 'can handle null/undefined'); - equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max'); + assert.equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max'); var neg = _.max([1, 2, 3], function(num){ return -num; }); - equal(neg, 1, 'can perform a computation-based max'); + assert.equal(neg, 1, 'can perform a computation-based max'); - equal(-Infinity, _.max({}), 'Maximum value of an empty object'); - equal(-Infinity, _.max([]), 'Maximum value of an empty array'); - equal(_.max({a: 'a'}), -Infinity, 'Maximum value of a non-numeric collection'); + assert.equal(-Infinity, _.max({}), 'Maximum value of an empty object'); + assert.equal(-Infinity, _.max([]), 'Maximum value of an empty array'); + assert.equal(_.max({a: 'a'}), -Infinity, 'Maximum value of a non-numeric collection'); - equal(299999, _.max(_.range(1, 300000)), 'Maximum value of a too-big array'); + assert.equal(299999, _.max(_.range(1, 300000)), 'Maximum value of a too-big array'); - equal(3, _.max([1, 2, 3, 'test']), 'Finds correct max in array starting with num and containing a NaN'); - equal(3, _.max(['test', 1, 2, 3]), 'Finds correct max in array starting with NaN'); + assert.equal(3, _.max([1, 2, 3, 'test']), 'Finds correct max in array starting with num and containing a NaN'); + assert.equal(3, _.max(['test', 1, 2, 3]), 'Finds correct max in array starting with NaN'); - deepEqual([3, 6], _.map([[1, 2, 3], [4, 5, 6]], _.max), 'Finds correct max in array when mapping through multiple arrays'); + assert.deepEqual([3, 6], _.map([[1, 2, 3], [4, 5, 6]], _.max), 'Finds correct max in array when mapping through multiple arrays'); var a = {x: -Infinity}; var b = {x: -Infinity}; var iterator = function(o){ return o.x; }; - equal(_.max([a, b], iterator), a, 'Respects iterator return value of -Infinity'); + assert.equal(_.max([a, b], iterator), a, 'Respects iterator return value of -Infinity'); - deepEqual(_.max([{a: 1}, {a: 0, b: 3}, {a: 4}, {a: 2}], 'a'), {a: 4}, 'String keys use property iterator'); + assert.deepEqual(_.max([{a: 1}, {a: 0, b: 3}, {a: 4}, {a: 2}], 'a'), {a: 4}, 'String keys use property iterator'); - deepEqual(_.max([0, 2], function(c){ return c * this.x; }, {x: 1}), 2, 'Iterator context'); - deepEqual(_.max([[1], [2, 3], [-1, 4], [5]], 0), [5], 'Lookup falsy iterator'); - deepEqual(_.max([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: 2}, 'Lookup falsy iterator'); + assert.deepEqual(_.max([0, 2], function(c){ return c * this.x; }, {x: 1}), 2, 'Iterator context'); + assert.deepEqual(_.max([[1], [2, 3], [-1, 4], [5]], 0), [5], 'Lookup falsy iterator'); + assert.deepEqual(_.max([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: 2}, 'Lookup falsy iterator'); }); - test('min', function() { - equal(Infinity, _.min(null), 'can handle null/undefined'); - equal(Infinity, _.min(void 0), 'can handle null/undefined'); - equal(Infinity, _.min(null, _.identity), 'can handle null/undefined'); + test('min', function(assert) { + assert.equal(Infinity, _.min(null), 'can handle null/undefined'); + assert.equal(Infinity, _.min(void 0), 'can handle null/undefined'); + assert.equal(Infinity, _.min(null, _.identity), 'can handle null/undefined'); - equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min'); + assert.equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min'); var neg = _.min([1, 2, 3], function(num){ return -num; }); - equal(neg, 3, 'can perform a computation-based min'); + assert.equal(neg, 3, 'can perform a computation-based min'); - equal(Infinity, _.min({}), 'Minimum value of an empty object'); - equal(Infinity, _.min([]), 'Minimum value of an empty array'); - equal(_.min({a: 'a'}), Infinity, 'Minimum value of a non-numeric collection'); + assert.equal(Infinity, _.min({}), 'Minimum value of an empty object'); + assert.equal(Infinity, _.min([]), 'Minimum value of an empty array'); + assert.equal(_.min({a: 'a'}), Infinity, 'Minimum value of a non-numeric collection'); - deepEqual([1, 4], _.map([[1, 2, 3], [4, 5, 6]], _.min), 'Finds correct min in array when mapping through multiple arrays'); + assert.deepEqual([1, 4], _.map([[1, 2, 3], [4, 5, 6]], _.min), 'Finds correct min in array when mapping through multiple arrays'); var now = new Date(9999999999); var then = new Date(0); - equal(_.min([now, then]), then); + assert.equal(_.min([now, then]), then); - equal(1, _.min(_.range(1, 300000)), 'Minimum value of a too-big array'); + assert.equal(1, _.min(_.range(1, 300000)), 'Minimum value of a too-big array'); - equal(1, _.min([1, 2, 3, 'test']), 'Finds correct min in array starting with num and containing a NaN'); - equal(1, _.min(['test', 1, 2, 3]), 'Finds correct min in array starting with NaN'); + assert.equal(1, _.min([1, 2, 3, 'test']), 'Finds correct min in array starting with num and containing a NaN'); + assert.equal(1, _.min(['test', 1, 2, 3]), 'Finds correct min in array starting with NaN'); var a = {x: Infinity}; var b = {x: Infinity}; var iterator = function(o){ return o.x; }; - equal(_.min([a, b], iterator), a, 'Respects iterator return value of Infinity'); + assert.equal(_.min([a, b], iterator), a, 'Respects iterator return value of Infinity'); - deepEqual(_.min([{a: 1}, {a: 0, b: 3}, {a: 4}, {a: 2}], 'a'), {a: 0, b: 3}, 'String keys use property iterator'); + assert.deepEqual(_.min([{a: 1}, {a: 0, b: 3}, {a: 4}, {a: 2}], 'a'), {a: 0, b: 3}, 'String keys use property iterator'); - deepEqual(_.min([0, 2], function(c){ return c * this.x; }, {x: -1}), 2, 'Iterator context'); - deepEqual(_.min([[1], [2, 3], [-1, 4], [5]], 0), [-1, 4], 'Lookup falsy iterator'); - deepEqual(_.min([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: -1}, 'Lookup falsy iterator'); + assert.deepEqual(_.min([0, 2], function(c){ return c * this.x; }, {x: -1}), 2, 'Iterator context'); + assert.deepEqual(_.min([[1], [2, 3], [-1, 4], [5]], 0), [-1, 4], 'Lookup falsy iterator'); + assert.deepEqual(_.min([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: -1}, 'Lookup falsy iterator'); }); - test('sortBy', function() { + test('sortBy', function(assert) { var people = [{name: 'curly', age: 50}, {name: 'moe', age: 30}]; people = _.sortBy(people, function(person){ return person.age; }); - deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'stooges sorted by age'); + assert.deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'stooges sorted by age'); var list = [void 0, 4, 1, void 0, 3, 2]; - deepEqual(_.sortBy(list, _.identity), [1, 2, 3, 4, void 0, void 0], 'sortBy with undefined values'); + assert.deepEqual(_.sortBy(list, _.identity), [1, 2, 3, 4, void 0, void 0], 'sortBy with undefined values'); list = ['one', 'two', 'three', 'four', 'five']; var sorted = _.sortBy(list, 'length'); - deepEqual(sorted, ['one', 'two', 'four', 'five', 'three'], 'sorted by length'); + assert.deepEqual(sorted, ['one', 'two', 'four', 'five', 'three'], 'sorted by length'); function Pair(x, y) { this.x = x; @@ -650,144 +650,144 @@ return pair.x; }); - deepEqual(actual, stableArray, 'sortBy should be stable for arrays'); - deepEqual(_.sortBy(stableArray, 'x'), stableArray, 'sortBy accepts property string'); + assert.deepEqual(actual, stableArray, 'sortBy should be stable for arrays'); + assert.deepEqual(_.sortBy(stableArray, 'x'), stableArray, 'sortBy accepts property string'); actual = _.sortBy(stableObject, function(pair) { return pair.x; }); - deepEqual(actual, stableArray, 'sortBy should be stable for objects'); + assert.deepEqual(actual, stableArray, 'sortBy should be stable for objects'); list = ['q', 'w', 'e', 'r', 't', 'y']; - deepEqual(_.sortBy(list), ['e', 'q', 'r', 't', 'w', 'y'], 'uses _.identity if iterator is not specified'); + assert.deepEqual(_.sortBy(list), ['e', 'q', 'r', 't', 'w', 'y'], 'uses _.identity if iterator is not specified'); }); - test('groupBy', function() { + test('groupBy', function(assert) { var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; }); - ok('0' in parity && '1' in parity, 'created a group for each value'); - deepEqual(parity[0], [2, 4, 6], 'put each even number in the right group'); + assert.ok('0' in parity && '1' in parity, 'created a group for each value'); + assert.deepEqual(parity[0], [2, 4, 6], 'put each even number in the right group'); var list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten']; var grouped = _.groupBy(list, 'length'); - deepEqual(grouped['3'], ['one', 'two', 'six', 'ten']); - deepEqual(grouped['4'], ['four', 'five', 'nine']); - deepEqual(grouped['5'], ['three', 'seven', 'eight']); + assert.deepEqual(grouped['3'], ['one', 'two', 'six', 'ten']); + assert.deepEqual(grouped['4'], ['four', 'five', 'nine']); + assert.deepEqual(grouped['5'], ['three', 'seven', 'eight']); var context = {}; - _.groupBy([{}], function(){ ok(this === context); }, context); + _.groupBy([{}], function(){ assert.ok(this === context); }, context); grouped = _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; }); - equal(grouped.constructor.length, 1); - equal(grouped.hasOwnProperty.length, 2); + assert.equal(grouped.constructor.length, 1); + assert.equal(grouped.hasOwnProperty.length, 2); var array = [{}]; - _.groupBy(array, function(value, index, obj){ ok(obj === array); }); + _.groupBy(array, function(value, index, obj){ assert.ok(obj === array); }); array = [1, 2, 1, 2, 3]; grouped = _.groupBy(array); - equal(grouped['1'].length, 2); - equal(grouped['3'].length, 1); + assert.equal(grouped['1'].length, 2); + assert.equal(grouped['3'].length, 1); var matrix = [ [1, 2], [1, 3], [2, 3] ]; - deepEqual(_.groupBy(matrix, 0), {1: [[1, 2], [1, 3]], 2: [[2, 3]]}); - deepEqual(_.groupBy(matrix, 1), {2: [[1, 2]], 3: [[1, 3], [2, 3]]}); + assert.deepEqual(_.groupBy(matrix, 0), {1: [[1, 2], [1, 3]], 2: [[2, 3]]}); + assert.deepEqual(_.groupBy(matrix, 1), {2: [[1, 2]], 3: [[1, 3], [2, 3]]}); }); - test('indexBy', function() { + test('indexBy', function(assert) { var parity = _.indexBy([1, 2, 3, 4, 5], function(num){ return num % 2 === 0; }); - equal(parity['true'], 4); - equal(parity['false'], 5); + assert.equal(parity['true'], 4); + assert.equal(parity['false'], 5); var list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten']; var grouped = _.indexBy(list, 'length'); - equal(grouped['3'], 'ten'); - equal(grouped['4'], 'nine'); - equal(grouped['5'], 'eight'); + assert.equal(grouped['3'], 'ten'); + assert.equal(grouped['4'], 'nine'); + assert.equal(grouped['5'], 'eight'); var array = [1, 2, 1, 2, 3]; grouped = _.indexBy(array); - equal(grouped['1'], 1); - equal(grouped['2'], 2); - equal(grouped['3'], 3); + assert.equal(grouped['1'], 1); + assert.equal(grouped['2'], 2); + assert.equal(grouped['3'], 3); }); - test('countBy', function() { + test('countBy', function(assert) { var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 === 0; }); - equal(parity['true'], 2); - equal(parity['false'], 3); + assert.equal(parity['true'], 2); + assert.equal(parity['false'], 3); var list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten']; var grouped = _.countBy(list, 'length'); - equal(grouped['3'], 4); - equal(grouped['4'], 3); - equal(grouped['5'], 3); + assert.equal(grouped['3'], 4); + assert.equal(grouped['4'], 3); + assert.equal(grouped['5'], 3); var context = {}; - _.countBy([{}], function(){ ok(this === context); }, context); + _.countBy([{}], function(){ assert.ok(this === context); }, context); grouped = _.countBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; }); - equal(grouped.constructor, 1); - equal(grouped.hasOwnProperty, 2); + assert.equal(grouped.constructor, 1); + assert.equal(grouped.hasOwnProperty, 2); var array = [{}]; - _.countBy(array, function(value, index, obj){ ok(obj === array); }); + _.countBy(array, function(value, index, obj){ assert.ok(obj === array); }); array = [1, 2, 1, 2, 3]; grouped = _.countBy(array); - equal(grouped['1'], 2); - equal(grouped['3'], 1); + assert.equal(grouped['1'], 2); + assert.equal(grouped['3'], 1); }); - test('shuffle', function() { - deepEqual(_.shuffle([1]), [1], 'behaves correctly on size 1 arrays'); + test('shuffle', function(assert) { + assert.deepEqual(_.shuffle([1]), [1], 'behaves correctly on size 1 arrays'); var numbers = _.range(20); var shuffled = _.shuffle(numbers); - notDeepEqual(numbers, shuffled, 'does change the order'); // Chance of false negative: 1 in ~2.4*10^18 - notStrictEqual(numbers, shuffled, 'original object is unmodified'); - deepEqual(numbers, _.sortBy(shuffled), 'contains the same members before and after shuffle'); + assert.notDeepEqual(numbers, shuffled, 'does change the order'); // Chance of false negative: 1 in ~2.4*10^18 + assert.notStrictEqual(numbers, shuffled, 'original object is unmodified'); + assert.deepEqual(numbers, _.sortBy(shuffled), 'contains the same members before and after shuffle'); shuffled = _.shuffle({a: 1, b: 2, c: 3, d: 4}); - equal(shuffled.length, 4); - deepEqual(shuffled.sort(), [1, 2, 3, 4], 'works on objects'); + assert.equal(shuffled.length, 4); + assert.deepEqual(shuffled.sort(), [1, 2, 3, 4], 'works on objects'); }); - test('sample', function() { - strictEqual(_.sample([1]), 1, 'behaves correctly when no second parameter is given'); - deepEqual(_.sample([1, 2, 3], -2), [], 'behaves correctly on negative n'); + test('sample', function(assert) { + assert.strictEqual(_.sample([1]), 1, 'behaves correctly when no second parameter is given'); + assert.deepEqual(_.sample([1, 2, 3], -2), [], 'behaves correctly on negative n'); var numbers = _.range(10); var allSampled = _.sample(numbers, 10).sort(); - deepEqual(allSampled, numbers, 'contains the same members before and after sample'); + assert.deepEqual(allSampled, numbers, 'contains the same members before and after sample'); allSampled = _.sample(numbers, 20).sort(); - deepEqual(allSampled, numbers, 'also works when sampling more objects than are present'); - ok(_.contains(numbers, _.sample(numbers)), 'sampling a single element returns something from the array'); - strictEqual(_.sample([]), void 0, 'sampling empty array with no number returns undefined'); - notStrictEqual(_.sample([], 5), [], 'sampling empty array with a number returns an empty array'); - notStrictEqual(_.sample([1, 2, 3], 0), [], 'sampling an array with 0 picks returns an empty array'); - deepEqual(_.sample([1, 2], -1), [], 'sampling a negative number of picks returns an empty array'); - ok(_.contains([1, 2, 3], _.sample({a: 1, b: 2, c: 3})), 'sample one value from an object'); + assert.deepEqual(allSampled, numbers, 'also works when sampling more objects than are present'); + assert.ok(_.contains(numbers, _.sample(numbers)), 'sampling a single element returns something from the array'); + assert.strictEqual(_.sample([]), void 0, 'sampling empty array with no number returns undefined'); + assert.notStrictEqual(_.sample([], 5), [], 'sampling empty array with a number returns an empty array'); + assert.notStrictEqual(_.sample([1, 2, 3], 0), [], 'sampling an array with 0 picks returns an empty array'); + assert.deepEqual(_.sample([1, 2], -1), [], 'sampling a negative number of picks returns an empty array'); + assert.ok(_.contains([1, 2, 3], _.sample({a: 1, b: 2, c: 3})), 'sample one value from an object'); var partialSample = _.sample(_.range(1000), 10); var partialSampleSorted = partialSample.sort(); - notDeepEqual(partialSampleSorted, _.range(10), 'samples from the whole array, not just the beginning'); + assert.notDeepEqual(partialSampleSorted, _.range(10), 'samples from the whole array, not just the beginning'); }); - test('toArray', function() { - ok(!_.isArray(arguments), 'arguments object is not an array'); - ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array'); + test('toArray', function(assert) { + assert.ok(!_.isArray(arguments), 'arguments object is not an array'); + assert.ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array'); var a = [1, 2, 3]; - ok(_.toArray(a) !== a, 'array is cloned'); - deepEqual(_.toArray(a), [1, 2, 3], 'cloned array contains same elements'); + assert.ok(_.toArray(a) !== a, 'array is cloned'); + assert.deepEqual(_.toArray(a), [1, 2, 3], 'cloned array contains same elements'); var numbers = _.toArray({one: 1, two: 2, three: 3}); - deepEqual(numbers, [1, 2, 3], 'object flattened into array'); + assert.deepEqual(numbers, [1, 2, 3], 'object flattened into array'); if (typeof document != 'undefined') { // test in IE < 9 @@ -795,78 +795,78 @@ try { actual = _.toArray(document.childNodes); } catch(e) { /* ignored */ } - deepEqual(actual, _.map(document.childNodes, _.identity), 'works on NodeList'); + assert.deepEqual(actual, _.map(document.childNodes, _.identity), 'works on NodeList'); } }); - test('size', function() { - equal(_.size({one: 1, two: 2, three: 3}), 3, 'can compute the size of an object'); - equal(_.size([1, 2, 3]), 3, 'can compute the size of an array'); - equal(_.size({length: 3, 0: 0, 1: 0, 2: 0}), 3, 'can compute the size of Array-likes'); + test('size', function(assert) { + assert.equal(_.size({one: 1, two: 2, three: 3}), 3, 'can compute the size of an object'); + assert.equal(_.size([1, 2, 3]), 3, 'can compute the size of an array'); + assert.equal(_.size({length: 3, 0: 0, 1: 0, 2: 0}), 3, 'can compute the size of Array-likes'); var func = function() { return _.size(arguments); }; - equal(func(1, 2, 3, 4), 4, 'can test the size of the arguments object'); + assert.equal(func(1, 2, 3, 4), 4, 'can test the size of the arguments object'); - equal(_.size('hello'), 5, 'can compute the size of a string literal'); - equal(_.size(new String('hello')), 5, 'can compute the size of string object'); + assert.equal(_.size('hello'), 5, 'can compute the size of a string literal'); + assert.equal(_.size(new String('hello')), 5, 'can compute the size of string object'); - equal(_.size(null), 0, 'handles nulls'); - equal(_.size(0), 0, 'handles numbers'); + assert.equal(_.size(null), 0, 'handles nulls'); + assert.equal(_.size(0), 0, 'handles numbers'); }); - test('partition', function() { + test('partition', function(assert) { var list = [0, 1, 2, 3, 4, 5]; - deepEqual(_.partition(list, function(x) { return x < 4; }), [[0, 1, 2, 3], [4, 5]], 'handles bool return values'); - deepEqual(_.partition(list, function(x) { return x & 1; }), [[1, 3, 5], [0, 2, 4]], 'handles 0 and 1 return values'); - deepEqual(_.partition(list, function(x) { return x - 3; }), [[0, 1, 2, 4, 5], [3]], 'handles other numeric return values'); - deepEqual(_.partition(list, function(x) { return x > 1 ? null : true; }), [[0, 1], [2, 3, 4, 5]], 'handles null return values'); - deepEqual(_.partition(list, function(x) { if (x < 2) return true; }), [[0, 1], [2, 3, 4, 5]], 'handles undefined return values'); - deepEqual(_.partition({a: 1, b: 2, c: 3}, function(x) { return x > 1; }), [[2, 3], [1]], 'handles objects'); + assert.deepEqual(_.partition(list, function(x) { return x < 4; }), [[0, 1, 2, 3], [4, 5]], 'handles bool return values'); + assert.deepEqual(_.partition(list, function(x) { return x & 1; }), [[1, 3, 5], [0, 2, 4]], 'handles 0 and 1 return values'); + assert.deepEqual(_.partition(list, function(x) { return x - 3; }), [[0, 1, 2, 4, 5], [3]], 'handles other numeric return values'); + assert.deepEqual(_.partition(list, function(x) { return x > 1 ? null : true; }), [[0, 1], [2, 3, 4, 5]], 'handles null return values'); + assert.deepEqual(_.partition(list, function(x) { if (x < 2) return true; }), [[0, 1], [2, 3, 4, 5]], 'handles undefined return values'); + assert.deepEqual(_.partition({a: 1, b: 2, c: 3}, function(x) { return x > 1; }), [[2, 3], [1]], 'handles objects'); - deepEqual(_.partition(list, function(x, index) { return index % 2; }), [[1, 3, 5], [0, 2, 4]], 'can reference the array index'); - deepEqual(_.partition(list, function(x, index, arr) { return x === arr.length - 1; }), [[5], [0, 1, 2, 3, 4]], 'can reference the collection'); + assert.deepEqual(_.partition(list, function(x, index) { return index % 2; }), [[1, 3, 5], [0, 2, 4]], 'can reference the array index'); + assert.deepEqual(_.partition(list, function(x, index, arr) { return x === arr.length - 1; }), [[5], [0, 1, 2, 3, 4]], 'can reference the collection'); // Default iterator - deepEqual(_.partition([1, false, true, '']), [[1, true], [false, '']], 'Default iterator'); - deepEqual(_.partition([{x: 1}, {x: 0}, {x: 1}], 'x'), [[{x: 1}, {x: 1}], [{x: 0}]], 'Takes a string'); + assert.deepEqual(_.partition([1, false, true, '']), [[1, true], [false, '']], 'Default iterator'); + assert.deepEqual(_.partition([{x: 1}, {x: 0}, {x: 1}], 'x'), [[{x: 1}, {x: 1}], [{x: 0}]], 'Takes a string'); // Context var predicate = function(x){ return x === this.x; }; - deepEqual(_.partition([1, 2, 3], predicate, {x: 2}), [[2], [1, 3]], 'partition takes a context argument'); + assert.deepEqual(_.partition([1, 2, 3], predicate, {x: 2}), [[2], [1, 3]], 'partition takes a context argument'); - deepEqual(_.partition([{a: 1}, {b: 2}, {a: 1, b: 2}], {a: 1}), [[{a: 1}, {a: 1, b: 2}], [{b: 2}]], 'predicate can be object'); + assert.deepEqual(_.partition([{a: 1}, {b: 2}, {a: 1, b: 2}], {a: 1}), [[{a: 1}, {a: 1, b: 2}], [{b: 2}]], 'predicate can be object'); var object = {a: 1}; _.partition(object, function(val, key, obj) { - equal(val, 1); - equal(key, 'a'); - equal(obj, object); - equal(this, predicate); + assert.equal(val, 1); + assert.equal(key, 'a'); + assert.equal(obj, object); + assert.equal(this, predicate); }, predicate); }); if (typeof document != 'undefined') { - test('Can use various collection methods on NodeLists', function() { + test('Can use various collection methods on NodeLists', function(assert) { var parent = document.createElement('div'); parent.innerHTML = 'textnode'; var elementChildren = _.filter(parent.childNodes, _.isElement); - equal(elementChildren.length, 2); + assert.equal(elementChildren.length, 2); - deepEqual(_.map(elementChildren, 'id'), ['id1', 'id2']); - deepEqual(_.map(parent.childNodes, 'nodeType'), [1, 3, 1]); + assert.deepEqual(_.map(elementChildren, 'id'), ['id1', 'id2']); + assert.deepEqual(_.map(parent.childNodes, 'nodeType'), [1, 3, 1]); - ok(!_.every(parent.childNodes, _.isElement)); - ok(_.some(parent.childNodes, _.isElement)); + assert.ok(!_.every(parent.childNodes, _.isElement)); + assert.ok(_.some(parent.childNodes, _.isElement)); function compareNode(node) { return _.isElement(node) ? node.id.charAt(2) : void 0; } - equal(_.max(parent.childNodes, compareNode), _.last(parent.childNodes)); - equal(_.min(parent.childNodes, compareNode), _.first(parent.childNodes)); + assert.equal(_.max(parent.childNodes, compareNode), _.last(parent.childNodes)); + assert.equal(_.min(parent.childNodes, compareNode), _.first(parent.childNodes)); }); } diff --git a/test/cross-document.js b/test/cross-document.js index 215d78e85..fff3a07d4 100644 --- a/test/cross-document.js +++ b/test/cross-document.js @@ -33,95 +33,95 @@ ); iDoc.close(); - test('isEqual', function() { + test('isEqual', function(assert) { - ok(!_.isEqual(iNumber, 101)); - ok(_.isEqual(iNumber, 100)); + assert.ok(!_.isEqual(iNumber, 101)); + assert.ok(_.isEqual(iNumber, 100)); // Objects from another frame. - ok(_.isEqual({}, iObject), 'Objects with equivalent members created in different documents are equal'); + assert.ok(_.isEqual({}, iObject), 'Objects with equivalent members created in different documents are equal'); // Array from another frame. - ok(_.isEqual([1, 2, 3], iArray), 'Arrays with equivalent elements created in different documents are equal'); + assert.ok(_.isEqual([1, 2, 3], iArray), 'Arrays with equivalent elements created in different documents are equal'); }); - test('isEmpty', function() { - ok(!_([iNumber]).isEmpty(), '[1] is not empty'); - ok(!_.isEmpty(iArray), '[] is empty'); - ok(_.isEmpty(iObject), '{} is empty'); + test('isEmpty', function(assert) { + assert.ok(!_([iNumber]).isEmpty(), '[1] is not empty'); + assert.ok(!_.isEmpty(iArray), '[] is empty'); + assert.ok(_.isEmpty(iObject), '{} is empty'); }); - test('isElement', function() { - ok(!_.isElement('div'), 'strings are not dom elements'); - ok(_.isElement(document.body), 'the body tag is a DOM element'); - ok(_.isElement(iElement), 'even from another frame'); + test('isElement', function(assert) { + assert.ok(!_.isElement('div'), 'strings are not dom elements'); + assert.ok(_.isElement(document.body), 'the body tag is a DOM element'); + assert.ok(_.isElement(iElement), 'even from another frame'); }); - test('isArguments', function() { - ok(_.isArguments(iArguments), 'even from another frame'); + test('isArguments', function(assert) { + assert.ok(_.isArguments(iArguments), 'even from another frame'); }); - test('isObject', function() { - ok(_.isObject(iElement), 'even from another frame'); - ok(_.isObject(iFunction), 'even from another frame'); + test('isObject', function(assert) { + assert.ok(_.isObject(iElement), 'even from another frame'); + assert.ok(_.isObject(iFunction), 'even from another frame'); }); - test('isArray', function() { - ok(_.isArray(iArray), 'even from another frame'); + test('isArray', function(assert) { + assert.ok(_.isArray(iArray), 'even from another frame'); }); - test('isString', function() { - ok(_.isString(iString), 'even from another frame'); + test('isString', function(assert) { + assert.ok(_.isString(iString), 'even from another frame'); }); - test('isNumber', function() { - ok(_.isNumber(iNumber), 'even from another frame'); + test('isNumber', function(assert) { + assert.ok(_.isNumber(iNumber), 'even from another frame'); }); - test('isBoolean', function() { - ok(_.isBoolean(iBoolean), 'even from another frame'); + test('isBoolean', function(assert) { + assert.ok(_.isBoolean(iBoolean), 'even from another frame'); }); - test('isFunction', function() { - ok(_.isFunction(iFunction), 'even from another frame'); + test('isFunction', function(assert) { + assert.ok(_.isFunction(iFunction), 'even from another frame'); }); - test('isDate', function() { - ok(_.isDate(iDate), 'even from another frame'); + test('isDate', function(assert) { + assert.ok(_.isDate(iDate), 'even from another frame'); }); - test('isRegExp', function() { - ok(_.isRegExp(iRegExp), 'even from another frame'); + test('isRegExp', function(assert) { + assert.ok(_.isRegExp(iRegExp), 'even from another frame'); }); - test('isNaN', function() { - ok(_.isNaN(iNaN), 'even from another frame'); + test('isNaN', function(assert) { + assert.ok(_.isNaN(iNaN), 'even from another frame'); }); - test('isNull', function() { - ok(_.isNull(iNull), 'even from another frame'); + test('isNull', function(assert) { + assert.ok(_.isNull(iNull), 'even from another frame'); }); - test('isUndefined', function() { - ok(_.isUndefined(iUndefined), 'even from another frame'); + test('isUndefined', function(assert) { + assert.ok(_.isUndefined(iUndefined), 'even from another frame'); }); - test('isError', function() { - ok(_.isError(iError), 'even from another frame'); + test('isError', function(assert) { + assert.ok(_.isError(iError), 'even from another frame'); }); if (typeof ActiveXObject != 'undefined') { - test('IE host objects', function() { + test('IE host objects', function(assert) { var xml = new ActiveXObject('Msxml2.DOMDocument.3.0'); - ok(!_.isNumber(xml)); - ok(!_.isBoolean(xml)); - ok(!_.isNaN(xml)); - ok(!_.isFunction(xml)); - ok(!_.isNull(xml)); - ok(!_.isUndefined(xml)); + assert.ok(!_.isNumber(xml)); + assert.ok(!_.isBoolean(xml)); + assert.ok(!_.isNaN(xml)); + assert.ok(!_.isFunction(xml)); + assert.ok(!_.isNull(xml)); + assert.ok(!_.isUndefined(xml)); }); - test('#1621 IE 11 compat mode DOM elements are not functions', function() { + test('#1621 IE 11 compat mode DOM elements are not functions', function(assert) { var fn = function() {}; var xml = new ActiveXObject('Msxml2.DOMDocument.3.0'); var div = document.createElement('div'); @@ -132,9 +132,9 @@ _.isFunction(fn); } - equal(_.isFunction(xml), false); - equal(_.isFunction(div), false); - equal(_.isFunction(fn), true); + assert.equal(_.isFunction(xml), false); + assert.equal(_.isFunction(div), false); + assert.equal(_.isFunction(fn), true); }); } diff --git a/test/functions.js b/test/functions.js index 7ceb49dfe..926681c9d 100644 --- a/test/functions.js +++ b/test/functions.js @@ -4,32 +4,32 @@ QUnit.module('Functions'); QUnit.config.asyncRetries = 3; - test('bind', function() { + test('bind', function(assert) { var context = {name: 'moe'}; var func = function(arg) { return 'name: ' + (this.name || arg); }; var bound = _.bind(func, context); - equal(bound(), 'name: moe', 'can bind a function to a context'); + assert.equal(bound(), 'name: moe', 'can bind a function to a context'); bound = _(func).bind(context); - equal(bound(), 'name: moe', 'can do OO-style binding'); + assert.equal(bound(), 'name: moe', 'can do OO-style binding'); bound = _.bind(func, null, 'curly'); var result = bound(); // Work around a PhantomJS bug when applying a function with null|undefined. - ok(result === 'name: curly' || result === 'name: ' + window.name, 'can bind without specifying a context'); + assert.ok(result === 'name: curly' || result === 'name: ' + window.name, 'can bind without specifying a context'); func = function(salutation, name) { return salutation + ': ' + name; }; func = _.bind(func, this, 'hello'); - equal(func('moe'), 'hello: moe', 'the function was partially applied in advance'); + assert.equal(func('moe'), 'hello: moe', 'the function was partially applied in advance'); func = _.bind(func, this, 'curly'); - equal(func(), 'hello: curly', 'the function was completely applied in advance'); + assert.equal(func(), 'hello: curly', 'the function was completely applied in advance'); func = function(salutation, firstname, lastname) { return salutation + ': ' + firstname + ' ' + lastname; }; func = _.bind(func, this, 'hello', 'moe', 'curly'); - equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments'); + assert.equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments'); - func = function(ctx, message) { equal(this, ctx, message); }; + func = function(ctx, message) { assert.equal(this, ctx, message); }; _.bind(func, 0, 0, 'can bind a function to `0`')(); _.bind(func, '', '', 'can bind a function to an empty string')(); _.bind(func, false, false, 'can bind a function to `false`')(); @@ -40,29 +40,29 @@ var boundf = _.bind(F, {hello: 'moe curly'}); var Boundf = boundf; // make eslint happy. var newBoundf = new Boundf(); - equal(newBoundf.hello, void 0, 'function should not be bound to the context, to comply with ECMAScript 5'); - equal(boundf().hello, 'moe curly', "When called without the new operator, it's OK to be bound to the context"); - ok(newBoundf instanceof F, 'a bound instance is an instance of the original function'); + assert.equal(newBoundf.hello, void 0, 'function should not be bound to the context, to comply with ECMAScript 5'); + assert.equal(boundf().hello, 'moe curly', "When called without the new operator, it's OK to be bound to the context"); + assert.ok(newBoundf instanceof F, 'a bound instance is an instance of the original function'); - throws(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function'); + assert.throws(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function'); }); - test('partial', function() { + test('partial', function(assert) { var obj = {name: 'moe'}; var func = function() { return this.name + ' ' + _.toArray(arguments).join(' '); }; obj.func = _.partial(func, 'a', 'b'); - equal(obj.func('c', 'd'), 'moe a b c d', 'can partially apply'); + assert.equal(obj.func('c', 'd'), 'moe a b c d', 'can partially apply'); obj.func = _.partial(func, _, 'b', _, 'd'); - equal(obj.func('a', 'c'), 'moe a b c d', 'can partially apply with placeholders'); + assert.equal(obj.func('a', 'c'), 'moe a b c d', 'can partially apply with placeholders'); func = _.partial(function() { return arguments.length; }, _, 'b', _, 'd'); - equal(func('a', 'c', 'e'), 5, 'accepts more arguments than the number of placeholders'); - equal(func('a'), 4, 'accepts fewer arguments than the number of placeholders'); + assert.equal(func('a', 'c', 'e'), 5, 'accepts more arguments than the number of placeholders'); + assert.equal(func('a'), 4, 'accepts fewer arguments than the number of placeholders'); func = _.partial(function() { return typeof arguments[2]; }, _, 'b', _, 'd'); - equal(func('a'), 'undefined', 'unfilled placeholders are undefined'); + assert.equal(func('a'), 'undefined', 'unfilled placeholders are undefined'); // passes context function MyWidget(name, options) { @@ -74,22 +74,22 @@ }; var MyWidgetWithCoolOpts = _.partial(MyWidget, _, {a: 1}); var widget = new MyWidgetWithCoolOpts('foo'); - ok(widget instanceof MyWidget, 'Can partially bind a constructor'); - equal(widget.get(), 'foo', 'keeps prototype'); - deepEqual(widget.options, {a: 1}); + assert.ok(widget instanceof MyWidget, 'Can partially bind a constructor'); + assert.equal(widget.get(), 'foo', 'keeps prototype'); + assert.deepEqual(widget.options, {a: 1}); _.partial.placeholder = obj; func = _.partial(function() { return arguments.length; }, obj, 'b', obj, 'd'); - equal(func('a'), 4, 'allows the placeholder to be swapped out'); + assert.equal(func('a'), 4, 'allows the placeholder to be swapped out'); _.partial.placeholder = {}; func = _.partial(function() { return arguments.length; }, obj, 'b', obj, 'd'); - equal(func('a'), 5, 'swapping the placeholder preserves previously bound arguments'); + assert.equal(func('a'), 5, 'swapping the placeholder preserves previously bound arguments'); _.partial.placeholder = _; }); - test('bindAll', function() { + test('bindAll', function(assert) { var curly = {name: 'curly'}, moe = { name: 'moe', getName: function() { return 'name: ' + this.name; }, @@ -98,8 +98,8 @@ curly.getName = moe.getName; _.bindAll(moe, 'getName', 'sayHi'); curly.sayHi = moe.sayHi; - equal(curly.getName(), 'name: curly', 'unbound function is bound to current object'); - equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object'); + assert.equal(curly.getName(), 'name: curly', 'unbound function is bound to current object'); + assert.equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object'); curly = {name: 'curly'}; moe = { @@ -109,57 +109,57 @@ sayLast: function() { return this.sayHi(_.last(arguments)); } }; - throws(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named'); - throws(function() { _.bindAll(moe, 'sayBye'); }, TypeError, 'throws an error for bindAll if the given key is undefined'); - throws(function() { _.bindAll(moe, 'name'); }, TypeError, 'throws an error for bindAll if the given key is not a function'); + assert.throws(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named'); + assert.throws(function() { _.bindAll(moe, 'sayBye'); }, TypeError, 'throws an error for bindAll if the given key is undefined'); + assert.throws(function() { _.bindAll(moe, 'name'); }, TypeError, 'throws an error for bindAll if the given key is not a function'); _.bindAll(moe, 'sayHi', 'sayLast'); curly.sayHi = moe.sayHi; - equal(curly.sayHi(), 'hi: moe'); + assert.equal(curly.sayHi(), 'hi: moe'); var sayLast = moe.sayLast; - equal(sayLast(1, 2, 3, 4, 5, 6, 7, 'Tom'), 'hi: moe', 'createCallback works with any number of arguments'); + assert.equal(sayLast(1, 2, 3, 4, 5, 6, 7, 'Tom'), 'hi: moe', 'createCallback works with any number of arguments'); _.bindAll(moe, ['getName']); var getName = moe.getName; - equal(getName(), 'name: moe', 'flattens arguments into a single list'); + assert.equal(getName(), 'name: moe', 'flattens arguments into a single list'); }); - test('memoize', function() { + test('memoize', function(assert) { var fib = function(n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }; - equal(fib(10), 55, 'a memoized version of fibonacci produces identical results'); + assert.equal(fib(10), 55, 'a memoized version of fibonacci produces identical results'); fib = _.memoize(fib); // Redefine `fib` for memoization - equal(fib(10), 55, 'a memoized version of fibonacci produces identical results'); + assert.equal(fib(10), 55, 'a memoized version of fibonacci produces identical results'); var o = function(str) { return str; }; var fastO = _.memoize(o); - equal(o('toString'), 'toString', 'checks hasOwnProperty'); - equal(fastO('toString'), 'toString', 'checks hasOwnProperty'); + assert.equal(o('toString'), 'toString', 'checks hasOwnProperty'); + assert.equal(fastO('toString'), 'toString', 'checks hasOwnProperty'); // Expose the cache. var upper = _.memoize(function(s) { return s.toUpperCase(); }); - equal(upper('foo'), 'FOO'); - equal(upper('bar'), 'BAR'); - deepEqual(upper.cache, {foo: 'FOO', bar: 'BAR'}); + assert.equal(upper('foo'), 'FOO'); + assert.equal(upper('bar'), 'BAR'); + assert.deepEqual(upper.cache, {foo: 'FOO', bar: 'BAR'}); upper.cache = {foo: 'BAR', bar: 'FOO'}; - equal(upper('foo'), 'BAR'); - equal(upper('bar'), 'FOO'); + assert.equal(upper('foo'), 'BAR'); + assert.equal(upper('bar'), 'FOO'); var hashed = _.memoize(function(key) { //https://github.com/jashkenas/underscore/pull/1679#discussion_r13736209 - ok(/[a-z]+/.test(key), 'hasher doesn\'t change keys'); + assert.ok(/[a-z]+/.test(key), 'hasher doesn\'t change keys'); return key; }, function(key) { return key.toUpperCase(); }); hashed('yep'); - deepEqual(hashed.cache, {YEP: 'yep'}, 'takes a hasher'); + assert.deepEqual(hashed.cache, {YEP: 'yep'}, 'takes a hasher'); // Test that the hash function can be used to swizzle the key. var objCacher = _.memoize(function(value, key) { @@ -169,78 +169,78 @@ }); var myObj = objCacher('a', 'alpha'); var myObjAlias = objCacher('b', 'alpha'); - notStrictEqual(myObj, void 0, 'object is created if second argument used as key'); - strictEqual(myObj, myObjAlias, 'object is cached if second argument used as key'); - strictEqual(myObj.value, 'a', 'object is not modified if second argument used as key'); + assert.notStrictEqual(myObj, void 0, 'object is created if second argument used as key'); + assert.strictEqual(myObj, myObjAlias, 'object is cached if second argument used as key'); + assert.strictEqual(myObj.value, 'a', 'object is not modified if second argument used as key'); }); - asyncTest('delay', 2, function() { + asyncTest('delay', 2, function(assert) { var delayed = false; _.delay(function(){ delayed = true; }, 100); - setTimeout(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50); - setTimeout(function(){ ok(delayed, 'delayed the function'); start(); }, 150); + setTimeout(function(){ assert.ok(!delayed, "didn't delay the function quite yet"); }, 50); + setTimeout(function(){ assert.ok(delayed, 'delayed the function'); start(); }, 150); }); - asyncTest('defer', 1, function() { + asyncTest('defer', 1, function(assert) { var deferred = false; _.defer(function(bool){ deferred = bool; }, true); - _.delay(function(){ ok(deferred, 'deferred the function'); start(); }, 50); + _.delay(function(){ assert.ok(deferred, 'deferred the function'); start(); }, 50); }); - asyncTest('throttle', 2, function() { + asyncTest('throttle', 2, function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 32); throttledIncr(); throttledIncr(); - equal(counter, 1, 'incr was called immediately'); - _.delay(function(){ equal(counter, 2, 'incr was throttled'); start(); }, 64); + assert.equal(counter, 1, 'incr was called immediately'); + _.delay(function(){ assert.equal(counter, 2, 'incr was throttled'); start(); }, 64); }); - asyncTest('throttle arguments', 2, function() { + asyncTest('throttle arguments', 2, function(assert) { var value = 0; var update = function(val){ value = val; }; var throttledUpdate = _.throttle(update, 32); throttledUpdate(1); throttledUpdate(2); _.delay(function(){ throttledUpdate(3); }, 64); - equal(value, 1, 'updated to latest value'); - _.delay(function(){ equal(value, 3, 'updated to latest value'); start(); }, 96); + assert.equal(value, 1, 'updated to latest value'); + _.delay(function(){ assert.equal(value, 3, 'updated to latest value'); start(); }, 96); }); - asyncTest('throttle once', 2, function() { + asyncTest('throttle once', 2, function(assert) { var counter = 0; var incr = function(){ return ++counter; }; var throttledIncr = _.throttle(incr, 32); var result = throttledIncr(); _.delay(function(){ - equal(result, 1, 'throttled functions return their value'); - equal(counter, 1, 'incr was called once'); start(); + assert.equal(result, 1, 'throttled functions return their value'); + assert.equal(counter, 1, 'incr was called once'); start(); }, 64); }); - asyncTest('throttle twice', 1, function() { + asyncTest('throttle twice', 1, function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 32); throttledIncr(); throttledIncr(); - _.delay(function(){ equal(counter, 2, 'incr was called twice'); start(); }, 64); + _.delay(function(){ assert.equal(counter, 2, 'incr was called twice'); start(); }, 64); }); - asyncTest('more throttling', 3, function() { + asyncTest('more throttling', 3, function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 30); throttledIncr(); throttledIncr(); - equal(counter, 1); + assert.equal(counter, 1); _.delay(function(){ - equal(counter, 2); + assert.equal(counter, 2); throttledIncr(); - equal(counter, 3); + assert.equal(counter, 3); start(); }, 85); }); - asyncTest('throttle repeatedly with results', 6, function() { + asyncTest('throttle repeatedly with results', 6, function(assert) { var counter = 0; var incr = function(){ return ++counter; }; var throttledIncr = _.throttle(incr, 100); @@ -252,17 +252,17 @@ _.delay(saveResult, 160); _.delay(saveResult, 230); _.delay(function() { - equal(results[0], 1, 'incr was called once'); - equal(results[1], 1, 'incr was throttled'); - equal(results[2], 1, 'incr was throttled'); - equal(results[3], 2, 'incr was called twice'); - equal(results[4], 2, 'incr was throttled'); - equal(results[5], 3, 'incr was called trailing'); + assert.equal(results[0], 1, 'incr was called once'); + assert.equal(results[1], 1, 'incr was throttled'); + assert.equal(results[2], 1, 'incr was throttled'); + assert.equal(results[3], 2, 'incr was called twice'); + assert.equal(results[4], 2, 'incr was throttled'); + assert.equal(results[5], 3, 'incr was called trailing'); start(); }, 300); }); - asyncTest('throttle triggers trailing call when invoked repeatedly', 2, function() { + asyncTest('throttle triggers trailing call when invoked repeatedly', 2, function(assert) { var counter = 0; var limit = 48; var incr = function(){ counter++; }; @@ -273,29 +273,29 @@ throttledIncr(); } var lastCount = counter; - ok(counter > 1); + assert.ok(counter > 1); _.delay(function() { - ok(counter > lastCount); + assert.ok(counter > lastCount); start(); }, 96); }); - asyncTest('throttle does not trigger leading call when leading is set to false', 2, function() { + asyncTest('throttle does not trigger leading call when leading is set to false', 2, function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 60, {leading: false}); throttledIncr(); throttledIncr(); - equal(counter, 0); + assert.equal(counter, 0); _.delay(function() { - equal(counter, 1); + assert.equal(counter, 1); start(); }, 96); }); - asyncTest('more throttle does not trigger leading call when leading is set to false', 3, function() { + asyncTest('more throttle does not trigger leading call when leading is set to false', 3, function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 100, {leading: false}); @@ -304,75 +304,75 @@ _.delay(throttledIncr, 50); _.delay(throttledIncr, 60); _.delay(throttledIncr, 200); - equal(counter, 0); + assert.equal(counter, 0); _.delay(function() { - equal(counter, 1); + assert.equal(counter, 1); }, 250); _.delay(function() { - equal(counter, 2); + assert.equal(counter, 2); start(); }, 350); }); - asyncTest('one more throttle with leading: false test', 2, function() { + asyncTest('one more throttle with leading: false test', 2, function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 100, {leading: false}); var time = new Date; while (new Date - time < 350) throttledIncr(); - ok(counter <= 3); + assert.ok(counter <= 3); _.delay(function() { - ok(counter <= 4); + assert.ok(counter <= 4); start(); }, 200); }); - asyncTest('throttle does not trigger trailing call when trailing is set to false', 4, function() { + asyncTest('throttle does not trigger trailing call when trailing is set to false', 4, function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 60, {trailing: false}); throttledIncr(); throttledIncr(); throttledIncr(); - equal(counter, 1); + assert.equal(counter, 1); _.delay(function() { - equal(counter, 1); + assert.equal(counter, 1); throttledIncr(); throttledIncr(); - equal(counter, 2); + assert.equal(counter, 2); _.delay(function() { - equal(counter, 2); + assert.equal(counter, 2); start(); }, 96); }, 96); }); - asyncTest('throttle continues to function after system time is set backwards', 2, function() { + asyncTest('throttle continues to function after system time is set backwards', 2, function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 100); var origNowFunc = _.now; throttledIncr(); - equal(counter, 1); + assert.equal(counter, 1); _.now = function() { return new Date(2013, 0, 1, 1, 1, 1); }; _.delay(function() { throttledIncr(); - equal(counter, 2); + assert.equal(counter, 2); start(); _.now = origNowFunc; }, 200); }); - asyncTest('throttle re-entrant', 2, function() { + asyncTest('throttle re-entrant', 2, function(assert) { var sequence = [ ['b1', 'b2'], ['c1', 'c2'] @@ -388,50 +388,50 @@ }; throttledAppend = _.throttle(append, 32); throttledAppend.call('a1', 'a2'); - equal(value, 'a1a2'); + assert.equal(value, 'a1a2'); _.delay(function(){ - equal(value, 'a1a2c1c2b1b2', 'append was throttled successfully'); + assert.equal(value, 'a1a2c1c2b1b2', 'append was throttled successfully'); start(); }, 100); }); - asyncTest('debounce', 1, function() { + asyncTest('debounce', 1, function(assert) { var counter = 0; var incr = function(){ counter++; }; var debouncedIncr = _.debounce(incr, 32); debouncedIncr(); debouncedIncr(); _.delay(debouncedIncr, 16); - _.delay(function(){ equal(counter, 1, 'incr was debounced'); start(); }, 96); + _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 96); }); - asyncTest('debounce asap', 4, function() { + asyncTest('debounce asap', 4, function(assert) { var a, b; var counter = 0; var incr = function(){ return ++counter; }; var debouncedIncr = _.debounce(incr, 64, true); a = debouncedIncr(); b = debouncedIncr(); - equal(a, 1); - equal(b, 1); - equal(counter, 1, 'incr was called immediately'); + assert.equal(a, 1); + assert.equal(b, 1); + assert.equal(counter, 1, 'incr was called immediately'); _.delay(debouncedIncr, 16); _.delay(debouncedIncr, 32); _.delay(debouncedIncr, 48); - _.delay(function(){ equal(counter, 1, 'incr was debounced'); start(); }, 128); + _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 128); }); - asyncTest('debounce asap recursively', 2, function() { + asyncTest('debounce asap recursively', 2, function(assert) { var counter = 0; var debouncedIncr = _.debounce(function(){ counter++; if (counter < 10) debouncedIncr(); }, 32, true); debouncedIncr(); - equal(counter, 1, 'incr was called immediately'); - _.delay(function(){ equal(counter, 1, 'incr was debounced'); start(); }, 96); + assert.equal(counter, 1, 'incr was called immediately'); + _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 96); }); - asyncTest('debounce after system time is set backwards', 2, function() { + asyncTest('debounce after system time is set backwards', 2, function(assert) { var counter = 0; var origNowFunc = _.now; var debouncedIncr = _.debounce(function(){ @@ -439,7 +439,7 @@ }, 100, true); debouncedIncr(); - equal(counter, 1, 'incr was called immediately'); + assert.equal(counter, 1, 'incr was called immediately'); _.now = function() { return new Date(2013, 0, 1, 1, 1, 1); @@ -447,13 +447,13 @@ _.delay(function() { debouncedIncr(); - equal(counter, 2, 'incr was debounced successfully'); + assert.equal(counter, 2, 'incr was debounced successfully'); start(); _.now = origNowFunc; }, 200); }); - asyncTest('debounce re-entrant', 2, function() { + asyncTest('debounce re-entrant', 2, function(assert) { var sequence = [ ['b1', 'b2'] ]; @@ -468,80 +468,80 @@ }; debouncedAppend = _.debounce(append, 32); debouncedAppend.call('a1', 'a2'); - equal(value, ''); + assert.equal(value, ''); _.delay(function(){ - equal(value, 'a1a2b1b2', 'append was debounced successfully'); + assert.equal(value, 'a1a2b1b2', 'append was debounced successfully'); start(); }, 100); }); - test('once', function() { + test('once', function(assert) { var num = 0; var increment = _.once(function(){ return ++num; }); increment(); increment(); - equal(num, 1); + assert.equal(num, 1); - equal(increment(), 1, 'stores a memo to the last value'); + assert.equal(increment(), 1, 'stores a memo to the last value'); }); - test('Recursive onced function.', 1, function() { + test('Recursive onced function.', 1, function(assert) { var f = _.once(function(){ - ok(true); + assert.ok(true); f(); }); f(); }); - test('wrap', function() { + test('wrap', function(assert) { var greet = function(name){ return 'hi: ' + name; }; var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); }); - equal(backwards('moe'), 'hi: moe eom', 'wrapped the salutation function'); + assert.equal(backwards('moe'), 'hi: moe eom', 'wrapped the salutation function'); var inner = function(){ return 'Hello '; }; var obj = {name: 'Moe'}; obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; }); - equal(obj.hi(), 'Hello Moe'); + assert.equal(obj.hi(), 'Hello Moe'); var noop = function(){}; var wrapped = _.wrap(noop, function(){ return Array.prototype.slice.call(arguments, 0); }); var ret = wrapped(['whats', 'your'], 'vector', 'victor'); - deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']); + assert.deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']); }); - test('negate', function() { + test('negate', function(assert) { var isOdd = function(n){ return n & 1; }; - equal(_.negate(isOdd)(2), true, 'should return the complement of the given function'); - equal(_.negate(isOdd)(3), false, 'should return the complement of the given function'); + assert.equal(_.negate(isOdd)(2), true, 'should return the complement of the given function'); + assert.equal(_.negate(isOdd)(3), false, 'should return the complement of the given function'); }); - test('compose', function() { + test('compose', function(assert) { var greet = function(name){ return 'hi: ' + name; }; var exclaim = function(sentence){ return sentence + '!'; }; var composed = _.compose(exclaim, greet); - equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another'); + assert.equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another'); composed = _.compose(greet, exclaim); - equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative'); + assert.equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative'); // f(g(h(x, y, z))) function h(x, y, z) { - equal(arguments.length, 3, 'First function called with multiple args'); + assert.equal(arguments.length, 3, 'First function called with multiple args'); return z * y; } function g(x) { - equal(arguments.length, 1, 'Composed function is called with 1 argument'); + assert.equal(arguments.length, 1, 'Composed function is called with 1 argument'); return x; } function f(x) { - equal(arguments.length, 1, 'Composed function is called with 1 argument'); + assert.equal(arguments.length, 1, 'Composed function is called with 1 argument'); return x * 2; } composed = _.compose(f, g, h); - equal(composed(1, 2, 3), 12); + assert.equal(composed(1, 2, 3), 12); }); - test('after', function() { + test('after', function(assert) { var testAfter = function(afterAmount, timesCalled) { var afterCalled = 0; var after = _.after(afterAmount, function() { @@ -551,13 +551,13 @@ return afterCalled; }; - equal(testAfter(5, 5), 1, 'after(N) should fire after being called N times'); - equal(testAfter(5, 4), 0, 'after(N) should not fire unless called N times'); - equal(testAfter(0, 0), 0, 'after(0) should not fire immediately'); - equal(testAfter(0, 1), 1, 'after(0) should fire when first invoked'); + assert.equal(testAfter(5, 5), 1, 'after(N) should fire after being called N times'); + assert.equal(testAfter(5, 4), 0, 'after(N) should not fire unless called N times'); + assert.equal(testAfter(0, 0), 0, 'after(0) should not fire immediately'); + assert.equal(testAfter(0, 1), 1, 'after(0) should fire when first invoked'); }); - test('before', function() { + test('before', function(assert) { var testBefore = function(beforeAmount, timesCalled) { var beforeCalled = 0; var before = _.before(beforeAmount, function() { beforeCalled++; }); @@ -565,58 +565,58 @@ return beforeCalled; }; - equal(testBefore(5, 5), 4, 'before(N) should not fire after being called N times'); - equal(testBefore(5, 4), 4, 'before(N) should fire before being called N times'); - equal(testBefore(0, 0), 0, 'before(0) should not fire immediately'); - equal(testBefore(0, 1), 0, 'before(0) should not fire when first invoked'); + assert.equal(testBefore(5, 5), 4, 'before(N) should not fire after being called N times'); + assert.equal(testBefore(5, 4), 4, 'before(N) should fire before being called N times'); + assert.equal(testBefore(0, 0), 0, 'before(0) should not fire immediately'); + assert.equal(testBefore(0, 1), 0, 'before(0) should not fire when first invoked'); var context = {num: 0}; var increment = _.before(3, function(){ return ++this.num; }); _.times(10, increment, context); - equal(increment(), 2, 'stores a memo to the last value'); - equal(context.num, 2, 'provides context'); + assert.equal(increment(), 2, 'stores a memo to the last value'); + assert.equal(context.num, 2, 'provides context'); }); - test('iteratee', function() { + test('iteratee', function(assert) { var identity = _.iteratee(); - equal(identity, _.identity, '_.iteratee is exposed as an external function.'); + assert.equal(identity, _.identity, '_.iteratee is exposed as an external function.'); function fn() { return arguments; } _.each([_.iteratee(fn), _.iteratee(fn, {})], function(cb) { - equal(cb().length, 0); - deepEqual(_.toArray(cb(1, 2, 3)), _.range(1, 4)); - deepEqual(_.toArray(cb(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), _.range(1, 11)); + assert.equal(cb().length, 0); + assert.deepEqual(_.toArray(cb(1, 2, 3)), _.range(1, 4)); + assert.deepEqual(_.toArray(cb(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), _.range(1, 11)); }); }); - test('restArgs', 10, function() { + test('restArgs', 10, function(assert) { _.restArgs(function(a, args) { - strictEqual(a, 1); - deepEqual(args, [2, 3], 'collects rest arguments into an array'); + assert.strictEqual(a, 1); + assert.deepEqual(args, [2, 3], 'collects rest arguments into an array'); })(1, 2, 3); _.restArgs(function(a, args) { - strictEqual(a, void 0); - deepEqual(args, [], 'passes empty array if there are not enough arguments'); + assert.strictEqual(a, void 0); + assert.deepEqual(args, [], 'passes empty array if there are not enough arguments'); })(); _.restArgs(function(a, b, c, args) { - strictEqual(arguments.length, 4); - deepEqual(args, [4, 5], 'works on functions with many named parameters'); + assert.strictEqual(arguments.length, 4); + assert.deepEqual(args, [4, 5], 'works on functions with many named parameters'); })(1, 2, 3, 4, 5); var obj = {}; _.restArgs(function() { - strictEqual(this, obj, 'invokes function with this context'); + assert.strictEqual(this, obj, 'invokes function with this context'); }).call(obj); _.restArgs(function(array, iteratee, context) { - deepEqual(array, [1, 2, 3, 4], 'startIndex can be used manually specify index of rest parameter'); - strictEqual(iteratee, void 0); - strictEqual(context, void 0); + assert.deepEqual(array, [1, 2, 3, 4], 'startIndex can be used manually specify index of rest parameter'); + assert.strictEqual(iteratee, void 0); + assert.strictEqual(context, void 0); }, 0)(1, 2, 3, 4); }); diff --git a/test/objects.js b/test/objects.js index 066264c2b..29bbd9281 100644 --- a/test/objects.js +++ b/test/objects.js @@ -5,16 +5,16 @@ var testElement = typeof document === 'object' ? document.createElement('div') : void 0; - test('keys', function() { - deepEqual(_.keys({one: 1, two: 2}), ['one', 'two'], 'can extract the keys from an object'); + test('keys', function(assert) { + assert.deepEqual(_.keys({one: 1, two: 2}), ['one', 'two'], 'can extract the keys from an object'); // the test above is not safe because it relies on for-in enumeration order var a = []; a[1] = 0; - deepEqual(_.keys(a), ['1'], 'is not fooled by sparse arrays; see issue #95'); - deepEqual(_.keys(null), []); - deepEqual(_.keys(void 0), []); - deepEqual(_.keys(1), []); - deepEqual(_.keys('a'), []); - deepEqual(_.keys(true), []); + assert.deepEqual(_.keys(a), ['1'], 'is not fooled by sparse arrays; see issue #95'); + assert.deepEqual(_.keys(null), []); + assert.deepEqual(_.keys(void 0), []); + assert.deepEqual(_.keys(1), []); + assert.deepEqual(_.keys('a'), []); + assert.deepEqual(_.keys(true), []); // keys that may be missed if the implementation isn't careful var trouble = { @@ -32,20 +32,20 @@ }; var troubleKeys = ['constructor', 'valueOf', 'hasOwnProperty', 'toString', 'toLocaleString', 'propertyIsEnumerable', 'isPrototypeOf', '__defineGetter__', '__defineSetter__', '__lookupSetter__', '__lookupGetter__'].sort(); - deepEqual(_.keys(trouble).sort(), troubleKeys, 'matches non-enumerable properties'); + assert.deepEqual(_.keys(trouble).sort(), troubleKeys, 'matches non-enumerable properties'); }); - test('allKeys', function() { - deepEqual(_.allKeys({one: 1, two: 2}), ['one', 'two'], 'can extract the allKeys from an object'); + test('allKeys', function(assert) { + assert.deepEqual(_.allKeys({one: 1, two: 2}), ['one', 'two'], 'can extract the allKeys from an object'); // the test above is not safe because it relies on for-in enumeration order var a = []; a[1] = 0; - deepEqual(_.allKeys(a), ['1'], 'is not fooled by sparse arrays; see issue #95'); + assert.deepEqual(_.allKeys(a), ['1'], 'is not fooled by sparse arrays; see issue #95'); a.a = a; - deepEqual(_.allKeys(a), ['1', 'a'], 'is not fooled by sparse arrays with additional properties'); + assert.deepEqual(_.allKeys(a), ['1', 'a'], 'is not fooled by sparse arrays with additional properties'); _.each([null, void 0, 1, 'a', true, NaN, {}, [], new Number(5), new Date(0)], function(val) { - deepEqual(_.allKeys(val), []); + assert.deepEqual(_.allKeys(val), []); }); // allKeys that may be missed if the implementation isn't careful @@ -60,255 +60,255 @@ }; var troubleKeys = ['constructor', 'valueOf', 'hasOwnProperty', 'toString', 'toLocaleString', 'propertyIsEnumerable', 'isPrototypeOf'].sort(); - deepEqual(_.allKeys(trouble).sort(), troubleKeys, 'matches non-enumerable properties'); + assert.deepEqual(_.allKeys(trouble).sort(), troubleKeys, 'matches non-enumerable properties'); function A() {} A.prototype.foo = 'foo'; var b = new A(); b.bar = 'bar'; - deepEqual(_.allKeys(b).sort(), ['bar', 'foo'], 'should include inherited keys'); + assert.deepEqual(_.allKeys(b).sort(), ['bar', 'foo'], 'should include inherited keys'); function y() {} y.x = 'z'; - deepEqual(_.allKeys(y), ['x'], 'should get keys from constructor'); + assert.deepEqual(_.allKeys(y), ['x'], 'should get keys from constructor'); }); - test('values', function() { - deepEqual(_.values({one: 1, two: 2}), [1, 2], 'can extract the values from an object'); - deepEqual(_.values({one: 1, two: 2, length: 3}), [1, 2, 3], '... even when one of them is "length"'); + test('values', function(assert) { + assert.deepEqual(_.values({one: 1, two: 2}), [1, 2], 'can extract the values from an object'); + assert.deepEqual(_.values({one: 1, two: 2, length: 3}), [1, 2, 3], '... even when one of them is "length"'); }); - test('pairs', function() { - deepEqual(_.pairs({one: 1, two: 2}), [['one', 1], ['two', 2]], 'can convert an object into pairs'); - deepEqual(_.pairs({one: 1, two: 2, length: 3}), [['one', 1], ['two', 2], ['length', 3]], '... even when one of them is "length"'); + test('pairs', function(assert) { + assert.deepEqual(_.pairs({one: 1, two: 2}), [['one', 1], ['two', 2]], 'can convert an object into pairs'); + assert.deepEqual(_.pairs({one: 1, two: 2, length: 3}), [['one', 1], ['two', 2], ['length', 3]], '... even when one of them is "length"'); }); - test('invert', function() { + test('invert', function(assert) { var obj = {first: 'Moe', second: 'Larry', third: 'Curly'}; - deepEqual(_.keys(_.invert(obj)), ['Moe', 'Larry', 'Curly'], 'can invert an object'); - deepEqual(_.invert(_.invert(obj)), obj, 'two inverts gets you back where you started'); + assert.deepEqual(_.keys(_.invert(obj)), ['Moe', 'Larry', 'Curly'], 'can invert an object'); + assert.deepEqual(_.invert(_.invert(obj)), obj, 'two inverts gets you back where you started'); obj = {length: 3}; - equal(_.invert(obj)['3'], 'length', 'can invert an object with "length"'); + assert.equal(_.invert(obj)['3'], 'length', 'can invert an object with "length"'); }); - test('functions', function() { + test('functions', function(assert) { var obj = {a: 'dash', b: _.map, c: /yo/, d: _.reduce}; - deepEqual(['b', 'd'], _.functions(obj), 'can grab the function names of any passed-in object'); + assert.deepEqual(['b', 'd'], _.functions(obj), 'can grab the function names of any passed-in object'); var Animal = function(){}; Animal.prototype.run = function(){}; - deepEqual(_.functions(new Animal), ['run'], 'also looks up functions on the prototype'); + assert.deepEqual(_.functions(new Animal), ['run'], 'also looks up functions on the prototype'); }); - test('methods', function() { - strictEqual(_.functions, _.methods, 'alias for functions'); + test('methods', function(assert) { + assert.strictEqual(_.functions, _.methods, 'alias for functions'); }); - test('extend', function() { + test('extend', function(assert) { var result; - equal(_.extend({}, {a: 'b'}).a, 'b', 'can extend an object with the attributes of another'); - equal(_.extend({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination'); - equal(_.extend({x: 'x'}, {a: 'b'}).x, 'x', "properties not in source don't get overriden"); + assert.equal(_.extend({}, {a: 'b'}).a, 'b', 'can extend an object with the attributes of another'); + assert.equal(_.extend({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination'); + assert.equal(_.extend({x: 'x'}, {a: 'b'}).x, 'x', "properties not in source don't get overriden"); result = _.extend({x: 'x'}, {a: 'a'}, {b: 'b'}); - deepEqual(result, {x: 'x', a: 'a', b: 'b'}, 'can extend from multiple source objects'); + assert.deepEqual(result, {x: 'x', a: 'a', b: 'b'}, 'can extend from multiple source objects'); result = _.extend({x: 'x'}, {a: 'a', x: 2}, {a: 'b'}); - deepEqual(result, {x: 2, a: 'b'}, 'extending from multiple source objects last property trumps'); + assert.deepEqual(result, {x: 2, a: 'b'}, 'extending from multiple source objects last property trumps'); result = _.extend({}, {a: void 0, b: null}); - deepEqual(_.keys(result), ['a', 'b'], 'extend copies undefined values'); + assert.deepEqual(_.keys(result), ['a', 'b'], 'extend copies undefined values'); var F = function() {}; F.prototype = {a: 'b'}; var subObj = new F(); subObj.c = 'd'; - deepEqual(_.extend({}, subObj), {a: 'b', c: 'd'}, 'extend copies all properties from source'); + assert.deepEqual(_.extend({}, subObj), {a: 'b', c: 'd'}, 'extend copies all properties from source'); _.extend(subObj, {}); - ok(!subObj.hasOwnProperty('a'), "extend does not convert destination object's 'in' properties to 'own' properties"); + assert.ok(!subObj.hasOwnProperty('a'), "extend does not convert destination object's 'in' properties to 'own' properties"); try { result = {}; _.extend(result, null, void 0, {a: 1}); } catch(e) { /* ignored */ } - equal(result.a, 1, 'should not error on `null` or `undefined` sources'); + assert.equal(result.a, 1, 'should not error on `null` or `undefined` sources'); - strictEqual(_.extend(null, {a: 1}), null, 'extending null results in null'); - strictEqual(_.extend(void 0, {a: 1}), void 0, 'extending undefined results in undefined'); + assert.strictEqual(_.extend(null, {a: 1}), null, 'extending null results in null'); + assert.strictEqual(_.extend(void 0, {a: 1}), void 0, 'extending undefined results in undefined'); }); - test('extendOwn', function() { + test('extendOwn', function(assert) { var result; - equal(_.extendOwn({}, {a: 'b'}).a, 'b', 'can assign an object with the attributes of another'); - equal(_.extendOwn({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination'); - equal(_.extendOwn({x: 'x'}, {a: 'b'}).x, 'x', "properties not in source don't get overriden"); + assert.equal(_.extendOwn({}, {a: 'b'}).a, 'b', 'can assign an object with the attributes of another'); + assert.equal(_.extendOwn({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination'); + assert.equal(_.extendOwn({x: 'x'}, {a: 'b'}).x, 'x', "properties not in source don't get overriden"); result = _.extendOwn({x: 'x'}, {a: 'a'}, {b: 'b'}); - deepEqual(result, {x: 'x', a: 'a', b: 'b'}, 'can assign from multiple source objects'); + assert.deepEqual(result, {x: 'x', a: 'a', b: 'b'}, 'can assign from multiple source objects'); result = _.assign({x: 'x'}, {a: 'a', x: 2}, {a: 'b'}); - deepEqual(result, {x: 2, a: 'b'}, 'assigning from multiple source objects last property trumps'); - deepEqual(_.extendOwn({}, {a: void 0, b: null}), {a: void 0, b: null}, 'assign copies undefined values'); + assert.deepEqual(result, {x: 2, a: 'b'}, 'assigning from multiple source objects last property trumps'); + assert.deepEqual(_.extendOwn({}, {a: void 0, b: null}), {a: void 0, b: null}, 'assign copies undefined values'); var F = function() {}; F.prototype = {a: 'b'}; var subObj = new F(); subObj.c = 'd'; - deepEqual(_.extendOwn({}, subObj), {c: 'd'}, 'assign copies own properties from source'); + assert.deepEqual(_.extendOwn({}, subObj), {c: 'd'}, 'assign copies own properties from source'); result = {}; - deepEqual(_.assign(result, null, void 0, {a: 1}), {a: 1}, 'should not error on `null` or `undefined` sources'); + assert.deepEqual(_.assign(result, null, void 0, {a: 1}), {a: 1}, 'should not error on `null` or `undefined` sources'); _.each(['a', 5, null, false], function(val) { - strictEqual(_.assign(val, {a: 1}), val, 'assigning non-objects results in returning the non-object value'); + assert.strictEqual(_.assign(val, {a: 1}), val, 'assigning non-objects results in returning the non-object value'); }); - strictEqual(_.extendOwn(void 0, {a: 1}), void 0, 'assigning undefined results in undefined'); + assert.strictEqual(_.extendOwn(void 0, {a: 1}), void 0, 'assigning undefined results in undefined'); result = _.extendOwn({a: 1, 0: 2, 1: '5', length: 6}, {0: 1, 1: 2, length: 2}); - deepEqual(result, {a: 1, 0: 1, 1: 2, length: 2}, 'assign should treat array-like objects like normal objects'); + assert.deepEqual(result, {a: 1, 0: 1, 1: 2, length: 2}, 'assign should treat array-like objects like normal objects'); }); - test('pick', function() { + test('pick', function(assert) { var result; result = _.pick({a: 1, b: 2, c: 3}, 'a', 'c'); - deepEqual(result, {a: 1, c: 3}, 'can restrict properties to those named'); + assert.deepEqual(result, {a: 1, c: 3}, 'can restrict properties to those named'); result = _.pick({a: 1, b: 2, c: 3}, ['b', 'c']); - deepEqual(result, {b: 2, c: 3}, 'can restrict properties to those named in an array'); + assert.deepEqual(result, {b: 2, c: 3}, 'can restrict properties to those named in an array'); result = _.pick({a: 1, b: 2, c: 3}, ['a'], 'b'); - deepEqual(result, {a: 1, b: 2}, 'can restrict properties to those named in mixed args'); + assert.deepEqual(result, {a: 1, b: 2}, 'can restrict properties to those named in mixed args'); result = _.pick(['a', 'b'], 1); - deepEqual(result, {1: 'b'}, 'can pick numeric properties'); + assert.deepEqual(result, {1: 'b'}, 'can pick numeric properties'); _.each([null, void 0], function(val) { - deepEqual(_.pick(val, 'hasOwnProperty'), {}, 'Called with null/undefined'); - deepEqual(_.pick(val, _.constant(true)), {}); + assert.deepEqual(_.pick(val, 'hasOwnProperty'), {}, 'Called with null/undefined'); + assert.deepEqual(_.pick(val, _.constant(true)), {}); }); - deepEqual(_.pick(5, 'toString', 'b'), {toString: Number.prototype.toString}, 'can iterate primitives'); + assert.deepEqual(_.pick(5, 'toString', 'b'), {toString: Number.prototype.toString}, 'can iterate primitives'); var data = {a: 1, b: 2, c: 3}; var callback = function(value, key, object) { - strictEqual(key, {1: 'a', 2: 'b', 3: 'c'}[value]); - strictEqual(object, data); + assert.strictEqual(key, {1: 'a', 2: 'b', 3: 'c'}[value]); + assert.strictEqual(object, data); return value !== this.value; }; result = _.pick(data, callback, {value: 2}); - deepEqual(result, {a: 1, c: 3}, 'can accept a predicate and context'); + assert.deepEqual(result, {a: 1, c: 3}, 'can accept a predicate and context'); var Obj = function(){}; Obj.prototype = {a: 1, b: 2, c: 3}; var instance = new Obj(); - deepEqual(_.pick(instance, 'a', 'c'), {a: 1, c: 3}, 'include prototype props'); + assert.deepEqual(_.pick(instance, 'a', 'c'), {a: 1, c: 3}, 'include prototype props'); - deepEqual(_.pick(data, function(val, key) { + assert.deepEqual(_.pick(data, function(val, key) { return this[key] === 3 && this === instance; }, instance), {c: 3}, 'function is given context'); - ok(!_.has(_.pick({}, 'foo'), 'foo'), 'does not set own property if property not in object'); + assert.ok(!_.has(_.pick({}, 'foo'), 'foo'), 'does not set own property if property not in object'); _.pick(data, function(value, key, obj) { - equal(obj, data, 'passes same object as third parameter of iteratee'); + assert.equal(obj, data, 'passes same object as third parameter of iteratee'); }); }); - test('omit', function() { + test('omit', function(assert) { var result; result = _.omit({a: 1, b: 2, c: 3}, 'b'); - deepEqual(result, {a: 1, c: 3}, 'can omit a single named property'); + assert.deepEqual(result, {a: 1, c: 3}, 'can omit a single named property'); result = _.omit({a: 1, b: 2, c: 3}, 'a', 'c'); - deepEqual(result, {b: 2}, 'can omit several named properties'); + assert.deepEqual(result, {b: 2}, 'can omit several named properties'); result = _.omit({a: 1, b: 2, c: 3}, ['b', 'c']); - deepEqual(result, {a: 1}, 'can omit properties named in an array'); + assert.deepEqual(result, {a: 1}, 'can omit properties named in an array'); result = _.omit(['a', 'b'], 0); - deepEqual(result, {1: 'b'}, 'can omit numeric properties'); + assert.deepEqual(result, {1: 'b'}, 'can omit numeric properties'); - deepEqual(_.omit(null, 'a', 'b'), {}, 'non objects return empty object'); - deepEqual(_.omit(void 0, 'toString'), {}, 'null/undefined return empty object'); - deepEqual(_.omit(5, 'toString', 'b'), {}, 'returns empty object for primitives'); + assert.deepEqual(_.omit(null, 'a', 'b'), {}, 'non objects return empty object'); + assert.deepEqual(_.omit(void 0, 'toString'), {}, 'null/undefined return empty object'); + assert.deepEqual(_.omit(5, 'toString', 'b'), {}, 'returns empty object for primitives'); var data = {a: 1, b: 2, c: 3}; var callback = function(value, key, object) { - strictEqual(key, {1: 'a', 2: 'b', 3: 'c'}[value]); - strictEqual(object, data); + assert.strictEqual(key, {1: 'a', 2: 'b', 3: 'c'}[value]); + assert.strictEqual(object, data); return value !== this.value; }; result = _.omit(data, callback, {value: 2}); - deepEqual(result, {b: 2}, 'can accept a predicate'); + assert.deepEqual(result, {b: 2}, 'can accept a predicate'); var Obj = function(){}; Obj.prototype = {a: 1, b: 2, c: 3}; var instance = new Obj(); - deepEqual(_.omit(instance, 'b'), {a: 1, c: 3}, 'include prototype props'); + assert.deepEqual(_.omit(instance, 'b'), {a: 1, c: 3}, 'include prototype props'); - deepEqual(_.omit(data, function(val, key) { + assert.deepEqual(_.omit(data, function(val, key) { return this[key] === 3 && this === instance; }, instance), {a: 1, b: 2}, 'function is given context'); }); - test('defaults', function() { + test('defaults', function(assert) { var options = {zero: 0, one: 1, empty: '', nan: NaN, nothing: null}; _.defaults(options, {zero: 1, one: 10, twenty: 20, nothing: 'str'}); - equal(options.zero, 0, 'value exists'); - equal(options.one, 1, 'value exists'); - equal(options.twenty, 20, 'default applied'); - equal(options.nothing, null, "null isn't overridden"); + assert.equal(options.zero, 0, 'value exists'); + assert.equal(options.one, 1, 'value exists'); + assert.equal(options.twenty, 20, 'default applied'); + assert.equal(options.nothing, null, "null isn't overridden"); _.defaults(options, {empty: 'full'}, {nan: 'nan'}, {word: 'word'}, {word: 'dog'}); - equal(options.empty, '', 'value exists'); - ok(_.isNaN(options.nan), "NaN isn't overridden"); - equal(options.word, 'word', 'new value is added, first one wins'); + assert.equal(options.empty, '', 'value exists'); + assert.ok(_.isNaN(options.nan), "NaN isn't overridden"); + assert.equal(options.word, 'word', 'new value is added, first one wins'); try { options = {}; _.defaults(options, null, void 0, {a: 1}); } catch(e) { /* ignored */ } - equal(options.a, 1, 'should not error on `null` or `undefined` sources'); + assert.equal(options.a, 1, 'should not error on `null` or `undefined` sources'); - deepEqual(_.defaults(null, {a: 1}), {a: 1}, 'defaults skips nulls'); - deepEqual(_.defaults(void 0, {a: 1}), {a: 1}, 'defaults skips undefined'); + assert.deepEqual(_.defaults(null, {a: 1}), {a: 1}, 'defaults skips nulls'); + assert.deepEqual(_.defaults(void 0, {a: 1}), {a: 1}, 'defaults skips undefined'); }); - test('clone', function() { + test('clone', function(assert) { var moe = {name: 'moe', lucky: [13, 27, 34]}; var clone = _.clone(moe); - equal(clone.name, 'moe', 'the clone as the attributes of the original'); + assert.equal(clone.name, 'moe', 'the clone as the attributes of the original'); clone.name = 'curly'; - ok(clone.name === 'curly' && moe.name === 'moe', 'clones can change shallow attributes without affecting the original'); + assert.ok(clone.name === 'curly' && moe.name === 'moe', 'clones can change shallow attributes without affecting the original'); clone.lucky.push(101); - equal(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original'); + assert.equal(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original'); - equal(_.clone(void 0), void 0, 'non objects should not be changed by clone'); - equal(_.clone(1), 1, 'non objects should not be changed by clone'); - equal(_.clone(null), null, 'non objects should not be changed by clone'); + assert.equal(_.clone(void 0), void 0, 'non objects should not be changed by clone'); + assert.equal(_.clone(1), 1, 'non objects should not be changed by clone'); + assert.equal(_.clone(null), null, 'non objects should not be changed by clone'); }); - test('create', function() { + test('create', function(assert) { var Parent = function() {}; Parent.prototype = {foo: function() {}, bar: 2}; _.each(['foo', null, void 0, 1], function(val) { - deepEqual(_.create(val), {}, 'should return empty object when a non-object is provided'); + assert.deepEqual(_.create(val), {}, 'should return empty object when a non-object is provided'); }); - ok(_.create([]) instanceof Array, 'should return new instance of array when array is provided'); + assert.ok(_.create([]) instanceof Array, 'should return new instance of array when array is provided'); var Child = function() {}; Child.prototype = _.create(Parent.prototype); - ok(new Child instanceof Parent, 'object should inherit prototype'); + assert.ok(new Child instanceof Parent, 'object should inherit prototype'); var func = function() {}; Child.prototype = _.create(Parent.prototype, {func: func}); - strictEqual(Child.prototype.func, func, 'properties should be added to object'); + assert.strictEqual(Child.prototype.func, func, 'properties should be added to object'); Child.prototype = _.create(Parent.prototype, {constructor: Child}); - strictEqual(Child.prototype.constructor, Child); + assert.strictEqual(Child.prototype.constructor, Child); Child.prototype.foo = 'foo'; var created = _.create(Child.prototype, new Child); - ok(!created.hasOwnProperty('foo'), 'should only add own properties'); + assert.ok(!created.hasOwnProperty('foo'), 'should only add own properties'); }); - test('isEqual', function() { + test('isEqual', function(assert) { function First() { this.value = 1; } @@ -319,128 +319,128 @@ Second.prototype.value = 2; // Basic equality and identity comparisons. - ok(_.isEqual(null, null), '`null` is equal to `null`'); - ok(_.isEqual(), '`undefined` is equal to `undefined`'); + assert.ok(_.isEqual(null, null), '`null` is equal to `null`'); + assert.ok(_.isEqual(), '`undefined` is equal to `undefined`'); - ok(!_.isEqual(0, -0), '`0` is not equal to `-0`'); - ok(!_.isEqual(-0, 0), 'Commutative equality is implemented for `0` and `-0`'); - ok(!_.isEqual(null, void 0), '`null` is not equal to `undefined`'); - ok(!_.isEqual(void 0, null), 'Commutative equality is implemented for `null` and `undefined`'); + assert.ok(!_.isEqual(0, -0), '`0` is not equal to `-0`'); + assert.ok(!_.isEqual(-0, 0), 'Commutative equality is implemented for `0` and `-0`'); + assert.ok(!_.isEqual(null, void 0), '`null` is not equal to `undefined`'); + assert.ok(!_.isEqual(void 0, null), 'Commutative equality is implemented for `null` and `undefined`'); // String object and primitive comparisons. - ok(_.isEqual('Curly', 'Curly'), 'Identical string primitives are equal'); - ok(_.isEqual(new String('Curly'), new String('Curly')), 'String objects with identical primitive values are equal'); - ok(_.isEqual(new String('Curly'), 'Curly'), 'String primitives and their corresponding object wrappers are equal'); - ok(_.isEqual('Curly', new String('Curly')), 'Commutative equality is implemented for string objects and primitives'); + assert.ok(_.isEqual('Curly', 'Curly'), 'Identical string primitives are equal'); + assert.ok(_.isEqual(new String('Curly'), new String('Curly')), 'String objects with identical primitive values are equal'); + assert.ok(_.isEqual(new String('Curly'), 'Curly'), 'String primitives and their corresponding object wrappers are equal'); + assert.ok(_.isEqual('Curly', new String('Curly')), 'Commutative equality is implemented for string objects and primitives'); - ok(!_.isEqual('Curly', 'Larry'), 'String primitives with different values are not equal'); - ok(!_.isEqual(new String('Curly'), new String('Larry')), 'String objects with different primitive values are not equal'); - ok(!_.isEqual(new String('Curly'), {toString: function(){ return 'Curly'; }}), 'String objects and objects with a custom `toString` method are not equal'); + assert.ok(!_.isEqual('Curly', 'Larry'), 'String primitives with different values are not equal'); + assert.ok(!_.isEqual(new String('Curly'), new String('Larry')), 'String objects with different primitive values are not equal'); + assert.ok(!_.isEqual(new String('Curly'), {toString: function(){ return 'Curly'; }}), 'String objects and objects with a custom `toString` method are not equal'); // Number object and primitive comparisons. - ok(_.isEqual(75, 75), 'Identical number primitives are equal'); - ok(_.isEqual(new Number(75), new Number(75)), 'Number objects with identical primitive values are equal'); - ok(_.isEqual(75, new Number(75)), 'Number primitives and their corresponding object wrappers are equal'); - ok(_.isEqual(new Number(75), 75), 'Commutative equality is implemented for number objects and primitives'); - ok(!_.isEqual(new Number(0), -0), '`new Number(0)` and `-0` are not equal'); - ok(!_.isEqual(0, new Number(-0)), 'Commutative equality is implemented for `new Number(0)` and `-0`'); + assert.ok(_.isEqual(75, 75), 'Identical number primitives are equal'); + assert.ok(_.isEqual(new Number(75), new Number(75)), 'Number objects with identical primitive values are equal'); + assert.ok(_.isEqual(75, new Number(75)), 'Number primitives and their corresponding object wrappers are equal'); + assert.ok(_.isEqual(new Number(75), 75), 'Commutative equality is implemented for number objects and primitives'); + assert.ok(!_.isEqual(new Number(0), -0), '`new Number(0)` and `-0` are not equal'); + assert.ok(!_.isEqual(0, new Number(-0)), 'Commutative equality is implemented for `new Number(0)` and `-0`'); - ok(!_.isEqual(new Number(75), new Number(63)), 'Number objects with different primitive values are not equal'); - ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), 'Number objects and objects with a `valueOf` method are not equal'); + assert.ok(!_.isEqual(new Number(75), new Number(63)), 'Number objects with different primitive values are not equal'); + assert.ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), 'Number objects and objects with a `valueOf` method are not equal'); // Comparisons involving `NaN`. - ok(_.isEqual(NaN, NaN), '`NaN` is equal to `NaN`'); - ok(_.isEqual(new Number(NaN), NaN), 'Object(`NaN`) is equal to `NaN`'); - ok(!_.isEqual(61, NaN), 'A number primitive is not equal to `NaN`'); - ok(!_.isEqual(new Number(79), NaN), 'A number object is not equal to `NaN`'); - ok(!_.isEqual(Infinity, NaN), '`Infinity` is not equal to `NaN`'); + assert.ok(_.isEqual(NaN, NaN), '`NaN` is equal to `NaN`'); + assert.ok(_.isEqual(new Number(NaN), NaN), 'Object(`NaN`) is equal to `NaN`'); + assert.ok(!_.isEqual(61, NaN), 'A number primitive is not equal to `NaN`'); + assert.ok(!_.isEqual(new Number(79), NaN), 'A number object is not equal to `NaN`'); + assert.ok(!_.isEqual(Infinity, NaN), '`Infinity` is not equal to `NaN`'); // Boolean object and primitive comparisons. - ok(_.isEqual(true, true), 'Identical boolean primitives are equal'); - ok(_.isEqual(new Boolean, new Boolean), 'Boolean objects with identical primitive values are equal'); - ok(_.isEqual(true, new Boolean(true)), 'Boolean primitives and their corresponding object wrappers are equal'); - ok(_.isEqual(new Boolean(true), true), 'Commutative equality is implemented for booleans'); - ok(!_.isEqual(new Boolean(true), new Boolean), 'Boolean objects with different primitive values are not equal'); + assert.ok(_.isEqual(true, true), 'Identical boolean primitives are equal'); + assert.ok(_.isEqual(new Boolean, new Boolean), 'Boolean objects with identical primitive values are equal'); + assert.ok(_.isEqual(true, new Boolean(true)), 'Boolean primitives and their corresponding object wrappers are equal'); + assert.ok(_.isEqual(new Boolean(true), true), 'Commutative equality is implemented for booleans'); + assert.ok(!_.isEqual(new Boolean(true), new Boolean), 'Boolean objects with different primitive values are not equal'); // Common type coercions. - ok(!_.isEqual(new Boolean(false), true), '`new Boolean(false)` is not equal to `true`'); - ok(!_.isEqual('75', 75), 'String and number primitives with like values are not equal'); - ok(!_.isEqual(new Number(63), new String(63)), 'String and number objects with like values are not equal'); - ok(!_.isEqual(75, '75'), 'Commutative equality is implemented for like string and number values'); - ok(!_.isEqual(0, ''), 'Number and string primitives with like values are not equal'); - ok(!_.isEqual(1, true), 'Number and boolean primitives with like values are not equal'); - ok(!_.isEqual(new Boolean(false), new Number(0)), 'Boolean and number objects with like values are not equal'); - ok(!_.isEqual(false, new String('')), 'Boolean primitives and string objects with like values are not equal'); - ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), 'Dates and their corresponding numeric primitive values are not equal'); + assert.ok(!_.isEqual(new Boolean(false), true), '`new Boolean(false)` is not equal to `true`'); + assert.ok(!_.isEqual('75', 75), 'String and number primitives with like values are not equal'); + assert.ok(!_.isEqual(new Number(63), new String(63)), 'String and number objects with like values are not equal'); + assert.ok(!_.isEqual(75, '75'), 'Commutative equality is implemented for like string and number values'); + assert.ok(!_.isEqual(0, ''), 'Number and string primitives with like values are not equal'); + assert.ok(!_.isEqual(1, true), 'Number and boolean primitives with like values are not equal'); + assert.ok(!_.isEqual(new Boolean(false), new Number(0)), 'Boolean and number objects with like values are not equal'); + assert.ok(!_.isEqual(false, new String('')), 'Boolean primitives and string objects with like values are not equal'); + assert.ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), 'Dates and their corresponding numeric primitive values are not equal'); // Dates. - ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), 'Date objects referencing identical times are equal'); - ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), 'Date objects referencing different times are not equal'); - ok(!_.isEqual(new Date(2009, 11, 13), { + assert.ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), 'Date objects referencing identical times are equal'); + assert.ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), 'Date objects referencing different times are not equal'); + assert.ok(!_.isEqual(new Date(2009, 11, 13), { getTime: function(){ return 12606876e5; } }), 'Date objects and objects with a `getTime` method are not equal'); - ok(!_.isEqual(new Date('Curly'), new Date('Curly')), 'Invalid dates are not equal'); + assert.ok(!_.isEqual(new Date('Curly'), new Date('Curly')), 'Invalid dates are not equal'); // Functions. - ok(!_.isEqual(First, Second), 'Different functions with identical bodies and source code representations are not equal'); + assert.ok(!_.isEqual(First, Second), 'Different functions with identical bodies and source code representations are not equal'); // RegExps. - ok(_.isEqual(/(?:)/gim, /(?:)/gim), 'RegExps with equivalent patterns and flags are equal'); - ok(_.isEqual(/(?:)/gi, /(?:)/ig), 'Flag order is not significant'); - ok(!_.isEqual(/(?:)/g, /(?:)/gi), 'RegExps with equivalent patterns and different flags are not equal'); - ok(!_.isEqual(/Moe/gim, /Curly/gim), 'RegExps with different patterns and equivalent flags are not equal'); - ok(!_.isEqual(/(?:)/gi, /(?:)/g), 'Commutative equality is implemented for RegExps'); - ok(!_.isEqual(/Curly/g, {source: 'Larry', global: true, ignoreCase: false, multiline: false}), 'RegExps and RegExp-like objects are not equal'); + assert.ok(_.isEqual(/(?:)/gim, /(?:)/gim), 'RegExps with equivalent patterns and flags are equal'); + assert.ok(_.isEqual(/(?:)/gi, /(?:)/ig), 'Flag order is not significant'); + assert.ok(!_.isEqual(/(?:)/g, /(?:)/gi), 'RegExps with equivalent patterns and different flags are not equal'); + assert.ok(!_.isEqual(/Moe/gim, /Curly/gim), 'RegExps with different patterns and equivalent flags are not equal'); + assert.ok(!_.isEqual(/(?:)/gi, /(?:)/g), 'Commutative equality is implemented for RegExps'); + assert.ok(!_.isEqual(/Curly/g, {source: 'Larry', global: true, ignoreCase: false, multiline: false}), 'RegExps and RegExp-like objects are not equal'); // Empty arrays, array-like objects, and object literals. - ok(_.isEqual({}, {}), 'Empty object literals are equal'); - ok(_.isEqual([], []), 'Empty array literals are equal'); - ok(_.isEqual([{}], [{}]), 'Empty nested arrays and objects are equal'); - ok(!_.isEqual({length: 0}, []), 'Array-like objects and arrays are not equal.'); - ok(!_.isEqual([], {length: 0}), 'Commutative equality is implemented for array-like objects'); + assert.ok(_.isEqual({}, {}), 'Empty object literals are equal'); + assert.ok(_.isEqual([], []), 'Empty array literals are equal'); + assert.ok(_.isEqual([{}], [{}]), 'Empty nested arrays and objects are equal'); + assert.ok(!_.isEqual({length: 0}, []), 'Array-like objects and arrays are not equal.'); + assert.ok(!_.isEqual([], {length: 0}), 'Commutative equality is implemented for array-like objects'); - ok(!_.isEqual({}, []), 'Object literals and array literals are not equal'); - ok(!_.isEqual([], {}), 'Commutative equality is implemented for objects and arrays'); + assert.ok(!_.isEqual({}, []), 'Object literals and array literals are not equal'); + assert.ok(!_.isEqual([], {}), 'Commutative equality is implemented for objects and arrays'); // Arrays with primitive and object values. - ok(_.isEqual([1, 'Larry', true], [1, 'Larry', true]), 'Arrays containing identical primitives are equal'); - ok(_.isEqual([/Moe/g, new Date(2009, 9, 25)], [/Moe/g, new Date(2009, 9, 25)]), 'Arrays containing equivalent elements are equal'); + assert.ok(_.isEqual([1, 'Larry', true], [1, 'Larry', true]), 'Arrays containing identical primitives are equal'); + assert.ok(_.isEqual([/Moe/g, new Date(2009, 9, 25)], [/Moe/g, new Date(2009, 9, 25)]), 'Arrays containing equivalent elements are equal'); // Multi-dimensional arrays. var a = [new Number(47), false, 'Larry', /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}]; var b = [new Number(47), false, 'Larry', /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}]; - ok(_.isEqual(a, b), 'Arrays containing nested arrays and objects are recursively compared'); + assert.ok(_.isEqual(a, b), 'Arrays containing nested arrays and objects are recursively compared'); // Overwrite the methods defined in ES 5.1 section 15.4.4. a.forEach = a.map = a.filter = a.every = a.indexOf = a.lastIndexOf = a.some = a.reduce = a.reduceRight = null; b.join = b.pop = b.reverse = b.shift = b.slice = b.splice = b.concat = b.sort = b.unshift = null; // Array elements and properties. - ok(_.isEqual(a, b), 'Arrays containing equivalent elements and different non-numeric properties are equal'); + assert.ok(_.isEqual(a, b), 'Arrays containing equivalent elements and different non-numeric properties are equal'); a.push('White Rocks'); - ok(!_.isEqual(a, b), 'Arrays of different lengths are not equal'); + assert.ok(!_.isEqual(a, b), 'Arrays of different lengths are not equal'); a.push('East Boulder'); b.push('Gunbarrel Ranch', 'Teller Farm'); - ok(!_.isEqual(a, b), 'Arrays of identical lengths containing different elements are not equal'); + assert.ok(!_.isEqual(a, b), 'Arrays of identical lengths containing different elements are not equal'); // Sparse arrays. - ok(_.isEqual(Array(3), Array(3)), 'Sparse arrays of identical lengths are equal'); - ok(!_.isEqual(Array(3), Array(6)), 'Sparse arrays of different lengths are not equal when both are empty'); + assert.ok(_.isEqual(Array(3), Array(3)), 'Sparse arrays of identical lengths are equal'); + assert.ok(!_.isEqual(Array(3), Array(6)), 'Sparse arrays of different lengths are not equal when both are empty'); var sparse = []; sparse[1] = 5; - ok(_.isEqual(sparse, [void 0, 5]), 'Handles sparse arrays as dense'); + assert.ok(_.isEqual(sparse, [void 0, 5]), 'Handles sparse arrays as dense'); // Simple objects. - ok(_.isEqual({a: 'Curly', b: 1, c: true}, {a: 'Curly', b: 1, c: true}), 'Objects containing identical primitives are equal'); - ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), 'Objects containing equivalent members are equal'); - ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), 'Objects of identical sizes with different values are not equal'); - ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), 'Objects of identical sizes with different property names are not equal'); - ok(!_.isEqual({a: 1, b: 2}, {a: 1}), 'Objects of different sizes are not equal'); - ok(!_.isEqual({a: 1}, {a: 1, b: 2}), 'Commutative equality is implemented for objects'); - ok(!_.isEqual({x: 1, y: void 0}, {x: 1, z: 2}), 'Objects with identical keys and different values are not equivalent'); + assert.ok(_.isEqual({a: 'Curly', b: 1, c: true}, {a: 'Curly', b: 1, c: true}), 'Objects containing identical primitives are equal'); + assert.ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), 'Objects containing equivalent members are equal'); + assert.ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), 'Objects of identical sizes with different values are not equal'); + assert.ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), 'Objects of identical sizes with different property names are not equal'); + assert.ok(!_.isEqual({a: 1, b: 2}, {a: 1}), 'Objects of different sizes are not equal'); + assert.ok(!_.isEqual({a: 1}, {a: 1, b: 2}), 'Commutative equality is implemented for objects'); + assert.ok(!_.isEqual({x: 1, y: void 0}, {x: 1, z: 2}), 'Objects with identical keys and different values are not equivalent'); // `A` contains nested objects and arrays. a = { @@ -471,456 +471,456 @@ seconds: 54 } }; - ok(_.isEqual(a, b), 'Objects with nested equivalent members are recursively compared'); + assert.ok(_.isEqual(a, b), 'Objects with nested equivalent members are recursively compared'); // Instances. - ok(_.isEqual(new First, new First), 'Object instances are equal'); - ok(!_.isEqual(new First, new Second), 'Objects with different constructors and identical own properties are not equal'); - ok(!_.isEqual({value: 1}, new First), 'Object instances and objects sharing equivalent properties are not equal'); - ok(!_.isEqual({value: 2}, new Second), 'The prototype chain of objects should not be examined'); + assert.ok(_.isEqual(new First, new First), 'Object instances are equal'); + assert.ok(!_.isEqual(new First, new Second), 'Objects with different constructors and identical own properties are not equal'); + assert.ok(!_.isEqual({value: 1}, new First), 'Object instances and objects sharing equivalent properties are not equal'); + assert.ok(!_.isEqual({value: 2}, new Second), 'The prototype chain of objects should not be examined'); // Circular Arrays. (a = []).push(a); (b = []).push(b); - ok(_.isEqual(a, b), 'Arrays containing circular references are equal'); + assert.ok(_.isEqual(a, b), 'Arrays containing circular references are equal'); a.push(new String('Larry')); b.push(new String('Larry')); - ok(_.isEqual(a, b), 'Arrays containing circular references and equivalent properties are equal'); + assert.ok(_.isEqual(a, b), 'Arrays containing circular references and equivalent properties are equal'); a.push('Shemp'); b.push('Curly'); - ok(!_.isEqual(a, b), 'Arrays containing circular references and different properties are not equal'); + assert.ok(!_.isEqual(a, b), 'Arrays containing circular references and different properties are not equal'); // More circular arrays #767. a = ['everything is checked but', 'this', 'is not']; a[1] = a; b = ['everything is checked but', ['this', 'array'], 'is not']; - ok(!_.isEqual(a, b), 'Comparison of circular references with non-circular references are not equal'); + assert.ok(!_.isEqual(a, b), 'Comparison of circular references with non-circular references are not equal'); // Circular Objects. a = {abc: null}; b = {abc: null}; a.abc = a; b.abc = b; - ok(_.isEqual(a, b), 'Objects containing circular references are equal'); + assert.ok(_.isEqual(a, b), 'Objects containing circular references are equal'); a.def = 75; b.def = 75; - ok(_.isEqual(a, b), 'Objects containing circular references and equivalent properties are equal'); + assert.ok(_.isEqual(a, b), 'Objects containing circular references and equivalent properties are equal'); a.def = new Number(75); b.def = new Number(63); - ok(!_.isEqual(a, b), 'Objects containing circular references and different properties are not equal'); + assert.ok(!_.isEqual(a, b), 'Objects containing circular references and different properties are not equal'); // More circular objects #767. a = {everything: 'is checked', but: 'this', is: 'not'}; a.but = a; b = {everything: 'is checked', but: {that: 'object'}, is: 'not'}; - ok(!_.isEqual(a, b), 'Comparison of circular references with non-circular object references are not equal'); + assert.ok(!_.isEqual(a, b), 'Comparison of circular references with non-circular object references are not equal'); // Cyclic Structures. a = [{abc: null}]; b = [{abc: null}]; (a[0].abc = a).push(a); (b[0].abc = b).push(b); - ok(_.isEqual(a, b), 'Cyclic structures are equal'); + assert.ok(_.isEqual(a, b), 'Cyclic structures are equal'); a[0].def = 'Larry'; b[0].def = 'Larry'; - ok(_.isEqual(a, b), 'Cyclic structures containing equivalent properties are equal'); + assert.ok(_.isEqual(a, b), 'Cyclic structures containing equivalent properties are equal'); a[0].def = new String('Larry'); b[0].def = new String('Curly'); - ok(!_.isEqual(a, b), 'Cyclic structures containing different properties are not equal'); + assert.ok(!_.isEqual(a, b), 'Cyclic structures containing different properties are not equal'); // Complex Circular References. a = {foo: {b: {foo: {c: {foo: null}}}}}; b = {foo: {b: {foo: {c: {foo: null}}}}}; a.foo.b.foo.c.foo = a; b.foo.b.foo.c.foo = b; - ok(_.isEqual(a, b), 'Cyclic structures with nested and identically-named properties are equal'); + assert.ok(_.isEqual(a, b), 'Cyclic structures with nested and identically-named properties are equal'); // Chaining. - ok(!_.isEqual(_({x: 1, y: void 0}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal'); + assert.ok(!_.isEqual(_({x: 1, y: void 0}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal'); a = _({x: 1, y: 2}).chain(); b = _({x: 1, y: 2}).chain(); - equal(_.isEqual(a.isEqual(b), _(true)), true, '`isEqual` can be chained'); + assert.equal(_.isEqual(a.isEqual(b), _(true)), true, '`isEqual` can be chained'); // Objects without a `constructor` property if (Object.create) { a = Object.create(null, {x: {value: 1, enumerable: true}}); b = {x: 1}; - ok(_.isEqual(a, b), 'Handles objects without a constructor (e.g. from Object.create'); + assert.ok(_.isEqual(a, b), 'Handles objects without a constructor (e.g. from Object.create'); } function Foo() { this.a = 1; } Foo.prototype.constructor = null; var other = {a: 1}; - strictEqual(_.isEqual(new Foo, other), false, 'Objects from different constructors are not equal'); + assert.strictEqual(_.isEqual(new Foo, other), false, 'Objects from different constructors are not equal'); // Tricky object cases val comparisions - equal(_.isEqual([0], [-0]), false); - equal(_.isEqual({a: 0}, {a: -0}), false); - equal(_.isEqual([NaN], [NaN]), true); - equal(_.isEqual({a: NaN}, {a: NaN}), true); - }); - - test('isEmpty', function() { - ok(!_([1]).isEmpty(), '[1] is not empty'); - ok(_.isEmpty([]), '[] is empty'); - ok(!_.isEmpty({one: 1}), '{one: 1} is not empty'); - ok(_.isEmpty({}), '{} is empty'); - ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty'); - ok(_.isEmpty(null), 'null is empty'); - ok(_.isEmpty(), 'undefined is empty'); - ok(_.isEmpty(''), 'the empty string is empty'); - ok(!_.isEmpty('moe'), 'but other strings are not'); + assert.equal(_.isEqual([0], [-0]), false); + assert.equal(_.isEqual({a: 0}, {a: -0}), false); + assert.equal(_.isEqual([NaN], [NaN]), true); + assert.equal(_.isEqual({a: NaN}, {a: NaN}), true); + }); + + test('isEmpty', function(assert) { + assert.ok(!_([1]).isEmpty(), '[1] is not empty'); + assert.ok(_.isEmpty([]), '[] is empty'); + assert.ok(!_.isEmpty({one: 1}), '{one: 1} is not empty'); + assert.ok(_.isEmpty({}), '{} is empty'); + assert.ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty'); + assert.ok(_.isEmpty(null), 'null is empty'); + assert.ok(_.isEmpty(), 'undefined is empty'); + assert.ok(_.isEmpty(''), 'the empty string is empty'); + assert.ok(!_.isEmpty('moe'), 'but other strings are not'); var obj = {one: 1}; delete obj.one; - ok(_.isEmpty(obj), 'deleting all the keys from an object empties it'); + assert.ok(_.isEmpty(obj), 'deleting all the keys from an object empties it'); var args = function(){ return arguments; }; - ok(_.isEmpty(args()), 'empty arguments object is empty'); - ok(!_.isEmpty(args('')), 'non-empty arguments object is not empty'); + assert.ok(_.isEmpty(args()), 'empty arguments object is empty'); + assert.ok(!_.isEmpty(args('')), 'non-empty arguments object is not empty'); // covers collecting non-enumerable properties in IE < 9 var nonEnumProp = {toString: 5}; - ok(!_.isEmpty(nonEnumProp), 'non-enumerable property is not empty'); + assert.ok(!_.isEmpty(nonEnumProp), 'non-enumerable property is not empty'); }); if (typeof document === 'object') { - test('isElement', function() { - ok(!_.isElement('div'), 'strings are not dom elements'); - ok(_.isElement(testElement), 'an element is a DOM element'); + test('isElement', function(assert) { + assert.ok(!_.isElement('div'), 'strings are not dom elements'); + assert.ok(_.isElement(testElement), 'an element is a DOM element'); }); } - test('isArguments', function() { + test('isArguments', function(assert) { var args = (function(){ return arguments; }(1, 2, 3)); - ok(!_.isArguments('string'), 'a string is not an arguments object'); - ok(!_.isArguments(_.isArguments), 'a function is not an arguments object'); - ok(_.isArguments(args), 'but the arguments object is an arguments object'); - ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array'); - ok(!_.isArguments([1, 2, 3]), 'and not vanilla arrays.'); + assert.ok(!_.isArguments('string'), 'a string is not an arguments object'); + assert.ok(!_.isArguments(_.isArguments), 'a function is not an arguments object'); + assert.ok(_.isArguments(args), 'but the arguments object is an arguments object'); + assert.ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array'); + assert.ok(!_.isArguments([1, 2, 3]), 'and not vanilla arrays.'); }); - test('isObject', function() { - ok(_.isObject(arguments), 'the arguments object is object'); - ok(_.isObject([1, 2, 3]), 'and arrays'); + test('isObject', function(assert) { + assert.ok(_.isObject(arguments), 'the arguments object is object'); + assert.ok(_.isObject([1, 2, 3]), 'and arrays'); if (testElement) { - ok(_.isObject(testElement), 'and DOM element'); + assert.ok(_.isObject(testElement), 'and DOM element'); } - ok(_.isObject(function() {}), 'and functions'); - ok(!_.isObject(null), 'but not null'); - ok(!_.isObject(void 0), 'and not undefined'); - ok(!_.isObject('string'), 'and not string'); - ok(!_.isObject(12), 'and not number'); - ok(!_.isObject(true), 'and not boolean'); - ok(_.isObject(new String('string')), 'but new String()'); + assert.ok(_.isObject(function() {}), 'and functions'); + assert.ok(!_.isObject(null), 'but not null'); + assert.ok(!_.isObject(void 0), 'and not undefined'); + assert.ok(!_.isObject('string'), 'and not string'); + assert.ok(!_.isObject(12), 'and not number'); + assert.ok(!_.isObject(true), 'and not boolean'); + assert.ok(_.isObject(new String('string')), 'but new String()'); }); - test('isArray', function() { - ok(!_.isArray(void 0), 'undefined vars are not arrays'); - ok(!_.isArray(arguments), 'the arguments object is not an array'); - ok(_.isArray([1, 2, 3]), 'but arrays are'); + test('isArray', function(assert) { + assert.ok(!_.isArray(void 0), 'undefined vars are not arrays'); + assert.ok(!_.isArray(arguments), 'the arguments object is not an array'); + assert.ok(_.isArray([1, 2, 3]), 'but arrays are'); }); - test('isString', function() { + test('isString', function(assert) { var obj = new String('I am a string object'); if (testElement) { - ok(!_.isString(testElement), 'an element is not a string'); + assert.ok(!_.isString(testElement), 'an element is not a string'); } - ok(_.isString([1, 2, 3].join(', ')), 'but strings are'); - strictEqual(_.isString('I am a string literal'), true, 'string literals are'); - ok(_.isString(obj), 'so are String objects'); - strictEqual(_.isString(1), false); - }); - - test('isNumber', function() { - ok(!_.isNumber('string'), 'a string is not a number'); - ok(!_.isNumber(arguments), 'the arguments object is not a number'); - ok(!_.isNumber(void 0), 'undefined is not a number'); - ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are'); - ok(_.isNumber(NaN), 'NaN *is* a number'); - ok(_.isNumber(Infinity), 'Infinity is a number'); - ok(!_.isNumber('1'), 'numeric strings are not numbers'); - }); - - test('isBoolean', function() { - ok(!_.isBoolean(2), 'a number is not a boolean'); - ok(!_.isBoolean('string'), 'a string is not a boolean'); - ok(!_.isBoolean('false'), 'the string "false" is not a boolean'); - ok(!_.isBoolean('true'), 'the string "true" is not a boolean'); - ok(!_.isBoolean(arguments), 'the arguments object is not a boolean'); - ok(!_.isBoolean(void 0), 'undefined is not a boolean'); - ok(!_.isBoolean(NaN), 'NaN is not a boolean'); - ok(!_.isBoolean(null), 'null is not a boolean'); - ok(_.isBoolean(true), 'but true is'); - ok(_.isBoolean(false), 'and so is false'); - }); - - test('isFunction', function() { - ok(!_.isFunction(void 0), 'undefined vars are not functions'); - ok(!_.isFunction([1, 2, 3]), 'arrays are not functions'); - ok(!_.isFunction('moe'), 'strings are not functions'); - ok(_.isFunction(_.isFunction), 'but functions are'); - ok(_.isFunction(function(){}), 'even anonymous ones'); + assert.ok(_.isString([1, 2, 3].join(', ')), 'but strings are'); + assert.strictEqual(_.isString('I am a string literal'), true, 'string literals are'); + assert.ok(_.isString(obj), 'so are String objects'); + assert.strictEqual(_.isString(1), false); + }); + + test('isNumber', function(assert) { + assert.ok(!_.isNumber('string'), 'a string is not a number'); + assert.ok(!_.isNumber(arguments), 'the arguments object is not a number'); + assert.ok(!_.isNumber(void 0), 'undefined is not a number'); + assert.ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are'); + assert.ok(_.isNumber(NaN), 'NaN *is* a number'); + assert.ok(_.isNumber(Infinity), 'Infinity is a number'); + assert.ok(!_.isNumber('1'), 'numeric strings are not numbers'); + }); + + test('isBoolean', function(assert) { + assert.ok(!_.isBoolean(2), 'a number is not a boolean'); + assert.ok(!_.isBoolean('string'), 'a string is not a boolean'); + assert.ok(!_.isBoolean('false'), 'the string "false" is not a boolean'); + assert.ok(!_.isBoolean('true'), 'the string "true" is not a boolean'); + assert.ok(!_.isBoolean(arguments), 'the arguments object is not a boolean'); + assert.ok(!_.isBoolean(void 0), 'undefined is not a boolean'); + assert.ok(!_.isBoolean(NaN), 'NaN is not a boolean'); + assert.ok(!_.isBoolean(null), 'null is not a boolean'); + assert.ok(_.isBoolean(true), 'but true is'); + assert.ok(_.isBoolean(false), 'and so is false'); + }); + + test('isFunction', function(assert) { + assert.ok(!_.isFunction(void 0), 'undefined vars are not functions'); + assert.ok(!_.isFunction([1, 2, 3]), 'arrays are not functions'); + assert.ok(!_.isFunction('moe'), 'strings are not functions'); + assert.ok(_.isFunction(_.isFunction), 'but functions are'); + assert.ok(_.isFunction(function(){}), 'even anonymous ones'); if (testElement) { - ok(!_.isFunction(testElement), 'elements are not functions'); + assert.ok(!_.isFunction(testElement), 'elements are not functions'); } var nodelist = typeof document != 'undefined' && document.childNodes; if (nodelist) { - ok(!_.isFunction(nodelist)); + assert.ok(!_.isFunction(nodelist)); } }); if (typeof Int8Array !== 'undefined') { - test('#1929 Typed Array constructors are functions', function() { + test('#1929 Typed Array constructors are functions', function(assert) { _.chain(['Float32Array', 'Float64Array', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array']) .map(_.propertyOf(typeof GLOBAL != 'undefined' ? GLOBAL : window)) .compact() .each(function(TypedArray) { // PhantomJS reports `typeof UInt8Array == 'object'` and doesn't report toString TypeArray // as a function - strictEqual(_.isFunction(TypedArray), Object.prototype.toString.call(TypedArray) === '[object Function]'); + assert.strictEqual(_.isFunction(TypedArray), Object.prototype.toString.call(TypedArray) === '[object Function]'); }); }); } - test('isDate', function() { - ok(!_.isDate(100), 'numbers are not dates'); - ok(!_.isDate({}), 'objects are not dates'); - ok(_.isDate(new Date()), 'but dates are'); + test('isDate', function(assert) { + assert.ok(!_.isDate(100), 'numbers are not dates'); + assert.ok(!_.isDate({}), 'objects are not dates'); + assert.ok(_.isDate(new Date()), 'but dates are'); }); - test('isRegExp', function() { - ok(!_.isRegExp(_.identity), 'functions are not RegExps'); - ok(_.isRegExp(/identity/), 'but RegExps are'); + test('isRegExp', function(assert) { + assert.ok(!_.isRegExp(_.identity), 'functions are not RegExps'); + assert.ok(_.isRegExp(/identity/), 'but RegExps are'); }); - test('isFinite', function() { - ok(!_.isFinite(void 0), 'undefined is not finite'); - ok(!_.isFinite(null), 'null is not finite'); - ok(!_.isFinite(NaN), 'NaN is not finite'); - ok(!_.isFinite(Infinity), 'Infinity is not finite'); - ok(!_.isFinite(-Infinity), '-Infinity is not finite'); - ok(_.isFinite('12'), 'Numeric strings are numbers'); - ok(!_.isFinite('1a'), 'Non numeric strings are not numbers'); - ok(!_.isFinite(''), 'Empty strings are not numbers'); + test('isFinite', function(assert) { + assert.ok(!_.isFinite(void 0), 'undefined is not finite'); + assert.ok(!_.isFinite(null), 'null is not finite'); + assert.ok(!_.isFinite(NaN), 'NaN is not finite'); + assert.ok(!_.isFinite(Infinity), 'Infinity is not finite'); + assert.ok(!_.isFinite(-Infinity), '-Infinity is not finite'); + assert.ok(_.isFinite('12'), 'Numeric strings are numbers'); + assert.ok(!_.isFinite('1a'), 'Non numeric strings are not numbers'); + assert.ok(!_.isFinite(''), 'Empty strings are not numbers'); var obj = new Number(5); - ok(_.isFinite(obj), 'Number instances can be finite'); - ok(_.isFinite(0), '0 is finite'); - ok(_.isFinite(123), 'Ints are finite'); - ok(_.isFinite(-12.44), 'Floats are finite'); - }); - - test('isNaN', function() { - ok(!_.isNaN(void 0), 'undefined is not NaN'); - ok(!_.isNaN(null), 'null is not NaN'); - ok(!_.isNaN(0), '0 is not NaN'); - ok(!_.isNaN(new Number(0)), 'wrapped 0 is not NaN'); - ok(_.isNaN(NaN), 'but NaN is'); - ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN'); - }); - - test('isNull', function() { - ok(!_.isNull(void 0), 'undefined is not null'); - ok(!_.isNull(NaN), 'NaN is not null'); - ok(_.isNull(null), 'but null is'); - }); - - test('isUndefined', function() { - ok(!_.isUndefined(1), 'numbers are defined'); - ok(!_.isUndefined(null), 'null is defined'); - ok(!_.isUndefined(false), 'false is defined'); - ok(!_.isUndefined(NaN), 'NaN is defined'); - ok(_.isUndefined(), 'nothing is undefined'); - ok(_.isUndefined(void 0), 'undefined is undefined'); - }); - - test('isError', function() { - ok(!_.isError(1), 'numbers are not Errors'); - ok(!_.isError(null), 'null is not an Error'); - ok(!_.isError(Error), 'functions are not Errors'); - ok(_.isError(new Error()), 'Errors are Errors'); - ok(_.isError(new EvalError()), 'EvalErrors are Errors'); - ok(_.isError(new RangeError()), 'RangeErrors are Errors'); - ok(_.isError(new ReferenceError()), 'ReferenceErrors are Errors'); - ok(_.isError(new SyntaxError()), 'SyntaxErrors are Errors'); - ok(_.isError(new TypeError()), 'TypeErrors are Errors'); - ok(_.isError(new URIError()), 'URIErrors are Errors'); - }); - - test('tap', function() { + assert.ok(_.isFinite(obj), 'Number instances can be finite'); + assert.ok(_.isFinite(0), '0 is finite'); + assert.ok(_.isFinite(123), 'Ints are finite'); + assert.ok(_.isFinite(-12.44), 'Floats are finite'); + }); + + test('isNaN', function(assert) { + assert.ok(!_.isNaN(void 0), 'undefined is not NaN'); + assert.ok(!_.isNaN(null), 'null is not NaN'); + assert.ok(!_.isNaN(0), '0 is not NaN'); + assert.ok(!_.isNaN(new Number(0)), 'wrapped 0 is not NaN'); + assert.ok(_.isNaN(NaN), 'but NaN is'); + assert.ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN'); + }); + + test('isNull', function(assert) { + assert.ok(!_.isNull(void 0), 'undefined is not null'); + assert.ok(!_.isNull(NaN), 'NaN is not null'); + assert.ok(_.isNull(null), 'but null is'); + }); + + test('isUndefined', function(assert) { + assert.ok(!_.isUndefined(1), 'numbers are defined'); + assert.ok(!_.isUndefined(null), 'null is defined'); + assert.ok(!_.isUndefined(false), 'false is defined'); + assert.ok(!_.isUndefined(NaN), 'NaN is defined'); + assert.ok(_.isUndefined(), 'nothing is undefined'); + assert.ok(_.isUndefined(void 0), 'undefined is undefined'); + }); + + test('isError', function(assert) { + assert.ok(!_.isError(1), 'numbers are not Errors'); + assert.ok(!_.isError(null), 'null is not an Error'); + assert.ok(!_.isError(Error), 'functions are not Errors'); + assert.ok(_.isError(new Error()), 'Errors are Errors'); + assert.ok(_.isError(new EvalError()), 'EvalErrors are Errors'); + assert.ok(_.isError(new RangeError()), 'RangeErrors are Errors'); + assert.ok(_.isError(new ReferenceError()), 'ReferenceErrors are Errors'); + assert.ok(_.isError(new SyntaxError()), 'SyntaxErrors are Errors'); + assert.ok(_.isError(new TypeError()), 'TypeErrors are Errors'); + assert.ok(_.isError(new URIError()), 'URIErrors are Errors'); + }); + + test('tap', function(assert) { var intercepted = null; var interceptor = function(obj) { intercepted = obj; }; var returned = _.tap(1, interceptor); - equal(intercepted, 1, 'passes tapped object to interceptor'); - equal(returned, 1, 'returns tapped object'); + assert.equal(intercepted, 1, 'passes tapped object to interceptor'); + assert.equal(returned, 1, 'returns tapped object'); returned = _([1, 2, 3]).chain(). map(function(n){ return n * 2; }). max(). tap(interceptor). value(); - equal(returned, 6, 'can use tapped objects in a chain'); - equal(intercepted, returned, 'can use tapped objects in a chain'); + assert.equal(returned, 6, 'can use tapped objects in a chain'); + assert.equal(intercepted, returned, 'can use tapped objects in a chain'); }); - test('has', function() { + test('has', function(assert) { var obj = {foo: 'bar', func: function(){}}; - ok(_.has(obj, 'foo'), 'has() checks that the object has a property.'); - ok(!_.has(obj, 'baz'), "has() returns false if the object doesn't have the property."); - ok(_.has(obj, 'func'), 'has() works for functions too.'); + assert.ok(_.has(obj, 'foo'), 'has() checks that the object has a property.'); + assert.ok(!_.has(obj, 'baz'), "has() returns false if the object doesn't have the property."); + assert.ok(_.has(obj, 'func'), 'has() works for functions too.'); obj.hasOwnProperty = null; - ok(_.has(obj, 'foo'), 'has() works even when the hasOwnProperty method is deleted.'); + assert.ok(_.has(obj, 'foo'), 'has() works even when the hasOwnProperty method is deleted.'); var child = {}; child.prototype = obj; - ok(!_.has(child, 'foo'), 'has() does not check the prototype chain for a property.'); - strictEqual(_.has(null, 'foo'), false, 'has() returns false for null'); - strictEqual(_.has(void 0, 'foo'), false, 'has() returns false for undefined'); + assert.ok(!_.has(child, 'foo'), 'has() does not check the prototype chain for a property.'); + assert.strictEqual(_.has(null, 'foo'), false, 'has() returns false for null'); + assert.strictEqual(_.has(void 0, 'foo'), false, 'has() returns false for undefined'); }); - test('isMatch', function() { + test('isMatch', function(assert) { var moe = {name: 'Moe Howard', hair: true}; var curly = {name: 'Curly Howard', hair: false}; - equal(_.isMatch(moe, {hair: true}), true, 'Returns a boolean'); - equal(_.isMatch(curly, {hair: true}), false, 'Returns a boolean'); + assert.equal(_.isMatch(moe, {hair: true}), true, 'Returns a boolean'); + assert.equal(_.isMatch(curly, {hair: true}), false, 'Returns a boolean'); - equal(_.isMatch(5, {__x__: void 0}), false, 'can match undefined props on primitives'); - equal(_.isMatch({__x__: void 0}, {__x__: void 0}), true, 'can match undefined props'); + assert.equal(_.isMatch(5, {__x__: void 0}), false, 'can match undefined props on primitives'); + assert.equal(_.isMatch({__x__: void 0}, {__x__: void 0}), true, 'can match undefined props'); - equal(_.isMatch(null, {}), true, 'Empty spec called with null object returns true'); - equal(_.isMatch(null, {a: 1}), false, 'Non-empty spec called with null object returns false'); + assert.equal(_.isMatch(null, {}), true, 'Empty spec called with null object returns true'); + assert.equal(_.isMatch(null, {a: 1}), false, 'Non-empty spec called with null object returns false'); - _.each([null, void 0], function(item) { strictEqual(_.isMatch(item, null), true, 'null matches null'); }); - _.each([null, void 0], function(item) { strictEqual(_.isMatch(item, null), true, 'null matches {}'); }); - strictEqual(_.isMatch({b: 1}, {a: void 0}), false, 'handles undefined values (1683)'); + _.each([null, void 0], function(item) { assert.strictEqual(_.isMatch(item, null), true, 'null matches null'); }); + _.each([null, void 0], function(item) { assert.strictEqual(_.isMatch(item, null), true, 'null matches {}'); }); + assert.strictEqual(_.isMatch({b: 1}, {a: void 0}), false, 'handles undefined values (1683)'); _.each([true, 5, NaN, null, void 0], function(item) { - strictEqual(_.isMatch({a: 1}, item), true, 'treats primitives as empty'); + assert.strictEqual(_.isMatch({a: 1}, item), true, 'treats primitives as empty'); }); function Prototest() {} Prototest.prototype.x = 1; var specObj = new Prototest; - equal(_.isMatch({x: 2}, specObj), true, 'spec is restricted to own properties'); + assert.equal(_.isMatch({x: 2}, specObj), true, 'spec is restricted to own properties'); specObj.y = 5; - equal(_.isMatch({x: 1, y: 5}, specObj), true); - equal(_.isMatch({x: 1, y: 4}, specObj), false); + assert.equal(_.isMatch({x: 1, y: 5}, specObj), true); + assert.equal(_.isMatch({x: 1, y: 4}, specObj), false); - ok(_.isMatch(specObj, {x: 1, y: 5}), 'inherited and own properties are checked on the test object'); + assert.ok(_.isMatch(specObj, {x: 1, y: 5}), 'inherited and own properties are checked on the test object'); Prototest.x = 5; - ok(_.isMatch({x: 5, y: 1}, Prototest), 'spec can be a function'); + assert.ok(_.isMatch({x: 5, y: 1}, Prototest), 'spec can be a function'); //null edge cases var oCon = {constructor: Object}; - deepEqual(_.map([null, void 0, 5, {}], _.partial(_.isMatch, _, oCon)), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); + assert.deepEqual(_.map([null, void 0, 5, {}], _.partial(_.isMatch, _, oCon)), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); }); - test('matcher', function() { + test('matcher', function(assert) { var moe = {name: 'Moe Howard', hair: true}; var curly = {name: 'Curly Howard', hair: false}; var stooges = [moe, curly]; - equal(_.matcher({hair: true})(moe), true, 'Returns a boolean'); - equal(_.matcher({hair: true})(curly), false, 'Returns a boolean'); + assert.equal(_.matcher({hair: true})(moe), true, 'Returns a boolean'); + assert.equal(_.matcher({hair: true})(curly), false, 'Returns a boolean'); - equal(_.matcher({__x__: void 0})(5), false, 'can match undefined props on primitives'); - equal(_.matcher({__x__: void 0})({__x__: void 0}), true, 'can match undefined props'); + assert.equal(_.matcher({__x__: void 0})(5), false, 'can match undefined props on primitives'); + assert.equal(_.matcher({__x__: void 0})({__x__: void 0}), true, 'can match undefined props'); - equal(_.matcher({})(null), true, 'Empty spec called with null object returns true'); - equal(_.matcher({a: 1})(null), false, 'Non-empty spec called with null object returns false'); + assert.equal(_.matcher({})(null), true, 'Empty spec called with null object returns true'); + assert.equal(_.matcher({a: 1})(null), false, 'Non-empty spec called with null object returns false'); - ok(_.find(stooges, _.matcher({hair: false})) === curly, 'returns a predicate that can be used by finding functions.'); - ok(_.find(stooges, _.matcher(moe)) === moe, 'can be used to locate an object exists in a collection.'); - deepEqual(_.where([null, void 0], {a: 1}), [], 'Do not throw on null values.'); + assert.ok(_.find(stooges, _.matcher({hair: false})) === curly, 'returns a predicate that can be used by finding functions.'); + assert.ok(_.find(stooges, _.matcher(moe)) === moe, 'can be used to locate an object exists in a collection.'); + assert.deepEqual(_.where([null, void 0], {a: 1}), [], 'Do not throw on null values.'); - deepEqual(_.where([null, void 0], null), [null, void 0], 'null matches null'); - deepEqual(_.where([null, void 0], {}), [null, void 0], 'null matches {}'); - deepEqual(_.where([{b: 1}], {a: void 0}), [], 'handles undefined values (1683)'); + assert.deepEqual(_.where([null, void 0], null), [null, void 0], 'null matches null'); + assert.deepEqual(_.where([null, void 0], {}), [null, void 0], 'null matches {}'); + assert.deepEqual(_.where([{b: 1}], {a: void 0}), [], 'handles undefined values (1683)'); _.each([true, 5, NaN, null, void 0], function(item) { - deepEqual(_.where([{a: 1}], item), [{a: 1}], 'treats primitives as empty'); + assert.deepEqual(_.where([{a: 1}], item), [{a: 1}], 'treats primitives as empty'); }); function Prototest() {} Prototest.prototype.x = 1; var specObj = new Prototest; var protospec = _.matcher(specObj); - equal(protospec({x: 2}), true, 'spec is restricted to own properties'); + assert.equal(protospec({x: 2}), true, 'spec is restricted to own properties'); specObj.y = 5; protospec = _.matcher(specObj); - equal(protospec({x: 1, y: 5}), true); - equal(protospec({x: 1, y: 4}), false); + assert.equal(protospec({x: 1, y: 5}), true); + assert.equal(protospec({x: 1, y: 4}), false); - ok(_.matcher({x: 1, y: 5})(specObj), 'inherited and own properties are checked on the test object'); + assert.ok(_.matcher({x: 1, y: 5})(specObj), 'inherited and own properties are checked on the test object'); Prototest.x = 5; - ok(_.matcher(Prototest)({x: 5, y: 1}), 'spec can be a function'); + assert.ok(_.matcher(Prototest)({x: 5, y: 1}), 'spec can be a function'); // #1729 var o = {b: 1}; var m = _.matcher(o); - equal(m({b: 1}), true); + assert.equal(m({b: 1}), true); o.b = 2; o.a = 1; - equal(m({b: 1}), true, 'changing spec object doesnt change matches result'); + assert.equal(m({b: 1}), true, 'changing spec object doesnt change matches result'); //null edge cases var oCon = _.matcher({constructor: Object}); - deepEqual(_.map([null, void 0, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); + assert.deepEqual(_.map([null, void 0, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); }); - test('findKey', function() { + test('findKey', function(assert) { var objects = { a: {a: 0, b: 0}, b: {a: 1, b: 1}, c: {a: 2, b: 2} }; - equal(_.findKey(objects, function(obj) { + assert.equal(_.findKey(objects, function(obj) { return obj.a === 0; }), 'a'); - equal(_.findKey(objects, function(obj) { + assert.equal(_.findKey(objects, function(obj) { return obj.b * obj.a === 4; }), 'c'); - equal(_.findKey(objects, 'a'), 'b', 'Uses lookupIterator'); + assert.equal(_.findKey(objects, 'a'), 'b', 'Uses lookupIterator'); - equal(_.findKey(objects, function(obj) { + assert.equal(_.findKey(objects, function(obj) { return obj.b * obj.a === 5; }), void 0); - strictEqual(_.findKey([1, 2, 3, 4, 5, 6], function(obj) { + assert.strictEqual(_.findKey([1, 2, 3, 4, 5, 6], function(obj) { return obj === 3; }), '2', 'Keys are strings'); - strictEqual(_.findKey(objects, function(a) { + assert.strictEqual(_.findKey(objects, function(a) { return a.foo === null; }), void 0); _.findKey({a: {a: 1}}, function(a, key, obj) { - equal(key, 'a'); - deepEqual(obj, {a: {a: 1}}); - strictEqual(this, objects, 'called with context'); + assert.equal(key, 'a'); + assert.deepEqual(obj, {a: {a: 1}}); + assert.strictEqual(this, objects, 'called with context'); }, objects); var array = [1, 2, 3, 4]; array.match = 55; - strictEqual(_.findKey(array, function(x) { return x === 55; }), 'match', 'matches array-likes keys'); + assert.strictEqual(_.findKey(array, function(x) { return x === 55; }), 'match', 'matches array-likes keys'); }); - test('mapObject', function() { + test('mapObject', function(assert) { var obj = {a: 1, b: 2}; var objects = { a: {a: 0, b: 0}, @@ -928,49 +928,49 @@ c: {a: 2, b: 2} }; - deepEqual(_.mapObject(obj, function(val) { + assert.deepEqual(_.mapObject(obj, function(val) { return val * 2; }), {a: 2, b: 4}, 'simple objects'); - deepEqual(_.mapObject(objects, function(val) { + assert.deepEqual(_.mapObject(objects, function(val) { return _.reduce(val, function(memo, v){ return memo + v; }, 0); }), {a: 0, b: 2, c: 4}, 'nested objects'); - deepEqual(_.mapObject(obj, function(val, key, o) { + assert.deepEqual(_.mapObject(obj, function(val, key, o) { return o[key] * 2; }), {a: 2, b: 4}, 'correct keys'); - deepEqual(_.mapObject([1, 2], function(val) { + assert.deepEqual(_.mapObject([1, 2], function(val) { return val * 2; }), {0: 2, 1: 4}, 'check behavior for arrays'); - deepEqual(_.mapObject(obj, function(val) { + assert.deepEqual(_.mapObject(obj, function(val) { return val * this.multiplier; }, {multiplier: 3}), {a: 3, b: 6}, 'keep context'); - deepEqual(_.mapObject({a: 1}, function() { + assert.deepEqual(_.mapObject({a: 1}, function() { return this.length; }, [1, 2]), {a: 2}, 'called with context'); var ids = _.mapObject({length: 2, 0: {id: '1'}, 1: {id: '2'}}, function(n){ return n.id; }); - deepEqual(ids, {length: void 0, 0: '1', 1: '2'}, 'Check with array-like objects'); + assert.deepEqual(ids, {length: void 0, 0: '1', 1: '2'}, 'Check with array-like objects'); // Passing a property name like _.pluck. var people = {a: {name: 'moe', age: 30}, b: {name: 'curly', age: 50}}; - deepEqual(_.mapObject(people, 'name'), {a: 'moe', b: 'curly'}, 'predicate string map to object properties'); + assert.deepEqual(_.mapObject(people, 'name'), {a: 'moe', b: 'curly'}, 'predicate string map to object properties'); _.each([null, void 0, 1, 'abc', [], {}, void 0], function(val){ - deepEqual(_.mapObject(val, _.identity), {}, 'mapValue identity'); + assert.deepEqual(_.mapObject(val, _.identity), {}, 'mapValue identity'); }); var Proto = function(){ this.a = 1; }; Proto.prototype.b = 1; var protoObj = new Proto(); - deepEqual(_.mapObject(protoObj, _.identity), {a: 1}, 'ignore inherited values from prototypes'); + assert.deepEqual(_.mapObject(protoObj, _.identity), {a: 1}, 'ignore inherited values from prototypes'); }); }()); diff --git a/test/utility.js b/test/utility.js index 61c0347a4..bb58ae8a3 100644 --- a/test/utility.js +++ b/test/utility.js @@ -15,18 +15,18 @@ }); if (typeof this == 'object') { - test('noConflict', function() { + test('noConflict', function(assert) { var underscore = _.noConflict(); - equal(underscore.identity(1), 1); + assert.equal(underscore.identity(1), 1); if (typeof require != 'function') { - equal(this._, void 0, 'global underscore is removed'); + assert.equal(this._, void 0, 'global underscore is removed'); this._ = underscore; } }); } if (typeof require == 'function') { - asyncTest('noConflict (node vm)', 2, function() { + asyncTest('noConflict (node vm)', 2, function(assert) { var fs = require('fs'); var vm = require('vm'); var filename = __dirname + '/../underscore.js'; @@ -37,179 +37,179 @@ ); var context = {_: 'oldvalue'}; sandbox.runInNewContext(context); - equal(context._, 'oldvalue'); - equal(context.underscore.VERSION, _.VERSION); + assert.equal(context._, 'oldvalue'); + assert.equal(context.underscore.VERSION, _.VERSION); start(); }); }); } - test('#750 - Return _ instance.', 2, function() { + test('#750 - Return _ instance.', 2, function(assert) { var instance = _([]); - ok(_(instance) === instance); - ok(new _(instance) === instance); + assert.ok(_(instance) === instance); + assert.ok(new _(instance) === instance); }); - test('identity', function() { + test('identity', function(assert) { var stooge = {name: 'moe'}; - equal(_.identity(stooge), stooge, 'stooge is the same as his identity'); + assert.equal(_.identity(stooge), stooge, 'stooge is the same as his identity'); }); - test('constant', function() { + test('constant', function(assert) { var stooge = {name: 'moe'}; - equal(_.constant(stooge)(), stooge, 'should create a function that returns stooge'); + assert.equal(_.constant(stooge)(), stooge, 'should create a function that returns stooge'); }); - test('noop', function() { - strictEqual(_.noop('curly', 'larry', 'moe'), void 0, 'should always return undefined'); + test('noop', function(assert) { + assert.strictEqual(_.noop('curly', 'larry', 'moe'), void 0, 'should always return undefined'); }); - test('property', function() { + test('property', function(assert) { var stooge = {name: 'moe'}; - equal(_.property('name')(stooge), 'moe', 'should return the property with the given name'); - equal(_.property('name')(null), void 0, 'should return undefined for null values'); - equal(_.property('name')(void 0), void 0, 'should return undefined for undefined values'); + assert.equal(_.property('name')(stooge), 'moe', 'should return the property with the given name'); + assert.equal(_.property('name')(null), void 0, 'should return undefined for null values'); + assert.equal(_.property('name')(void 0), void 0, 'should return undefined for undefined values'); }); - test('propertyOf', function() { + test('propertyOf', function(assert) { var stoogeRanks = _.propertyOf({curly: 2, moe: 1, larry: 3}); - equal(stoogeRanks('curly'), 2, 'should return the property with the given name'); - equal(stoogeRanks(null), void 0, 'should return undefined for null values'); - equal(stoogeRanks(void 0), void 0, 'should return undefined for undefined values'); + assert.equal(stoogeRanks('curly'), 2, 'should return the property with the given name'); + assert.equal(stoogeRanks(null), void 0, 'should return undefined for null values'); + assert.equal(stoogeRanks(void 0), void 0, 'should return undefined for undefined values'); function MoreStooges() { this.shemp = 87; } MoreStooges.prototype = {curly: 2, moe: 1, larry: 3}; var moreStoogeRanks = _.propertyOf(new MoreStooges()); - equal(moreStoogeRanks('curly'), 2, 'should return properties from further up the prototype chain'); + assert.equal(moreStoogeRanks('curly'), 2, 'should return properties from further up the prototype chain'); var nullPropertyOf = _.propertyOf(null); - equal(nullPropertyOf('curly'), void 0, 'should return undefined when obj is null'); + assert.equal(nullPropertyOf('curly'), void 0, 'should return undefined when obj is null'); var undefPropertyOf = _.propertyOf(void 0); - equal(undefPropertyOf('curly'), void 0, 'should return undefined when obj is undefined'); + assert.equal(undefPropertyOf('curly'), void 0, 'should return undefined when obj is undefined'); }); - test('random', function() { + test('random', function(assert) { var array = _.range(1000); var min = Math.pow(2, 31); var max = Math.pow(2, 62); - ok(_.every(array, function() { + assert.ok(_.every(array, function() { return _.random(min, max) >= min; }), 'should produce a random number greater than or equal to the minimum number'); - ok(_.some(array, function() { + assert.ok(_.some(array, function() { return _.random(Number.MAX_VALUE) > 0; }), 'should produce a random number when passed `Number.MAX_VALUE`'); }); - test('now', function() { + test('now', function(assert) { var diff = _.now() - new Date().getTime(); - ok(diff <= 0 && diff > -5, 'Produces the correct time in milliseconds');//within 5ms + assert.ok(diff <= 0 && diff > -5, 'Produces the correct time in milliseconds');//within 5ms }); - test('uniqueId', function() { + test('uniqueId', function(assert) { var ids = [], i = 0; while (i++ < 100) ids.push(_.uniqueId()); - equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids'); + assert.equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids'); }); - test('times', function() { + test('times', function(assert) { var vals = []; _.times(3, function(i) { vals.push(i); }); - deepEqual(vals, [0, 1, 2], 'is 0 indexed'); + assert.deepEqual(vals, [0, 1, 2], 'is 0 indexed'); // vals = []; _(3).times(function(i) { vals.push(i); }); - deepEqual(vals, [0, 1, 2], 'works as a wrapper'); + assert.deepEqual(vals, [0, 1, 2], 'works as a wrapper'); // collects return values - deepEqual([0, 1, 2], _.times(3, function(i) { return i; }), 'collects return values'); + assert.deepEqual([0, 1, 2], _.times(3, function(i) { return i; }), 'collects return values'); - deepEqual(_.times(0, _.identity), []); - deepEqual(_.times(-1, _.identity), []); - deepEqual(_.times(parseFloat('-Infinity'), _.identity), []); + assert.deepEqual(_.times(0, _.identity), []); + assert.deepEqual(_.times(-1, _.identity), []); + assert.deepEqual(_.times(parseFloat('-Infinity'), _.identity), []); }); - test('mixin', function() { + test('mixin', function(assert) { _.mixin({ myReverse: function(string) { return string.split('').reverse().join(''); } }); - equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _'); - equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper'); + assert.equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _'); + assert.equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper'); }); - test('_.escape', function() { - equal(_.escape(null), ''); + test('_.escape', function(assert) { + assert.equal(_.escape(null), ''); }); - test('_.unescape', function() { + test('_.unescape', function(assert) { var string = 'Curly & Moe'; - equal(_.unescape(null), ''); - equal(_.unescape(_.escape(string)), string); - equal(_.unescape(string), string, 'don\'t unescape unnecessarily'); + assert.equal(_.unescape(null), ''); + assert.equal(_.unescape(_.escape(string)), string); + assert.equal(_.unescape(string), string, 'don\'t unescape unnecessarily'); }); // Don't care what they escape them to just that they're escaped and can be unescaped - test('_.escape & unescape', function() { + test('_.escape & unescape', function(assert) { // test & (&) seperately obviously var escapeCharacters = ['<', '>', '"', '\'', '`']; _.each(escapeCharacters, function(escapeChar) { var s = 'a ' + escapeChar + ' string escaped'; var e = _.escape(s); - notEqual(s, e, escapeChar + ' is escaped'); - equal(s, _.unescape(e), escapeChar + ' can be unescaped'); + assert.notEqual(s, e, escapeChar + ' is escaped'); + assert.equal(s, _.unescape(e), escapeChar + ' can be unescaped'); s = 'a ' + escapeChar + escapeChar + escapeChar + 'some more string' + escapeChar; e = _.escape(s); - equal(e.indexOf(escapeChar), -1, 'can escape multiple occurances of ' + escapeChar); - equal(_.unescape(e), s, 'multiple occurrences of ' + escapeChar + ' can be unescaped'); + assert.equal(e.indexOf(escapeChar), -1, 'can escape multiple occurances of ' + escapeChar); + assert.equal(_.unescape(e), s, 'multiple occurrences of ' + escapeChar + ' can be unescaped'); }); // handles multiple escape characters at once var joiner = ' other stuff '; var allEscaped = escapeCharacters.join(joiner); allEscaped += allEscaped; - ok(_.every(escapeCharacters, function(escapeChar) { + assert.ok(_.every(escapeCharacters, function(escapeChar) { return allEscaped.indexOf(escapeChar) !== -1; }), 'handles multiple characters'); - ok(allEscaped.indexOf(joiner) >= 0, 'can escape multiple escape characters at the same time'); + assert.ok(allEscaped.indexOf(joiner) >= 0, 'can escape multiple escape characters at the same time'); // test & -> & var str = 'some string & another string & yet another'; var escaped = _.escape(str); - ok(escaped.indexOf('&') !== -1, 'handles & aka &'); - equal(_.unescape(str), str, 'can unescape &'); + assert.ok(escaped.indexOf('&') !== -1, 'handles & aka &'); + assert.equal(_.unescape(str), str, 'can unescape &'); }); - test('template', function() { + test('template', function(assert) { var basicTemplate = _.template("<%= thing %> is gettin' on my noives!"); var result = basicTemplate({thing: 'This'}); - equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation'); + assert.equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation'); var sansSemicolonTemplate = _.template('A <% this %> B'); - equal(sansSemicolonTemplate(), 'A B'); + assert.equal(sansSemicolonTemplate(), 'A B'); var backslashTemplate = _.template('<%= thing %> is \\ridanculous'); - equal(backslashTemplate({thing: 'This'}), 'This is \\ridanculous'); + assert.equal(backslashTemplate({thing: 'This'}), 'This is \\ridanculous'); var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>'); - equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.'); + assert.equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.'); var fancyTemplate = _.template(' <% ' + ' for (var key in people) { ' + '%>
'); result = fancyTemplate({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}}); - equal(result, '- <%= people[key] %>
<% } %>', 'can run arbitrary javascript in templates'); + assert.equal(result, '
- Moe
- Larry
- Curly
', 'can run arbitrary javascript in templates'); var escapedCharsInJavascriptTemplate = _.template('
- Moe
- Larry
- Curly
<% _.each(numbers.split("\\n"), function(item) { %>
'); result = escapedCharsInJavascriptTemplate({numbers: 'one\ntwo\nthree\nfour'}); - equal(result, '- <%= item %>
<% }) %>', 'Can use escaped characters (e.g. \\n) in JavaScript'); + assert.equal(result, '
- one
- two
- three
- four
', 'Can use escaped characters (e.g. \\n) in JavaScript'); var namespaceCollisionTemplate = _.template('<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %><% }); %>'); result = namespaceCollisionTemplate({ @@ -220,32 +220,32 @@ 3: 'p3-thumbnail.gif' } }); - equal(result, '3 p3-thumbnail.gif '); + assert.equal(result, '3 p3-thumbnail.gif '); var noInterpolateTemplate = _.template('
- one
- two
- three
- four
'); result = noInterpolateTemplate(); - equal(result, 'Just some text. Hey, I know this is silly but it aids consistency.
'); + assert.equal(result, 'Just some text. Hey, I know this is silly but it aids consistency.
'); var quoteTemplate = _.template("It's its, not it's"); - equal(quoteTemplate({}), "It's its, not it's"); + assert.equal(quoteTemplate({}), "It's its, not it's"); var quoteInStatementAndBody = _.template('<% ' + " if(foo == 'bar'){ " + "%>Statement quotes and 'quotes'.<% } %>"); - equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'."); + assert.equal(quoteInStatementAndBody({foo: 'bar'}), "Statement quotes and 'quotes'."); var withNewlinesAndTabs = _.template('This\n\t\tis: <%= x %>.\n\tok.\nend.'); - equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.'); + assert.equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.'); var template = _.template('<%- value %>'); result = template({value: ' + diff --git a/underscore.js b/underscore.js index ba5f828d8..7b78f2adb 100644 --- a/underscore.js +++ b/underscore.js @@ -48,8 +48,10 @@ // Export the Underscore object for **Node.js**, with // backwards-compatibility for their old module API. If we're in // the browser, add `_` as a global object. - if (typeof exports != 'undefined') { - if (typeof module != 'undefined' && module.exports) { + // (`nodeType` is checked to ensure that `module` + // and `exports` are not HTML elements.) + if (typeof exports != 'undefined' && !exports.nodeType) { + if (typeof module != 'undefined' && !module.nodeType && module.exports) { exports = module.exports = _; } exports._ = _; From 66d28bfb43a666cb508846676d367394c06b03e1 Mon Sep 17 00:00:00 2001 From: Graeme YeatesJust some text. Hey, I know this is silly but it aids consistency.
Date: Thu, 22 Oct 2015 09:56:42 -0400 Subject: [PATCH 079/263] Use karma concurrency for initiating parallel sauce tests Conform matrix to backbone's --- .travis.yml | 7 +------ karma.conf-sauce.js | 26 ++++++++++++++++---------- package.json | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index c4d7577f5..d5c846134 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,12 +18,7 @@ before_script: script: - npm test - "[ $BROWSER == false ] || npm run test-browser" - # Karma sauce is limited to running about 5-7 browsers (or it will tiemout) at a time so we just run vendor by vendor here - - "[ $BROWSER == false ] || karma start karma.conf-sauce.js --browsers FIREFOX_V4,FIREFOX_V11,FIREFOX_V20,FIREFOX_V30,FIREFOX_V35" - - "[ $BROWSER == false ] || karma start karma.conf-sauce.js --browsers CHROME_V28,CHROME_V35,CHROME_V40,ANDROID_V4.0,ANDROID_V4.3" - - "[ $BROWSER == false ] || karma start karma.conf-sauce.js --browsers INTERNET_EXPLORER_V9,INTERNET_EXPLORER_V10,INTERNET_EXPLORER_V11,MICROSOFTEDGE_V20.10240" - - "[ $BROWSER == false ] || karma start karma.conf-sauce.js --browsers SAFARI_V5,SAFARI_V6,SAFARI_V7" - - "[ $BROWSER == false ] || karma start karma.conf-sauce.js --browsers OPERA_V11,OPERA_V12" + - "[ $BROWSER == false ] || karma start karma.conf-sauce.js" notifications: email: false env: diff --git a/karma.conf-sauce.js b/karma.conf-sauce.js index 1938fdd7e..3a3c460c6 100644 --- a/karma.conf-sauce.js +++ b/karma.conf-sauce.js @@ -4,32 +4,34 @@ var _ = require('./'); var sauceBrowsers = _.reduce([ ['firefox', '35'], ['firefox', '30'], - ['firefox', '20'], + ['firefox', '21'], ['firefox', '11'], ['firefox', '4'], ['chrome', '40'], - ['chrome', '35'], - ['chrome', '28'], + ['chrome', '39'], + ['chrome', '31'], + ['chrome', '26'], - ['microsoftedge', '20.10240', 'Windows 10'], + ['microsoftedge', '20', 'Windows 10'], ['internet explorer', '11', 'Windows 10'], ['internet explorer', '10', 'Windows 8'], ['internet explorer', '9', 'Windows 7'], - // Currently do not work with Karma. - // ['internet explorer', '8', 'Windows 7'], - // ['internet explorer', '7', 'Windows XP'], + ['internet explorer', '8'], + ['internet explorer', '7', 'Windows XP'], // ['internet explorer', '6', 'Windows XP'], ['opera', '12'], ['opera', '11'], - ['android', '4.3'], + ['android', '5'], + ['android', '4.4'], + ['android', '4.3'], ['android', '4.0'], - ['safari', '8'], - ['safari', '6'], + ['safari', '8.0', 'OS X 10.10'], ['safari', '7'], + ['safari', '6'], ['safari', '5'] ], function(memo, platform) { var label = (platform[0] + '_v' + platform[1]).replace(' ', '_').toUpperCase(); @@ -59,6 +61,10 @@ module.exports = function(config) { 'underscore.js', 'test/*.js' ], + + // Number of sauce tests to start in parallel + concurrency: 2, + // test results reporter to use reporters: ['dots', 'saucelabs'], port: 9876, diff --git a/package.json b/package.json index 2cb4cc47c..26e00c2aa 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "coveralls": "^2.11.2", "docco": "*", "eslint": "0.21.x", - "karma": "~0.12.31", + "karma": "^0.13.13", "karma-qunit": "~0.1.4", "nyc": "^2.1.3", "qunit-cli": "~0.2.0", From 77149bc2d7e248598f142d86307bf25e2e49789a Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Mon, 26 Oct 2015 12:00:57 -0400 Subject: [PATCH 080/263] Fix karma sauce init for default browser case --- karma.conf-sauce.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/karma.conf-sauce.js b/karma.conf-sauce.js index 3a3c460c6..24fe7bd4b 100644 --- a/karma.conf-sauce.js +++ b/karma.conf-sauce.js @@ -13,20 +13,21 @@ var sauceBrowsers = _.reduce([ ['chrome', '31'], ['chrome', '26'], - ['microsoftedge', '20', 'Windows 10'], + ['microsoftedge', '20.10240', 'Windows 10'], ['internet explorer', '11', 'Windows 10'], ['internet explorer', '10', 'Windows 8'], ['internet explorer', '9', 'Windows 7'], ['internet explorer', '8'], - ['internet explorer', '7', 'Windows XP'], - // ['internet explorer', '6', 'Windows XP'], + // Currently karma-sauce has issues with sockets and these browsers + // ['internet explorer', '7'], + // ['internet explorer', '6'], ['opera', '12'], ['opera', '11'], ['android', '5'], ['android', '4.4'], - ['android', '4.3'], + ['android', '4.3'], ['android', '4.0'], ['safari', '8.0', 'OS X 10.10'], @@ -34,7 +35,12 @@ var sauceBrowsers = _.reduce([ ['safari', '6'], ['safari', '5'] ], function(memo, platform) { - var label = (platform[0] + '_v' + platform[1]).replace(' ', '_').toUpperCase(); + // internet explorer -> ie + var label = platform[0].split(' '); + if (label.length > 1) { + label = _.invoke(label, 'charAt', 0) + } + label = (label.join("") + '_v' + platform[1]).replace(' ', '_').toUpperCase(); memo[label] = _.pick({ 'base': 'SauceLabs', 'browserName': platform[0], @@ -63,7 +69,7 @@ module.exports = function(config) { ], // Number of sauce tests to start in parallel - concurrency: 2, + concurrency: 9, // test results reporter to use reporters: ['dots', 'saucelabs'], @@ -76,14 +82,11 @@ module.exports = function(config) { tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER }, - // TODO(vojta): remove once SauceLabs supports websockets. - // This speeds up the capturing a bit, as browsers don't even try to use websocket. - transports: ['xhr-polling'], captureTimeout: 120000, - customLaunchers: sauceBrowsers + customLaunchers: sauceBrowsers, // Browsers to launch, commented out to prevent karma from starting // too many concurrent browsers and timing sauce out. - // browsers: _.keys(sauceBrowsers) + browsers: _.keys(sauceBrowsers) }); }; From cd54225d3cc41389dd1ae562e3ddc78962e5f2cb Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Mon, 26 Oct 2015 12:12:56 -0400 Subject: [PATCH 081/263] Temp disable some old ie due to external disconnect issues --- karma.conf-sauce.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/karma.conf-sauce.js b/karma.conf-sauce.js index 24fe7bd4b..1b2f622ed 100644 --- a/karma.conf-sauce.js +++ b/karma.conf-sauce.js @@ -17,8 +17,8 @@ var sauceBrowsers = _.reduce([ ['internet explorer', '11', 'Windows 10'], ['internet explorer', '10', 'Windows 8'], ['internet explorer', '9', 'Windows 7'], - ['internet explorer', '8'], - // Currently karma-sauce has issues with sockets and these browsers + // Currently disabled due to karma-sauce issues + // ['internet explorer', '8'], // ['internet explorer', '7'], // ['internet explorer', '6'], From 1b5b1eeb9ab4a0507bb764087aeaf5701df14487 Mon Sep 17 00:00:00 2001 From: Graeme Yeates Date: Mon, 26 Oct 2015 12:21:41 -0400 Subject: [PATCH 082/263] Add node v4.0 to the test matrix --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d5c846134..cb9a86882 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,12 @@ language: node_js sudo: false node_js: - "0.8" + - "0.10" - "0.12" - "io.js" matrix: include: - - node_js: "0.10" + - node_js: "4.0" env: BROWSER=true before_install: - npm install -g npm@2.6 From 3521ab29ec9c66b1962abede2d9b4d68634bfd40 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Mon, 26 Oct 2015 14:41:37 -0700 Subject: [PATCH 083/263] Drop io.js from travis.yml. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cb9a86882..172af86c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ node_js: - "0.8" - "0.10" - "0.12" - - "io.js" matrix: include: - node_js: "4.0" From 37d00493a4cadb5b35dbe17e3fce5347f41040d3 Mon Sep 17 00:00:00 2001 From: Ricardo Bin Date: Thu, 29 Oct 2015 22:28:26 -0200 Subject: [PATCH 084/263] Adding preserve -0 test to _.range --- test/arrays.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/arrays.js b/test/arrays.js index 0de58e07e..550f0bc4e 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -537,6 +537,7 @@ assert.deepEqual(_.range(3, 10, 15), [3], 'range with three arguments a & b & c, c > b-a, a < b generates an array with a single element, equal to a'); assert.deepEqual(_.range(12, 7, -2), [12, 10, 8], 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b'); assert.deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs'); + assert.strictEqual(1 / _.range(-0, 1)[0], -Infinity, 'should preserve -0'); }); test('chunk', function(assert) { From 2fa0ac6e25d900100a4e14f32f4551e34daef61b Mon Sep 17 00:00:00 2001 From: guiled Date: Wed, 26 Mar 2014 23:17:02 +0100 Subject: [PATCH 085/263] New feature : reset the debounce It seems a little crappy to add a function into a function, but it provides a feature that was asked in #952 without breaking backward compatibility. --- underscore.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 7b78f2adb..0480b08df 100644 --- a/underscore.js +++ b/underscore.js @@ -857,7 +857,7 @@ } }; - return function() { + var func = function() { context = this; args = arguments; timestamp = _.now(); @@ -870,6 +870,12 @@ return result; }; + func.reset = function () { + clearTimeout(timeout); + timeout = null; + }; + + return func; }; // Returns the first function passed as an argument to the second, From c7bb6359a4fd57113b5a6f4ac9e89012c179e87a Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 5 Nov 2015 11:02:03 -0500 Subject: [PATCH 086/263] Clear debounced function Supersedes https://github.com/jashkenas/underscore/pull/1542. --- test/functions.js | 26 ++++++++++++++++++++++++++ underscore.js | 11 ++++++----- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/test/functions.js b/test/functions.js index 926681c9d..18ab66e26 100644 --- a/test/functions.js +++ b/test/functions.js @@ -404,6 +404,15 @@ _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 96); }); + asyncTest('debounce cleared', 1, function(assert) { + var counter = 0; + var incr = function(){ counter++; }; + var debouncedIncr = _.debounce(incr, 32); + debouncedIncr(); + debouncedIncr.clear(); + _.delay(function(){ assert.equal(counter, 0, 'incr was not called'); start(); }, 96); + }); + asyncTest('debounce asap', 4, function(assert) { var a, b; var counter = 0; @@ -420,6 +429,23 @@ _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 128); }); + asyncTest('debounce asap cleared', 4, function(assert) { + var a, b; + var counter = 0; + var incr = function(){ return ++counter; }; + var debouncedIncr = _.debounce(incr, 64, true); + a = debouncedIncr(); + debouncedIncr.clear(); + b = debouncedIncr(); + assert.equal(a, 1); + assert.equal(b, 2); + assert.equal(counter, 2, 'incr was called immediately'); + _.delay(debouncedIncr, 16); + _.delay(debouncedIncr, 32); + _.delay(debouncedIncr, 48); + _.delay(function(){ assert.equal(counter, 2, 'incr was debounced'); start(); }, 128); + }); + asyncTest('debounce asap recursively', 2, function(assert) { var counter = 0; var debouncedIncr = _.debounce(function(){ diff --git a/underscore.js b/underscore.js index 0480b08df..ead4987ae 100644 --- a/underscore.js +++ b/underscore.js @@ -857,7 +857,7 @@ } }; - var func = function() { + var debounced = function() { context = this; args = arguments; timestamp = _.now(); @@ -870,12 +870,13 @@ return result; }; - func.reset = function () { + + debounced.clear = function() { clearTimeout(timeout); - timeout = null; + timeout = context = args = null; }; - - return func; + + return debounced; }; // Returns the first function passed as an argument to the second, From 8a70f347e32650f9ca114b99ee09c61e711ecc08 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 5 Nov 2015 14:50:20 -0500 Subject: [PATCH 087/263] Clear the throttle --- test/functions.js | 24 ++++++++++++++++++++++++ underscore.js | 15 ++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/test/functions.js b/test/functions.js index 18ab66e26..0e02b3531 100644 --- a/test/functions.js +++ b/test/functions.js @@ -395,6 +395,30 @@ }, 100); }); + asyncTest('throttle cleared', function(assert) { + var counter = 0; + var incr = function(){ counter++; }; + var throttledIncr = _.throttle(incr, 32); + throttledIncr(); + throttledIncr.clear(); + throttledIncr(); + throttledIncr(); + + assert.equal(counter, 2, 'incr was called immediately'); + _.delay(function(){ assert.equal(counter, 3, 'incr was throttled'); start(); }, 64); + }); + + asyncTest('throttle cleared with leading: false', function(assert) { + var counter = 0; + var incr = function(){ counter++; }; + var throttledIncr = _.throttle(incr, 32, {leading: false}); + throttledIncr(); + throttledIncr.clear(); + + assert.equal(counter, 0, 'incr was throttled'); + _.delay(function(){ assert.equal(counter, 0, 'incr was throttled'); start(); }, 64); + }); + asyncTest('debounce', 1, function(assert) { var counter = 0; var incr = function(){ counter++; }; diff --git a/underscore.js b/underscore.js index ead4987ae..6a8f254c8 100644 --- a/underscore.js +++ b/underscore.js @@ -805,17 +805,18 @@ // but if you'd like to disable the execution on the leading edge, pass // `{leading: false}`. To disable execution on the trailing edge, ditto. _.throttle = function(func, wait, options) { - var context, args, result; - var timeout = null; + var timeout, context, args, result; var previous = 0; if (!options) options = {}; + var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; - return function() { + + var throttled = function() { var now = _.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); @@ -834,6 +835,14 @@ } return result; }; + + throttled.clear = function() { + clearTimeout(timeout); + previous = 0; + timeout = context = args = null; + }; + + return throttled; }; // Returns a function, that, as long as it continues to be invoked, will not From f812ba7b00e97a332d5d7374f8a6afaf2576ca50 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 5 Nov 2015 14:56:28 -0500 Subject: [PATCH 088/263] Cleanup the debounce function --- underscore.js | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/underscore.js b/underscore.js index ead4987ae..4d0aa1b5d 100644 --- a/underscore.js +++ b/underscore.js @@ -790,7 +790,7 @@ // Delays a function for the given number of milliseconds, and then calls // it with the arguments supplied. _.delay = restArgs(function(func, wait, args) { - return setTimeout(function(){ + return setTimeout(function() { return func.apply(null, args); }, wait); }); @@ -841,35 +841,25 @@ // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. _.debounce = function(func, wait, immediate) { - var timeout, args, context, timestamp, result; + var timeout, result; - var later = function() { - var last = _.now() - timestamp; - - if (last < wait && last >= 0) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) { - result = func.apply(context, args); - if (!timeout) context = args = null; - } - } + var later = function(context, args) { + timeout = null; + if (args) result = func.apply(context, args); }; - var debounced = function() { - context = this; - args = arguments; - timestamp = _.now(); + var debounced = restArgs(function(args) { var callNow = immediate && !timeout; - if (!timeout) timeout = setTimeout(later, wait); + if (timeout) clearTimeout(timeout); if (callNow) { - result = func.apply(context, args); - context = args = null; + timeout = setTimeout(later, wait); + result = func.apply(this, args); + } else if (!immediate) { + timeout = _.delay(later, wait, this, args); } return result; - }; + }); debounced.clear = function() { clearTimeout(timeout); From e7221cb4d03667b83a6a99a4d37ae465169550ed Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 5 Nov 2015 17:25:58 -0500 Subject: [PATCH 089/263] Fix debounce clear error Just spotted this, re: #2340. --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 262765672..77c8ecd12 100644 --- a/underscore.js +++ b/underscore.js @@ -872,7 +872,7 @@ debounced.clear = function() { clearTimeout(timeout); - timeout = context = args = null; + timeout = null; }; return debounced; From fb700690bdd72cd19182c85978ed69e28a10350d Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Tue, 10 Nov 2015 17:54:04 -0800 Subject: [PATCH 090/263] enable eslint no-undef rule; ref #2341 --- .eslintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc b/.eslintrc index 0e88b37eb..216f4a0c3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -66,6 +66,7 @@ "no-spaced-func": 2, "no-throw-literal": 2, "no-trailing-spaces": 2, + "no-undef": 2, "no-undef-init": 2, "no-undefined": 2, "no-unneeded-ternary": 2, From e2e1d65147d5007c0c6288591bc8ed145e1958fa Mon Sep 17 00:00:00 2001 From: Adam Krebs Date: Thu, 12 Nov 2015 14:07:14 -0500 Subject: [PATCH 091/263] enable QUnit.config.noglobals in tests --- karma.conf-sauce.js | 1 + karma.conf.js | 1 + test/index.html | 2 +- test/qunit-setup.js | 3 +++ test/utility.js | 2 ++ 5 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 test/qunit-setup.js diff --git a/karma.conf-sauce.js b/karma.conf-sauce.js index 1b2f622ed..7cf946ecd 100644 --- a/karma.conf-sauce.js +++ b/karma.conf-sauce.js @@ -64,6 +64,7 @@ module.exports = function(config) { // list of files / patterns to load in the browser files: [ 'test/vendor/qunit-extras.js', + 'test/qunit-setup.js', 'underscore.js', 'test/*.js' ], diff --git a/karma.conf.js b/karma.conf.js index fb0fa376b..d01f24ee0 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -15,6 +15,7 @@ module.exports = function(config) { // list of files / patterns to load in the browser files: [ 'test/vendor/qunit-extras.js', + 'test/qunit-setup.js', 'underscore.js', 'test/*.js' ], diff --git a/test/index.html b/test/index.html index 4b4e03072..ab523afe4 100644 --- a/test/index.html +++ b/test/index.html @@ -11,7 +11,7 @@ - + diff --git a/test/qunit-setup.js b/test/qunit-setup.js new file mode 100644 index 000000000..ad1e8cd8c --- /dev/null +++ b/test/qunit-setup.js @@ -0,0 +1,3 @@ +(function() { + QUnit.config.noglobals = true; +}()); diff --git a/test/utility.js b/test/utility.js index bb58ae8a3..09cd54d62 100644 --- a/test/utility.js +++ b/test/utility.js @@ -21,6 +21,8 @@ if (typeof require != 'function') { assert.equal(this._, void 0, 'global underscore is removed'); this._ = underscore; + } else if (typeof global !== 'undefined') { + delete global._; } }); } From 749861bcf7c8b190d69b9cfbdba82c0609a48af8 Mon Sep 17 00:00:00 2001 From: Chris Martin Date: Mon, 16 Nov 2015 20:22:59 -0800 Subject: [PATCH 092/263] debounce doc: which invocation's args are used --- index.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/index.html b/index.html index e1fc14051..8094957db 100644 --- a/index.html +++ b/index.html @@ -1233,6 +1233,12 @@ Function (uh, ahem) Functions
has stopped being resized, and so on.+ At the end of the wait interval, the function will be called + with the arguments that were passed most recently to the + debounced function. +
+Pass true for the immediate argument to cause debounce to trigger the function on the leading instead of the From a7f8ae120bc35e45e950a3745800d76db0d736c1 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge
Date: Tue, 17 Nov 2015 20:57:48 -0800 Subject: [PATCH 093/263] Remove redundant empty string handing in _.toArray() As part of the review for pull request #2298, @jdalton requested that we add this check to handle the empty string case. However, I'm guessing he didn't realize that the first line of the function, `if (!obj) return [];`, already handles that case. As part of that pull request, @JonAbrams wisely added a test for the empty string case, so as long as tests are passing this change should be safe. See: https://github.com/jashkenas/underscore/pull/2298#discussion_r39480698 --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 77c8ecd12..682cdf647 100644 --- a/underscore.js +++ b/underscore.js @@ -441,7 +441,7 @@ if (_.isArray(obj)) return slice.call(obj); if (_.isString(obj)) { // Keep surrogate pair characters together - return obj ? obj.match(reStrSymbol) : []; + return obj.match(reStrSymbol); } if (isArrayLike(obj)) return _.map(obj, _.identity); return _.values(obj); From a6fcdd3a50358c2d7824521a85515526da5ecdb7 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Mon, 23 Nov 2015 19:08:26 -0800 Subject: [PATCH 094/263] Clean up assertion descriptions for _.flatten() --- test/arrays.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 550f0bc4e..8dc134cd9 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -80,11 +80,11 @@ }); test('flatten', function(assert) { - assert.deepEqual(_.flatten(null), [], 'Flattens supports null'); - assert.deepEqual(_.flatten(void 0), [], 'Flattens supports undefined'); + assert.deepEqual(_.flatten(null), [], 'supports null'); + assert.deepEqual(_.flatten(void 0), [], 'supports undefined'); - assert.deepEqual(_.flatten([[], [[]], []]), [], 'Flattens empty arrays'); - assert.deepEqual(_.flatten([[], [[]], []], true), [[]], 'Flattens empty arrays'); + assert.deepEqual(_.flatten([[], [[]], []]), [], 'supports empty arrays'); + assert.deepEqual(_.flatten([[], [[]], []], true), [[]], 'can shallowly flatten empty arrays'); var list = [1, [2], [3, [[[4]]]]]; assert.deepEqual(_.flatten(list), [1, 2, 3, 4], 'can flatten nested arrays'); @@ -94,15 +94,15 @@ list = [[1], [2], [3], [[4]]]; assert.deepEqual(_.flatten(list, true), [1, 2, 3, [4]], 'can shallowly flatten arrays containing only other arrays'); - assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3], true).length, 23); - assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23); - assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'Flatten can handle massive collections'); - assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'Flatten can handle massive collections'); + assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3], true).length, 23, 'can flatten medium length arrays'); + assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23, 'can shallowly flatten medium length arrays'); + assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'can handle massive arrays'); + assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'can handle massive arrays in shallow mode'); var x = _.range(100000); for (var i = 0; i < 1000; i++) x = [x]; - assert.deepEqual(_.flatten(x), _.range(100000), 'Flatten can handle very deep arrays'); - assert.deepEqual(_.flatten(x, true), x[0], 'Flatten can handle very deep arrays with shallow'); + assert.deepEqual(_.flatten(x), _.range(100000), 'can handle very deep arrays'); + assert.deepEqual(_.flatten(x, true), x[0], 'can handle very deep arrays in shallow mode'); }); test('without', function(assert) { From db30872e27aae757cf3110e096915ec28b150dbe Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 24 Nov 2015 09:00:26 -0800 Subject: [PATCH 095/263] Remove redundant _.first() test This test was originally added in pull request #500 as a way to affirm that the `_.take()` alias was working. In pull request #1663 we moved to testing aliases explicitly, but left this test an additional `_.first()` test. It is redundant because it is functionally identical to the test on line 10. --- test/arrays.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 8dc134cd9..44fd1553c 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -13,8 +13,6 @@ assert.equal(result, 4, 'works on an arguments object.'); result = _.map([[1, 2, 3], [1, 2, 3]], _.first); assert.deepEqual(result, [1, 1], 'works well with _.map'); - result = (function() { return _.first([1, 2, 3], 2); }()); - assert.deepEqual(result, [1, 2]); assert.equal(_.first(null), void 0, 'handles nulls'); assert.strictEqual(_.first([1, 2, 3], -1).length, 0); From b99f2f7d5d80d892ede0a0c4fbc06c455d6d5bfe Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 24 Nov 2015 09:19:11 -0800 Subject: [PATCH 096/263] Clean up assertions for _.first() Makes the assertion descriptions more consistent. In the case of the `-n` test, I opted to rewrite it to be more explicit. Asserting that it actually returns an empty array is ever so slightly more meaningful than testing that its return value has a length of 0. --- test/arrays.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 44fd1553c..2ee9bd6c4 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -6,16 +6,15 @@ test('first', function(assert) { assert.equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array'); assert.equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"'); - assert.deepEqual(_.first([1, 2, 3], 0), [], 'can pass an index to first'); - assert.deepEqual(_.first([1, 2, 3], 2), [1, 2], 'can pass an index to first'); - assert.deepEqual(_.first([1, 2, 3], 5), [1, 2, 3], 'can pass an index to first'); + assert.deepEqual(_.first([1, 2, 3], 0), [], 'can fetch the first 0 elements'); + assert.deepEqual(_.first([1, 2, 3], 2), [1, 2], 'can fetch the first n elements'); + assert.deepEqual(_.first([1, 2, 3], 5), [1, 2, 3], 'returns the whole array if n > length'); var result = (function(){ return _.first(arguments); }(4, 3, 2, 1)); - assert.equal(result, 4, 'works on an arguments object.'); + assert.equal(result, 4, 'works on an arguments object'); result = _.map([[1, 2, 3], [1, 2, 3]], _.first); assert.deepEqual(result, [1, 1], 'works well with _.map'); - - assert.equal(_.first(null), void 0, 'handles nulls'); - assert.strictEqual(_.first([1, 2, 3], -1).length, 0); + assert.equal(_.first(null), void 0, 'returns undefined when called on null'); + assert.deepEqual(_.first([1, 2, 3], -1), [], 'returns an empty array when asked for -n elements'); }); test('head', function(assert) { From e2c67d1f6aa44b2dc93390e05aac73c00dca002e Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 24 Nov 2015 10:56:09 -0800 Subject: [PATCH 097/263] Clean up testing of aliases * Ensure all tests are run against the canonical function name * Ensure all aliases mentioned in the documentation are tested * Remove redundant tests which were originally meant to test aliases * Make alias assertion descriptions consistent readable sentences * Use `(actual, expected)` argument order in alias assertions --- test/arrays.js | 10 +++++----- test/collections.js | 48 +++++++++++++++++++++++---------------------- test/objects.js | 30 +++++++++++++++++----------- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 2ee9bd6c4..596fb87ca 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -18,11 +18,11 @@ }); test('head', function(assert) { - assert.strictEqual(_.first, _.head, 'alias for first'); + assert.strictEqual(_.head, _.first, 'is an alias for first'); }); test('take', function(assert) { - assert.strictEqual(_.first, _.take, 'alias for first'); + assert.strictEqual(_.take, _.first, 'is an alias for first'); }); test('rest', function(assert) { @@ -39,11 +39,11 @@ }); test('tail', function(assert) { - assert.strictEqual(_.rest, _.tail, 'alias for rest'); + assert.strictEqual(_.tail, _.rest, 'is an alias for rest'); }); test('drop', function(assert) { - assert.strictEqual(_.rest, _.drop, 'alias for rest'); + assert.strictEqual(_.drop, _.rest, 'is an alias for rest'); }); test('initial', function(assert) { @@ -192,7 +192,7 @@ }); test('unique', function(assert) { - assert.strictEqual(_.uniq, _.unique, 'alias for uniq'); + assert.strictEqual(_.unique, _.uniq, 'is an alias for uniq'); }); test('intersection', function(assert) { diff --git a/test/collections.js b/test/collections.js index d900f88ae..721f4acb7 100644 --- a/test/collections.js +++ b/test/collections.js @@ -14,7 +14,7 @@ answers = []; _.each([1, 2, 3], function(num){ answers.push(num); }); - assert.deepEqual(answers, [1, 2, 3], 'aliased as "forEach"'); + assert.deepEqual(answers, [1, 2, 3], 'can iterate a simple array'); answers = []; var obj = {one: 1, two: 2, three: 3}; @@ -46,7 +46,7 @@ }); test('forEach', function(assert) { - assert.strictEqual(_.each, _.forEach, 'alias for each'); + assert.strictEqual(_.forEach, _.each, 'is an alias for each'); }); test('lookupIterator with contexts', function(assert) { @@ -172,7 +172,7 @@ }); test('collect', function(assert) { - assert.strictEqual(_.map, _.collect, 'alias for map'); + assert.strictEqual(_.collect, _.map, 'is an alias for map'); }); test('reduce', function(assert) { @@ -183,9 +183,6 @@ sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num * this.multiplier; }, 0, context); assert.equal(sum, 18, 'can reduce with a context object'); - sum = _.inject([1, 2, 3], function(memo, num){ return memo + num; }, 0); - assert.equal(sum, 6, 'aliased as "inject"'); - sum = _([1, 2, 3]).reduce(function(memo, num){ return memo + num; }, 0); assert.equal(sum, 6, 'OO-style reduce'); @@ -202,7 +199,11 @@ }); test('foldl', function(assert) { - assert.strictEqual(_.reduce, _.foldl, 'alias for reduce'); + assert.strictEqual(_.foldl, _.reduce, 'is an alias for reduce'); + }); + + test('inject', function(assert) { + assert.strictEqual(_.inject, _.reduce, 'is an alias for reduce'); }); test('reduceRight', function(assert) { @@ -256,7 +257,7 @@ }); test('foldr', function(assert) { - assert.strictEqual(_.reduceRight, _.foldr, 'alias for reduceRight'); + assert.strictEqual(_.foldr, _.reduceRight, 'is an alias for reduceRight'); }); test('find', function(assert) { @@ -298,7 +299,7 @@ }); test('detect', function(assert) { - assert.strictEqual(_.detect, _.find, 'alias for detect'); + assert.strictEqual(_.detect, _.find, 'is an alias for find'); }); test('filter', function(assert) { @@ -323,7 +324,7 @@ }); test('select', function(assert) { - assert.strictEqual(_.filter, _.select, 'alias for filter'); + assert.strictEqual(_.select, _.filter, 'is an alias for filter'); }); test('reject', function(assert) { @@ -373,7 +374,7 @@ }); test('all', function(assert) { - assert.strictEqual(_.all, _.every, 'alias for all'); + assert.strictEqual(_.all, _.every, 'is an alias for every'); }); test('some', function(assert) { @@ -403,7 +404,7 @@ }); test('any', function(assert) { - assert.strictEqual(_.any, _.some, 'alias for any'); + assert.strictEqual(_.any, _.some, 'is an alias for some'); }); test('includes', function(assert) { @@ -417,24 +418,25 @@ assert.ok(_.includes({moe: 1, larry: 3, curly: 9}, 3) === true, '_.includes on objects checks their values'); assert.ok(_([1, 2, 3]).includes(2), 'OO-style includes'); + + var numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; + assert.strictEqual(_.includes(numbers, 1, 1), true, 'takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, -1), false, 'takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, -2), false, 'takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, -3), true, 'takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, 6), true, 'takes a fromIndex'); + assert.strictEqual(_.includes(numbers, 1, 7), false, 'takes a fromIndex'); + + assert.ok(_.every([1, 2, 3], _.partial(_.includes, numbers)), 'fromIndex is guarded'); }); test('include', function(assert) { - assert.strictEqual(_.includes, _.include, 'alias for includes'); + assert.strictEqual(_.include, _.includes, 'is an alias for includes'); }); test('contains', function(assert) { - assert.strictEqual(_.includes, _.contains, 'alias for includes'); + assert.strictEqual(_.contains, _.includes, 'is an alias for includes'); - var numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; - assert.strictEqual(_.includes(numbers, 1, 1), true, 'contains takes a fromIndex'); - assert.strictEqual(_.includes(numbers, 1, -1), false, 'contains takes a fromIndex'); - assert.strictEqual(_.includes(numbers, 1, -2), false, 'contains takes a fromIndex'); - assert.strictEqual(_.includes(numbers, 1, -3), true, 'contains takes a fromIndex'); - assert.strictEqual(_.includes(numbers, 1, 6), true, 'contains takes a fromIndex'); - assert.strictEqual(_.includes(numbers, 1, 7), false, 'contains takes a fromIndex'); - - assert.ok(_.every([1, 2, 3], _.partial(_.contains, numbers)), 'fromIndex is guarded'); }); test('includes with NaN', function(assert) { diff --git a/test/objects.js b/test/objects.js index 29bbd9281..bc3075839 100644 --- a/test/objects.js +++ b/test/objects.js @@ -102,7 +102,7 @@ }); test('methods', function(assert) { - assert.strictEqual(_.functions, _.methods, 'alias for functions'); + assert.strictEqual(_.methods, _.functions, 'is an alias for functions'); }); test('extend', function(assert) { @@ -138,32 +138,36 @@ test('extendOwn', function(assert) { var result; - assert.equal(_.extendOwn({}, {a: 'b'}).a, 'b', 'can assign an object with the attributes of another'); + assert.equal(_.extendOwn({}, {a: 'b'}).a, 'b', 'can extend an object with the attributes of another'); assert.equal(_.extendOwn({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination'); assert.equal(_.extendOwn({x: 'x'}, {a: 'b'}).x, 'x', "properties not in source don't get overriden"); result = _.extendOwn({x: 'x'}, {a: 'a'}, {b: 'b'}); - assert.deepEqual(result, {x: 'x', a: 'a', b: 'b'}, 'can assign from multiple source objects'); - result = _.assign({x: 'x'}, {a: 'a', x: 2}, {a: 'b'}); - assert.deepEqual(result, {x: 2, a: 'b'}, 'assigning from multiple source objects last property trumps'); - assert.deepEqual(_.extendOwn({}, {a: void 0, b: null}), {a: void 0, b: null}, 'assign copies undefined values'); + assert.deepEqual(result, {x: 'x', a: 'a', b: 'b'}, 'can extend from multiple source objects'); + result = _.extendOwn({x: 'x'}, {a: 'a', x: 2}, {a: 'b'}); + assert.deepEqual(result, {x: 2, a: 'b'}, 'extending from multiple source objects last property trumps'); + assert.deepEqual(_.extendOwn({}, {a: void 0, b: null}), {a: void 0, b: null}, 'copies undefined values'); var F = function() {}; F.prototype = {a: 'b'}; var subObj = new F(); subObj.c = 'd'; - assert.deepEqual(_.extendOwn({}, subObj), {c: 'd'}, 'assign copies own properties from source'); + assert.deepEqual(_.extendOwn({}, subObj), {c: 'd'}, 'copies own properties from source'); result = {}; - assert.deepEqual(_.assign(result, null, void 0, {a: 1}), {a: 1}, 'should not error on `null` or `undefined` sources'); + assert.deepEqual(_.extendOwn(result, null, void 0, {a: 1}), {a: 1}, 'should not error on `null` or `undefined` sources'); _.each(['a', 5, null, false], function(val) { - assert.strictEqual(_.assign(val, {a: 1}), val, 'assigning non-objects results in returning the non-object value'); + assert.strictEqual(_.extendOwn(val, {a: 1}), val, 'extending non-objects results in returning the non-object value'); }); - assert.strictEqual(_.extendOwn(void 0, {a: 1}), void 0, 'assigning undefined results in undefined'); + assert.strictEqual(_.extendOwn(void 0, {a: 1}), void 0, 'extending undefined results in undefined'); result = _.extendOwn({a: 1, 0: 2, 1: '5', length: 6}, {0: 1, 1: 2, length: 2}); - assert.deepEqual(result, {a: 1, 0: 1, 1: 2, length: 2}, 'assign should treat array-like objects like normal objects'); + assert.deepEqual(result, {a: 1, 0: 1, 1: 2, length: 2}, 'should treat array-like objects like normal objects'); + }); + + test('assign', function(assert) { + assert.strictEqual(_.assign, _.extendOwn, 'is an alias for extendOwn'); }); test('pick', function(assert) { @@ -879,6 +883,10 @@ assert.deepEqual(_.map([null, void 0, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); }); + test('matches', function(assert) { + assert.strictEqual(_.matches, _.matcher, 'is an alias for matcher'); + }); + test('findKey', function(assert) { var objects = { a: {a: 0, b: 0}, From e38a9debcc73f03bca4179f147159aab6fcaf1c4 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 24 Nov 2015 12:02:58 -0800 Subject: [PATCH 098/263] Clean up assertions for _.rest() Clean up assertion descriptions, and remove a duplicate assertion. The duplicate assertion is a remnant from when that assertion was used to test the `_.drop` alias. It was made obsolete in pull request #1663. --- test/arrays.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 596fb87ca..6e5e6b87f 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -27,15 +27,13 @@ test('rest', function(assert) { var numbers = [1, 2, 3, 4]; - assert.deepEqual(_.rest(numbers), [2, 3, 4], 'working rest()'); - assert.deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'working rest(0)'); - assert.deepEqual(_.rest(numbers, 2), [3, 4], 'rest can take an index'); + assert.deepEqual(_.rest(numbers), [2, 3, 4], 'fetches all but the first element'); + assert.deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'returns the whole array when n is 0'); + assert.deepEqual(_.rest(numbers, 2), [3, 4], 'returns all but the first n elements'); var result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4)); - assert.deepEqual(result, [2, 3, 4], 'works on arguments object'); + assert.deepEqual(result, [2, 3, 4], 'works on an arguments object'); result = _.map([[1, 2, 3], [1, 2, 3]], _.rest); assert.deepEqual(_.flatten(result), [2, 3, 2, 3], 'works well with _.map'); - result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4)); - assert.deepEqual(result, [2, 3, 4], 'works on arguments object'); }); test('tail', function(assert) { From c74610d089f0010bbdb48902b255a78b029467f8 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 24 Nov 2015 14:23:16 -0800 Subject: [PATCH 099/263] Cleanup _.rest() assertion descriptions again Make the language better match the documentation --- test/arrays.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 6e5e6b87f..f0f250b7b 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -28,8 +28,8 @@ test('rest', function(assert) { var numbers = [1, 2, 3, 4]; assert.deepEqual(_.rest(numbers), [2, 3, 4], 'fetches all but the first element'); - assert.deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'returns the whole array when n is 0'); - assert.deepEqual(_.rest(numbers, 2), [3, 4], 'returns all but the first n elements'); + assert.deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'returns the whole array when index is 0'); + assert.deepEqual(_.rest(numbers, 2), [3, 4], 'returns elements starting at the given index'); var result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4)); assert.deepEqual(result, [2, 3, 4], 'works on an arguments object'); result = _.map([[1, 2, 3], [1, 2, 3]], _.rest); From c6e0658e1979f2f301a28622016012ff79c008d2 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 24 Nov 2015 14:28:20 -0800 Subject: [PATCH 100/263] Cleanup assertion descriptions for _.initial() --- test/arrays.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 6e5e6b87f..ad9100c66 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -45,13 +45,13 @@ }); test('initial', function(assert) { - assert.deepEqual(_.initial([1, 2, 3, 4, 5]), [1, 2, 3, 4], 'working initial()'); - assert.deepEqual(_.initial([1, 2, 3, 4], 2), [1, 2], 'initial can take an index'); - assert.deepEqual(_.initial([1, 2, 3, 4], 6), [], 'initial can take a large index'); + assert.deepEqual(_.initial([1, 2, 3, 4, 5]), [1, 2, 3, 4], 'returns all but the last element'); + assert.deepEqual(_.initial([1, 2, 3, 4], 2), [1, 2], 'returns all but the last n elements'); + assert.deepEqual(_.initial([1, 2, 3, 4], 6), [], 'returns an empty array when n > length'); var result = (function(){ return _(arguments).initial(); }(1, 2, 3, 4)); - assert.deepEqual(result, [1, 2, 3], 'initial works on arguments object'); + assert.deepEqual(result, [1, 2, 3], 'works on an arguments object'); result = _.map([[1, 2, 3], [1, 2, 3]], _.initial); - assert.deepEqual(_.flatten(result), [1, 2, 1, 2], 'initial works with _.map'); + assert.deepEqual(_.flatten(result), [1, 2, 1, 2], 'works well with _.map'); }); test('last', function(assert) { From 1fb7d5cb94de4728f246c63cf54b9979f05a3185 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 24 Nov 2015 14:46:50 -0800 Subject: [PATCH 101/263] Clean up assertions for _.last() Improves messages and ordering. Also makes the `-n` assertion explicitly check for an empty array. --- test/arrays.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 6e5e6b87f..92dc1d6dc 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -56,16 +56,16 @@ test('last', function(assert) { assert.equal(_.last([1, 2, 3]), 3, 'can pull out the last element of an array'); - assert.deepEqual(_.last([1, 2, 3], 0), [], 'can pass an index to last'); - assert.deepEqual(_.last([1, 2, 3], 2), [2, 3], 'can pass an index to last'); - assert.deepEqual(_.last([1, 2, 3], 5), [1, 2, 3], 'can pass an index to last'); + assert.equal(_([1, 2, 3]).last(), 3, 'can perform OO-style "last()"'); + assert.deepEqual(_.last([1, 2, 3], 0), [], 'returns an empty array when n <= 0 (0 case)'); + assert.deepEqual(_.last([1, 2, 3], -1), [], 'returns an empty array when n <= 0 (negative case)'); + assert.deepEqual(_.last([1, 2, 3], 2), [2, 3], 'can fetch the last n elements'); + assert.deepEqual(_.last([1, 2, 3], 5), [1, 2, 3], 'returns the whole array if n > length'); var result = (function(){ return _(arguments).last(); }(1, 2, 3, 4)); assert.equal(result, 4, 'works on an arguments object'); result = _.map([[1, 2, 3], [1, 2, 3]], _.last); assert.deepEqual(result, [3, 3], 'works well with _.map'); - - assert.equal(_.last(null), void 0, 'handles nulls'); - assert.strictEqual(_.last([1, 2, 3], -1).length, 0); + assert.equal(_.last(null), void 0, 'returns undefined when called on null'); }); test('compact', function(assert) { From 276ab6cae0423710fe70108b499e7a1a5b509a8d Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 24 Nov 2015 15:36:27 -0800 Subject: [PATCH 102/263] Improve assertions for _.compact() Explicitly test all falsy values, and assert it works with map. --- test/arrays.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 6e5e6b87f..6bc7d3cf5 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -69,9 +69,11 @@ }); test('compact', function(assert) { - assert.equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values'); - var result = (function(){ return _.compact(arguments).length; }(0, 1, false, 2, false, 3)); - assert.equal(result, 3, 'works on an arguments object'); + assert.deepEqual(_.compact([1, false, null, 0, '', void 0, NaN, 2]), [1, 2], 'removes all falsy values'); + var result = (function(){ return _.compact(arguments); }(0, 1, false, 2, false, 3)); + assert.deepEqual(result, [1, 2, 3], 'works on an arguments object'); + result = _.map([[1, false, false], [false, false, 3]], _.compact); + assert.deepEqual(result, [[1], [3]], 'works well with _.map'); }); test('flatten', function(assert) { From 0380082865ac2ed5136bdb8fb6d8478ee296c68a Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 25 Nov 2015 16:56:56 -0800 Subject: [PATCH 103/263] Make _.first() assertions consistant with _.last()'s In pull request #2360 @michaelficarra suggested an improvement to the assertion messages for `_.last()`'s two `n <= 0` cases. This change brings `_.first()` assertions in line with this improved format. --- test/arrays.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index d53ec8584..fb1a328b5 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -6,7 +6,8 @@ test('first', function(assert) { assert.equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array'); assert.equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"'); - assert.deepEqual(_.first([1, 2, 3], 0), [], 'can fetch the first 0 elements'); + assert.deepEqual(_.first([1, 2, 3], 0), [], 'returns an empty array when n <= 0 (0 case)'); + assert.deepEqual(_.first([1, 2, 3], -1), [], 'returns an empty array when n <= 0 (negative case)'); assert.deepEqual(_.first([1, 2, 3], 2), [1, 2], 'can fetch the first n elements'); assert.deepEqual(_.first([1, 2, 3], 5), [1, 2, 3], 'returns the whole array if n > length'); var result = (function(){ return _.first(arguments); }(4, 3, 2, 1)); @@ -14,7 +15,6 @@ result = _.map([[1, 2, 3], [1, 2, 3]], _.first); assert.deepEqual(result, [1, 1], 'works well with _.map'); assert.equal(_.first(null), void 0, 'returns undefined when called on null'); - assert.deepEqual(_.first([1, 2, 3], -1), [], 'returns an empty array when asked for -n elements'); }); test('head', function(assert) { From ad304d32000194622d3f2671876e2735f821c829 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sat, 28 Nov 2015 16:10:26 -0800 Subject: [PATCH 104/263] Improve assertion messages for _.without() --- test/arrays.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index d53ec8584..c20db97d3 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -102,13 +102,13 @@ test('without', function(assert) { var list = [1, 2, 1, 0, 3, 1, 4]; - assert.deepEqual(_.without(list, 0, 1), [2, 3, 4], 'can remove all instances of an object'); + assert.deepEqual(_.without(list, 0, 1), [2, 3, 4], 'removes all instances of the given values'); var result = (function(){ return _.without(arguments, 0, 1); }(1, 2, 1, 0, 3, 1, 4)); assert.deepEqual(result, [2, 3, 4], 'works on an arguments object'); list = [{one: 1}, {two: 2}]; - assert.equal(_.without(list, {one: 1}).length, 2, 'uses real object identity for comparisons.'); - assert.equal(_.without(list, list[0]).length, 1, 'ditto.'); + assert.deepEqual(_.without(list, {one: 1}), list, 'compares objects by reference (value case)'); + assert.deepEqual(_.without(list, list[0]), [{two: 2}], 'compares objects by reference (reference case)'); }); test('sortedIndex', function(assert) { From a595fe10aa14f382efcac03a793270ef779c5b37 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Mon, 30 Nov 2015 22:59:42 -0500 Subject: [PATCH 105/263] Negative Ranges Fixes https://github.com/jashkenas/underscore/issues/2364. --- test/arrays.js | 3 ++- underscore.js | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 41d14e7cf..0e0e87dec 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -529,12 +529,13 @@ assert.deepEqual(_.range(0), [], 'range with 0 as a first argument generates an empty array'); assert.deepEqual(_.range(4), [0, 1, 2, 3], 'range with a single positive argument generates an array of elements 0,1,2,...,n-1'); assert.deepEqual(_.range(5, 8), [5, 6, 7], 'range with two arguments a & b, a<b generates an array of elements a,a+1,a+2,...,b-2,b-1'); - assert.deepEqual(_.range(8, 5), [], 'range with two arguments a & b, b<a generates an empty array'); assert.deepEqual(_.range(3, 10, 3), [3, 6, 9], 'range with three arguments a & b & c, c < b-a, a < b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) < c'); assert.deepEqual(_.range(3, 10, 15), [3], 'range with three arguments a & b & c, c > b-a, a < b generates an array with a single element, equal to a'); assert.deepEqual(_.range(12, 7, -2), [12, 10, 8], 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b'); assert.deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs'); assert.strictEqual(1 / _.range(-0, 1)[0], -Infinity, 'should preserve -0'); + assert.deepEqual(_.range(8, 5), [8, 7, 6], 'negative range generates descending array'); + assert.deepEqual(_.range(-3), [0, -1, -2], 'negative range generates descending array'); }); test('chunk', function(assert) { diff --git a/underscore.js b/underscore.js index 682cdf647..719473471 100644 --- a/underscore.js +++ b/underscore.js @@ -693,7 +693,9 @@ stop = start || 0; start = 0; } - step = step || 1; + if (!step) { + step = stop < start ? -1 : 1; + } var length = Math.max(Math.ceil((stop - start) / step), 0); var range = Array(length); From ac3e7ff98a9d7f9bb12d5daf17765afc01eb213a Mon Sep 17 00:00:00 2001 From: Henry Wong Date: Sat, 5 Dec 2015 00:58:42 -0800 Subject: [PATCH 106/263] chore(arrays.js): clarify comment Made the comment clear by fixing the grammar. Took @michaelficarra suggestion to make comment change even better. --- test/arrays.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 0e0e87dec..154764d0f 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -251,8 +251,7 @@ var stooges = _.zip(['moe', 30, 'stooge 1'], ['larry', 40, 'stooge 2'], ['curly', 50, 'stooge 3']); assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs'); - // In the case of difference lengths of the tuples undefineds - // should be used as placeholder + //In the case of different lengths of the tuples, undefined values stooges = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [void 0, void 0, 'extra data']], 'zipped pairs with empties'); From 188c60c2a9f5b6dd3cacbf64f02c57f0f189070f Mon Sep 17 00:00:00 2001 From: Henry Wong Date: Sat, 5 Dec 2015 15:53:55 -0800 Subject: [PATCH 107/263] chore(arrays.js): clarify comment, added line 255 back. accidentally delete line 255. --- test/arrays.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/arrays.js b/test/arrays.js index 154764d0f..f22dc6184 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -252,6 +252,7 @@ assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs'); //In the case of different lengths of the tuples, undefined values + // should be used as placeholder stooges = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [void 0, void 0, 'extra data']], 'zipped pairs with empties'); From 5b0d22aeadfd98679588844339a93f05600b5aaa Mon Sep 17 00:00:00 2001 From: Henry Wong Date: Sat, 5 Dec 2015 22:03:34 -0800 Subject: [PATCH 108/263] chore(arrays.js): added space on line 254. Added space on the comment on line 254 so it is consistent with other comments. --- test/arrays.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/arrays.js b/test/arrays.js index f22dc6184..acefbe8c0 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -251,7 +251,7 @@ var stooges = _.zip(['moe', 30, 'stooge 1'], ['larry', 40, 'stooge 2'], ['curly', 50, 'stooge 3']); assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs'); - //In the case of different lengths of the tuples, undefined values + // In the case of different lengths of the tuples, undefined values // should be used as placeholder stooges = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [void 0, void 0, 'extra data']], 'zipped pairs with empties'); From ed8c4e06f58e8dc34b7e5170e101bc7835a3a28f Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 6 Dec 2015 17:37:55 -0800 Subject: [PATCH 109/263] Clean up comments on cb() and _.iteratee() In commit 44a47fb03de1d9dbf49ea96f265fd3c3f5f5ffd4, `_.iteratee()` was converted into the fully internal function `cb()`. However, the comment was not not updated to reflect its new internal status. --- underscore.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/underscore.js b/underscore.js index 719473471..7eddd5644 100644 --- a/underscore.js +++ b/underscore.js @@ -85,9 +85,9 @@ }; }; - // A mostly-internal function to generate callbacks that can be applied - // to each element in a collection, returning the desired result — either - // `identity`, an arbitrary callback, a property matcher, or a property accessor. + // An internal function to generate callbacks that can be applied to each + // element in a collection, returning the desired result — either `identity`, + // an arbitrary callback, a property matcher, or a property accessor. var cb = function(value, context, argCount) { if (value == null) return _.identity; if (_.isFunction(value)) return optimizeCb(value, context, argCount); @@ -95,6 +95,7 @@ return _.property(value); }; + // An external wrapper for the internal callback generator _.iteratee = function(value, context) { return cb(value, context, Infinity); }; From 58377aec6867d8d09e7703c7110f0ad4e1881d37 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 6 Dec 2015 20:58:30 -0800 Subject: [PATCH 110/263] Cleanup assertions for _.sortedIndex Makes assertion messages more consistent and readable. The rational for the second assertion, "finds the smallest index...", was outlined in pull request #563, but not clearly documented. I've attempted to remedy that with the updated message. --- test/arrays.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index acefbe8c0..d159b37a8 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -114,29 +114,30 @@ }); test('sortedIndex', function(assert) { - var numbers = [10, 20, 30, 40, 50], num = 35; - var indexForNum = _.sortedIndex(numbers, num); - assert.equal(indexForNum, 3, '35 should be inserted at index 3'); - + var numbers = [10, 20, 30, 40, 50]; + var indexFor35 = _.sortedIndex(numbers, 35); + assert.equal(indexFor35, 3, 'finds the index at which a value should be inserted to retain order'); var indexFor30 = _.sortedIndex(numbers, 30); - assert.equal(indexFor30, 2, '30 should be inserted at index 2'); + assert.equal(indexFor30, 2, 'finds the smallest index at which a value could be inserted to retain order'); var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}]; var iterator = function(obj){ return obj.x; }; - assert.strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2); - assert.strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3); + assert.strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2, 'uses the result of `iterator` for order comparisons'); + assert.strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3, 'when `iterator` is a string, uses that key for order comparisons'); var context = {1: 2, 2: 3, 3: 4}; iterator = function(obj){ return this[obj]; }; - assert.strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1); + assert.strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1, 'can execute its iterator in the given context'); - var values = [0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647]; - var array = Array(Math.pow(2, 32) - 1); + var values = [0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, + 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647]; + var largeArray = Array(Math.pow(2, 32) - 1); var length = values.length; + // Sparsely populate `array` while (length--) { - array[values[length]] = values[length]; + largeArray[values[length]] = values[length]; } - assert.equal(_.sortedIndex(array, 2147483648), 2147483648, 'should work with large indexes'); + assert.equal(_.sortedIndex(largeArray, 2147483648), 2147483648, 'works with large indexes'); }); test('uniq', function(assert) { From 21f24118267d2383a9069044bda9287fac5dbf49 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 9 Dec 2015 14:25:58 -0800 Subject: [PATCH 111/263] Improve comment in createReduce() This incomplete comment was introduced in pull request #1991. I believe I have captured the intended intent. --- underscore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/underscore.js b/underscore.js index 719473471..42f004789 100644 --- a/underscore.js +++ b/underscore.js @@ -187,8 +187,8 @@ // Create a reducing function iterating left or right. var createReduce = function(dir) { - // Optimized iterator function as using arguments.length - // in the main function will deoptimize the, see #1991. + // Wrap code that reassigns argument variables in a separate function than + // the one that accesses `arguments.length` to avoid a perf hit. (#1191) var reducer = function(obj, iteratee, memo, initial) { var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, From e8c252b205813fbb4070cf87118f6502dc1099be Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 10 Dec 2015 11:14:02 -0500 Subject: [PATCH 112/263] Rename throttled and debounced cancel function https://github.com/jashkenas/underscore/commit/8a70f347e32650f9ca114b99ee09c61e711ecc08#commitcomment-14893333 --- test/functions.js | 16 ++++++++-------- underscore.js | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/functions.js b/test/functions.js index 0e02b3531..09512feb7 100644 --- a/test/functions.js +++ b/test/functions.js @@ -395,12 +395,12 @@ }, 100); }); - asyncTest('throttle cleared', function(assert) { + asyncTest('throttle cancel', function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 32); throttledIncr(); - throttledIncr.clear(); + throttledIncr.cancel(); throttledIncr(); throttledIncr(); @@ -408,12 +408,12 @@ _.delay(function(){ assert.equal(counter, 3, 'incr was throttled'); start(); }, 64); }); - asyncTest('throttle cleared with leading: false', function(assert) { + asyncTest('throttle cancel with leading: false', function(assert) { var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 32, {leading: false}); throttledIncr(); - throttledIncr.clear(); + throttledIncr.cancel(); assert.equal(counter, 0, 'incr was throttled'); _.delay(function(){ assert.equal(counter, 0, 'incr was throttled'); start(); }, 64); @@ -428,12 +428,12 @@ _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 96); }); - asyncTest('debounce cleared', 1, function(assert) { + asyncTest('debounce cancel', 1, function(assert) { var counter = 0; var incr = function(){ counter++; }; var debouncedIncr = _.debounce(incr, 32); debouncedIncr(); - debouncedIncr.clear(); + debouncedIncr.cancel(); _.delay(function(){ assert.equal(counter, 0, 'incr was not called'); start(); }, 96); }); @@ -453,13 +453,13 @@ _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 128); }); - asyncTest('debounce asap cleared', 4, function(assert) { + asyncTest('debounce asap cancel', 4, function(assert) { var a, b; var counter = 0; var incr = function(){ return ++counter; }; var debouncedIncr = _.debounce(incr, 64, true); a = debouncedIncr(); - debouncedIncr.clear(); + debouncedIncr.cancel(); b = debouncedIncr(); assert.equal(a, 1); assert.equal(b, 2); diff --git a/underscore.js b/underscore.js index a02b58cd8..288886743 100644 --- a/underscore.js +++ b/underscore.js @@ -839,7 +839,7 @@ return result; }; - throttled.clear = function() { + throttled.cancel = function() { clearTimeout(timeout); previous = 0; timeout = context = args = null; @@ -873,7 +873,7 @@ return result; }); - debounced.clear = function() { + debounced.cancel = function() { clearTimeout(timeout); timeout = null; }; From f361f8df8b2c0c640b2339aec3667aca72b3b237 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Thu, 10 Dec 2015 10:43:39 -0800 Subject: [PATCH 113/263] Correct pull requst number in createReduce comment I mistyped the pull request number in my previous commit. --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 288886743..6fdfb3caf 100644 --- a/underscore.js +++ b/underscore.js @@ -189,7 +189,7 @@ // Create a reducing function iterating left or right. var createReduce = function(dir) { // Wrap code that reassigns argument variables in a separate function than - // the one that accesses `arguments.length` to avoid a perf hit. (#1191) + // the one that accesses `arguments.length` to avoid a perf hit. (#1991) var reducer = function(obj, iteratee, memo, initial) { var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, From 13e93b41b89dc61f95cbfdfe055e9806bc579d3d Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 8 Dec 2015 20:26:14 -0800 Subject: [PATCH 114/263] Clean up assertions for _.uniq() * Improve assertion grouping * Improve assertion messages * Remove unused properties from test objects * Reuse existing sorted "score" list for sorted tests * Remove clever/confusing usage of _.map for asserting list equality * Simplify test data to be more terse and readable (yes I feel guilty for removing the cute kittens) --- test/arrays.js | 46 +++++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index d159b37a8..f6b581596 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -143,33 +143,23 @@ test('uniq', function(assert) { var list = [1, 2, 1, 3, 1, 4]; assert.deepEqual(_.uniq(list), [1, 2, 3, 4], 'can find the unique values of an unsorted array'); - list = [1, 1, 1, 2, 2, 3]; assert.deepEqual(_.uniq(list, true), [1, 2, 3], 'can find the unique values of a sorted array faster'); - list = [{name: 'moe'}, {name: 'curly'}, {name: 'larry'}, {name: 'curly'}]; - var iterator = function(value) { return value.name; }; - assert.deepEqual(_.map(_.uniq(list, false, iterator), iterator), ['moe', 'curly', 'larry'], 'can find the unique values of an array using a custom iterator'); - - assert.deepEqual(_.map(_.uniq(list, iterator), iterator), ['moe', 'curly', 'larry'], 'can find the unique values of an array using a custom iterator without specifying whether array is sorted'); - - iterator = function(value) { return value + 1; }; - list = [1, 2, 2, 3, 4, 4]; - assert.deepEqual(_.uniq(list, true, iterator), [1, 2, 3, 4], 'iterator works with sorted array'); - - var kittens = [ - {kitten: 'Celery', cuteness: 8}, - {kitten: 'Juniper', cuteness: 10}, - {kitten: 'Spottis', cuteness: 10} - ]; - - var expected = [ - {kitten: 'Celery', cuteness: 8}, - {kitten: 'Juniper', cuteness: 10} - ]; + list = [{name: 'Moe'}, {name: 'Curly'}, {name: 'Larry'}, {name: 'Curly'}]; + var expected = [{name: 'Moe'}, {name: 'Curly'}, {name: 'Larry'}]; + var iterator = function(stooge) { return stooge.name; }; + assert.deepEqual(_.uniq(list, false, iterator), expected, 'uses the result of `iterator` for uniqueness comparisons (unsorted case)'); + assert.deepEqual(_.uniq(list, iterator), expected, '`sorted` argument defaults to false when omitted'); + assert.deepEqual(_.uniq(list, 'name'), expected, 'when `iterator` is a string, uses that key for comparisons (unsorted case)'); - assert.deepEqual(_.uniq(kittens, true, 'cuteness'), expected, 'string iterator works with sorted array'); + list = [{score: 8}, {score: 10}, {score: 10}]; + expected = [{score: 8}, {score: 10}]; + iterator = function(item) { return item.score; }; + assert.deepEqual(_.uniq(list, true, iterator), expected, 'uses the result of `iterator` for uniqueness comparisons (sorted case)'); + assert.deepEqual(_.uniq(list, true, 'score'), expected, 'when `iterator` is a string, uses that key for comparisons (sorted case)'); + assert.deepEqual(_.uniq([{0: 1}, {0: 1}, {0: 1}, {0: 2}], 0), [{0: 1}, {0: 2}], 'can use falsey pluck like iterator'); var result = (function(){ return _.uniq(arguments); }(1, 2, 1, 3, 1, 4)); assert.deepEqual(result, [1, 2, 3, 4], 'works on an arguments object'); @@ -177,19 +167,17 @@ var a = {}, b = {}, c = {}; assert.deepEqual(_.uniq([a, b, a, b, c]), [a, b, c], 'works on values that can be tested for equivalency but not ordered'); - assert.deepEqual(_.uniq(null), []); + assert.deepEqual(_.uniq(null), [], 'returns an empty array when `array` is not iterable'); var context = {}; list = [3]; _.uniq(list, function(value, index, array) { - assert.strictEqual(this, context); - assert.strictEqual(value, 3); - assert.strictEqual(index, 0); - assert.strictEqual(array, list); + assert.strictEqual(this, context, 'executes its iterator in the given context'); + assert.strictEqual(value, 3, 'passes its iterator the value'); + assert.strictEqual(index, 0, 'passes its iterator the index'); + assert.strictEqual(array, list, 'passes its iterator the entire array'); }, context); - assert.deepEqual(_.uniq([{a: 1, b: 1}, {a: 1, b: 2}, {a: 1, b: 3}, {a: 2, b: 1}], 'a'), [{a: 1, b: 1}, {a: 2, b: 1}], 'can use pluck like iterator'); - assert.deepEqual(_.uniq([{0: 1, b: 1}, {0: 1, b: 2}, {0: 1, b: 3}, {0: 2, b: 1}], 0), [{0: 1, b: 1}, {0: 2, b: 1}], 'can use falsey pluck like iterator'); }); test('unique', function(assert) { From b6ebffbc2a935c9456c83cac804ece79b37bb4f4 Mon Sep 17 00:00:00 2001 From: Craig Martin Date: Fri, 11 Dec 2015 16:02:55 -0500 Subject: [PATCH 115/263] trust npm to set up $PATH --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 26e00c2aa..860a76819 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "coveralls": "nyc npm run test-node && nyc report --reporter=text-lcov | coveralls", "lint": "eslint --reset underscore.js test/*.js", "test-node": "qunit-cli test/*.js", - "test-browser": "npm i karma-phantomjs-launcher && ./node_modules/karma/bin/karma start", + "test-browser": "npm i karma-phantomjs-launcher && karma start", "build": "uglifyjs underscore.js -c \"evaluate=false\" --comments \"/ .*/\" -m --source-map underscore-min.map --source-map-url \" \" -o underscore-min.js", "doc": "docco underscore.js" }, From 8684a63e2a1918ea81eee22f459660e901513c00 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 13 Dec 2015 21:23:08 -0800 Subject: [PATCH 116/263] Don't let eslint ignore global _ in tests As of pull request #2033 (commit 2646f2eaaa3a1b6511051b5e0c461bcaf238e778) we explicitly define `_` in our test files, so we no longer need this exception. --- test/.eslintrc | 1 - 1 file changed, 1 deletion(-) diff --git a/test/.eslintrc b/test/.eslintrc index 052484beb..0fa854fd3 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -3,7 +3,6 @@ "browser": true }, "globals": { - "_": false, "test": false, "ok": false, "is": false, From 6da9a2b6f68707a6239c4395389ad349683003d4 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 13 Dec 2015 22:01:57 -0800 Subject: [PATCH 117/263] Use assert.raises instead of .throws In some environments `.throws()` is a reserved word, so QUnit offers an alias `.raises()`. Using `.raises` seems safer, and also allows us to remove an eslint exception. --- test/.eslintrc | 1 - test/collections.js | 2 +- test/functions.js | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/test/.eslintrc b/test/.eslintrc index 052484beb..e86eb4f6e 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -21,7 +21,6 @@ }, "rules": { "brace-style": 0, - "dot-notation": 1, "no-new-wrappers": 0, "no-sparse-arrays": 0, "no-extend-native": 0 diff --git a/test/collections.js b/test/collections.js index 721f4acb7..864b04f6f 100644 --- a/test/collections.js +++ b/test/collections.js @@ -467,7 +467,7 @@ assert.deepEqual(_.invoke([{a: null}, {}, {a: _.constant(1)}], 'a'), [null, void 0, 1], 'handles null & undefined'); - assert.throws(function() { + assert.raises(function() { _.invoke([{a: 1}], 'a'); }, TypeError, 'throws for non-functions'); }); diff --git a/test/functions.js b/test/functions.js index 09512feb7..ec15c272d 100644 --- a/test/functions.js +++ b/test/functions.js @@ -44,7 +44,7 @@ assert.equal(boundf().hello, 'moe curly', "When called without the new operator, it's OK to be bound to the context"); assert.ok(newBoundf instanceof F, 'a bound instance is an instance of the original function'); - assert.throws(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function'); + assert.raises(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function'); }); test('partial', function(assert) { @@ -109,9 +109,9 @@ sayLast: function() { return this.sayHi(_.last(arguments)); } }; - assert.throws(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named'); - assert.throws(function() { _.bindAll(moe, 'sayBye'); }, TypeError, 'throws an error for bindAll if the given key is undefined'); - assert.throws(function() { _.bindAll(moe, 'name'); }, TypeError, 'throws an error for bindAll if the given key is not a function'); + assert.raises(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named'); + assert.raises(function() { _.bindAll(moe, 'sayBye'); }, TypeError, 'throws an error for bindAll if the given key is undefined'); + assert.raises(function() { _.bindAll(moe, 'name'); }, TypeError, 'throws an error for bindAll if the given key is not a function'); _.bindAll(moe, 'sayHi', 'sayLast'); curly.sayHi = moe.sayHi; From ca693cf5942ff1292a90f1a620dbaded4b956423 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 13 Dec 2015 23:50:47 -0800 Subject: [PATCH 118/263] Use same version of QUnit in browser as CLI In our `package.json` we list `"qunitjs": "^1.18.0"`, but the version in `tests/vendor` was only 1.17.1. This brings our browser test runner up to date. --- test/vendor/qunit.css | 19 +- test/vendor/qunit.js | 1395 ++++++++++++++++++++++++++++++++++------- 2 files changed, 1189 insertions(+), 225 deletions(-) mode change 100644 => 100755 test/vendor/qunit.css mode change 100644 => 100755 test/vendor/qunit.js diff --git a/test/vendor/qunit.css b/test/vendor/qunit.css old mode 100644 new mode 100755 index 447caa3d5..f1dcd4e1c --- a/test/vendor/qunit.css +++ b/test/vendor/qunit.css @@ -1,12 +1,12 @@ /*! - * QUnit 1.17.1 + * QUnit 1.18.0 * http://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * - * Date: 2015-01-20T19:39Z + * Date: 2015-04-03T10:23Z */ /** Font Family and Sizes */ @@ -116,7 +116,13 @@ #qunit-tests.hidepass li.running, #qunit-tests.hidepass li.pass { - display: none; + visibility: hidden; + position: absolute; + width: 0px; + height: 0px; + padding: 0; + border: 0; + margin: 0; } #qunit-tests li strong { @@ -132,6 +138,11 @@ color: #C2CCD1; text-decoration: none; } + +#qunit-tests li p a { + padding: 0.25em; + color: #6B6464; +} #qunit-tests li a:hover, #qunit-tests li a:focus { color: #000; @@ -277,4 +288,4 @@ left: -10000px; width: 1000px; height: 1000px; -} \ No newline at end of file +} diff --git a/test/vendor/qunit.js b/test/vendor/qunit.js old mode 100644 new mode 100755 index f03c3c58d..f3542ca9d --- a/test/vendor/qunit.js +++ b/test/vendor/qunit.js @@ -1,12 +1,12 @@ /*! - * QUnit 1.17.1 + * QUnit 1.18.0 * http://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license * - * Date: 2015-01-20T19:39Z + * Date: 2015-04-03T10:23Z */ (function( window ) { @@ -116,6 +116,9 @@ config = { // when enabled, all tests must call expect() requireExpects: false, + // depth up-to which object will be dumped + maxDepth: 5, + // add checkboxes that are persisted in the query-string // when enabled, the id is set to `true` as a `QUnit.config` property urlConfig: [ @@ -185,11 +188,17 @@ config.modules.push( config.currentModule ); // String search anywhere in moduleName+testName config.filter = urlParams.filter; + if ( urlParams.maxDepth ) { + config.maxDepth = parseInt( urlParams.maxDepth, 10 ) === -1 ? + Number.POSITIVE_INFINITY : + urlParams.maxDepth; + } + config.testId = []; if ( urlParams.testId ) { // Ensure that urlParams.testId is an array - urlParams.testId = [].concat( urlParams.testId ); + urlParams.testId = decodeURIComponent( urlParams.testId ).split( "," ); for ( i = 0; i < urlParams.testId.length; i++ ) { config.testId.push( urlParams.testId[ i ] ); } @@ -197,6 +206,9 @@ config.modules.push( config.currentModule ); // Figure out if we're running the tests from a server or not QUnit.isLocal = location.protocol === "file:"; + + // Expose the current QUnit version + QUnit.version = "1.18.0"; }()); // Root QUnit object. @@ -484,20 +496,14 @@ function done() { }); } -// Doesn't support IE6 to IE9 +// Doesn't support IE6 to IE9, it will return undefined on these browsers // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack function extractStacktrace( e, offset ) { offset = offset === undefined ? 4 : offset; var stack, include, i; - if ( e.stacktrace ) { - - // Opera 12.x - return e.stacktrace.split( "\n" )[ offset + 3 ]; - } else if ( e.stack ) { - - // Firefox, Chrome, Safari 6+, IE10+, PhantomJS and Node + if ( e.stack ) { stack = e.stack.split( "\n" ); if ( /^error$/i.test( stack[ 0 ] ) ) { stack.shift(); @@ -515,9 +521,10 @@ function extractStacktrace( e, offset ) { } } return stack[ offset ]; + + // Support: Safari <=6 only } else if ( e.sourceURL ) { - // Safari < 6 // exclude useless self-reference for generated Error objects if ( /qunit.js$/.test( e.sourceURL ) ) { return; @@ -529,16 +536,19 @@ function extractStacktrace( e, offset ) { } function sourceFromStacktrace( offset ) { - var e = new Error(); - if ( !e.stack ) { + var error = new Error(); + + // Support: Safari <=7 only, IE <=10 - 11 only + // Not all browsers generate the `stack` property for `new Error()`, see also #636 + if ( !error.stack ) { try { - throw e; + throw error; } catch ( err ) { - // This should already be true in most browsers - e = err; + error = err; } } - return extractStacktrace( e, offset ); + + return extractStacktrace( error, offset ); } function synchronize( callback, last ) { @@ -1123,7 +1133,7 @@ Test.prototype = { valid: function() { var include, - filter = config.filter, + filter = config.filter && config.filter.toLowerCase(), module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(), fullName = ( this.module.name + ": " + this.testName ).toLowerCase(); @@ -1146,7 +1156,7 @@ Test.prototype = { include = filter.charAt( 0 ) !== "!"; if ( !include ) { - filter = filter.toLowerCase().slice( 1 ); + filter = filter.slice( 1 ); } // If the filter matches, we need to honour include @@ -1284,87 +1294,52 @@ QUnit.assert = Assert.prototype = { return assert.test.push.apply( assert.test, arguments ); }, - /** - * Asserts rough true-ish result. - * @name ok - * @function - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); - */ ok: function( result, message ) { message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " + QUnit.dump.parse( result ) ); this.push( !!result, result, true, message ); }, - /** - * Assert that the first two arguments are equal, with an optional message. - * Prints out both actual and expected values. - * @name equal - * @function - * @example equal( format( "{0} bytes.", 2), "2 bytes.", "replaces {0} with next argument" ); - */ + notOk: function( result, message ) { + message = message || ( !result ? "okay" : "failed, expected argument to be falsy, was: " + + QUnit.dump.parse( result ) ); + this.push( !result, result, false, message ); + }, + equal: function( actual, expected, message ) { /*jshint eqeqeq:false */ this.push( expected == actual, actual, expected, message ); }, - /** - * @name notEqual - * @function - */ notEqual: function( actual, expected, message ) { /*jshint eqeqeq:false */ this.push( expected != actual, actual, expected, message ); }, - /** - * @name propEqual - * @function - */ propEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); this.push( QUnit.equiv( actual, expected ), actual, expected, message ); }, - /** - * @name notPropEqual - * @function - */ notPropEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); }, - /** - * @name deepEqual - * @function - */ deepEqual: function( actual, expected, message ) { this.push( QUnit.equiv( actual, expected ), actual, expected, message ); }, - /** - * @name notDeepEqual - * @function - */ notDeepEqual: function( actual, expected, message ) { this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); }, - /** - * @name strictEqual - * @function - */ strictEqual: function( actual, expected, message ) { this.push( expected === actual, actual, expected, message ); }, - /** - * @name notStrictEqual - * @function - */ notStrictEqual: function( actual, expected, message ) { this.push( expected !== actual, actual, expected, message ); }, @@ -1372,7 +1347,8 @@ QUnit.assert = Assert.prototype = { "throws": function( block, expected, message ) { var actual, expectedType, expectedOutput = expected, - ok = false; + ok = false, + currentTest = ( this instanceof Assert && this.test ) || QUnit.config.current; // 'expected' is optional unless doing string comparison if ( message == null && typeof expected === "string" ) { @@ -1380,13 +1356,13 @@ QUnit.assert = Assert.prototype = { expected = null; } - this.test.ignoreGlobalErrors = true; + currentTest.ignoreGlobalErrors = true; try { - block.call( this.test.testEnvironment ); + block.call( currentTest.testEnvironment ); } catch (e) { actual = e; } - this.test.ignoreGlobalErrors = false; + currentTest.ignoreGlobalErrors = false; if ( actual ) { expectedType = QUnit.objectType( expected ); @@ -1419,11 +1395,9 @@ QUnit.assert = Assert.prototype = { expectedOutput = null; ok = true; } - - this.push( ok, actual, expectedOutput, message ); - } else { - this.test.pushFailure( message, null, "No exception was thrown." ); } + + currentTest.assert.push( ok, actual, expectedOutput, message ); } }; @@ -1435,7 +1409,7 @@ QUnit.assert = Assert.prototype = { }()); // Test for equality any JavaScript type. -// Author: Philippe Rathé +// Author: Philippe Rathé QUnit.equiv = (function() { // Call the o related callback with the given arguments. @@ -1783,7 +1757,7 @@ QUnit.dump = (function() { join: join, // depth: 1, - maxDepth: 5, + maxDepth: QUnit.config.maxDepth, // This is the list of parsers, to modify them, use dump.setParser parsers: { @@ -1830,7 +1804,7 @@ QUnit.dump = (function() { nonEnumerableProperties = [ "message", "name" ]; for ( i in nonEnumerableProperties ) { key = nonEnumerableProperties[ i ]; - if ( key in map && !( key in keys ) ) { + if ( key in map && inArray( key, keys ) < 0 ) { keys.push( key ); } } @@ -1949,6 +1923,7 @@ if ( typeof window !== "undefined" ) { "start", "stop", "ok", + "notOk", "equal", "notEqual", "propEqual", @@ -1981,6 +1956,13 @@ if ( typeof exports !== "undefined" && exports ) { exports.QUnit = QUnit; } +if ( typeof define === "function" && define.amd ) { + define( function() { + return QUnit; + } ); + QUnit.config.autostart = false; +} + // Get a reference to the global object, like window in browsers }( (function() { return this; @@ -1989,150 +1971,1088 @@ if ( typeof exports !== "undefined" && exports ) { /*istanbul ignore next */ // jscs:disable maximumLineLength /* - * Javascript Diff Algorithm - * By John Resig (http://ejohn.org/) - * Modified by Chu Alan "sprite" + * This file is a modified version of google-diff-match-patch's JavaScript implementation + * (https://code.google.com/p/google-diff-match-patch/source/browse/trunk/javascript/diff_match_patch_uncompressed.js), + * modifications are licensed as more fully set forth in LICENSE.txt. + * + * The original source of google-diff-match-patch is attributable and licensed as follows: + * + * Copyright 2006 Google Inc. + * http://code.google.com/p/google-diff-match-patch/ * - * Released under the MIT license. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * More Info: - * http://ejohn.org/projects/javascript-diff-algorithm/ + * https://code.google.com/p/google-diff-match-patch/ * * Usage: QUnit.diff(expected, actual) * - * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brownfoxjumpedjumps over" + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) === "the quickbrownfox jumpsed0; i-- ) { - if ( n[ i ].text != null && n[ i - 1 ].text == null && n[ i ].row > 0 && o[ n[ i ].row - 1 ].text == null && - n[ i - 1 ] == o[ n[ i ].row - 1 ] ) { - - n[ i - 1 ] = { - text: n[ i - 1 ], - row: n[ i ].row - 1 - }; - o[ n[ i ].row - 1 ] = { - text: o[ n[ i ].row - 1 ], - row: i - 1 - }; - } - } - - return { - o: o, - n: n - }; - } - - return function( o, n ) { - o = o.replace( /\s+$/, "" ); - n = n.replace( /\s+$/, "" ); - - var i, pre, - str = "", - out = diff( o === "" ? [] : o.split( /\s+/ ), n === "" ? [] : n.split( /\s+/ ) ), - oSpace = o.match( /\s+/g ), - nSpace = n.match( /\s+/g ); - - if ( oSpace == null ) { - oSpace = [ " " ]; - } else { - oSpace.push( " " ); - } - - if ( nSpace == null ) { - nSpace = [ " " ]; - } else { - nSpace.push( " " ); - } - - if ( out.n.length === 0 ) { - for ( i = 0; i < out.o.length; i++ ) { - str += "" + out.o[ i ] + oSpace[ i ] + ""; - } - } else { - if ( out.n[ 0 ].text == null ) { - for ( n = 0; n < out.o.length && out.o[ n ].text == null; n++ ) { - str += "" + out.o[ n ] + oSpace[ n ] + ""; - } - } - - for ( i = 0; i < out.n.length; i++ ) { - if ( out.n[ i ].text == null ) { - str += "" + out.n[ i ] + nSpace[ i ] + ""; - } else { - - // `pre` initialized at top of scope - pre = ""; - - for ( n = out.n[ i ].row + 1; n < out.o.length && out.o[ n ].text == null; n++ ) { - pre += "" + out.o[ n ] + oSpace[ n ] + ""; - } - str += " " + out.n[ i ].text + nSpace[ i ] + pre; - } - } - } - - return str; - }; + function DiffMatchPatch() { + + // Defaults. + // Redefine these in your program to override the defaults. + + // Number of seconds to map a diff before giving up (0 for infinity). + this.DiffTimeout = 1.0; + // Cost of an empty edit operation in terms of edit characters. + this.DiffEditCost = 4; + } + + // DIFF FUNCTIONS + + /** + * The data structure representing a diff is an array of tuples: + * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']] + * which means: delete 'Hello', add 'Goodbye' and keep ' world.' + */ + var DIFF_DELETE = -1, + DIFF_INSERT = 1, + DIFF_EQUAL = 0; + + /** + * Find the differences between two texts. Simplifies the problem by stripping + * any common prefix or suffix off the texts before diffing. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {boolean=} optChecklines Optional speedup flag. If present and false, + * then don't run a line-level diff first to identify the changed areas. + * Defaults to true, which does a faster, slightly less optimal diff. + * @param {number} optDeadline Optional time when the diff should be complete + * by. Used internally for recursive calls. Users should set DiffTimeout + * instead. + * @return {!Array.} Array of diff tuples. + */ + DiffMatchPatch.prototype.DiffMain = function( text1, text2, optChecklines, optDeadline ) { + var deadline, checklines, commonlength, + commonprefix, commonsuffix, diffs; + // Set a deadline by which time the diff must be complete. + if ( typeof optDeadline === "undefined" ) { + if ( this.DiffTimeout <= 0 ) { + optDeadline = Number.MAX_VALUE; + } else { + optDeadline = ( new Date() ).getTime() + this.DiffTimeout * 1000; + } + } + deadline = optDeadline; + + // Check for null inputs. + if ( text1 === null || text2 === null ) { + throw new Error( "Null input. (DiffMain)" ); + } + + // Check for equality (speedup). + if ( text1 === text2 ) { + if ( text1 ) { + return [ + [ DIFF_EQUAL, text1 ] + ]; + } + return []; + } + + if ( typeof optChecklines === "undefined" ) { + optChecklines = true; + } + + checklines = optChecklines; + + // Trim off common prefix (speedup). + commonlength = this.diffCommonPrefix( text1, text2 ); + commonprefix = text1.substring( 0, commonlength ); + text1 = text1.substring( commonlength ); + text2 = text2.substring( commonlength ); + + // Trim off common suffix (speedup). + ///////// + commonlength = this.diffCommonSuffix( text1, text2 ); + commonsuffix = text1.substring( text1.length - commonlength ); + text1 = text1.substring( 0, text1.length - commonlength ); + text2 = text2.substring( 0, text2.length - commonlength ); + + // Compute the diff on the middle block. + diffs = this.diffCompute( text1, text2, checklines, deadline ); + + // Restore the prefix and suffix. + if ( commonprefix ) { + diffs.unshift( [ DIFF_EQUAL, commonprefix ] ); + } + if ( commonsuffix ) { + diffs.push( [ DIFF_EQUAL, commonsuffix ] ); + } + this.diffCleanupMerge( diffs ); + return diffs; + }; + + /** + * Reduce the number of edits by eliminating operationally trivial equalities. + * @param {!Array.} diffs Array of diff tuples. + */ + DiffMatchPatch.prototype.diffCleanupEfficiency = function( diffs ) { + var changes, equalities, equalitiesLength, lastequality, + pointer, preIns, preDel, postIns, postDel; + changes = false; + equalities = []; // Stack of indices where equalities are found. + equalitiesLength = 0; // Keeping our own length var is faster in JS. + /** @type {?string} */ + lastequality = null; + // Always equal to diffs[equalities[equalitiesLength - 1]][1] + pointer = 0; // Index of current position. + // Is there an insertion operation before the last equality. + preIns = false; + // Is there a deletion operation before the last equality. + preDel = false; + // Is there an insertion operation after the last equality. + postIns = false; + // Is there a deletion operation after the last equality. + postDel = false; + while ( pointer < diffs.length ) { + if ( diffs[ pointer ][ 0 ] === DIFF_EQUAL ) { // Equality found. + if ( diffs[ pointer ][ 1 ].length < this.DiffEditCost && ( postIns || postDel ) ) { + // Candidate found. + equalities[ equalitiesLength++ ] = pointer; + preIns = postIns; + preDel = postDel; + lastequality = diffs[ pointer ][ 1 ]; + } else { + // Not a candidate, and can never become one. + equalitiesLength = 0; + lastequality = null; + } + postIns = postDel = false; + } else { // An insertion or deletion. + if ( diffs[ pointer ][ 0 ] === DIFF_DELETE ) { + postDel = true; + } else { + postIns = true; + } + /* + * Five types to be split: + * ABXYCD+ * AXCD+ * ABXC + * AXCD+ * ABXC+ */ + if ( lastequality && ( ( preIns && preDel && postIns && postDel ) || + ( ( lastequality.length < this.DiffEditCost / 2 ) && + ( preIns + preDel + postIns + postDel ) === 3 ) ) ) { + // Duplicate record. + diffs.splice( equalities[equalitiesLength - 1], 0, [ DIFF_DELETE, lastequality ] ); + // Change second copy to insert. + diffs[ equalities[ equalitiesLength - 1 ] + 1 ][ 0 ] = DIFF_INSERT; + equalitiesLength--; // Throw away the equality we just deleted; + lastequality = null; + if (preIns && preDel) { + // No changes made which could affect previous entry, keep going. + postIns = postDel = true; + equalitiesLength = 0; + } else { + equalitiesLength--; // Throw away the previous equality. + pointer = equalitiesLength > 0 ? equalities[ equalitiesLength - 1 ] : -1; + postIns = postDel = false; + } + changes = true; + } + } + pointer++; + } + + if ( changes ) { + this.diffCleanupMerge( diffs ); + } + }; + + /** + * Convert a diff array into a pretty HTML report. + * @param {!Array.} diffs Array of diff tuples. + * @param {integer} string to be beautified. + * @return {string} HTML representation. + */ + DiffMatchPatch.prototype.diffPrettyHtml = function( diffs ) { + var op, data, x, html = []; + for ( x = 0; x < diffs.length; x++ ) { + op = diffs[x][0]; // Operation (insert, delete, equal) + data = diffs[x][1]; // Text of change. + switch ( op ) { + case DIFF_INSERT: + html[x] = "" + data + ""; + break; + case DIFF_DELETE: + html[x] = "" + data + ""; + break; + case DIFF_EQUAL: + html[x] = "" + data + ""; + break; + } + } + return html.join(""); + }; + + /** + * Determine the common prefix of two strings. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {number} The number of characters common to the start of each + * string. + */ + DiffMatchPatch.prototype.diffCommonPrefix = function( text1, text2 ) { + var pointermid, pointermax, pointermin, pointerstart; + // Quick check for common null cases. + if ( !text1 || !text2 || text1.charAt(0) !== text2.charAt(0) ) { + return 0; + } + // Binary search. + // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + pointermin = 0; + pointermax = Math.min( text1.length, text2.length ); + pointermid = pointermax; + pointerstart = 0; + while ( pointermin < pointermid ) { + if ( text1.substring( pointerstart, pointermid ) === text2.substring( pointerstart, pointermid ) ) { + pointermin = pointermid; + pointerstart = pointermin; + } else { + pointermax = pointermid; + } + pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin ); + } + return pointermid; + }; + + /** + * Determine the common suffix of two strings. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {number} The number of characters common to the end of each string. + */ + DiffMatchPatch.prototype.diffCommonSuffix = function( text1, text2 ) { + var pointermid, pointermax, pointermin, pointerend; + // Quick check for common null cases. + if (!text1 || !text2 || text1.charAt(text1.length - 1) !== text2.charAt(text2.length - 1)) { + return 0; + } + // Binary search. + // Performance analysis: http://neil.fraser.name/news/2007/10/09/ + pointermin = 0; + pointermax = Math.min(text1.length, text2.length); + pointermid = pointermax; + pointerend = 0; + while ( pointermin < pointermid ) { + if (text1.substring( text1.length - pointermid, text1.length - pointerend ) === + text2.substring( text2.length - pointermid, text2.length - pointerend ) ) { + pointermin = pointermid; + pointerend = pointermin; + } else { + pointermax = pointermid; + } + pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin ); + } + return pointermid; + }; + + /** + * Find the differences between two texts. Assumes that the texts do not + * have any common prefix or suffix. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {boolean} checklines Speedup flag. If false, then don't run a + * line-level diff first to identify the changed areas. + * If true, then run a faster, slightly less optimal diff. + * @param {number} deadline Time when the diff should be complete by. + * @return {!Array.} Array of diff tuples. + * @private + */ + DiffMatchPatch.prototype.diffCompute = function( text1, text2, checklines, deadline ) { + var diffs, longtext, shorttext, i, hm, + text1A, text2A, text1B, text2B, + midCommon, diffsA, diffsB; + + if ( !text1 ) { + // Just add some text (speedup). + return [ + [ DIFF_INSERT, text2 ] + ]; + } + + if (!text2) { + // Just delete some text (speedup). + return [ + [ DIFF_DELETE, text1 ] + ]; + } + + longtext = text1.length > text2.length ? text1 : text2; + shorttext = text1.length > text2.length ? text2 : text1; + i = longtext.indexOf( shorttext ); + if ( i !== -1 ) { + // Shorter text is inside the longer text (speedup). + diffs = [ + [ DIFF_INSERT, longtext.substring( 0, i ) ], + [ DIFF_EQUAL, shorttext ], + [ DIFF_INSERT, longtext.substring( i + shorttext.length ) ] + ]; + // Swap insertions for deletions if diff is reversed. + if ( text1.length > text2.length ) { + diffs[0][0] = diffs[2][0] = DIFF_DELETE; + } + return diffs; + } + + if ( shorttext.length === 1 ) { + // Single character string. + // After the previous speedup, the character can't be an equality. + return [ + [ DIFF_DELETE, text1 ], + [ DIFF_INSERT, text2 ] + ]; + } + + // Check to see if the problem can be split in two. + hm = this.diffHalfMatch(text1, text2); + if (hm) { + // A half-match was found, sort out the return data. + text1A = hm[0]; + text1B = hm[1]; + text2A = hm[2]; + text2B = hm[3]; + midCommon = hm[4]; + // Send both pairs off for separate processing. + diffsA = this.DiffMain(text1A, text2A, checklines, deadline); + diffsB = this.DiffMain(text1B, text2B, checklines, deadline); + // Merge the results. + return diffsA.concat([ + [ DIFF_EQUAL, midCommon ] + ], diffsB); + } + + if (checklines && text1.length > 100 && text2.length > 100) { + return this.diffLineMode(text1, text2, deadline); + } + + return this.diffBisect(text1, text2, deadline); + }; + + /** + * Do the two texts share a substring which is at least half the length of the + * longer text? + * This speedup can produce non-minimal diffs. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {Array.} Five element Array, containing the prefix of + * text1, the suffix of text1, the prefix of text2, the suffix of + * text2 and the common middle. Or null if there was no match. + * @private + */ + DiffMatchPatch.prototype.diffHalfMatch = function(text1, text2) { + var longtext, shorttext, dmp, + text1A, text2B, text2A, text1B, midCommon, + hm1, hm2, hm; + if (this.DiffTimeout <= 0) { + // Don't risk returning a non-optimal diff if we have unlimited time. + return null; + } + longtext = text1.length > text2.length ? text1 : text2; + shorttext = text1.length > text2.length ? text2 : text1; + if (longtext.length < 4 || shorttext.length * 2 < longtext.length) { + return null; // Pointless. + } + dmp = this; // 'this' becomes 'window' in a closure. + + /** + * Does a substring of shorttext exist within longtext such that the substring + * is at least half the length of longtext? + * Closure, but does not reference any external variables. + * @param {string} longtext Longer string. + * @param {string} shorttext Shorter string. + * @param {number} i Start index of quarter length substring within longtext. + * @return {Array. } Five element Array, containing the prefix of + * longtext, the suffix of longtext, the prefix of shorttext, the suffix + * of shorttext and the common middle. Or null if there was no match. + * @private + */ + function diffHalfMatchI(longtext, shorttext, i) { + var seed, j, bestCommon, prefixLength, suffixLength, + bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB; + // Start with a 1/4 length substring at position i as a seed. + seed = longtext.substring(i, i + Math.floor(longtext.length / 4)); + j = -1; + bestCommon = ""; + while ((j = shorttext.indexOf(seed, j + 1)) !== -1) { + prefixLength = dmp.diffCommonPrefix(longtext.substring(i), + shorttext.substring(j)); + suffixLength = dmp.diffCommonSuffix(longtext.substring(0, i), + shorttext.substring(0, j)); + if (bestCommon.length < suffixLength + prefixLength) { + bestCommon = shorttext.substring(j - suffixLength, j) + + shorttext.substring(j, j + prefixLength); + bestLongtextA = longtext.substring(0, i - suffixLength); + bestLongtextB = longtext.substring(i + prefixLength); + bestShorttextA = shorttext.substring(0, j - suffixLength); + bestShorttextB = shorttext.substring(j + prefixLength); + } + } + if (bestCommon.length * 2 >= longtext.length) { + return [ bestLongtextA, bestLongtextB, + bestShorttextA, bestShorttextB, bestCommon + ]; + } else { + return null; + } + } + + // First check if the second quarter is the seed for a half-match. + hm1 = diffHalfMatchI(longtext, shorttext, + Math.ceil(longtext.length / 4)); + // Check again based on the third quarter. + hm2 = diffHalfMatchI(longtext, shorttext, + Math.ceil(longtext.length / 2)); + if (!hm1 && !hm2) { + return null; + } else if (!hm2) { + hm = hm1; + } else if (!hm1) { + hm = hm2; + } else { + // Both matched. Select the longest. + hm = hm1[4].length > hm2[4].length ? hm1 : hm2; + } + + // A half-match was found, sort out the return data. + text1A, text1B, text2A, text2B; + if (text1.length > text2.length) { + text1A = hm[0]; + text1B = hm[1]; + text2A = hm[2]; + text2B = hm[3]; + } else { + text2A = hm[0]; + text2B = hm[1]; + text1A = hm[2]; + text1B = hm[3]; + } + midCommon = hm[4]; + return [ text1A, text1B, text2A, text2B, midCommon ]; + }; + + /** + * Do a quick line-level diff on both strings, then rediff the parts for + * greater accuracy. + * This speedup can produce non-minimal diffs. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {number} deadline Time when the diff should be complete by. + * @return {!Array.} Array of diff tuples. + * @private + */ + DiffMatchPatch.prototype.diffLineMode = function(text1, text2, deadline) { + var a, diffs, linearray, pointer, countInsert, + countDelete, textInsert, textDelete, j; + // Scan the text on a line-by-line basis first. + a = this.diffLinesToChars(text1, text2); + text1 = a.chars1; + text2 = a.chars2; + linearray = a.lineArray; + + diffs = this.DiffMain(text1, text2, false, deadline); + + // Convert the diff back to original text. + this.diffCharsToLines(diffs, linearray); + // Eliminate freak matches (e.g. blank lines) + this.diffCleanupSemantic(diffs); + + // Rediff any replacement blocks, this time character-by-character. + // Add a dummy entry at the end. + diffs.push( [ DIFF_EQUAL, "" ] ); + pointer = 0; + countDelete = 0; + countInsert = 0; + textDelete = ""; + textInsert = ""; + while (pointer < diffs.length) { + switch ( diffs[pointer][0] ) { + case DIFF_INSERT: + countInsert++; + textInsert += diffs[pointer][1]; + break; + case DIFF_DELETE: + countDelete++; + textDelete += diffs[pointer][1]; + break; + case DIFF_EQUAL: + // Upon reaching an equality, check for prior redundancies. + if (countDelete >= 1 && countInsert >= 1) { + // Delete the offending records and add the merged ones. + diffs.splice(pointer - countDelete - countInsert, + countDelete + countInsert); + pointer = pointer - countDelete - countInsert; + a = this.DiffMain(textDelete, textInsert, false, deadline); + for (j = a.length - 1; j >= 0; j--) { + diffs.splice( pointer, 0, a[j] ); + } + pointer = pointer + a.length; + } + countInsert = 0; + countDelete = 0; + textDelete = ""; + textInsert = ""; + break; + } + pointer++; + } + diffs.pop(); // Remove the dummy entry at the end. + + return diffs; + }; + + /** + * Find the 'middle snake' of a diff, split the problem in two + * and return the recursively constructed diff. + * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {number} deadline Time at which to bail if not yet complete. + * @return {!Array.} Array of diff tuples. + * @private + */ + DiffMatchPatch.prototype.diffBisect = function(text1, text2, deadline) { + var text1Length, text2Length, maxD, vOffset, vLength, + v1, v2, x, delta, front, k1start, k1end, k2start, + k2end, k2Offset, k1Offset, x1, x2, y1, y2, d, k1, k2; + // Cache the text lengths to prevent multiple calls. + text1Length = text1.length; + text2Length = text2.length; + maxD = Math.ceil((text1Length + text2Length) / 2); + vOffset = maxD; + vLength = 2 * maxD; + v1 = new Array(vLength); + v2 = new Array(vLength); + // Setting all elements to -1 is faster in Chrome & Firefox than mixing + // integers and undefined. + for (x = 0; x < vLength; x++) { + v1[x] = -1; + v2[x] = -1; + } + v1[vOffset + 1] = 0; + v2[vOffset + 1] = 0; + delta = text1Length - text2Length; + // If the total number of characters is odd, then the front path will collide + // with the reverse path. + front = (delta % 2 !== 0); + // Offsets for start and end of k loop. + // Prevents mapping of space beyond the grid. + k1start = 0; + k1end = 0; + k2start = 0; + k2end = 0; + for (d = 0; d < maxD; d++) { + // Bail out if deadline is reached. + if ((new Date()).getTime() > deadline) { + break; + } + + // Walk the front path one step. + for (k1 = -d + k1start; k1 <= d - k1end; k1 += 2) { + k1Offset = vOffset + k1; + if ( k1 === -d || ( k1 !== d && v1[ k1Offset - 1 ] < v1[ k1Offset + 1 ] ) ) { + x1 = v1[k1Offset + 1]; + } else { + x1 = v1[k1Offset - 1] + 1; + } + y1 = x1 - k1; + while (x1 < text1Length && y1 < text2Length && + text1.charAt(x1) === text2.charAt(y1)) { + x1++; + y1++; + } + v1[k1Offset] = x1; + if (x1 > text1Length) { + // Ran off the right of the graph. + k1end += 2; + } else if (y1 > text2Length) { + // Ran off the bottom of the graph. + k1start += 2; + } else if (front) { + k2Offset = vOffset + delta - k1; + if (k2Offset >= 0 && k2Offset < vLength && v2[k2Offset] !== -1) { + // Mirror x2 onto top-left coordinate system. + x2 = text1Length - v2[k2Offset]; + if (x1 >= x2) { + // Overlap detected. + return this.diffBisectSplit(text1, text2, x1, y1, deadline); + } + } + } + } + + // Walk the reverse path one step. + for (k2 = -d + k2start; k2 <= d - k2end; k2 += 2) { + k2Offset = vOffset + k2; + if ( k2 === -d || (k2 !== d && v2[ k2Offset - 1 ] < v2[ k2Offset + 1 ] ) ) { + x2 = v2[k2Offset + 1]; + } else { + x2 = v2[k2Offset - 1] + 1; + } + y2 = x2 - k2; + while (x2 < text1Length && y2 < text2Length && + text1.charAt(text1Length - x2 - 1) === + text2.charAt(text2Length - y2 - 1)) { + x2++; + y2++; + } + v2[k2Offset] = x2; + if (x2 > text1Length) { + // Ran off the left of the graph. + k2end += 2; + } else if (y2 > text2Length) { + // Ran off the top of the graph. + k2start += 2; + } else if (!front) { + k1Offset = vOffset + delta - k2; + if (k1Offset >= 0 && k1Offset < vLength && v1[k1Offset] !== -1) { + x1 = v1[k1Offset]; + y1 = vOffset + x1 - k1Offset; + // Mirror x2 onto top-left coordinate system. + x2 = text1Length - x2; + if (x1 >= x2) { + // Overlap detected. + return this.diffBisectSplit(text1, text2, x1, y1, deadline); + } + } + } + } + } + // Diff took too long and hit the deadline or + // number of diffs equals number of characters, no commonality at all. + return [ + [ DIFF_DELETE, text1 ], + [ DIFF_INSERT, text2 ] + ]; + }; + + /** + * Given the location of the 'middle snake', split the diff in two parts + * and recurse. + * @param {string} text1 Old string to be diffed. + * @param {string} text2 New string to be diffed. + * @param {number} x Index of split point in text1. + * @param {number} y Index of split point in text2. + * @param {number} deadline Time at which to bail if not yet complete. + * @return {!Array.} Array of diff tuples. + * @private + */ + DiffMatchPatch.prototype.diffBisectSplit = function( text1, text2, x, y, deadline ) { + var text1a, text1b, text2a, text2b, diffs, diffsb; + text1a = text1.substring(0, x); + text2a = text2.substring(0, y); + text1b = text1.substring(x); + text2b = text2.substring(y); + + // Compute both diffs serially. + diffs = this.DiffMain(text1a, text2a, false, deadline); + diffsb = this.DiffMain(text1b, text2b, false, deadline); + + return diffs.concat(diffsb); + }; + + /** + * Reduce the number of edits by eliminating semantically trivial equalities. + * @param {!Array.} diffs Array of diff tuples. + */ + DiffMatchPatch.prototype.diffCleanupSemantic = function(diffs) { + var changes, equalities, equalitiesLength, lastequality, + pointer, lengthInsertions2, lengthDeletions2, lengthInsertions1, + lengthDeletions1, deletion, insertion, overlapLength1, overlapLength2; + changes = false; + equalities = []; // Stack of indices where equalities are found. + equalitiesLength = 0; // Keeping our own length var is faster in JS. + /** @type {?string} */ + lastequality = null; + // Always equal to diffs[equalities[equalitiesLength - 1]][1] + pointer = 0; // Index of current position. + // Number of characters that changed prior to the equality. + lengthInsertions1 = 0; + lengthDeletions1 = 0; + // Number of characters that changed after the equality. + lengthInsertions2 = 0; + lengthDeletions2 = 0; + while (pointer < diffs.length) { + if (diffs[pointer][0] === DIFF_EQUAL) { // Equality found. + equalities[equalitiesLength++] = pointer; + lengthInsertions1 = lengthInsertions2; + lengthDeletions1 = lengthDeletions2; + lengthInsertions2 = 0; + lengthDeletions2 = 0; + lastequality = diffs[pointer][1]; + } else { // An insertion or deletion. + if (diffs[pointer][0] === DIFF_INSERT) { + lengthInsertions2 += diffs[pointer][1].length; + } else { + lengthDeletions2 += diffs[pointer][1].length; + } + // Eliminate an equality that is smaller or equal to the edits on both + // sides of it. + if (lastequality && (lastequality.length <= + Math.max(lengthInsertions1, lengthDeletions1)) && + (lastequality.length <= Math.max(lengthInsertions2, + lengthDeletions2))) { + // Duplicate record. + diffs.splice( equalities[ equalitiesLength - 1 ], 0, [ DIFF_DELETE, lastequality ] ); + // Change second copy to insert. + diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT; + // Throw away the equality we just deleted. + equalitiesLength--; + // Throw away the previous equality (it needs to be reevaluated). + equalitiesLength--; + pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1; + lengthInsertions1 = 0; // Reset the counters. + lengthDeletions1 = 0; + lengthInsertions2 = 0; + lengthDeletions2 = 0; + lastequality = null; + changes = true; + } + } + pointer++; + } + + // Normalize the diff. + if (changes) { + this.diffCleanupMerge(diffs); + } + + // Find any overlaps between deletions and insertions. + // e.g: abcxxxxxxdef + // ->abcxxxdef + // e.g:xxxabcdefxxx + // -> defxxxabc+ // Only extract an overlap if it is as big as the edit ahead or behind it. + pointer = 1; + while (pointer < diffs.length) { + if (diffs[pointer - 1][0] === DIFF_DELETE && + diffs[pointer][0] === DIFF_INSERT) { + deletion = diffs[pointer - 1][1]; + insertion = diffs[pointer][1]; + overlapLength1 = this.diffCommonOverlap(deletion, insertion); + overlapLength2 = this.diffCommonOverlap(insertion, deletion); + if (overlapLength1 >= overlapLength2) { + if (overlapLength1 >= deletion.length / 2 || + overlapLength1 >= insertion.length / 2) { + // Overlap found. Insert an equality and trim the surrounding edits. + diffs.splice( pointer, 0, [ DIFF_EQUAL, insertion.substring( 0, overlapLength1 ) ] ); + diffs[pointer - 1][1] = + deletion.substring(0, deletion.length - overlapLength1); + diffs[pointer + 1][1] = insertion.substring(overlapLength1); + pointer++; + } + } else { + if (overlapLength2 >= deletion.length / 2 || + overlapLength2 >= insertion.length / 2) { + // Reverse overlap found. + // Insert an equality and swap and trim the surrounding edits. + diffs.splice( pointer, 0, [ DIFF_EQUAL, deletion.substring( 0, overlapLength2 ) ] ); + diffs[pointer - 1][0] = DIFF_INSERT; + diffs[pointer - 1][1] = + insertion.substring(0, insertion.length - overlapLength2); + diffs[pointer + 1][0] = DIFF_DELETE; + diffs[pointer + 1][1] = + deletion.substring(overlapLength2); + pointer++; + } + } + pointer++; + } + pointer++; + } + }; + + /** + * Determine if the suffix of one string is the prefix of another. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {number} The number of characters common to the end of the first + * string and the start of the second string. + * @private + */ + DiffMatchPatch.prototype.diffCommonOverlap = function(text1, text2) { + var text1Length, text2Length, textLength, + best, length, pattern, found; + // Cache the text lengths to prevent multiple calls. + text1Length = text1.length; + text2Length = text2.length; + // Eliminate the null case. + if (text1Length === 0 || text2Length === 0) { + return 0; + } + // Truncate the longer string. + if (text1Length > text2Length) { + text1 = text1.substring(text1Length - text2Length); + } else if (text1Length < text2Length) { + text2 = text2.substring(0, text1Length); + } + textLength = Math.min(text1Length, text2Length); + // Quick check for the worst case. + if (text1 === text2) { + return textLength; + } + + // Start by looking for a single character match + // and increase length until no match is found. + // Performance analysis: http://neil.fraser.name/news/2010/11/04/ + best = 0; + length = 1; + while (true) { + pattern = text1.substring(textLength - length); + found = text2.indexOf(pattern); + if (found === -1) { + return best; + } + length += found; + if (found === 0 || text1.substring(textLength - length) === + text2.substring(0, length)) { + best = length; + length++; + } + } + }; + + /** + * Split two texts into an array of strings. Reduce the texts to a string of + * hashes where each Unicode character represents one line. + * @param {string} text1 First string. + * @param {string} text2 Second string. + * @return {{chars1: string, chars2: string, lineArray: !Array.}} + * An object containing the encoded text1, the encoded text2 and + * the array of unique strings. + * The zeroth element of the array of unique strings is intentionally blank. + * @private + */ + DiffMatchPatch.prototype.diffLinesToChars = function(text1, text2) { + var lineArray, lineHash, chars1, chars2; + lineArray = []; // e.g. lineArray[4] === 'Hello\n' + lineHash = {}; // e.g. lineHash['Hello\n'] === 4 + + // '\x00' is a valid character, but various debuggers don't like it. + // So we'll insert a junk entry to avoid generating a null character. + lineArray[0] = ""; + + /** + * Split a text into an array of strings. Reduce the texts to a string of + * hashes where each Unicode character represents one line. + * Modifies linearray and linehash through being a closure. + * @param {string} text String to encode. + * @return {string} Encoded string. + * @private + */ + function diffLinesToCharsMunge(text) { + var chars, lineStart, lineEnd, lineArrayLength, line; + chars = ""; + // Walk the text, pulling out a substring for each line. + // text.split('\n') would would temporarily double our memory footprint. + // Modifying text would create many large strings to garbage collect. + lineStart = 0; + lineEnd = -1; + // Keeping our own length variable is faster than looking it up. + lineArrayLength = lineArray.length; + while (lineEnd < text.length - 1) { + lineEnd = text.indexOf("\n", lineStart); + if (lineEnd === -1) { + lineEnd = text.length - 1; + } + line = text.substring(lineStart, lineEnd + 1); + lineStart = lineEnd + 1; + + if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : + (lineHash[line] !== undefined)) { + chars += String.fromCharCode( lineHash[ line ] ); + } else { + chars += String.fromCharCode(lineArrayLength); + lineHash[line] = lineArrayLength; + lineArray[lineArrayLength++] = line; + } + } + return chars; + } + + chars1 = diffLinesToCharsMunge(text1); + chars2 = diffLinesToCharsMunge(text2); + return { + chars1: chars1, + chars2: chars2, + lineArray: lineArray + }; + }; + + /** + * Rehydrate the text in a diff from a string of line hashes to real lines of + * text. + * @param {!Array.} diffs Array of diff tuples. + * @param {!Array. } lineArray Array of unique strings. + * @private + */ + DiffMatchPatch.prototype.diffCharsToLines = function( diffs, lineArray ) { + var x, chars, text, y; + for ( x = 0; x < diffs.length; x++ ) { + chars = diffs[x][1]; + text = []; + for ( y = 0; y < chars.length; y++ ) { + text[y] = lineArray[chars.charCodeAt(y)]; + } + diffs[x][1] = text.join(""); + } + }; + + /** + * Reorder and merge like edit sections. Merge equalities. + * Any edit section can move as long as it doesn't cross an equality. + * @param {!Array.} diffs Array of diff tuples. + */ + DiffMatchPatch.prototype.diffCleanupMerge = function(diffs) { + var pointer, countDelete, countInsert, textInsert, textDelete, + commonlength, changes; + diffs.push( [ DIFF_EQUAL, "" ] ); // Add a dummy entry at the end. + pointer = 0; + countDelete = 0; + countInsert = 0; + textDelete = ""; + textInsert = ""; + commonlength; + while (pointer < diffs.length) { + switch ( diffs[ pointer ][ 0 ] ) { + case DIFF_INSERT: + countInsert++; + textInsert += diffs[pointer][1]; + pointer++; + break; + case DIFF_DELETE: + countDelete++; + textDelete += diffs[pointer][1]; + pointer++; + break; + case DIFF_EQUAL: + // Upon reaching an equality, check for prior redundancies. + if (countDelete + countInsert > 1) { + if (countDelete !== 0 && countInsert !== 0) { + // Factor out any common prefixies. + commonlength = this.diffCommonPrefix(textInsert, textDelete); + if (commonlength !== 0) { + if ((pointer - countDelete - countInsert) > 0 && + diffs[pointer - countDelete - countInsert - 1][0] === + DIFF_EQUAL) { + diffs[pointer - countDelete - countInsert - 1][1] += + textInsert.substring(0, commonlength); + } else { + diffs.splice( 0, 0, [ DIFF_EQUAL, + textInsert.substring( 0, commonlength ) + ] ); + pointer++; + } + textInsert = textInsert.substring(commonlength); + textDelete = textDelete.substring(commonlength); + } + // Factor out any common suffixies. + commonlength = this.diffCommonSuffix(textInsert, textDelete); + if (commonlength !== 0) { + diffs[pointer][1] = textInsert.substring(textInsert.length - + commonlength) + diffs[pointer][1]; + textInsert = textInsert.substring(0, textInsert.length - + commonlength); + textDelete = textDelete.substring(0, textDelete.length - + commonlength); + } + } + // Delete the offending records and add the merged ones. + if (countDelete === 0) { + diffs.splice( pointer - countInsert, + countDelete + countInsert, [ DIFF_INSERT, textInsert ] ); + } else if (countInsert === 0) { + diffs.splice( pointer - countDelete, + countDelete + countInsert, [ DIFF_DELETE, textDelete ] ); + } else { + diffs.splice( pointer - countDelete - countInsert, + countDelete + countInsert, [ DIFF_DELETE, textDelete ], [ DIFF_INSERT, textInsert ] ); + } + pointer = pointer - countDelete - countInsert + + (countDelete ? 1 : 0) + (countInsert ? 1 : 0) + 1; + } else if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) { + // Merge this equality with the previous one. + diffs[pointer - 1][1] += diffs[pointer][1]; + diffs.splice(pointer, 1); + } else { + pointer++; + } + countInsert = 0; + countDelete = 0; + textDelete = ""; + textInsert = ""; + break; + } + } + if (diffs[diffs.length - 1][1] === "") { + diffs.pop(); // Remove the dummy entry at the end. + } + + // Second pass: look for single edits surrounded on both sides by equalities + // which can be shifted sideways to eliminate an equality. + // e.g: ABAC -> ABAC + changes = false; + pointer = 1; + // Intentionally ignore the first and last element (don't need checking). + while (pointer < diffs.length - 1) { + if (diffs[pointer - 1][0] === DIFF_EQUAL && + diffs[pointer + 1][0] === DIFF_EQUAL) { + // This is a single edit surrounded by equalities. + if ( diffs[ pointer ][ 1 ].substring( diffs[ pointer ][ 1 ].length - + diffs[ pointer - 1 ][ 1 ].length ) === diffs[ pointer - 1 ][ 1 ] ) { + // Shift the edit over the previous equality. + diffs[pointer][1] = diffs[pointer - 1][1] + + diffs[pointer][1].substring(0, diffs[pointer][1].length - + diffs[pointer - 1][1].length); + diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1]; + diffs.splice(pointer - 1, 1); + changes = true; + } else if ( diffs[ pointer ][ 1 ].substring( 0, diffs[ pointer + 1 ][ 1 ].length ) === + diffs[ pointer + 1 ][ 1 ] ) { + // Shift the edit over the next equality. + diffs[pointer - 1][1] += diffs[pointer + 1][1]; + diffs[pointer][1] = + diffs[pointer][1].substring(diffs[pointer + 1][1].length) + + diffs[pointer + 1][1]; + diffs.splice(pointer + 1, 1); + changes = true; + } + } + pointer++; + } + // If shifts were made, the diff needs reordering and another shift sweep. + if (changes) { + this.diffCleanupMerge(diffs); + } + }; + + return function(o, n) { + var diff, output, text; + diff = new DiffMatchPatch(); + output = diff.DiffMain(o, n); + //console.log(output); + diff.diffCleanupEfficiency(output); + text = diff.diffPrettyHtml(output); + + return text; + }; }()); // jscs:enable @@ -2256,7 +3176,14 @@ function addEvent( elem, type, fn ) { } else if ( elem.attachEvent ) { // support: IE <9 - elem.attachEvent( "on" + type, fn ); + elem.attachEvent( "on" + type, function() { + var event = window.event; + if ( !event.target ) { + event.target = event.srcElement || document; + } + + fn.call( elem, event ); + }); } } @@ -2427,12 +3354,16 @@ function setUrl( params ) { } function applyUrlParams() { - var selectBox = id( "qunit-modulefilter" ), - selection = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value ), + var selectedModule, + modulesList = id( "qunit-modulefilter" ), filter = id( "qunit-filter-input" ).value; + selectedModule = modulesList ? + decodeURIComponent( modulesList.options[ modulesList.selectedIndex ].value ) : + undefined; + window.location = setUrl({ - module: ( selection === "" ) ? undefined : selection, + module: ( selectedModule === "" ) ? undefined : selectedModule, filter: ( filter === "" ) ? undefined : filter, // Remove testId filter @@ -2588,9 +3519,14 @@ function storeFixture() { function appendUserAgent() { var userAgent = id( "qunit-userAgent" ); + if ( userAgent ) { userAgent.innerHTML = ""; - userAgent.appendChild( document.createTextNode( navigator.userAgent ) ); + userAgent.appendChild( + document.createTextNode( + "QUnit " + QUnit.version + "; " + navigator.userAgent + ) + ); } } @@ -2696,7 +3632,7 @@ QUnit.done(function( details ) { if ( config.altertitle && defined.document && document.title ) { - // show ✖ for good, ✔ for bad suite result in title + // show ✖ for good, ✔ for bad suite result in title // use escape sequences in case file gets loaded with non-utf-8-charset document.title = [ ( details.failed ? "\u2716" : "\u2714" ), @@ -2733,7 +3669,7 @@ function getNameHtml( name, module ) { } QUnit.testStart(function( details ) { - var running, testBlock; + var running, testBlock, bad; testBlock = id( "qunit-test-output-" + details.testId ); if ( testBlock ) { @@ -2746,7 +3682,13 @@ QUnit.testStart(function( details ) { running = id( "qunit-testresult" ); if ( running ) { - running.innerHTML = "Running:
" + getNameHtml( details.name, details.module ); + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + details.module + "-" + details.name ); + + running.innerHTML = ( bad ? + "Rerunning previously failed test:
" : + "Running:
" ) + + getNameHtml( details.name, details.module ); } }); @@ -2779,6 +3721,15 @@ QUnit.log(function( details ) { actual + ""; + } else { + if ( expected.indexOf( "[object Array]" ) !== -1 || + expected.indexOf( "[object Object]" ) !== -1 ) { + message += " "; + } } if ( details.source ) { @@ -2863,13 +3814,15 @@ QUnit.testDone(function( details ) { } }); -if ( !defined.document || document.readyState === "complete" ) { +if ( defined.document ) { + if ( document.readyState === "complete" ) { + QUnit.load(); + } else { + addEvent( window, "load", QUnit.load ); + } +} else { config.pageLoaded = true; config.autorun = true; } -if ( defined.document ) { - addEvent( window, "load", QUnit.load ); -} - -})(); \ No newline at end of file +})(); From fce4a78514830f9f2f4d666f9a252b4415db954d Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Diff: " + QUnit.diff( expected, actual ) + "Date: Sun, 13 Dec 2015 20:35:30 -0800 Subject: [PATCH 119/263] Replace global test() with QUnit.test Helps avoid implicit globals, and starts us on the path toward compatibility with QUnit 2.0. --- test/.eslintrc | 1 - test/arrays.js | 60 ++++++++++++++-------------- test/chaining.js | 18 ++++----- test/collections.js | 88 +++++++++++++++++++++--------------------- test/cross-document.js | 36 ++++++++--------- test/functions.js | 26 ++++++------- test/objects.js | 80 +++++++++++++++++++------------------- test/utility.js | 62 ++++++++++++++--------------- 8 files changed, 185 insertions(+), 186 deletions(-) diff --git a/test/.eslintrc b/test/.eslintrc index 8ced41115..b7af19c2e 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -3,7 +3,6 @@ "browser": true }, "globals": { - "test": false, "ok": false, "is": false, "equal": false, diff --git a/test/arrays.js b/test/arrays.js index d159b37a8..953116a40 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -3,7 +3,7 @@ QUnit.module('Arrays'); - test('first', function(assert) { + QUnit.test('first', function(assert) { assert.equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array'); assert.equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"'); assert.deepEqual(_.first([1, 2, 3], 0), [], 'returns an empty array when n <= 0 (0 case)'); @@ -17,15 +17,15 @@ assert.equal(_.first(null), void 0, 'returns undefined when called on null'); }); - test('head', function(assert) { + QUnit.test('head', function(assert) { assert.strictEqual(_.head, _.first, 'is an alias for first'); }); - test('take', function(assert) { + QUnit.test('take', function(assert) { assert.strictEqual(_.take, _.first, 'is an alias for first'); }); - test('rest', function(assert) { + QUnit.test('rest', function(assert) { var numbers = [1, 2, 3, 4]; assert.deepEqual(_.rest(numbers), [2, 3, 4], 'fetches all but the first element'); assert.deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'returns the whole array when index is 0'); @@ -36,15 +36,15 @@ assert.deepEqual(_.flatten(result), [2, 3, 2, 3], 'works well with _.map'); }); - test('tail', function(assert) { + QUnit.test('tail', function(assert) { assert.strictEqual(_.tail, _.rest, 'is an alias for rest'); }); - test('drop', function(assert) { + QUnit.test('drop', function(assert) { assert.strictEqual(_.drop, _.rest, 'is an alias for rest'); }); - test('initial', function(assert) { + QUnit.test('initial', function(assert) { assert.deepEqual(_.initial([1, 2, 3, 4, 5]), [1, 2, 3, 4], 'returns all but the last element'); assert.deepEqual(_.initial([1, 2, 3, 4], 2), [1, 2], 'returns all but the last n elements'); assert.deepEqual(_.initial([1, 2, 3, 4], 6), [], 'returns an empty array when n > length'); @@ -54,7 +54,7 @@ assert.deepEqual(_.flatten(result), [1, 2, 1, 2], 'works well with _.map'); }); - test('last', function(assert) { + QUnit.test('last', function(assert) { assert.equal(_.last([1, 2, 3]), 3, 'can pull out the last element of an array'); assert.equal(_([1, 2, 3]).last(), 3, 'can perform OO-style "last()"'); assert.deepEqual(_.last([1, 2, 3], 0), [], 'returns an empty array when n <= 0 (0 case)'); @@ -68,7 +68,7 @@ assert.equal(_.last(null), void 0, 'returns undefined when called on null'); }); - test('compact', function(assert) { + QUnit.test('compact', function(assert) { assert.deepEqual(_.compact([1, false, null, 0, '', void 0, NaN, 2]), [1, 2], 'removes all falsy values'); var result = (function(){ return _.compact(arguments); }(0, 1, false, 2, false, 3)); assert.deepEqual(result, [1, 2, 3], 'works on an arguments object'); @@ -76,7 +76,7 @@ assert.deepEqual(result, [[1], [3]], 'works well with _.map'); }); - test('flatten', function(assert) { + QUnit.test('flatten', function(assert) { assert.deepEqual(_.flatten(null), [], 'supports null'); assert.deepEqual(_.flatten(void 0), [], 'supports undefined'); @@ -102,7 +102,7 @@ assert.deepEqual(_.flatten(x, true), x[0], 'can handle very deep arrays in shallow mode'); }); - test('without', function(assert) { + QUnit.test('without', function(assert) { var list = [1, 2, 1, 0, 3, 1, 4]; assert.deepEqual(_.without(list, 0, 1), [2, 3, 4], 'removes all instances of the given values'); var result = (function(){ return _.without(arguments, 0, 1); }(1, 2, 1, 0, 3, 1, 4)); @@ -113,7 +113,7 @@ assert.deepEqual(_.without(list, list[0]), [{two: 2}], 'compares objects by reference (reference case)'); }); - test('sortedIndex', function(assert) { + QUnit.test('sortedIndex', function(assert) { var numbers = [10, 20, 30, 40, 50]; var indexFor35 = _.sortedIndex(numbers, 35); assert.equal(indexFor35, 3, 'finds the index at which a value should be inserted to retain order'); @@ -140,7 +140,7 @@ assert.equal(_.sortedIndex(largeArray, 2147483648), 2147483648, 'works with large indexes'); }); - test('uniq', function(assert) { + QUnit.test('uniq', function(assert) { var list = [1, 2, 1, 3, 1, 4]; assert.deepEqual(_.uniq(list), [1, 2, 3, 4], 'can find the unique values of an unsorted array'); @@ -192,11 +192,11 @@ assert.deepEqual(_.uniq([{0: 1, b: 1}, {0: 1, b: 2}, {0: 1, b: 3}, {0: 2, b: 1}], 0), [{0: 1, b: 1}, {0: 2, b: 1}], 'can use falsey pluck like iterator'); }); - test('unique', function(assert) { + QUnit.test('unique', function(assert) { assert.strictEqual(_.unique, _.uniq, 'is an alias for uniq'); }); - test('intersection', function(assert) { + QUnit.test('intersection', function(assert) { var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho']; assert.deepEqual(_.intersection(stooges, leaders), ['moe'], 'can take the set intersection of two arrays'); assert.deepEqual(_(stooges).intersection(leaders), ['moe'], 'can perform an OO-style intersection'); @@ -214,7 +214,7 @@ assert.equal(result.length, 0, 'returns an empty array when passed null as argument beyond the first'); }); - test('union', function(assert) { + QUnit.test('union', function(assert) { var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]); assert.deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays'); @@ -230,7 +230,7 @@ assert.deepEqual(result, [1, 2, 3], 'restrict the union to arrays only'); }); - test('difference', function(assert) { + QUnit.test('difference', function(assert) { var result = _.difference([1, 2, 3], [2, 30, 40]); assert.deepEqual(result, [1, 3], 'takes the difference of two arrays'); @@ -241,7 +241,7 @@ assert.deepEqual(result, [1, 2, 3], 'restrict the difference to arrays only'); }); - test('zip', function(assert) { + QUnit.test('zip', function(assert) { var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true]; assert.deepEqual(_.zip(names, ages, leaders), [ ['moe', 30, true], @@ -264,7 +264,7 @@ assert.deepEqual(_.zip(), [], '_.zip() returns []'); }); - test('unzip', function(assert) { + QUnit.test('unzip', function(assert) { assert.deepEqual(_.unzip(null), [], 'handles null'); assert.deepEqual(_.unzip([['a', 'b'], [1, 2]]), [['a', 1], ['b', 2]]); @@ -277,7 +277,7 @@ assert.deepEqual(_.unzip(zipped), [['moe', 30, void 0], ['larry', 40, void 0], ['curly', 50, 'extra data']], 'Uses length of largest array'); }); - test('object', function(assert) { + QUnit.test('object', function(assert) { var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]); var shouldBe = {moe: 30, larry: 40, curly: 50}; assert.deepEqual(result, shouldBe, 'two arrays zipped together into an object'); @@ -292,7 +292,7 @@ assert.deepEqual(_.object(null), {}, 'handles nulls'); }); - test('indexOf', function(assert) { + QUnit.test('indexOf', function(assert) { var numbers = [1, 2, 3]; assert.equal(_.indexOf(numbers, 2), 1, 'can compute indexOf'); var result = (function(){ return _.indexOf(arguments, 2); }(1, 2, 3)); @@ -343,7 +343,7 @@ assert.equal(index, -1, 'empty array with truthy `isSorted` returns -1'); }); - test('indexOf with NaN', function(assert) { + QUnit.test('indexOf with NaN', function(assert) { assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN), 2, 'Expected [1, 2, NaN] to contain NaN'); assert.strictEqual(_.indexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); @@ -355,14 +355,14 @@ }(1, 2, NaN, NaN)); }); - test('indexOf with +- 0', function(assert) { + QUnit.test('indexOf with +- 0', function(assert) { _.each([-0, +0], function(val) { assert.strictEqual(_.indexOf([1, 2, val, val], val), 2); assert.strictEqual(_.indexOf([1, 2, val, val], -val), 2); }); }); - test('lastIndexOf', function(assert) { + QUnit.test('lastIndexOf', function(assert) { var numbers = [1, 0, 1]; var falsey = [void 0, '', 0, false, NaN, null, void 0]; assert.equal(_.lastIndexOf(numbers, 1), 2); @@ -420,7 +420,7 @@ }), [0, -1, -1]); }); - test('lastIndexOf with NaN', function(assert) { + QUnit.test('lastIndexOf with NaN', function(assert) { assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN), 3, 'Expected [1, 2, NaN] to contain NaN'); assert.strictEqual(_.lastIndexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); @@ -432,7 +432,7 @@ }(1, 2, NaN, NaN)); }); - test('lastIndexOf with +- 0', function(assert) { + QUnit.test('lastIndexOf with +- 0', function(assert) { _.each([-0, +0], function(val) { assert.strictEqual(_.lastIndexOf([1, 2, val, val], val), 3); assert.strictEqual(_.lastIndexOf([1, 2, val, val], -val), 3); @@ -440,7 +440,7 @@ }); }); - test('findIndex', function(assert) { + QUnit.test('findIndex', function(assert) { var objects = [ {a: 0, b: 0}, {a: 1, b: 1}, @@ -483,7 +483,7 @@ assert.strictEqual(_.findIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); }); - test('findLastIndex', function(assert) { + QUnit.test('findLastIndex', function(assert) { var objects = [ {a: 0, b: 0}, {a: 1, b: 1}, @@ -526,7 +526,7 @@ assert.strictEqual(_.findLastIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); }); - test('range', function(assert) { + QUnit.test('range', function(assert) { assert.deepEqual(_.range(0), [], 'range with 0 as a first argument generates an empty array'); assert.deepEqual(_.range(4), [0, 1, 2, 3], 'range with a single positive argument generates an array of elements 0,1,2,...,n-1'); assert.deepEqual(_.range(5, 8), [5, 6, 7], 'range with two arguments a & b, a<b generates an array of elements a,a+1,a+2,...,b-2,b-1'); @@ -539,7 +539,7 @@ assert.deepEqual(_.range(-3), [0, -1, -2], 'negative range generates descending array'); }); - test('chunk', function(assert) { + QUnit.test('chunk', function(assert) { assert.deepEqual(_.chunk([], 2), [], 'chunk for empty array returns an empty array'); assert.deepEqual(_.chunk([1, 2, 3], 0), [], 'chunk into parts of 0 elements returns empty array'); diff --git a/test/chaining.js b/test/chaining.js index 1e708b90b..6ad21dcf6 100644 --- a/test/chaining.js +++ b/test/chaining.js @@ -3,7 +3,7 @@ QUnit.module('Chaining'); - test('map/flatten/reduce', function(assert) { + QUnit.test('map/flatten/reduce', function(assert) { var lyrics = [ 'I\'m a lumberjack and I\'m okay', 'I sleep all night and I work all day', @@ -23,7 +23,7 @@ assert.equal(counts.e, 10, 'counted all the letters in the song'); }); - test('select/reject/sortBy', function(assert) { + QUnit.test('select/reject/sortBy', function(assert) { var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; numbers = _(numbers).chain().select(function(n) { return n % 2 === 0; @@ -35,7 +35,7 @@ assert.deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); }); - test('select/reject/sortBy in functional style', function(assert) { + QUnit.test('select/reject/sortBy in functional style', function(assert) { var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; numbers = _.chain(numbers).select(function(n) { return n % 2 === 0; @@ -47,7 +47,7 @@ assert.deepEqual(numbers, [10, 6, 2], 'filtered and reversed the numbers'); }); - test('reverse/concat/unshift/pop/map', function(assert) { + QUnit.test('reverse/concat/unshift/pop/map', function(assert) { var numbers = [1, 2, 3, 4, 5]; numbers = _(numbers).chain() .reverse() @@ -59,7 +59,7 @@ assert.deepEqual(numbers, [34, 10, 8, 6, 4, 2, 10, 10], 'can chain together array functions.'); }); - test('splice', function(assert) { + QUnit.test('splice', function(assert) { var instance = _([1, 2, 3, 4, 5]).chain(); assert.deepEqual(instance.splice(1, 3).value(), [1, 5]); assert.deepEqual(instance.splice(1, 0).value(), [1, 5]); @@ -67,27 +67,27 @@ assert.deepEqual(instance.splice(0, 1).value(), [], '#397 Can create empty array'); }); - test('shift', function(assert) { + QUnit.test('shift', function(assert) { var instance = _([1, 2, 3]).chain(); assert.deepEqual(instance.shift().value(), [2, 3]); assert.deepEqual(instance.shift().value(), [3]); assert.deepEqual(instance.shift().value(), [], '#397 Can create empty array'); }); - test('pop', function(assert) { + QUnit.test('pop', function(assert) { var instance = _([1, 2, 3]).chain(); assert.deepEqual(instance.pop().value(), [1, 2]); assert.deepEqual(instance.pop().value(), [1]); assert.deepEqual(instance.pop().value(), [], '#397 Can create empty array'); }); - test('chaining works in small stages', function(assert) { + QUnit.test('chaining works in small stages', function(assert) { var o = _([1, 2, 3, 4]).chain(); assert.deepEqual(o.filter(function(i) { return i < 3; }).value(), [1, 2]); assert.deepEqual(o.filter(function(i) { return i > 2; }).value(), [3, 4]); }); - test('#1562: Engine proxies for chained functions', function(assert) { + QUnit.test('#1562: Engine proxies for chained functions', function(assert) { var wrapped = _(512); assert.strictEqual(wrapped.toJSON(), 512); assert.strictEqual(wrapped.valueOf(), 512); diff --git a/test/collections.js b/test/collections.js index 864b04f6f..1bc14790e 100644 --- a/test/collections.js +++ b/test/collections.js @@ -3,7 +3,7 @@ QUnit.module('Collections'); - test('each', function(assert) { + QUnit.test('each', function(assert) { _.each([1, 2, 3], function(num, i) { assert.equal(num, i + 1, 'each iterators provide value and iteration count'); }); @@ -45,11 +45,11 @@ assert.strictEqual(_.each(null, function(){}), null); }); - test('forEach', function(assert) { + QUnit.test('forEach', function(assert) { assert.strictEqual(_.forEach, _.each, 'is an alias for each'); }); - test('lookupIterator with contexts', function(assert) { + QUnit.test('lookupIterator with contexts', function(assert) { _.each([true, false, 'yes', '', 0, 1, {}], function(context) { _.each([1], function() { assert.equal(this, context); @@ -57,7 +57,7 @@ }); }); - test('Iterating objects with sketchy length properties', function(assert) { + QUnit.test('Iterating objects with sketchy length properties', function(assert) { var functions = [ 'each', 'map', 'filter', 'find', 'some', 'every', 'max', 'min', @@ -101,7 +101,7 @@ }); }); - test('Resistant to collection length and properties changing while iterating', function(assert) { + QUnit.test('Resistant to collection length and properties changing while iterating', function(assert) { var collection = [ 'each', 'map', 'filter', 'find', @@ -145,7 +145,7 @@ }); }); - test('map', function(assert) { + QUnit.test('map', function(assert) { var doubled = _.map([1, 2, 3], function(num){ return num * 2; }); assert.deepEqual(doubled, [2, 4, 6], 'doubled numbers'); @@ -171,11 +171,11 @@ assert.deepEqual(_.map(people, 'name'), ['moe', 'curly'], 'predicate string map to object properties'); }); - test('collect', function(assert) { + QUnit.test('collect', function(assert) { assert.strictEqual(_.collect, _.map, 'is an alias for map'); }); - test('reduce', function(assert) { + QUnit.test('reduce', function(assert) { var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0); assert.equal(sum, 6, 'can sum up an array'); @@ -198,15 +198,15 @@ assert.equal(_.reduce([], _.noop), void 0, 'returns undefined when collection is empty and no initial value'); }); - test('foldl', function(assert) { + QUnit.test('foldl', function(assert) { assert.strictEqual(_.foldl, _.reduce, 'is an alias for reduce'); }); - test('inject', function(assert) { + QUnit.test('inject', function(assert) { assert.strictEqual(_.inject, _.reduce, 'is an alias for reduce'); }); - test('reduceRight', function(assert) { + QUnit.test('reduceRight', function(assert) { var list = _.reduceRight(['foo', 'bar', 'baz'], function(memo, str){ return memo + str; }, ''); assert.equal(list, 'bazbarfoo', 'can perform right folds'); @@ -256,11 +256,11 @@ assert.deepEqual(args, expected); }); - test('foldr', function(assert) { + QUnit.test('foldr', function(assert) { assert.strictEqual(_.foldr, _.reduceRight, 'is an alias for reduceRight'); }); - test('find', function(assert) { + QUnit.test('find', function(assert) { var array = [1, 2, 3, 4]; assert.strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found `value`'); assert.strictEqual(_.find(array, function() { return false; }), void 0, 'should return `undefined` if `value` is not found'); @@ -298,11 +298,11 @@ }, _); }); - test('detect', function(assert) { + QUnit.test('detect', function(assert) { assert.strictEqual(_.detect, _.find, 'is an alias for find'); }); - test('filter', function(assert) { + QUnit.test('filter', function(assert) { var evenArray = [1, 2, 3, 4, 5, 6]; var evenObject = {one: 1, two: 2, three: 3}; var isEven = function(num){ return num % 2 === 0; }; @@ -323,11 +323,11 @@ assert.deepEqual(_(list).filter({}), list, 'OO-filter'); }); - test('select', function(assert) { + QUnit.test('select', function(assert) { assert.strictEqual(_.select, _.filter, 'is an alias for filter'); }); - test('reject', function(assert) { + QUnit.test('reject', function(assert) { var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 === 0; }); assert.deepEqual(odds, [1, 3, 5], 'rejected each even number'); @@ -349,7 +349,7 @@ assert.deepEqual(_.reject(list, []), [], 'Returns empty list given empty array'); }); - test('every', function(assert) { + QUnit.test('every', function(assert) { assert.ok(_.every([], _.identity), 'the empty set'); assert.ok(_.every([true, true, true], _.identity), 'every true values'); assert.ok(!_.every([true, false, true], _.identity), 'one false value'); @@ -373,11 +373,11 @@ assert.ok(!_.every(['a', 'b', 'c', 'd', 'f'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); }); - test('all', function(assert) { + QUnit.test('all', function(assert) { assert.strictEqual(_.all, _.every, 'is an alias for every'); }); - test('some', function(assert) { + QUnit.test('some', function(assert) { assert.ok(!_.some([]), 'the empty set'); assert.ok(!_.some([false, false, false]), 'all false values'); assert.ok(_.some([false, false, true]), 'one true value'); @@ -403,11 +403,11 @@ assert.ok(!_.some(['x', 'y', 'z'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); }); - test('any', function(assert) { + QUnit.test('any', function(assert) { assert.strictEqual(_.any, _.some, 'is an alias for some'); }); - test('includes', function(assert) { + QUnit.test('includes', function(assert) { _.each([null, void 0, 0, 1, NaN, {}, []], function(val) { assert.strictEqual(_.includes(val, 'hasOwnProperty'), false); }); @@ -430,21 +430,21 @@ assert.ok(_.every([1, 2, 3], _.partial(_.includes, numbers)), 'fromIndex is guarded'); }); - test('include', function(assert) { + QUnit.test('include', function(assert) { assert.strictEqual(_.include, _.includes, 'is an alias for includes'); }); - test('contains', function(assert) { + QUnit.test('contains', function(assert) { assert.strictEqual(_.contains, _.includes, 'is an alias for includes'); }); - test('includes with NaN', function(assert) { + QUnit.test('includes with NaN', function(assert) { assert.strictEqual(_.includes([1, 2, NaN, NaN], NaN), true, 'Expected [1, 2, NaN] to contain NaN'); assert.strictEqual(_.includes([1, 2, Infinity], NaN), false, 'Expected [1, 2, NaN] to contain NaN'); }); - test('includes with +- 0', function(assert) { + QUnit.test('includes with +- 0', function(assert) { _.each([-0, +0], function(val) { assert.strictEqual(_.includes([1, 2, val, val], val), true); assert.strictEqual(_.includes([1, 2, val, val], -val), true); @@ -453,7 +453,7 @@ }); - test('invoke', 5, function(assert) { + QUnit.test('invoke', 5, function(assert) { var list = [[5, 1, 7], [3, 2, 1]]; var result = _.invoke(list, 'sort'); assert.deepEqual(result[0], [1, 5, 7], 'first array sorted'); @@ -472,7 +472,7 @@ }, TypeError, 'throws for non-functions'); }); - test('invoke w/ function reference', function(assert) { + QUnit.test('invoke w/ function reference', function(assert) { var list = [[5, 1, 7], [3, 2, 1]]; var result = _.invoke(list, Array.prototype.sort); assert.deepEqual(result[0], [1, 5, 7], 'first array sorted'); @@ -484,7 +484,7 @@ }); // Relevant when using ClojureScript - test('invoke when strings have a call method', function(assert) { + QUnit.test('invoke when strings have a call method', function(assert) { String.prototype.call = function() { return 42; }; @@ -498,7 +498,7 @@ assert.equal(s.call, void 0, 'call function removed'); }); - test('pluck', function(assert) { + QUnit.test('pluck', function(assert) { var people = [{name: 'moe', age: 30}, {name: 'curly', age: 50}]; assert.deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'pulls names out of objects'); assert.deepEqual(_.pluck(people, 'address'), [void 0, void 0], 'missing properties are returned as undefined'); @@ -506,7 +506,7 @@ assert.deepEqual(_.pluck([{'[object Object]': 1}], {}), [1]); }); - test('where', function(assert) { + QUnit.test('where', function(assert) { var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; var result = _.where(list, {a: 1}); assert.equal(result.length, 3); @@ -522,7 +522,7 @@ assert.deepEqual(_.where([_, {a: 1, b: 2}, _], test), [_, _], 'checks properties given function'); }); - test('findWhere', function(assert) { + QUnit.test('findWhere', function(assert) { var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}]; var result = _.findWhere(list, {a: 1}); assert.deepEqual(result, {a: 1, b: 2}); @@ -547,7 +547,7 @@ assert.deepEqual(_.findWhere([{y: 5, b: 6}, expect], new TestClass()), expect, 'uses class instance properties'); }); - test('max', function(assert) { + QUnit.test('max', function(assert) { assert.equal(-Infinity, _.max(null), 'can handle null/undefined'); assert.equal(-Infinity, _.max(void 0), 'can handle null/undefined'); assert.equal(-Infinity, _.max(null, _.identity), 'can handle null/undefined'); @@ -592,7 +592,7 @@ assert.deepEqual(_.max([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: 2}, 'Lookup falsy iterator'); }); - test('min', function(assert) { + QUnit.test('min', function(assert) { assert.equal(Infinity, _.min(null), 'can handle null/undefined'); assert.equal(Infinity, _.min(void 0), 'can handle null/undefined'); assert.equal(Infinity, _.min(null, _.identity), 'can handle null/undefined'); @@ -635,7 +635,7 @@ assert.deepEqual(_.min([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: -1}, 'Lookup falsy iterator'); }); - test('sortBy', function(assert) { + QUnit.test('sortBy', function(assert) { var people = [{name: 'curly', age: 50}, {name: 'moe', age: 30}]; people = _.sortBy(people, function(person){ return person.age; }); assert.deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'stooges sorted by age'); @@ -683,7 +683,7 @@ assert.deepEqual(_.sortBy(list), ['e', 'q', 'r', 't', 'w', 'y'], 'uses _.identity if iterator is not specified'); }); - test('groupBy', function(assert) { + QUnit.test('groupBy', function(assert) { var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; }); assert.ok('0' in parity && '1' in parity, 'created a group for each value'); assert.deepEqual(parity[0], [2, 4, 6], 'put each even number in the right group'); @@ -720,7 +720,7 @@ assert.deepEqual(_.groupBy(matrix, 1), {2: [[1, 2]], 3: [[1, 3], [2, 3]]}); }); - test('indexBy', function(assert) { + QUnit.test('indexBy', function(assert) { var parity = _.indexBy([1, 2, 3, 4, 5], function(num){ return num % 2 === 0; }); assert.equal(parity['true'], 4); assert.equal(parity['false'], 5); @@ -738,7 +738,7 @@ assert.equal(grouped['3'], 3); }); - test('countBy', function(assert) { + QUnit.test('countBy', function(assert) { var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 === 0; }); assert.equal(parity['true'], 2); assert.equal(parity['false'], 3); @@ -767,7 +767,7 @@ assert.equal(grouped['3'], 1); }); - test('shuffle', function(assert) { + QUnit.test('shuffle', function(assert) { assert.deepEqual(_.shuffle([1]), [1], 'behaves correctly on size 1 arrays'); var numbers = _.range(20); var shuffled = _.shuffle(numbers); @@ -780,7 +780,7 @@ assert.deepEqual(shuffled.sort(), [1, 2, 3, 4], 'works on objects'); }); - test('sample', function(assert) { + QUnit.test('sample', function(assert) { assert.strictEqual(_.sample([1]), 1, 'behaves correctly when no second parameter is given'); assert.deepEqual(_.sample([1, 2, 3], -2), [], 'behaves correctly on negative n'); var numbers = _.range(10); @@ -799,7 +799,7 @@ assert.notDeepEqual(partialSampleSorted, _.range(10), 'samples from the whole array, not just the beginning'); }); - test('toArray', function(assert) { + QUnit.test('toArray', function(assert) { assert.ok(!_.isArray(arguments), 'arguments object is not an array'); assert.ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array'); var a = [1, 2, 3]; @@ -825,7 +825,7 @@ } }); - test('size', function(assert) { + QUnit.test('size', function(assert) { assert.equal(_.size({one: 1, two: 2, three: 3}), 3, 'can compute the size of an object'); assert.equal(_.size([1, 2, 3]), 3, 'can compute the size of an array'); assert.equal(_.size({length: 3, 0: 0, 1: 0, 2: 0}), 3, 'can compute the size of Array-likes'); @@ -843,7 +843,7 @@ assert.equal(_.size(0), 0, 'handles numbers'); }); - test('partition', function(assert) { + QUnit.test('partition', function(assert) { var list = [0, 1, 2, 3, 4, 5]; assert.deepEqual(_.partition(list, function(x) { return x < 4; }), [[0, 1, 2, 3], [4, 5]], 'handles bool return values'); assert.deepEqual(_.partition(list, function(x) { return x & 1; }), [[1, 3, 5], [0, 2, 4]], 'handles 0 and 1 return values'); @@ -875,7 +875,7 @@ }); if (typeof document != 'undefined') { - test('Can use various collection methods on NodeLists', function(assert) { + QUnit.test('Can use various collection methods on NodeLists', function(assert) { var parent = document.createElement('div'); parent.innerHTML = 'textnode'; diff --git a/test/cross-document.js b/test/cross-document.js index fff3a07d4..cb68a3d9b 100644 --- a/test/cross-document.js +++ b/test/cross-document.js @@ -33,7 +33,7 @@ ); iDoc.close(); - test('isEqual', function(assert) { + QUnit.test('isEqual', function(assert) { assert.ok(!_.isEqual(iNumber, 101)); assert.ok(_.isEqual(iNumber, 100)); @@ -45,73 +45,73 @@ assert.ok(_.isEqual([1, 2, 3], iArray), 'Arrays with equivalent elements created in different documents are equal'); }); - test('isEmpty', function(assert) { + QUnit.test('isEmpty', function(assert) { assert.ok(!_([iNumber]).isEmpty(), '[1] is not empty'); assert.ok(!_.isEmpty(iArray), '[] is empty'); assert.ok(_.isEmpty(iObject), '{} is empty'); }); - test('isElement', function(assert) { + QUnit.test('isElement', function(assert) { assert.ok(!_.isElement('div'), 'strings are not dom elements'); assert.ok(_.isElement(document.body), 'the body tag is a DOM element'); assert.ok(_.isElement(iElement), 'even from another frame'); }); - test('isArguments', function(assert) { + QUnit.test('isArguments', function(assert) { assert.ok(_.isArguments(iArguments), 'even from another frame'); }); - test('isObject', function(assert) { + QUnit.test('isObject', function(assert) { assert.ok(_.isObject(iElement), 'even from another frame'); assert.ok(_.isObject(iFunction), 'even from another frame'); }); - test('isArray', function(assert) { + QUnit.test('isArray', function(assert) { assert.ok(_.isArray(iArray), 'even from another frame'); }); - test('isString', function(assert) { + QUnit.test('isString', function(assert) { assert.ok(_.isString(iString), 'even from another frame'); }); - test('isNumber', function(assert) { + QUnit.test('isNumber', function(assert) { assert.ok(_.isNumber(iNumber), 'even from another frame'); }); - test('isBoolean', function(assert) { + QUnit.test('isBoolean', function(assert) { assert.ok(_.isBoolean(iBoolean), 'even from another frame'); }); - test('isFunction', function(assert) { + QUnit.test('isFunction', function(assert) { assert.ok(_.isFunction(iFunction), 'even from another frame'); }); - test('isDate', function(assert) { + QUnit.test('isDate', function(assert) { assert.ok(_.isDate(iDate), 'even from another frame'); }); - test('isRegExp', function(assert) { + QUnit.test('isRegExp', function(assert) { assert.ok(_.isRegExp(iRegExp), 'even from another frame'); }); - test('isNaN', function(assert) { + QUnit.test('isNaN', function(assert) { assert.ok(_.isNaN(iNaN), 'even from another frame'); }); - test('isNull', function(assert) { + QUnit.test('isNull', function(assert) { assert.ok(_.isNull(iNull), 'even from another frame'); }); - test('isUndefined', function(assert) { + QUnit.test('isUndefined', function(assert) { assert.ok(_.isUndefined(iUndefined), 'even from another frame'); }); - test('isError', function(assert) { + QUnit.test('isError', function(assert) { assert.ok(_.isError(iError), 'even from another frame'); }); if (typeof ActiveXObject != 'undefined') { - test('IE host objects', function(assert) { + QUnit.test('IE host objects', function(assert) { var xml = new ActiveXObject('Msxml2.DOMDocument.3.0'); assert.ok(!_.isNumber(xml)); assert.ok(!_.isBoolean(xml)); @@ -121,7 +121,7 @@ assert.ok(!_.isUndefined(xml)); }); - test('#1621 IE 11 compat mode DOM elements are not functions', function(assert) { + QUnit.test('#1621 IE 11 compat mode DOM elements are not functions', function(assert) { var fn = function() {}; var xml = new ActiveXObject('Msxml2.DOMDocument.3.0'); var div = document.createElement('div'); diff --git a/test/functions.js b/test/functions.js index ec15c272d..c35a17395 100644 --- a/test/functions.js +++ b/test/functions.js @@ -4,7 +4,7 @@ QUnit.module('Functions'); QUnit.config.asyncRetries = 3; - test('bind', function(assert) { + QUnit.test('bind', function(assert) { var context = {name: 'moe'}; var func = function(arg) { return 'name: ' + (this.name || arg); }; var bound = _.bind(func, context); @@ -47,7 +47,7 @@ assert.raises(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function'); }); - test('partial', function(assert) { + QUnit.test('partial', function(assert) { var obj = {name: 'moe'}; var func = function() { return this.name + ' ' + _.toArray(arguments).join(' '); }; @@ -89,7 +89,7 @@ _.partial.placeholder = _; }); - test('bindAll', function(assert) { + QUnit.test('bindAll', function(assert) { var curly = {name: 'curly'}, moe = { name: 'moe', getName: function() { return 'name: ' + this.name; }, @@ -125,7 +125,7 @@ assert.equal(getName(), 'name: moe', 'flattens arguments into a single list'); }); - test('memoize', function(assert) { + QUnit.test('memoize', function(assert) { var fib = function(n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }; @@ -525,7 +525,7 @@ }, 100); }); - test('once', function(assert) { + QUnit.test('once', function(assert) { var num = 0; var increment = _.once(function(){ return ++num; }); increment(); @@ -535,7 +535,7 @@ assert.equal(increment(), 1, 'stores a memo to the last value'); }); - test('Recursive onced function.', 1, function(assert) { + QUnit.test('Recursive onced function.', 1, function(assert) { var f = _.once(function(){ assert.ok(true); f(); @@ -543,7 +543,7 @@ f(); }); - test('wrap', function(assert) { + QUnit.test('wrap', function(assert) { var greet = function(name){ return 'hi: ' + name; }; var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); }); assert.equal(backwards('moe'), 'hi: moe eom', 'wrapped the salutation function'); @@ -559,13 +559,13 @@ assert.deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']); }); - test('negate', function(assert) { + QUnit.test('negate', function(assert) { var isOdd = function(n){ return n & 1; }; assert.equal(_.negate(isOdd)(2), true, 'should return the complement of the given function'); assert.equal(_.negate(isOdd)(3), false, 'should return the complement of the given function'); }); - test('compose', function(assert) { + QUnit.test('compose', function(assert) { var greet = function(name){ return 'hi: ' + name; }; var exclaim = function(sentence){ return sentence + '!'; }; var composed = _.compose(exclaim, greet); @@ -591,7 +591,7 @@ assert.equal(composed(1, 2, 3), 12); }); - test('after', function(assert) { + QUnit.test('after', function(assert) { var testAfter = function(afterAmount, timesCalled) { var afterCalled = 0; var after = _.after(afterAmount, function() { @@ -607,7 +607,7 @@ assert.equal(testAfter(0, 1), 1, 'after(0) should fire when first invoked'); }); - test('before', function(assert) { + QUnit.test('before', function(assert) { var testBefore = function(beforeAmount, timesCalled) { var beforeCalled = 0; var before = _.before(beforeAmount, function() { beforeCalled++; }); @@ -627,7 +627,7 @@ assert.equal(context.num, 2, 'provides context'); }); - test('iteratee', function(assert) { + QUnit.test('iteratee', function(assert) { var identity = _.iteratee(); assert.equal(identity, _.identity, '_.iteratee is exposed as an external function.'); @@ -642,7 +642,7 @@ }); - test('restArgs', 10, function(assert) { + QUnit.test('restArgs', 10, function(assert) { _.restArgs(function(a, args) { assert.strictEqual(a, 1); assert.deepEqual(args, [2, 3], 'collects rest arguments into an array'); diff --git a/test/objects.js b/test/objects.js index bc3075839..fff8ea962 100644 --- a/test/objects.js +++ b/test/objects.js @@ -5,7 +5,7 @@ var testElement = typeof document === 'object' ? document.createElement('div') : void 0; - test('keys', function(assert) { + QUnit.test('keys', function(assert) { assert.deepEqual(_.keys({one: 1, two: 2}), ['one', 'two'], 'can extract the keys from an object'); // the test above is not safe because it relies on for-in enumeration order var a = []; a[1] = 0; @@ -35,7 +35,7 @@ assert.deepEqual(_.keys(trouble).sort(), troubleKeys, 'matches non-enumerable properties'); }); - test('allKeys', function(assert) { + QUnit.test('allKeys', function(assert) { assert.deepEqual(_.allKeys({one: 1, two: 2}), ['one', 'two'], 'can extract the allKeys from an object'); // the test above is not safe because it relies on for-in enumeration order var a = []; a[1] = 0; @@ -73,17 +73,17 @@ assert.deepEqual(_.allKeys(y), ['x'], 'should get keys from constructor'); }); - test('values', function(assert) { + QUnit.test('values', function(assert) { assert.deepEqual(_.values({one: 1, two: 2}), [1, 2], 'can extract the values from an object'); assert.deepEqual(_.values({one: 1, two: 2, length: 3}), [1, 2, 3], '... even when one of them is "length"'); }); - test('pairs', function(assert) { + QUnit.test('pairs', function(assert) { assert.deepEqual(_.pairs({one: 1, two: 2}), [['one', 1], ['two', 2]], 'can convert an object into pairs'); assert.deepEqual(_.pairs({one: 1, two: 2, length: 3}), [['one', 1], ['two', 2], ['length', 3]], '... even when one of them is "length"'); }); - test('invert', function(assert) { + QUnit.test('invert', function(assert) { var obj = {first: 'Moe', second: 'Larry', third: 'Curly'}; assert.deepEqual(_.keys(_.invert(obj)), ['Moe', 'Larry', 'Curly'], 'can invert an object'); assert.deepEqual(_.invert(_.invert(obj)), obj, 'two inverts gets you back where you started'); @@ -92,7 +92,7 @@ assert.equal(_.invert(obj)['3'], 'length', 'can invert an object with "length"'); }); - test('functions', function(assert) { + QUnit.test('functions', function(assert) { var obj = {a: 'dash', b: _.map, c: /yo/, d: _.reduce}; assert.deepEqual(['b', 'd'], _.functions(obj), 'can grab the function names of any passed-in object'); @@ -101,11 +101,11 @@ assert.deepEqual(_.functions(new Animal), ['run'], 'also looks up functions on the prototype'); }); - test('methods', function(assert) { + QUnit.test('methods', function(assert) { assert.strictEqual(_.methods, _.functions, 'is an alias for functions'); }); - test('extend', function(assert) { + QUnit.test('extend', function(assert) { var result; assert.equal(_.extend({}, {a: 'b'}).a, 'b', 'can extend an object with the attributes of another'); assert.equal(_.extend({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination'); @@ -136,7 +136,7 @@ assert.strictEqual(_.extend(void 0, {a: 1}), void 0, 'extending undefined results in undefined'); }); - test('extendOwn', function(assert) { + QUnit.test('extendOwn', function(assert) { var result; assert.equal(_.extendOwn({}, {a: 'b'}).a, 'b', 'can extend an object with the attributes of another'); assert.equal(_.extendOwn({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination'); @@ -166,11 +166,11 @@ assert.deepEqual(result, {a: 1, 0: 1, 1: 2, length: 2}, 'should treat array-like objects like normal objects'); }); - test('assign', function(assert) { + QUnit.test('assign', function(assert) { assert.strictEqual(_.assign, _.extendOwn, 'is an alias for extendOwn'); }); - test('pick', function(assert) { + QUnit.test('pick', function(assert) { var result; result = _.pick({a: 1, b: 2, c: 3}, 'a', 'c'); assert.deepEqual(result, {a: 1, c: 3}, 'can restrict properties to those named'); @@ -211,7 +211,7 @@ }); }); - test('omit', function(assert) { + QUnit.test('omit', function(assert) { var result; result = _.omit({a: 1, b: 2, c: 3}, 'b'); assert.deepEqual(result, {a: 1, c: 3}, 'can omit a single named property'); @@ -245,7 +245,7 @@ }, instance), {a: 1, b: 2}, 'function is given context'); }); - test('defaults', function(assert) { + QUnit.test('defaults', function(assert) { var options = {zero: 0, one: 1, empty: '', nan: NaN, nothing: null}; _.defaults(options, {zero: 1, one: 10, twenty: 20, nothing: 'str'}); @@ -270,7 +270,7 @@ assert.deepEqual(_.defaults(void 0, {a: 1}), {a: 1}, 'defaults skips undefined'); }); - test('clone', function(assert) { + QUnit.test('clone', function(assert) { var moe = {name: 'moe', lucky: [13, 27, 34]}; var clone = _.clone(moe); assert.equal(clone.name, 'moe', 'the clone as the attributes of the original'); @@ -286,7 +286,7 @@ assert.equal(_.clone(null), null, 'non objects should not be changed by clone'); }); - test('create', function(assert) { + QUnit.test('create', function(assert) { var Parent = function() {}; Parent.prototype = {foo: function() {}, bar: 2}; @@ -312,7 +312,7 @@ assert.ok(!created.hasOwnProperty('foo'), 'should only add own properties'); }); - test('isEqual', function(assert) { + QUnit.test('isEqual', function(assert) { function First() { this.value = 1; } @@ -567,7 +567,7 @@ assert.equal(_.isEqual({a: NaN}, {a: NaN}), true); }); - test('isEmpty', function(assert) { + QUnit.test('isEmpty', function(assert) { assert.ok(!_([1]).isEmpty(), '[1] is not empty'); assert.ok(_.isEmpty([]), '[] is empty'); assert.ok(!_.isEmpty({one: 1}), '{one: 1} is not empty'); @@ -592,13 +592,13 @@ }); if (typeof document === 'object') { - test('isElement', function(assert) { + QUnit.test('isElement', function(assert) { assert.ok(!_.isElement('div'), 'strings are not dom elements'); assert.ok(_.isElement(testElement), 'an element is a DOM element'); }); } - test('isArguments', function(assert) { + QUnit.test('isArguments', function(assert) { var args = (function(){ return arguments; }(1, 2, 3)); assert.ok(!_.isArguments('string'), 'a string is not an arguments object'); assert.ok(!_.isArguments(_.isArguments), 'a function is not an arguments object'); @@ -607,7 +607,7 @@ assert.ok(!_.isArguments([1, 2, 3]), 'and not vanilla arrays.'); }); - test('isObject', function(assert) { + QUnit.test('isObject', function(assert) { assert.ok(_.isObject(arguments), 'the arguments object is object'); assert.ok(_.isObject([1, 2, 3]), 'and arrays'); if (testElement) { @@ -622,13 +622,13 @@ assert.ok(_.isObject(new String('string')), 'but new String()'); }); - test('isArray', function(assert) { + QUnit.test('isArray', function(assert) { assert.ok(!_.isArray(void 0), 'undefined vars are not arrays'); assert.ok(!_.isArray(arguments), 'the arguments object is not an array'); assert.ok(_.isArray([1, 2, 3]), 'but arrays are'); }); - test('isString', function(assert) { + QUnit.test('isString', function(assert) { var obj = new String('I am a string object'); if (testElement) { assert.ok(!_.isString(testElement), 'an element is not a string'); @@ -639,7 +639,7 @@ assert.strictEqual(_.isString(1), false); }); - test('isNumber', function(assert) { + QUnit.test('isNumber', function(assert) { assert.ok(!_.isNumber('string'), 'a string is not a number'); assert.ok(!_.isNumber(arguments), 'the arguments object is not a number'); assert.ok(!_.isNumber(void 0), 'undefined is not a number'); @@ -649,7 +649,7 @@ assert.ok(!_.isNumber('1'), 'numeric strings are not numbers'); }); - test('isBoolean', function(assert) { + QUnit.test('isBoolean', function(assert) { assert.ok(!_.isBoolean(2), 'a number is not a boolean'); assert.ok(!_.isBoolean('string'), 'a string is not a boolean'); assert.ok(!_.isBoolean('false'), 'the string "false" is not a boolean'); @@ -662,7 +662,7 @@ assert.ok(_.isBoolean(false), 'and so is false'); }); - test('isFunction', function(assert) { + QUnit.test('isFunction', function(assert) { assert.ok(!_.isFunction(void 0), 'undefined vars are not functions'); assert.ok(!_.isFunction([1, 2, 3]), 'arrays are not functions'); assert.ok(!_.isFunction('moe'), 'strings are not functions'); @@ -680,7 +680,7 @@ }); if (typeof Int8Array !== 'undefined') { - test('#1929 Typed Array constructors are functions', function(assert) { + QUnit.test('#1929 Typed Array constructors are functions', function(assert) { _.chain(['Float32Array', 'Float64Array', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array']) .map(_.propertyOf(typeof GLOBAL != 'undefined' ? GLOBAL : window)) .compact() @@ -692,18 +692,18 @@ }); } - test('isDate', function(assert) { + QUnit.test('isDate', function(assert) { assert.ok(!_.isDate(100), 'numbers are not dates'); assert.ok(!_.isDate({}), 'objects are not dates'); assert.ok(_.isDate(new Date()), 'but dates are'); }); - test('isRegExp', function(assert) { + QUnit.test('isRegExp', function(assert) { assert.ok(!_.isRegExp(_.identity), 'functions are not RegExps'); assert.ok(_.isRegExp(/identity/), 'but RegExps are'); }); - test('isFinite', function(assert) { + QUnit.test('isFinite', function(assert) { assert.ok(!_.isFinite(void 0), 'undefined is not finite'); assert.ok(!_.isFinite(null), 'null is not finite'); assert.ok(!_.isFinite(NaN), 'NaN is not finite'); @@ -719,7 +719,7 @@ assert.ok(_.isFinite(-12.44), 'Floats are finite'); }); - test('isNaN', function(assert) { + QUnit.test('isNaN', function(assert) { assert.ok(!_.isNaN(void 0), 'undefined is not NaN'); assert.ok(!_.isNaN(null), 'null is not NaN'); assert.ok(!_.isNaN(0), '0 is not NaN'); @@ -728,13 +728,13 @@ assert.ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN'); }); - test('isNull', function(assert) { + QUnit.test('isNull', function(assert) { assert.ok(!_.isNull(void 0), 'undefined is not null'); assert.ok(!_.isNull(NaN), 'NaN is not null'); assert.ok(_.isNull(null), 'but null is'); }); - test('isUndefined', function(assert) { + QUnit.test('isUndefined', function(assert) { assert.ok(!_.isUndefined(1), 'numbers are defined'); assert.ok(!_.isUndefined(null), 'null is defined'); assert.ok(!_.isUndefined(false), 'false is defined'); @@ -743,7 +743,7 @@ assert.ok(_.isUndefined(void 0), 'undefined is undefined'); }); - test('isError', function(assert) { + QUnit.test('isError', function(assert) { assert.ok(!_.isError(1), 'numbers are not Errors'); assert.ok(!_.isError(null), 'null is not an Error'); assert.ok(!_.isError(Error), 'functions are not Errors'); @@ -756,7 +756,7 @@ assert.ok(_.isError(new URIError()), 'URIErrors are Errors'); }); - test('tap', function(assert) { + QUnit.test('tap', function(assert) { var intercepted = null; var interceptor = function(obj) { intercepted = obj; }; var returned = _.tap(1, interceptor); @@ -772,7 +772,7 @@ assert.equal(intercepted, returned, 'can use tapped objects in a chain'); }); - test('has', function(assert) { + QUnit.test('has', function(assert) { var obj = {foo: 'bar', func: function(){}}; assert.ok(_.has(obj, 'foo'), 'has() checks that the object has a property.'); assert.ok(!_.has(obj, 'baz'), "has() returns false if the object doesn't have the property."); @@ -786,7 +786,7 @@ assert.strictEqual(_.has(void 0, 'foo'), false, 'has() returns false for undefined'); }); - test('isMatch', function(assert) { + QUnit.test('isMatch', function(assert) { var moe = {name: 'Moe Howard', hair: true}; var curly = {name: 'Curly Howard', hair: false}; @@ -826,7 +826,7 @@ assert.deepEqual(_.map([null, void 0, 5, {}], _.partial(_.isMatch, _, oCon)), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); }); - test('matcher', function(assert) { + QUnit.test('matcher', function(assert) { var moe = {name: 'Moe Howard', hair: true}; var curly = {name: 'Curly Howard', hair: false}; var stooges = [moe, curly]; @@ -883,11 +883,11 @@ assert.deepEqual(_.map([null, void 0, 5, {}], oCon), [false, false, false, true], 'doesnt falsey match constructor on undefined/null'); }); - test('matches', function(assert) { + QUnit.test('matches', function(assert) { assert.strictEqual(_.matches, _.matcher, 'is an alias for matcher'); }); - test('findKey', function(assert) { + QUnit.test('findKey', function(assert) { var objects = { a: {a: 0, b: 0}, b: {a: 1, b: 1}, @@ -928,7 +928,7 @@ }); - test('mapObject', function(assert) { + QUnit.test('mapObject', function(assert) { var obj = {a: 1, b: 2}; var objects = { a: {a: 0, b: 0}, diff --git a/test/utility.js b/test/utility.js index 09cd54d62..674b99cbc 100644 --- a/test/utility.js +++ b/test/utility.js @@ -15,7 +15,7 @@ }); if (typeof this == 'object') { - test('noConflict', function(assert) { + QUnit.test('noConflict', function(assert) { var underscore = _.noConflict(); assert.equal(underscore.identity(1), 1); if (typeof require != 'function') { @@ -47,34 +47,34 @@ }); } - test('#750 - Return _ instance.', 2, function(assert) { + QUnit.test('#750 - Return _ instance.', 2, function(assert) { var instance = _([]); assert.ok(_(instance) === instance); assert.ok(new _(instance) === instance); }); - test('identity', function(assert) { + QUnit.test('identity', function(assert) { var stooge = {name: 'moe'}; assert.equal(_.identity(stooge), stooge, 'stooge is the same as his identity'); }); - test('constant', function(assert) { + QUnit.test('constant', function(assert) { var stooge = {name: 'moe'}; assert.equal(_.constant(stooge)(), stooge, 'should create a function that returns stooge'); }); - test('noop', function(assert) { + QUnit.test('noop', function(assert) { assert.strictEqual(_.noop('curly', 'larry', 'moe'), void 0, 'should always return undefined'); }); - test('property', function(assert) { + QUnit.test('property', function(assert) { var stooge = {name: 'moe'}; assert.equal(_.property('name')(stooge), 'moe', 'should return the property with the given name'); assert.equal(_.property('name')(null), void 0, 'should return undefined for null values'); assert.equal(_.property('name')(void 0), void 0, 'should return undefined for undefined values'); }); - test('propertyOf', function(assert) { + QUnit.test('propertyOf', function(assert) { var stoogeRanks = _.propertyOf({curly: 2, moe: 1, larry: 3}); assert.equal(stoogeRanks('curly'), 2, 'should return the property with the given name'); assert.equal(stoogeRanks(null), void 0, 'should return undefined for null values'); @@ -92,7 +92,7 @@ assert.equal(undefPropertyOf('curly'), void 0, 'should return undefined when obj is undefined'); }); - test('random', function(assert) { + QUnit.test('random', function(assert) { var array = _.range(1000); var min = Math.pow(2, 31); var max = Math.pow(2, 62); @@ -106,18 +106,18 @@ }), 'should produce a random number when passed `Number.MAX_VALUE`'); }); - test('now', function(assert) { + QUnit.test('now', function(assert) { var diff = _.now() - new Date().getTime(); assert.ok(diff <= 0 && diff > -5, 'Produces the correct time in milliseconds');//within 5ms }); - test('uniqueId', function(assert) { + QUnit.test('uniqueId', function(assert) { var ids = [], i = 0; while (i++ < 100) ids.push(_.uniqueId()); assert.equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids'); }); - test('times', function(assert) { + QUnit.test('times', function(assert) { var vals = []; _.times(3, function(i) { vals.push(i); }); assert.deepEqual(vals, [0, 1, 2], 'is 0 indexed'); @@ -133,7 +133,7 @@ assert.deepEqual(_.times(parseFloat('-Infinity'), _.identity), []); }); - test('mixin', function(assert) { + QUnit.test('mixin', function(assert) { _.mixin({ myReverse: function(string) { return string.split('').reverse().join(''); @@ -143,11 +143,11 @@ assert.equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper'); }); - test('_.escape', function(assert) { + QUnit.test('_.escape', function(assert) { assert.equal(_.escape(null), ''); }); - test('_.unescape', function(assert) { + QUnit.test('_.unescape', function(assert) { var string = 'Curly & Moe'; assert.equal(_.unescape(null), ''); assert.equal(_.unescape(_.escape(string)), string); @@ -155,7 +155,7 @@ }); // Don't care what they escape them to just that they're escaped and can be unescaped - test('_.escape & unescape', function(assert) { + QUnit.test('_.escape & unescape', function(assert) { // test & (&) seperately obviously var escapeCharacters = ['<', '>', '"', '\'', '`']; @@ -189,7 +189,7 @@ assert.equal(_.unescape(str), str, 'can unescape &'); }); - test('template', function(assert) { + QUnit.test('template', function(assert) { var basicTemplate = _.template("<%= thing %> is gettin' on my noives!"); var result = basicTemplate({thing: 'This'}); assert.equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation'); @@ -298,7 +298,7 @@ assert.equal(templateWithNull({planet: 'world'}), 'a null undefined world', 'can handle missing escape and evaluate settings'); }); - test('_.template provides the generated function source, when a SyntaxError occurs', function(assert) { + QUnit.test('_.template provides the generated function source, when a SyntaxError occurs', function(assert) { var source; try { _.template('<%= if x %>'); @@ -308,12 +308,12 @@ assert.ok(/__p/.test(source)); }); - test('_.template handles \\u2028 & \\u2029', function(assert) { + QUnit.test('_.template handles \\u2028 & \\u2029', function(assert) { var tmpl = _.template(' \u2028<%= "\\u2028\\u2029" %>\u2029
'); assert.strictEqual(tmpl(), '\u2028\u2028\u2029\u2029
'); }); - test('result calls functions and returns primitives', function(assert) { + QUnit.test('result calls functions and returns primitives', function(assert) { var obj = {w: '', x: 'x', y: function(){ return this.x; }}; assert.strictEqual(_.result(obj, 'w'), ''); assert.strictEqual(_.result(obj, 'x'), 'x'); @@ -322,34 +322,34 @@ assert.strictEqual(_.result(null, 'x'), void 0); }); - test('result returns a default value if object is null or undefined', function(assert) { + QUnit.test('result returns a default value if object is null or undefined', function(assert) { assert.strictEqual(_.result(null, 'b', 'default'), 'default'); assert.strictEqual(_.result(void 0, 'c', 'default'), 'default'); assert.strictEqual(_.result(''.match('missing'), 1, 'default'), 'default'); }); - test('result returns a default value if property of object is missing', function(assert) { + QUnit.test('result returns a default value if property of object is missing', function(assert) { assert.strictEqual(_.result({d: null}, 'd', 'default'), null); assert.strictEqual(_.result({e: false}, 'e', 'default'), false); }); - test('result only returns the default value if the object does not have the property or is undefined', function(assert) { + QUnit.test('result only returns the default value if the object does not have the property or is undefined', function(assert) { assert.strictEqual(_.result({}, 'b', 'default'), 'default'); assert.strictEqual(_.result({d: void 0}, 'd', 'default'), 'default'); }); - test('result does not return the default if the property of an object is found in the prototype', function(assert) { + QUnit.test('result does not return the default if the property of an object is found in the prototype', function(assert) { var Foo = function(){}; Foo.prototype.bar = 1; assert.strictEqual(_.result(new Foo, 'bar', 2), 1); }); - test('result does use the fallback when the result of invoking the property is undefined', function(assert) { + QUnit.test('result does use the fallback when the result of invoking the property is undefined', function(assert) { var obj = {a: function() {}}; assert.strictEqual(_.result(obj, 'a', 'failed'), void 0); }); - test('result fallback can use a function', function(assert) { + QUnit.test('result fallback can use a function', function(assert) { var obj = {a: [1, 2, 3]}; assert.strictEqual(_.result(obj, 'b', _.constant(5)), 5); assert.strictEqual(_.result(obj, 'b', function() { @@ -357,7 +357,7 @@ }), obj.a, 'called with context'); }); - test('_.templateSettings.variable', function(assert) { + QUnit.test('_.templateSettings.variable', function(assert) { var s = '<%=data.x%>'; var data = {x: 'x'}; var tmp = _.template(s, {variable: 'data'}); @@ -366,13 +366,13 @@ assert.strictEqual(_.template(s)(data), 'x'); }); - test('#547 - _.templateSettings is unchanged by custom settings.', function(assert) { + QUnit.test('#547 - _.templateSettings is unchanged by custom settings.', function(assert) { assert.ok(!_.templateSettings.variable); _.template('', {}, {variable: 'x'}); assert.ok(!_.templateSettings.variable); }); - test('#556 - undefined template variables.', function(assert) { + QUnit.test('#556 - undefined template variables.', function(assert) { var template = _.template('<%=x%>'); assert.strictEqual(template({x: null}), ''); assert.strictEqual(template({x: void 0}), ''); @@ -390,7 +390,7 @@ assert.strictEqual(templateWithPropertyEscaped({x: {}}), ''); }); - test('interpolate evaluates code only once.', 2, function(assert) { + QUnit.test('interpolate evaluates code only once.', 2, function(assert) { var count = 0; var template = _.template('<%= f() %>'); template({f: function(){ assert.ok(!count++); }}); @@ -400,13 +400,13 @@ templateEscaped({f: function(){ assert.ok(!countEscaped++); }}); }); - test('#746 - _.template settings are not modified.', 1, function(assert) { + QUnit.test('#746 - _.template settings are not modified.', 1, function(assert) { var settings = {}; _.template('', null, settings); assert.deepEqual(settings, {}); }); - test('#779 - delimeters are applied to unescaped text.', 1, function(assert) { + QUnit.test('#779 - delimeters are applied to unescaped text.', 1, function(assert) { var template = _.template('<<\nx\n>>', null, {evaluate: /<<(.*?)>>/g}); assert.strictEqual(template(), '<<\nx\n>>'); }); From 97963986d909f03c1feea11c14c277043915f9c7 Mon Sep 17 00:00:00 2001 From: Jordan EldredgeDate: Sun, 13 Dec 2015 20:42:19 -0800 Subject: [PATCH 120/263] Don't allow the global expect() in tests We are already using QUnit.expect in all cases, and QUnit version 2 will not support the global `expect` function. --- test/.eslintrc | 1 - 1 file changed, 1 deletion(-) diff --git a/test/.eslintrc b/test/.eslintrc index b7af19c2e..3d2d9faf6 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -14,7 +14,6 @@ "throws": false, "asyncTest": false, "start": false, - "expect": false, "QUnit": false }, "rules": { From 2fc589e41abfb857616668c4167145ef10c27c1e Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 13 Dec 2015 20:47:26 -0800 Subject: [PATCH 121/263] Don't permit global QUnit assertion syntax We aren't doing it currently, and as of QUnit2, it will no longer be supported. --- test/.eslintrc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/.eslintrc b/test/.eslintrc index 3d2d9faf6..545fc53af 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -3,15 +3,6 @@ "browser": true }, "globals": { - "ok": false, - "is": false, - "equal": false, - "deepEqual": false, - "strictEqual": false, - "notStrictEqual": false, - "notEqual": false, - "notDeepEqual": false, - "throws": false, "asyncTest": false, "start": false, "QUnit": false From 151de4d905a1a6689ae27f1043f8a8739a714ac3 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 13 Dec 2015 20:50:06 -0800 Subject: [PATCH 122/263] Use QUnit2 syntax for setup/teardown QUnit 2 will require us to use this new syntax. --- test/utility.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utility.js b/test/utility.js index 674b99cbc..ff8363530 100644 --- a/test/utility.js +++ b/test/utility.js @@ -4,11 +4,11 @@ QUnit.module('Utility', { - setup: function() { + beforeEach: function() { templateSettings = _.clone(_.templateSettings); }, - teardown: function() { + afterEach: function() { _.templateSettings = templateSettings; } From 2f5b91f43d84944fd1504c4bae17251fdf8b4796 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 13 Dec 2015 21:08:25 -0800 Subject: [PATCH 123/263] Use QUnit 2 async testing style --- test/.eslintrc | 2 - test/functions.js | 120 +++++++++++++++++++++++++++------------------- test/utility.js | 5 +- 3 files changed, 75 insertions(+), 52 deletions(-) diff --git a/test/.eslintrc b/test/.eslintrc index 545fc53af..867008dfe 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -3,8 +3,6 @@ "browser": true }, "globals": { - "asyncTest": false, - "start": false, "QUnit": false }, "rules": { diff --git a/test/functions.js b/test/functions.js index c35a17395..3b4549129 100644 --- a/test/functions.js +++ b/test/functions.js @@ -174,59 +174,66 @@ assert.strictEqual(myObj.value, 'a', 'object is not modified if second argument used as key'); }); - asyncTest('delay', 2, function(assert) { + QUnit.test('delay', 2, function(assert) { + var done = assert.async(); var delayed = false; _.delay(function(){ delayed = true; }, 100); setTimeout(function(){ assert.ok(!delayed, "didn't delay the function quite yet"); }, 50); - setTimeout(function(){ assert.ok(delayed, 'delayed the function'); start(); }, 150); + setTimeout(function(){ assert.ok(delayed, 'delayed the function'); done(); }, 150); }); - asyncTest('defer', 1, function(assert) { + QUnit.test('defer', 1, function(assert) { + var done = assert.async(); var deferred = false; _.defer(function(bool){ deferred = bool; }, true); - _.delay(function(){ assert.ok(deferred, 'deferred the function'); start(); }, 50); + _.delay(function(){ assert.ok(deferred, 'deferred the function'); done(); }, 50); }); - asyncTest('throttle', 2, function(assert) { + QUnit.test('throttle', 2, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 32); throttledIncr(); throttledIncr(); assert.equal(counter, 1, 'incr was called immediately'); - _.delay(function(){ assert.equal(counter, 2, 'incr was throttled'); start(); }, 64); + _.delay(function(){ assert.equal(counter, 2, 'incr was throttled'); done(); }, 64); }); - asyncTest('throttle arguments', 2, function(assert) { + QUnit.test('throttle arguments', 2, function(assert) { + var done = assert.async(); var value = 0; var update = function(val){ value = val; }; var throttledUpdate = _.throttle(update, 32); throttledUpdate(1); throttledUpdate(2); _.delay(function(){ throttledUpdate(3); }, 64); assert.equal(value, 1, 'updated to latest value'); - _.delay(function(){ assert.equal(value, 3, 'updated to latest value'); start(); }, 96); + _.delay(function(){ assert.equal(value, 3, 'updated to latest value'); done(); }, 96); }); - asyncTest('throttle once', 2, function(assert) { + QUnit.test('throttle once', 2, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ return ++counter; }; var throttledIncr = _.throttle(incr, 32); var result = throttledIncr(); _.delay(function(){ assert.equal(result, 1, 'throttled functions return their value'); - assert.equal(counter, 1, 'incr was called once'); start(); + assert.equal(counter, 1, 'incr was called once'); done(); }, 64); }); - asyncTest('throttle twice', 1, function(assert) { + QUnit.test('throttle twice', 1, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 32); throttledIncr(); throttledIncr(); - _.delay(function(){ assert.equal(counter, 2, 'incr was called twice'); start(); }, 64); + _.delay(function(){ assert.equal(counter, 2, 'incr was called twice'); done(); }, 64); }); - asyncTest('more throttling', 3, function(assert) { + QUnit.test('more throttling', 3, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 30); @@ -236,11 +243,12 @@ assert.equal(counter, 2); throttledIncr(); assert.equal(counter, 3); - start(); + done(); }, 85); }); - asyncTest('throttle repeatedly with results', 6, function(assert) { + QUnit.test('throttle repeatedly with results', 6, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ return ++counter; }; var throttledIncr = _.throttle(incr, 100); @@ -258,11 +266,12 @@ assert.equal(results[3], 2, 'incr was called twice'); assert.equal(results[4], 2, 'incr was throttled'); assert.equal(results[5], 3, 'incr was called trailing'); - start(); + done(); }, 300); }); - asyncTest('throttle triggers trailing call when invoked repeatedly', 2, function(assert) { + QUnit.test('throttle triggers trailing call when invoked repeatedly', 2, function(assert) { + var done = assert.async(); var counter = 0; var limit = 48; var incr = function(){ counter++; }; @@ -277,11 +286,12 @@ _.delay(function() { assert.ok(counter > lastCount); - start(); + done(); }, 96); }); - asyncTest('throttle does not trigger leading call when leading is set to false', 2, function(assert) { + QUnit.test('throttle does not trigger leading call when leading is set to false', 2, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 60, {leading: false}); @@ -291,11 +301,12 @@ _.delay(function() { assert.equal(counter, 1); - start(); + done(); }, 96); }); - asyncTest('more throttle does not trigger leading call when leading is set to false', 3, function(assert) { + QUnit.test('more throttle does not trigger leading call when leading is set to false', 3, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 100, {leading: false}); @@ -312,11 +323,12 @@ _.delay(function() { assert.equal(counter, 2); - start(); + done(); }, 350); }); - asyncTest('one more throttle with leading: false test', 2, function(assert) { + QUnit.test('one more throttle with leading: false test', 2, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 100, {leading: false}); @@ -327,11 +339,12 @@ _.delay(function() { assert.ok(counter <= 4); - start(); + done(); }, 200); }); - asyncTest('throttle does not trigger trailing call when trailing is set to false', 4, function(assert) { + QUnit.test('throttle does not trigger trailing call when trailing is set to false', 4, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 60, {trailing: false}); @@ -347,12 +360,13 @@ _.delay(function() { assert.equal(counter, 2); - start(); + done(); }, 96); }, 96); }); - asyncTest('throttle continues to function after system time is set backwards', 2, function(assert) { + QUnit.test('throttle continues to function after system time is set backwards', 2, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 100); @@ -367,12 +381,13 @@ _.delay(function() { throttledIncr(); assert.equal(counter, 2); - start(); + done(); _.now = origNowFunc; }, 200); }); - asyncTest('throttle re-entrant', 2, function(assert) { + QUnit.test('throttle re-entrant', 2, function(assert) { + var done = assert.async(); var sequence = [ ['b1', 'b2'], ['c1', 'c2'] @@ -391,11 +406,12 @@ assert.equal(value, 'a1a2'); _.delay(function(){ assert.equal(value, 'a1a2c1c2b1b2', 'append was throttled successfully'); - start(); + done(); }, 100); }); - asyncTest('throttle cancel', function(assert) { + QUnit.test('throttle cancel', function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 32); @@ -405,10 +421,11 @@ throttledIncr(); assert.equal(counter, 2, 'incr was called immediately'); - _.delay(function(){ assert.equal(counter, 3, 'incr was throttled'); start(); }, 64); + _.delay(function(){ assert.equal(counter, 3, 'incr was throttled'); done(); }, 64); }); - asyncTest('throttle cancel with leading: false', function(assert) { + QUnit.test('throttle cancel with leading: false', function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var throttledIncr = _.throttle(incr, 32, {leading: false}); @@ -416,28 +433,31 @@ throttledIncr.cancel(); assert.equal(counter, 0, 'incr was throttled'); - _.delay(function(){ assert.equal(counter, 0, 'incr was throttled'); start(); }, 64); + _.delay(function(){ assert.equal(counter, 0, 'incr was throttled'); done(); }, 64); }); - asyncTest('debounce', 1, function(assert) { + QUnit.test('debounce', 1, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var debouncedIncr = _.debounce(incr, 32); debouncedIncr(); debouncedIncr(); _.delay(debouncedIncr, 16); - _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 96); + _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); done(); }, 96); }); - asyncTest('debounce cancel', 1, function(assert) { + QUnit.test('debounce cancel', 1, function(assert) { + var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; var debouncedIncr = _.debounce(incr, 32); debouncedIncr(); debouncedIncr.cancel(); - _.delay(function(){ assert.equal(counter, 0, 'incr was not called'); start(); }, 96); + _.delay(function(){ assert.equal(counter, 0, 'incr was not called'); done(); }, 96); }); - asyncTest('debounce asap', 4, function(assert) { + QUnit.test('debounce asap', 4, function(assert) { + var done = assert.async(); var a, b; var counter = 0; var incr = function(){ return ++counter; }; @@ -450,10 +470,11 @@ _.delay(debouncedIncr, 16); _.delay(debouncedIncr, 32); _.delay(debouncedIncr, 48); - _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 128); + _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); done(); }, 128); }); - asyncTest('debounce asap cancel', 4, function(assert) { + QUnit.test('debounce asap cancel', 4, function(assert) { + var done = assert.async(); var a, b; var counter = 0; var incr = function(){ return ++counter; }; @@ -467,10 +488,11 @@ _.delay(debouncedIncr, 16); _.delay(debouncedIncr, 32); _.delay(debouncedIncr, 48); - _.delay(function(){ assert.equal(counter, 2, 'incr was debounced'); start(); }, 128); + _.delay(function(){ assert.equal(counter, 2, 'incr was debounced'); done(); }, 128); }); - asyncTest('debounce asap recursively', 2, function(assert) { + QUnit.test('debounce asap recursively', 2, function(assert) { + var done = assert.async(); var counter = 0; var debouncedIncr = _.debounce(function(){ counter++; @@ -478,10 +500,11 @@ }, 32, true); debouncedIncr(); assert.equal(counter, 1, 'incr was called immediately'); - _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); start(); }, 96); + _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); done(); }, 96); }); - asyncTest('debounce after system time is set backwards', 2, function(assert) { + QUnit.test('debounce after system time is set backwards', 2, function(assert) { + var done = assert.async(); var counter = 0; var origNowFunc = _.now; var debouncedIncr = _.debounce(function(){ @@ -498,12 +521,13 @@ _.delay(function() { debouncedIncr(); assert.equal(counter, 2, 'incr was debounced successfully'); - start(); + done(); _.now = origNowFunc; }, 200); }); - asyncTest('debounce re-entrant', 2, function(assert) { + QUnit.test('debounce re-entrant', 2, function(assert) { + var done = assert.async(); var sequence = [ ['b1', 'b2'] ]; @@ -521,7 +545,7 @@ assert.equal(value, ''); _.delay(function(){ assert.equal(value, 'a1a2b1b2', 'append was debounced successfully'); - start(); + done(); }, 100); }); diff --git a/test/utility.js b/test/utility.js index ff8363530..6e1b33b2c 100644 --- a/test/utility.js +++ b/test/utility.js @@ -28,7 +28,8 @@ } if (typeof require == 'function') { - asyncTest('noConflict (node vm)', 2, function(assert) { + QUnit.test('noConflict (node vm)', 2, function(assert) { + var done = assert.async(); var fs = require('fs'); var vm = require('vm'); var filename = __dirname + '/../underscore.js'; @@ -42,7 +43,7 @@ assert.equal(context._, 'oldvalue'); assert.equal(context.underscore.VERSION, _.VERSION); - start(); + done(); }); }); } From 38ac797c34631a3b6a26cd9ef927b363a40da9ae Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 13 Dec 2015 21:51:55 -0800 Subject: [PATCH 124/263] Use QUnit 2 expect() syntax --- test/collections.js | 3 +- test/functions.js | 72 ++++++++++++++++++++++++++++++--------------- test/utility.js | 15 ++++++---- 3 files changed, 60 insertions(+), 30 deletions(-) diff --git a/test/collections.js b/test/collections.js index 1bc14790e..c66239f12 100644 --- a/test/collections.js +++ b/test/collections.js @@ -453,7 +453,8 @@ }); - QUnit.test('invoke', 5, function(assert) { + QUnit.test('invoke', function(assert) { + assert.expect(5); var list = [[5, 1, 7], [3, 2, 1]]; var result = _.invoke(list, 'sort'); assert.deepEqual(result[0], [1, 5, 7], 'first array sorted'); diff --git a/test/functions.js b/test/functions.js index 3b4549129..db627ccc1 100644 --- a/test/functions.js +++ b/test/functions.js @@ -174,7 +174,8 @@ assert.strictEqual(myObj.value, 'a', 'object is not modified if second argument used as key'); }); - QUnit.test('delay', 2, function(assert) { + QUnit.test('delay', function(assert) { + assert.expect(2); var done = assert.async(); var delayed = false; _.delay(function(){ delayed = true; }, 100); @@ -182,14 +183,16 @@ setTimeout(function(){ assert.ok(delayed, 'delayed the function'); done(); }, 150); }); - QUnit.test('defer', 1, function(assert) { + QUnit.test('defer', function(assert) { + assert.expect(1); var done = assert.async(); var deferred = false; _.defer(function(bool){ deferred = bool; }, true); _.delay(function(){ assert.ok(deferred, 'deferred the function'); done(); }, 50); }); - QUnit.test('throttle', 2, function(assert) { + QUnit.test('throttle', function(assert) { + assert.expect(2); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -200,7 +203,8 @@ _.delay(function(){ assert.equal(counter, 2, 'incr was throttled'); done(); }, 64); }); - QUnit.test('throttle arguments', 2, function(assert) { + QUnit.test('throttle arguments', function(assert) { + assert.expect(2); var done = assert.async(); var value = 0; var update = function(val){ value = val; }; @@ -211,7 +215,8 @@ _.delay(function(){ assert.equal(value, 3, 'updated to latest value'); done(); }, 96); }); - QUnit.test('throttle once', 2, function(assert) { + QUnit.test('throttle once', function(assert) { + assert.expect(2); var done = assert.async(); var counter = 0; var incr = function(){ return ++counter; }; @@ -223,7 +228,8 @@ }, 64); }); - QUnit.test('throttle twice', 1, function(assert) { + QUnit.test('throttle twice', function(assert) { + assert.expect(1); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -232,7 +238,8 @@ _.delay(function(){ assert.equal(counter, 2, 'incr was called twice'); done(); }, 64); }); - QUnit.test('more throttling', 3, function(assert) { + QUnit.test('more throttling', function(assert) { + assert.expect(3); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -247,7 +254,8 @@ }, 85); }); - QUnit.test('throttle repeatedly with results', 6, function(assert) { + QUnit.test('throttle repeatedly with results', function(assert) { + assert.expect(6); var done = assert.async(); var counter = 0; var incr = function(){ return ++counter; }; @@ -270,7 +278,8 @@ }, 300); }); - QUnit.test('throttle triggers trailing call when invoked repeatedly', 2, function(assert) { + QUnit.test('throttle triggers trailing call when invoked repeatedly', function(assert) { + assert.expect(2); var done = assert.async(); var counter = 0; var limit = 48; @@ -290,7 +299,8 @@ }, 96); }); - QUnit.test('throttle does not trigger leading call when leading is set to false', 2, function(assert) { + QUnit.test('throttle does not trigger leading call when leading is set to false', function(assert) { + assert.expect(2); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -305,7 +315,8 @@ }, 96); }); - QUnit.test('more throttle does not trigger leading call when leading is set to false', 3, function(assert) { + QUnit.test('more throttle does not trigger leading call when leading is set to false', function(assert) { + assert.expect(3); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -327,7 +338,8 @@ }, 350); }); - QUnit.test('one more throttle with leading: false test', 2, function(assert) { + QUnit.test('one more throttle with leading: false test', function(assert) { + assert.expect(2); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -343,7 +355,8 @@ }, 200); }); - QUnit.test('throttle does not trigger trailing call when trailing is set to false', 4, function(assert) { + QUnit.test('throttle does not trigger trailing call when trailing is set to false', function(assert) { + assert.expect(4); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -365,7 +378,8 @@ }, 96); }); - QUnit.test('throttle continues to function after system time is set backwards', 2, function(assert) { + QUnit.test('throttle continues to function after system time is set backwards', function(assert) { + assert.expect(2); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -386,7 +400,8 @@ }, 200); }); - QUnit.test('throttle re-entrant', 2, function(assert) { + QUnit.test('throttle re-entrant', function(assert) { + assert.expect(2); var done = assert.async(); var sequence = [ ['b1', 'b2'], @@ -436,7 +451,8 @@ _.delay(function(){ assert.equal(counter, 0, 'incr was throttled'); done(); }, 64); }); - QUnit.test('debounce', 1, function(assert) { + QUnit.test('debounce', function(assert) { + assert.expect(1); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -446,7 +462,8 @@ _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); done(); }, 96); }); - QUnit.test('debounce cancel', 1, function(assert) { + QUnit.test('debounce cancel', function(assert) { + assert.expect(1); var done = assert.async(); var counter = 0; var incr = function(){ counter++; }; @@ -456,7 +473,8 @@ _.delay(function(){ assert.equal(counter, 0, 'incr was not called'); done(); }, 96); }); - QUnit.test('debounce asap', 4, function(assert) { + QUnit.test('debounce asap', function(assert) { + assert.expect(4); var done = assert.async(); var a, b; var counter = 0; @@ -473,7 +491,8 @@ _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); done(); }, 128); }); - QUnit.test('debounce asap cancel', 4, function(assert) { + QUnit.test('debounce asap cancel', function(assert) { + assert.expect(4); var done = assert.async(); var a, b; var counter = 0; @@ -491,7 +510,8 @@ _.delay(function(){ assert.equal(counter, 2, 'incr was debounced'); done(); }, 128); }); - QUnit.test('debounce asap recursively', 2, function(assert) { + QUnit.test('debounce asap recursively', function(assert) { + assert.expect(2); var done = assert.async(); var counter = 0; var debouncedIncr = _.debounce(function(){ @@ -503,7 +523,8 @@ _.delay(function(){ assert.equal(counter, 1, 'incr was debounced'); done(); }, 96); }); - QUnit.test('debounce after system time is set backwards', 2, function(assert) { + QUnit.test('debounce after system time is set backwards', function(assert) { + assert.expect(2); var done = assert.async(); var counter = 0; var origNowFunc = _.now; @@ -526,7 +547,8 @@ }, 200); }); - QUnit.test('debounce re-entrant', 2, function(assert) { + QUnit.test('debounce re-entrant', function(assert) { + assert.expect(2); var done = assert.async(); var sequence = [ ['b1', 'b2'] @@ -559,7 +581,8 @@ assert.equal(increment(), 1, 'stores a memo to the last value'); }); - QUnit.test('Recursive onced function.', 1, function(assert) { + QUnit.test('Recursive onced function.', function(assert) { + assert.expect(1); var f = _.once(function(){ assert.ok(true); f(); @@ -666,7 +689,8 @@ }); - QUnit.test('restArgs', 10, function(assert) { + QUnit.test('restArgs', function(assert) { + assert.expect(10); _.restArgs(function(a, args) { assert.strictEqual(a, 1); assert.deepEqual(args, [2, 3], 'collects rest arguments into an array'); diff --git a/test/utility.js b/test/utility.js index 6e1b33b2c..fbd54df31 100644 --- a/test/utility.js +++ b/test/utility.js @@ -28,7 +28,8 @@ } if (typeof require == 'function') { - QUnit.test('noConflict (node vm)', 2, function(assert) { + QUnit.test('noConflict (node vm)', function(assert) { + assert.expect(2); var done = assert.async(); var fs = require('fs'); var vm = require('vm'); @@ -48,7 +49,8 @@ }); } - QUnit.test('#750 - Return _ instance.', 2, function(assert) { + QUnit.test('#750 - Return _ instance.', function(assert) { + assert.expect(2); var instance = _([]); assert.ok(_(instance) === instance); assert.ok(new _(instance) === instance); @@ -391,7 +393,8 @@ assert.strictEqual(templateWithPropertyEscaped({x: {}}), ''); }); - QUnit.test('interpolate evaluates code only once.', 2, function(assert) { + QUnit.test('interpolate evaluates code only once.', function(assert) { + assert.expect(2); var count = 0; var template = _.template('<%= f() %>'); template({f: function(){ assert.ok(!count++); }}); @@ -401,13 +404,15 @@ templateEscaped({f: function(){ assert.ok(!countEscaped++); }}); }); - QUnit.test('#746 - _.template settings are not modified.', 1, function(assert) { + QUnit.test('#746 - _.template settings are not modified.', function(assert) { + assert.expect(1); var settings = {}; _.template('', null, settings); assert.deepEqual(settings, {}); }); - QUnit.test('#779 - delimeters are applied to unescaped text.', 1, function(assert) { + QUnit.test('#779 - delimeters are applied to unescaped text.', function(assert) { + assert.expect(1); var template = _.template('<<\nx\n>>', null, {evaluate: /<<(.*?)>>/g}); assert.strictEqual(template(), '<<\nx\n>>'); }); From bd91acc072c405ba315a7ffb703eb14e2c3508ca Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 15 Dec 2015 09:26:09 -0800 Subject: [PATCH 125/263] Upgrade ESLint The new version of ESLint has all rules off by default, which matches our existing usage of the tool. Some rules have been renamed, or their behavior has changed slightly. Most obviously, the `indent` rule is no-longer as lax about the indention of variable declarations. I think upgrading the tool is a net win, and the changes (while arguably trivial to the point of annoyance) do at least represent an increase in consistency. --- .eslintrc | 10 ++++++---- package.json | 4 ++-- test/collections.js | 14 +++++--------- test/functions.js | 3 ++- test/objects.js | 4 ++-- underscore.js | 20 +++++++++----------- 6 files changed, 26 insertions(+), 29 deletions(-) diff --git a/.eslintrc b/.eslintrc index 216f4a0c3..89bbb2f49 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,16 +6,18 @@ }, "rules": { + "array-bracket-spacing": [2], "block-scoped-var": 1, "brace-style": [1, "1tbs"], "camelcase": 2, "comma-dangle": [2, "never"], "comma-spacing": 2, + "computed-property-spacing": [2, "never"], "consistent-return": 1, "dot-notation": [2, { "allowKeywords": false }], "eol-last": 2, "eqeqeq": [2, "smart"], - "indent": [2, 2, {"indentSwitchCase": true}], + "indent": [2, 2, {"SwitchCase": 1, "VariableDeclarator": 2}], "key-spacing": 1, "linebreak-style": 2, "max-depth": [1, 4], @@ -32,7 +34,7 @@ "no-dupe-keys": 2, "no-duplicate-case": 2, "no-else-return": 1, - "no-empty-class": 2, + "no-empty-character-class": 2, "no-empty-label": 2, "no-eval": 2, "no-ex-assign": 2, @@ -61,7 +63,6 @@ "no-octal-escape": 2, "no-proto": 2, "no-redeclare": 2, - "no-reserved-keys": 2, "no-shadow": 2, "no-spaced-func": 2, "no-throw-literal": 2, @@ -75,13 +76,14 @@ "no-unused-vars": 2, "no-use-before-define": [2, "nofunc"], "no-with": 2, + "object-curly-spacing": [2, "never"], + "quote-props": 2, "quote-props": [1, "as-needed"], "quotes": [2, "single", "avoid-escape"], "radix": 2, "semi": 2, "space-after-keywords": [2, "always"], "space-before-function-paren": [2, {"anonymous": "never", "named": "never"}], - "space-in-brackets": [2, "never"], "space-infix-ops": 2, "space-return-throw-case": 2, "space-unary-ops": [2, { "words": true, "nonwords": false }], diff --git a/package.json b/package.json index 860a76819..b56d80770 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "devDependencies": { "coveralls": "^2.11.2", "docco": "*", - "eslint": "0.21.x", + "eslint": "1.10.x", "karma": "^0.13.13", "karma-qunit": "~0.1.4", "nyc": "^2.1.3", @@ -31,7 +31,7 @@ "test": "npm run test-node && npm run lint", "coverage": "nyc npm run test-node && nyc report", "coveralls": "nyc npm run test-node && nyc report --reporter=text-lcov | coveralls", - "lint": "eslint --reset underscore.js test/*.js", + "lint": "eslint underscore.js test/*.js", "test-node": "qunit-cli test/*.js", "test-browser": "npm i karma-phantomjs-launcher && karma start", "build": "uglifyjs underscore.js -c \"evaluate=false\" --comments \"/ .*/\" -m --source-map underscore-min.map --source-map-url \" \" -o underscore-min.js", diff --git a/test/collections.js b/test/collections.js index c66239f12..182f7a218 100644 --- a/test/collections.js +++ b/test/collections.js @@ -59,19 +59,15 @@ QUnit.test('Iterating objects with sketchy length properties', function(assert) { var functions = [ - 'each', 'map', 'filter', 'find', - 'some', 'every', 'max', 'min', - 'groupBy', 'countBy', 'partition', 'indexBy' + 'each', 'map', 'filter', 'find', + 'some', 'every', 'max', 'min', + 'groupBy', 'countBy', 'partition', 'indexBy' ]; var reducers = ['reduce', 'reduceRight']; var tricks = [ {length: '5'}, - { - length: { - valueOf: _.constant(5) - } - }, + {length: {valueOf: _.constant(5)}}, {length: Math.pow(2, 53) + 1}, {length: Math.pow(2, 53)}, {length: null}, @@ -821,7 +817,7 @@ var actual; try { actual = _.toArray(document.childNodes); - } catch(e) { /* ignored */ } + } catch (e) { /* ignored */ } assert.deepEqual(actual, _.map(document.childNodes, _.identity), 'works on NodeList'); } }); diff --git a/test/functions.js b/test/functions.js index db627ccc1..8d2b4dbb3 100644 --- a/test/functions.js +++ b/test/functions.js @@ -90,7 +90,8 @@ }); QUnit.test('bindAll', function(assert) { - var curly = {name: 'curly'}, moe = { + var curly = {name: 'curly'}; + var moe = { name: 'moe', getName: function() { return 'name: ' + this.name; }, sayHi: function() { return 'hi: ' + this.name; } diff --git a/test/objects.js b/test/objects.js index fff8ea962..ea3711370 100644 --- a/test/objects.js +++ b/test/objects.js @@ -128,7 +128,7 @@ try { result = {}; _.extend(result, null, void 0, {a: 1}); - } catch(e) { /* ignored */ } + } catch (e) { /* ignored */ } assert.equal(result.a, 1, 'should not error on `null` or `undefined` sources'); @@ -262,7 +262,7 @@ try { options = {}; _.defaults(options, null, void 0, {a: 1}); - } catch(e) { /* ignored */ } + } catch (e) { /* ignored */ } assert.equal(options.a, 1, 'should not error on `null` or `undefined` sources'); diff --git a/underscore.js b/underscore.js index 6fdfb3caf..19b3f7c9c 100644 --- a/underscore.js +++ b/underscore.js @@ -22,18 +22,16 @@ var ArrayProto = Array.prototype, ObjProto = Object.prototype; // Create quick reference variables for speed access to core prototypes. - var - push = ArrayProto.push, - slice = ArrayProto.slice, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; + var push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; // All **ECMAScript 5** native function implementations that we hope to use // are declared here. - var - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeCreate = Object.create; + var nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeCreate = Object.create; // Naked function reference for surrogate-prototype-swapping. var Ctor = function(){}; @@ -998,8 +996,8 @@ _.mapObject = function(obj, iteratee, context) { iteratee = cb(iteratee, context); var keys = _.keys(obj), - length = keys.length, - results = {}; + length = keys.length, + results = {}; for (var index = 0; index < length; index++) { var currentKey = keys[index]; results[currentKey] = iteratee(obj[currentKey], currentKey, obj); From 1e9f5d65528f5c73d4ae0f6a6f20b4b0725c85a3 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 15 Dec 2015 14:54:28 -0800 Subject: [PATCH 126/263] Remove duplicate eslint rule definition Accidentally added this rule a second time in pull request #2390. --- .eslintrc | 1 - 1 file changed, 1 deletion(-) diff --git a/.eslintrc b/.eslintrc index 89bbb2f49..73a97e193 100644 --- a/.eslintrc +++ b/.eslintrc @@ -77,7 +77,6 @@ "no-use-before-define": [2, "nofunc"], "no-with": 2, "object-curly-spacing": [2, "never"], - "quote-props": 2, "quote-props": [1, "as-needed"], "quotes": [2, "single", "avoid-escape"], "radix": 2, From e3ab2305cb315eeb5771469702cfc28263b8bc04 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 16 Dec 2015 19:30:31 -0800 Subject: [PATCH 127/263] Improve example for _.every() Using `_.identity` (the default predicate) as an example predicate is confusing. It implies that `predicate` is actually a required argument and if you want to evaluate the values untransformed, you must pass `_.identity` explicitly. --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 8094957db..be25e6f1a 100644 --- a/index.html +++ b/index.html @@ -602,7 +602,7 @@ Collection Functions (Arrays or Objects)
if a false element is found.-_.every([true, 1, null, 'yes'], _.identity); +_.every([2, 4, 5], function(num) { return num % 2 == 0; }); => falseFrom 2bce5b0b74a563607a93d24d7c477b522f1c39e1 Mon Sep 17 00:00:00 2001 From: Jordan EldredgeDate: Fri, 18 Dec 2015 08:44:00 -0800 Subject: [PATCH 128/263] Remove _.where from _.matcher tests Avoids making assumptions about _.where's implementation. --- test/objects.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/objects.js b/test/objects.js index ea3711370..027e42b6c 100644 --- a/test/objects.js +++ b/test/objects.js @@ -842,14 +842,14 @@ assert.ok(_.find(stooges, _.matcher({hair: false})) === curly, 'returns a predicate that can be used by finding functions.'); assert.ok(_.find(stooges, _.matcher(moe)) === moe, 'can be used to locate an object exists in a collection.'); - assert.deepEqual(_.where([null, void 0], {a: 1}), [], 'Do not throw on null values.'); + assert.deepEqual(_.filter([null, void 0], _.matcher({a: 1})), [], 'Do not throw on null values.'); - assert.deepEqual(_.where([null, void 0], null), [null, void 0], 'null matches null'); - assert.deepEqual(_.where([null, void 0], {}), [null, void 0], 'null matches {}'); - assert.deepEqual(_.where([{b: 1}], {a: void 0}), [], 'handles undefined values (1683)'); + assert.deepEqual(_.filter([null, void 0], _.matcher(null)), [null, void 0], 'null matches null'); + assert.deepEqual(_.filter([null, void 0], _.matcher({})), [null, void 0], 'null matches {}'); + assert.deepEqual(_.filter([{b: 1}], _.matcher({a: void 0})), [], 'handles undefined values (1683)'); _.each([true, 5, NaN, null, void 0], function(item) { - assert.deepEqual(_.where([{a: 1}], item), [{a: 1}], 'treats primitives as empty'); + assert.equal(_.matcher(item)({a: 1}), true, 'treats primitives as empty'); }); function Prototest() {} From 296063a017537dd51ae456cda7504e9abcbdb089 Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Sun, 3 Jan 2016 07:48:51 -0800 Subject: [PATCH 129/263] add isSymbol function --- index.html | 11 +++++++++++ test/objects.js | 11 +++++++++++ underscore.js | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index be25e6f1a..5e12e45b6 100644 --- a/index.html +++ b/index.html @@ -308,6 +308,7 @@ - isDate - isRegExp - isError +- isSymbol - isNaN - isNull - isUndefined @@ -1756,6 +1757,16 @@Object Functions
_.isError(o_O) } => true ++ isSymbol
+_.isSymbol(object)
+
+ Returns true if object is a Symbol. ++_.isSymbol(Symbol()); +=> truediff --git a/test/objects.js b/test/objects.js index 027e42b6c..6ca0a106f 100644 --- a/test/objects.js +++ b/test/objects.js @@ -639,6 +639,17 @@ assert.strictEqual(_.isString(1), false); }); + QUnit.test('isSymbol', function(assert) { + assert.ok(!_.isSymbol(0), 'numbers are not symbols'); + assert.ok(!_.isSymbol(''), 'strings are not symbols'); + assert.ok(!_.isSymbol(_.isSymbol), 'functions are not symbols'); + if (typeof Symbol === 'function') { + assert.ok(_.isSymbol(Symbol()), 'symbols are symbols'); + assert.ok(_.isSymbol(Symbol('description')), 'described symbols are symbols'); + assert.ok(_.isSymbol(Object(Symbol())), 'boxed symbols are symbols'); + } + }); + QUnit.test('isNumber', function(assert) { assert.ok(!_.isNumber('string'), 'a string is not a number'); assert.ok(!_.isNumber(arguments), 'the arguments object is not a number'); diff --git a/underscore.js b/underscore.js index 19b3f7c9c..d8c741b22 100644 --- a/underscore.js +++ b/underscore.js @@ -1286,7 +1286,7 @@ }; // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. - _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { + _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Symbol'], function(name) { _['is' + name] = function(obj) { return toString.call(obj) === '[object ' + name + ']'; }; From dd19d54709dbe4abe1641623722bfe80d8564748 Mon Sep 17 00:00:00 2001 From: Michael Ficarra
Date: Sun, 3 Jan 2016 07:54:35 -0800 Subject: [PATCH 130/263] add missing semicolon --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index be25e6f1a..478cce5c0 100644 --- a/index.html +++ b/index.html @@ -1753,7 +1753,7 @@ Object Functions
try { throw new TypeError("Example"); } catch (o_O) { - _.isError(o_O) + _.isError(o_O); } => trueDate: Sun, 3 Jan 2016 22:48:05 -0600 Subject: [PATCH 131/263] Remove deprecated component.json Same as https://github.com/jashkenas/backbone/pull/3917 component.json has been [deprecated since June](https://github.com/componentjs/component#this-project-is-deprecated) So there's no reason to keep maintaining it. And as it is, @jashkenas [does](https://github.com/jashkenas/underscore/pull/884#issuecomment-10999128) [not](https://github.com/jashkenas/backbone/pull/2622#issuecomment-19669694) [like](https://github.com/jashkenas/backbone/pull/2811#issuecomment-26351438) [it](https://github.com/jashkenas/backbone/commit/28d345a231cfae6b4fcc6a0e394a3534269cd168#commitcomment-4557129). --- bower.json | 2 +- component.json | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 component.json diff --git a/bower.json b/bower.json index 951eabb18..d5e1d7852 100644 --- a/bower.json +++ b/bower.json @@ -2,5 +2,5 @@ "name": "underscore", "main": "underscore.js", "keywords": ["util", "functional", "server", "client", "browser"], - "ignore" : ["docs", "test", "*.yml", "CNAME", "index.html", "favicon.ico", "CONTRIBUTING.md", ".*", "component.json", "package.json", "karma.*"] + "ignore" : ["docs", "test", "*.yml", "CNAME", "index.html", "favicon.ico", "CONTRIBUTING.md", ".*", "package.json", "karma.*"] } diff --git a/component.json b/component.json deleted file mode 100644 index 8c033f640..000000000 --- a/component.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name" : "underscore", - "description" : "JavaScript's functional programming helper library.", - "keywords" : ["util", "functional", "server", "client", "browser"], - "repo" : "jashkenas/underscore", - "main" : "underscore.js", - "scripts" : ["underscore.js"], - "version" : "1.8.3", - "license" : "MIT" -} From f796632ddc0de111236fecc84aa640664de1ee5c Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Sun, 3 Jan 2016 07:23:59 -0800 Subject: [PATCH 132/263] fixes #2402: symbol support for _.isFinite --- test/objects.js | 5 +++++ underscore.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/objects.js b/test/objects.js index 6ca0a106f..614d1cd8f 100644 --- a/test/objects.js +++ b/test/objects.js @@ -728,6 +728,11 @@ assert.ok(_.isFinite(0), '0 is finite'); assert.ok(_.isFinite(123), 'Ints are finite'); assert.ok(_.isFinite(-12.44), 'Floats are finite'); + if (typeof Symbol === 'function') { + assert.ok(!_.isFinite(Symbol()), 'symbols are not numbers'); + assert.ok(!_.isFinite(Symbol('description')), 'described symbols are not numbers'); + assert.ok(!_.isFinite(Object(Symbol())), 'boxed symbols are not numbers'); + } }); QUnit.test('isNaN', function(assert) { diff --git a/underscore.js b/underscore.js index d8c741b22..8c2874eda 100644 --- a/underscore.js +++ b/underscore.js @@ -1311,7 +1311,7 @@ // Is a given object a finite number? _.isFinite = function(obj) { - return isFinite(obj) && !isNaN(parseFloat(obj)); + return !_.isSymbol(obj) && isFinite(obj) && !isNaN(parseFloat(obj)); }; // Is the given value `NaN`? From b887a4d0ef6d0dbe0b774d1dbb6583d481d6ad53 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sat, 9 Jan 2016 08:59:50 -0800 Subject: [PATCH 133/263] Use canonical name for `_.uniq` in documentation --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index b7b91a3cb..a5d9ec206 100644 --- a/index.html +++ b/index.html @@ -1905,7 +1905,7 @@ Utility Functions
through _.iteratee is map, find, filter, reject, every, some, max, min, sortBy, groupBy, indexBy, - countBy, sortedIndex, partition, and unique. + countBy, sortedIndex, partition, and uniq.var stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}]; From 9de10a86878598f8d99cec2865e4a55a62051595 Mon Sep 17 00:00:00 2001 From: Nuno Arruda+Date: Sun, 10 Jan 2016 12:48:09 +0700 Subject: [PATCH 134/263] update copyright year range --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index ad0e71bc4..447239f3d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative +Copyright (c) 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors Permission is hereby granted, free of charge, to any person From 0e6d1e545451cba9838ad8883384f6872980a8be Mon Sep 17 00:00:00 2001 From: Adam Krebs Date: Mon, 11 Jan 2016 13:42:54 -0500 Subject: [PATCH 135/263] update copyright year --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 8c2874eda..9db5560d7 100644 --- a/underscore.js +++ b/underscore.js @@ -1,6 +1,6 @@ // Underscore.js 1.8.3 // http://underscorejs.org -// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// (c) 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license. (function() { From 0eb701c71d058ace66953feb630cfd3d74cbbeed Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Thu, 14 Jan 2016 17:48:34 -0800 Subject: [PATCH 136/263] Add missing methods to _.iteratee docs The following methods are transformed through `cb()` but are not listed in the `_.itereatee` documentation: * findIndex * findKey * findLastIndex * mapObject I've added them here, and alphabetized the list. --- index.html | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index a5d9ec206..f9f4271e9 100644 --- a/index.html +++ b/index.html @@ -1902,10 +1902,11 @@ Utility Functions
identity, an arbitrary callback, a property matcher, or a property accessor.
The full list of Underscore methods that transform predicates - through _.iteratee is map, find, - filter, reject, every, some, max, - min, sortBy, groupBy, indexBy, - countBy, sortedIndex, partition, and uniq. + through _.iteratee is countBy, every, filter, + find, findIndex, findKey, findLastIndex, + groupBy, indexBy, map, mapObject, max, + min, partition, reject, some, sortBy, + sortedIndex, and uniqvar stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}]; From 1f607d47c207acef34030eb3e7bfe69d3f16c92d Mon Sep 17 00:00:00 2001 From: Jordan Eldredgetags in _.iteratee docs I forgot to close these tags in the #2414. --- index.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index f9f4271e9..6897cbeaf 100644 --- a/index.html +++ b/index.html @@ -1902,11 +1902,11 @@Date: Tue, 19 Jan 2016 18:16:47 -0800 Subject: [PATCH 137/263] Clean up assertions for _.intersection() --- test/arrays.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 6f9cd67b6..41931c64a 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -186,20 +186,18 @@ QUnit.test('intersection', function(assert) { var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho']; - assert.deepEqual(_.intersection(stooges, leaders), ['moe'], 'can take the set intersection of two arrays'); + assert.deepEqual(_.intersection(stooges, leaders), ['moe'], 'can find the set intersection of two arrays'); assert.deepEqual(_(stooges).intersection(leaders), ['moe'], 'can perform an OO-style intersection'); var result = (function(){ return _.intersection(arguments, leaders); }('moe', 'curly', 'larry')); assert.deepEqual(result, ['moe'], 'works on an arguments object'); var theSixStooges = ['moe', 'moe', 'curly', 'curly', 'larry', 'larry']; assert.deepEqual(_.intersection(theSixStooges, leaders), ['moe'], 'returns a duplicate-free array'); result = _.intersection([2, 4, 3, 1], [1, 2, 3]); - assert.deepEqual(result, [2, 3, 1], 'preserves order of first array'); + assert.deepEqual(result, [2, 3, 1], 'preserves the order of the first array'); result = _.intersection(null, [1, 2, 3]); - assert.equal(Object.prototype.toString.call(result), '[object Array]', 'returns an empty array when passed null as first argument'); - assert.equal(result.length, 0, 'returns an empty array when passed null as first argument'); + assert.deepEqual(result, [], 'returns an empty array when passed null as the first argument'); result = _.intersection([1, 2, 3], null); - assert.equal(Object.prototype.toString.call(result), '[object Array]', 'returns an empty array when passed null as argument beyond the first'); - assert.equal(result.length, 0, 'returns an empty array when passed null as argument beyond the first'); + assert.deepEqual(result, [], 'returns an empty array when passed null as an argument beyond the first'); }); QUnit.test('union', function(assert) { From 2e3cc40d06ad3c49a9996f13e481fca67b369c06 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 20 Jan 2016 09:16:30 -0800 Subject: [PATCH 138/263] Clean up assertions for _.union() --- test/arrays.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 6f9cd67b6..ee4c92e2b 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -204,18 +204,21 @@ QUnit.test('union', function(assert) { var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]); - assert.deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays'); + assert.deepEqual(result, [1, 2, 3, 30, 40], 'can find the union of a list of arrays'); + + result = _([1, 2, 3]).union([2, 30, 1], [1, 40]); + assert.deepEqual(result, [1, 2, 3, 30, 40], 'can perform an OO-style union'); result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]); - assert.deepEqual(result, [1, 2, 3, 30, 40, [1]], 'takes the union of a list of nested arrays'); + assert.deepEqual(result, [1, 2, 3, 30, 40, [1]], 'can find the union of a list of nested arrays'); + + result = _.union([10, 20], [1, 30, 10], [0, 40]); + assert.deepEqual(result, [10, 20, 1, 30, 0, 40], 'orders values by their first encounter'); - var args = null; - (function(){ args = arguments; }(1, 2, 3)); - result = _.union(args, [2, 30, 1], [1, 40]); - assert.deepEqual(result, [1, 2, 3, 30, 40], 'takes the union of a list of arrays'); + result = (function(){ return _.union(arguments, [2, 30, 1], [1, 40]); }(1, 2, 3)); + assert.deepEqual(result, [1, 2, 3, 30, 40], 'works on an arguments object'); - result = _.union([1, 2, 3], 4); - assert.deepEqual(result, [1, 2, 3], 'restrict the union to arrays only'); + assert.deepEqual(_.union([1, 2, 3], 4), [1, 2, 3], 'restricts the union to arrays only'); }); QUnit.test('difference', function(assert) { From 1e69d38a5a8f24c1330c29e748fa6174436c122b Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 20 Jan 2016 09:58:48 -0800 Subject: [PATCH 139/263] Clean up assertions for _.difference() --- test/arrays.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 90e2a4b91..748edea4f 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -221,10 +221,19 @@ QUnit.test('difference', function(assert) { var result = _.difference([1, 2, 3], [2, 30, 40]); - assert.deepEqual(result, [1, 3], 'takes the difference of two arrays'); + assert.deepEqual(result, [1, 3], 'can find the difference of two arrays'); + + result = _([1, 2, 3]).difference([2, 30, 40]); + assert.deepEqual(result, [1, 3], 'can perform an OO-style difference'); result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]); - assert.deepEqual(result, [3, 4], 'takes the difference of three arrays'); + assert.deepEqual(result, [3, 4], 'can find the difference of three arrays'); + + result = _.difference([8, 9, 3, 1], [3, 8]); + assert.deepEqual(result, [9, 1], 'preserves the order of the first array'); + + result = (function(){ return _.difference(arguments, [2, 30, 40]); }(1, 2, 3)); + assert.deepEqual(result, [1, 3], 'works on an arguments object'); result = _.difference([1, 2, 3], 1); assert.deepEqual(result, [1, 2, 3], 'restrict the difference to arrays only'); From 34b45d8b6110a4ea18ed2b4629877fb4a2002333 Mon Sep 17 00:00:00 2001 From: Craig Martin Date: Thu, 21 Jan 2016 08:58:28 -0500 Subject: [PATCH 140/263] add gitter and stackoverflow links to readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c2ba2590c..f29a03c51 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ without extending any core JavaScript objects. For Docs, License, Tests, and pre-packed downloads, see: http://underscorejs.org +For support and questions, please use +[the gitter channel](https://gitter.im/jashkenas/underscore) +or [stackoverflow](http://stackoverflow.com/search?q=underscore.js) + Underscore is an open-sourced component of DocumentCloud: https://github.com/documentcloud From b7925e0819557abe4f113df5ee2e19ff64e77776 Mon Sep 17 00:00:00 2001 From: Craig Martin Date: Wed, 27 Jan 2016 09:38:50 -0500 Subject: [PATCH 141/263] disable npm's progress bar in travis ci for quicker install --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 172af86c3..f0e6ad148 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ notifications: email: false env: global: + - NPM_CONFIG_PROGRESS="false" - secure: bDZSBQfqr21hCayjcZ20IxrV6+XGhxQPFIfwWqEKLrF93Gu8LLVjZRxXE/mE8I8N4Z5WtDNb4ZHrm/TTzmcPa5MuHgIxEdknQCncobH8oimwc83SHwEPk6okeNKl39VlCjvvnmoe/V/KpnknuYn3Rqghtl/Uv9KLpCwskwjTtcw= - secure: SRECgXuwcZTcD3GVxTS2bYNgRyye4vq6BLrV2PH9FyNenowsKQR2EwlC/dppc1Q8NWMgv79J/R96q9JOFh+mEH9L5dlBb2yhnGH8amVeM/ChAJHT/F8YktKM453uVpz5fR00QcCQDDUOx6Pvx374ID0OKNpWKAkQBWA9mPTsLnE= matrix: BROWSER=false From 65b5398d432083727e3f8f0461f781e6c5fe3001 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 27 Jan 2016 08:05:06 -0800 Subject: [PATCH 142/263] Fix closing Utility Functions
identity, an arbitrary callback, a property matcher, or a property accessor.
The full list of Underscore methods that transform predicates - through _.iteratee is countBy, every, filter, - find, findIndex, findKey, findLastIndex, - groupBy, indexBy, map, mapObject, max, - min, partition, reject, some, sortBy, - sortedIndex, and uniq + through _.iteratee is countBy, every, filter, + find, findIndex, findKey, findLastIndex, + groupBy, indexBy, map, mapObject, max, + min, partition, reject, some, sortBy, + sortedIndex, and uniqvar stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}]; From ed96600c23798168f998eb873bde629f4bbbcc67 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge-Date: Wed, 27 Jan 2016 08:18:10 -0800 Subject: [PATCH 143/263] Separate object-oriented style and chaining in docs I think the fact that the object-oriented style and chaining share implementation details has lead us to conflate them in the docs. In practice, the two features have almost nothing to do with each other. The existing documentation could easily lead one to believe that they could start a chain using the OOP style. This confusion is compounded by a few factors: 1. Lodash supports chains starting with the OOP wrapper. 2. The fact that we share names with native Array methods can lead to manual tests that appear to work. For example: _([1,2,3]).reverse().map(function(n){ return n * 2; }); This appears to be an example of successfully starting a chain with the OOP style. The astute observer will note that the lack of a `.value()` call, proves this is not Underscore chaining, but a new user attempting to clarify the behavior for herself may not catch that detail. --- index.html | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index 6897cbeaf..60c290e5a 100644 --- a/index.html +++ b/index.html @@ -334,6 +334,9 @@ - template + + OOP Style + Chaining @@ -1861,7 +1864,7 @@Utility Functions
iteratee is called with an index argument. Produces an array of the returned values.
- Note: this example uses the chaining syntax. + Note: this example uses the object-oriented syntax._(3).times(function(n){ genie.grantWishNumber(n); });@@ -2055,7 +2058,7 @@Utility Functions
</script>Chaining
+Object-Oriented Style
You can use Underscore in either an object-oriented or a functional style, @@ -2067,6 +2070,8 @@
Chaining
_.map([1, 2, 3], function(n){ return n * 2; }); _([1, 2, 3]).map(function(n){ return n * 2; });Chaining
+Calling chain will cause all future method calls to return wrapped objects. When you've finished the computation, call @@ -2119,13 +2124,13 @@
Chaining
- value_(obj).value()
+ value_.chain(obj).value()
Extracts the value of a wrapped object.
-_([1, 2, 3]).value(); -=> [1, 2, 3] +_.chain([1, 2, 3]).reverse().value(); +=> [3, 2, 1]
-_.unzip([['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]]) -=> ["moe", 30, true], ["larry", 40, false], ["curly", 50, false] +_.unzip([["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]); +=> [['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]]
From 723aaff63df45520eeea4daabf35623427c712d1 Mon Sep 17 00:00:00 2001
From: Adam Krebs
Underscore.php,
- a PHP port of the functions that are applicable in both languages. Tailored for PHP 5.4 and made with data-type tolerance in mind.
+ a PHP port of the functions that are applicable in both languages.
+ Tailored for PHP 5.4 and made with data-type tolerance in mind.
(source)
Links & Suggested Reading
Links & Suggested Reading
reverse, sprintf, and more.
+ Underscore-java, + a java port of the functions that are applicable in both languages. + Includes OOP-wrapping and chaining. + (source) +
+Ruby's Enumerable module.
From 15f10acf2b9a2b2df3a30551f87e67c095202908 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge
iteratee_.iteratee(value, [context])
- A mostly-internal function to generate callbacks that can be applied
- to each element in a collection, returning the desired result — either
- identity, an arbitrary callback, a property matcher, or a property accessor.
-
- The full list of Underscore methods that transform predicates
- through _.iteratee is countBy, every, filter,
- find, findIndex, findKey, findLastIndex,
- groupBy, indexBy, map, mapObject, max,
- min, partition, reject, some, sortBy,
- sortedIndex, and uniq
+ Generates a callback that can be applied to each element in
+ a collection. _.iteratee supports a number of shorthand
+ syntaxes for common callback use cases. Depending value's type
+ _.iteratee will return:
-var stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}]; -_.map(stooges, _.iteratee('age')); -=> [25, 21, 23]; -+// No value +_.iteratee(); +=> _.identity() + +// Function +_.iteratee(function(n) { return n * 2; }); +=> function(n) { return n * 2; } + +// Object +_.iteratee({firstName: 'Chelsea'}); +=> _.matcher({firstName: 'Chelsea'}); + +// Anything else +_.iteratee('firstName'); +=> _.property('firstName'); + +
+ The following Underscore methods transform their predicates through + _.iteratee: countBy, every, + filter, find, findIndex, findKey, + findLastIndex, groupBy, indexBy, + map, mapObject, max, min, + partition, reject, some, sortBy, + sortedIndex, and uniq +
uniqueId_.uniqueId([prefix])
From b51863962a5d9246bb054106d3bf94f2d5e75929 Mon Sep 17 00:00:00 2001
From: Jordan Eldredge Utility Functions
Generates a callback that can be applied to each element in
a collection. _.iteratee supports a number of shorthand
- syntaxes for common callback use cases. Depending value's type
- _.iteratee will return:
+ syntaxes for common callback use cases. Depending upon value's
+ type, _.iteratee will return:
// No value From f32dfc6fde825976a3126b12cc81dad4e42cfcc5 Mon Sep 17 00:00:00 2001 From: Jordan EldredgeDate: Wed, 30 Mar 2016 08:53:01 -0700 Subject: [PATCH 166/263] Document customizing `_.iteratee` --- index.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/index.html b/index.html index 17ee2e2af..04f129aaf 100644 --- a/index.html +++ b/index.html @@ -1932,6 +1932,17 @@ Utility Functions
sortedIndex, and uniq ++ You may overwrite _.iteratee with your own custom function, + if you want additional or different shorthand syntaxes: +
++// Support `RegExp` predicate shorthand. +var builtinIteratee = _.iteratee; +_.iteratee = function(value, context) { + if (_.isRegExp(value)) return function(obj) { return value.test(obj) }; + return builtinIteratee(value, context); +};uniqueId
_.uniqueId([prefix])
From 012fe2b77e3d206d763c0c078d3b97a63639fc24 Mon Sep 17 00:00:00 2001 From: Jordan EldredgeDate: Sun, 3 Apr 2016 18:45:44 -0700 Subject: [PATCH 167/263] Cleanup comment indentation --- underscore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/underscore.js b/underscore.js index f2f04dc24..db5d62845 100644 --- a/underscore.js +++ b/underscore.js @@ -1099,7 +1099,7 @@ return result; }); - // Return a copy of the object without the blacklisted properties. + // Return a copy of the object without the blacklisted properties. _.omit = restArgs(function(obj, keys) { var iteratee = keys[0], context; if (_.isFunction(iteratee)) { @@ -1408,7 +1408,7 @@ return new Date().getTime(); }; - // List of HTML entities for escaping. + // List of HTML entities for escaping. var escapeMap = { '&': '&', '<': '<', From 0c10935623cd378d15ec3b04f82c6a5359274a7e Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 3 Apr 2016 22:48:48 -0700 Subject: [PATCH 168/263] Fix the argument order of some assertions Error messages assume the order `actual, expected`. Using https://github.com/platinumazure/eslint-plugin-qunit/blob/master/docs/rules/literal-compare-order.md I was able to automatically detect some of our tests which don't follow this convention. I'm sure there are others. --- test/collections.js | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/test/collections.js b/test/collections.js index 182f7a218..b3e4f8623 100644 --- a/test/collections.js +++ b/test/collections.js @@ -549,7 +549,7 @@ assert.equal(-Infinity, _.max(void 0), 'can handle null/undefined'); assert.equal(-Infinity, _.max(null, _.identity), 'can handle null/undefined'); - assert.equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max'); + assert.equal(_.max([1, 2, 3]), 3, 'can perform a regular Math.max'); var neg = _.max([1, 2, 3], function(num){ return -num; }); assert.equal(neg, 1, 'can perform a computation-based max'); @@ -558,24 +558,24 @@ assert.equal(-Infinity, _.max([]), 'Maximum value of an empty array'); assert.equal(_.max({a: 'a'}), -Infinity, 'Maximum value of a non-numeric collection'); - assert.equal(299999, _.max(_.range(1, 300000)), 'Maximum value of a too-big array'); + assert.equal(_.max(_.range(1, 300000)), 299999, 'Maximum value of a too-big array'); - assert.equal(3, _.max([1, 2, 3, 'test']), 'Finds correct max in array starting with num and containing a NaN'); - assert.equal(3, _.max(['test', 1, 2, 3]), 'Finds correct max in array starting with NaN'); + assert.equal(_.max([1, 2, 3, 'test']), 3, 'Finds correct max in array starting with num and containing a NaN'); + assert.equal(_.max(['test', 1, 2, 3]), 3, 'Finds correct max in array starting with NaN'); - assert.equal(3, _.max([1, 2, 3, null]), 'Finds correct max in array starting with num and containing a `null`'); - assert.equal(3, _.max([null, 1, 2, 3]), 'Finds correct max in array starting with a `null`'); + assert.equal(_.max([1, 2, 3, null]), 3, 'Finds correct max in array starting with num and containing a `null`'); + assert.equal(_.max([null, 1, 2, 3]), 3, 'Finds correct max in array starting with a `null`'); - assert.equal(3, _.max([1, 2, 3, '']), 'Finds correct max in array starting with num and containing an empty string'); - assert.equal(3, _.max(['', 1, 2, 3]), 'Finds correct max in array starting with an empty string'); + assert.equal(_.max([1, 2, 3, '']), 3, 'Finds correct max in array starting with num and containing an empty string'); + assert.equal(_.max(['', 1, 2, 3]), 3, 'Finds correct max in array starting with an empty string'); - assert.equal(3, _.max([1, 2, 3, false]), 'Finds correct max in array starting with num and containing a false'); - assert.equal(3, _.max([false, 1, 2, 3]), 'Finds correct max in array starting with a false'); + assert.equal(_.max([1, 2, 3, false]), 3, 'Finds correct max in array starting with num and containing a false'); + assert.equal(_.max([false, 1, 2, 3]), 3, 'Finds correct max in array starting with a false'); - assert.equal(4, _.max([0, 1, 2, 3, 4]), 'Finds correct max in array containing a zero'); - assert.equal(0, _.max([-3, -2, -1, 0]), 'Finds correct max in array containing negative numbers'); + assert.equal(_.max([0, 1, 2, 3, 4]), 4, 'Finds correct max in array containing a zero'); + assert.equal(_.max([-3, -2, -1, 0]), 0, 'Finds correct max in array containing negative numbers'); - assert.deepEqual([3, 6], _.map([[1, 2, 3], [4, 5, 6]], _.max), 'Finds correct max in array when mapping through multiple arrays'); + assert.deepEqual(_.map([[1, 2, 3], [4, 5, 6]], _.max), [3, 6], 'Finds correct max in array when mapping through multiple arrays'); var a = {x: -Infinity}; var b = {x: -Infinity}; @@ -590,35 +590,35 @@ }); QUnit.test('min', function(assert) { - assert.equal(Infinity, _.min(null), 'can handle null/undefined'); - assert.equal(Infinity, _.min(void 0), 'can handle null/undefined'); - assert.equal(Infinity, _.min(null, _.identity), 'can handle null/undefined'); + assert.equal(_.min(null), Infinity, 'can handle null/undefined'); + assert.equal(_.min(void 0), Infinity, 'can handle null/undefined'); + assert.equal(_.min(null, _.identity), Infinity, 'can handle null/undefined'); - assert.equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min'); + assert.equal(_.min([1, 2, 3]), 1, 'can perform a regular Math.min'); var neg = _.min([1, 2, 3], function(num){ return -num; }); assert.equal(neg, 3, 'can perform a computation-based min'); - assert.equal(Infinity, _.min({}), 'Minimum value of an empty object'); - assert.equal(Infinity, _.min([]), 'Minimum value of an empty array'); + assert.equal(_.min({}), Infinity, 'Minimum value of an empty object'); + assert.equal(_.min([]), Infinity, 'Minimum value of an empty array'); assert.equal(_.min({a: 'a'}), Infinity, 'Minimum value of a non-numeric collection'); - assert.deepEqual([1, 4], _.map([[1, 2, 3], [4, 5, 6]], _.min), 'Finds correct min in array when mapping through multiple arrays'); + assert.deepEqual(_.map([[1, 2, 3], [4, 5, 6]], _.min), [1, 4], 'Finds correct min in array when mapping through multiple arrays'); var now = new Date(9999999999); var then = new Date(0); assert.equal(_.min([now, then]), then); - assert.equal(1, _.min(_.range(1, 300000)), 'Minimum value of a too-big array'); + assert.equal(_.min(_.range(1, 300000)), 1, 'Minimum value of a too-big array'); - assert.equal(1, _.min([1, 2, 3, 'test']), 'Finds correct min in array starting with num and containing a NaN'); - assert.equal(1, _.min(['test', 1, 2, 3]), 'Finds correct min in array starting with NaN'); + assert.equal(_.min([1, 2, 3, 'test']), 1, 'Finds correct min in array starting with num and containing a NaN'); + assert.equal(_.min(['test', 1, 2, 3]), 1, 'Finds correct min in array starting with NaN'); - assert.equal(1, _.min([1, 2, 3, null]), 'Finds correct min in array starting with num and containing a `null`'); - assert.equal(1, _.min([null, 1, 2, 3]), 'Finds correct min in array starting with a `null`'); + assert.equal(_.min([1, 2, 3, null]), 1, 'Finds correct min in array starting with num and containing a `null`'); + assert.equal(_.min([null, 1, 2, 3]), 1, 'Finds correct min in array starting with a `null`'); - assert.equal(0, _.min([0, 1, 2, 3, 4]), 'Finds correct min in array containing a zero'); - assert.equal(-3, _.min([-3, -2, -1, 0]), 'Finds correct min in array containing negative numbers'); + assert.equal(_.min([0, 1, 2, 3, 4]), 0, 'Finds correct min in array containing a zero'); + assert.equal(_.min([-3, -2, -1, 0]), -3, 'Finds correct min in array containing negative numbers'); var a = {x: Infinity}; var b = {x: Infinity}; From 7943530568a94af59f36804cf82c9aaff7afbc89 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 3 Apr 2016 22:34:54 -0700 Subject: [PATCH 169/263] Use descriptive assertions Using descriptive assertions can help give better failure messages. These were found using @platinumazure's [`eslint-plugin-qunit`](https://github.com/platinumazure/eslint-plugin-qunit). Once it reaches version 1.0, we could consider including it as part of our linting. --- test/collections.js | 24 ++++++++++++------------ test/objects.js | 4 ++-- test/utility.js | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/test/collections.js b/test/collections.js index 182f7a218..00f1a8a22 100644 --- a/test/collections.js +++ b/test/collections.js @@ -188,7 +188,7 @@ var prod = _.reduce([1, 2, 3, 4], function(memo, num){ return memo * num; }); assert.equal(prod, 24, 'can reduce via multiplication'); - assert.ok(_.reduce(null, _.noop, 138) === 138, 'handles a null (with initial value) properly'); + assert.strictEqual(_.reduce(null, _.noop, 138), 138, 'handles a null (with initial value) properly'); assert.equal(_.reduce([], _.noop, void 0), void 0, 'undefined can be passed as a special case'); assert.equal(_.reduce([_], _.noop), _, 'collection of length one with no initial value returns the first item'); assert.equal(_.reduce([], _.noop), void 0, 'returns undefined when collection is empty and no initial value'); @@ -212,7 +212,7 @@ var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(memo, num){ return memo + num; }); assert.equal(sum, 6, 'default initial value on object'); - assert.ok(_.reduceRight(null, _.noop, 138) === 138, 'handles a null (with initial value) properly'); + assert.strictEqual(_.reduceRight(null, _.noop, 138), 138, 'handles a null (with initial value) properly'); assert.equal(_.reduceRight([_], _.noop), _, 'collection of length one with no initial value returns the first item'); assert.equal(_.reduceRight([], _.noop, void 0), void 0, 'undefined can be passed as a special case'); @@ -351,8 +351,8 @@ assert.ok(!_.every([true, false, true], _.identity), 'one false value'); assert.ok(_.every([0, 10, 28], function(num){ return num % 2 === 0; }), 'even numbers'); assert.ok(!_.every([0, 11, 28], function(num){ return num % 2 === 0; }), 'an odd number'); - assert.ok(_.every([1], _.identity) === true, 'cast to boolean - true'); - assert.ok(_.every([0], _.identity) === false, 'cast to boolean - false'); + assert.strictEqual(_.every([1], _.identity), true, 'cast to boolean - true'); + assert.strictEqual(_.every([0], _.identity), false, 'cast to boolean - false'); assert.ok(!_.every([void 0, void 0, void 0], _.identity), 'works with arrays of undefined'); var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; @@ -381,8 +381,8 @@ assert.ok(!_.some([null, 0, '', false]), 'falsy values'); assert.ok(!_.some([1, 11, 29], function(num){ return num % 2 === 0; }), 'all odd numbers'); assert.ok(_.some([1, 10, 29], function(num){ return num % 2 === 0; }), 'an even number'); - assert.ok(_.some([1], _.identity) === true, 'cast to boolean - true'); - assert.ok(_.some([0], _.identity) === false, 'cast to boolean - false'); + assert.strictEqual(_.some([1], _.identity), true, 'cast to boolean - true'); + assert.strictEqual(_.some([0], _.identity), false, 'cast to boolean - false'); assert.ok(_.some([false, false, true])); var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; @@ -412,7 +412,7 @@ assert.strictEqual(_.includes([5, 4, 3, 2, 1], 5, true), true, 'doesn\'t delegate to binary search'); - assert.ok(_.includes({moe: 1, larry: 3, curly: 9}, 3) === true, '_.includes on objects checks their values'); + assert.strictEqual(_.includes({moe: 1, larry: 3, curly: 9}, 3), true, '_.includes on objects checks their values'); assert.ok(_([1, 2, 3]).includes(2), 'OO-style includes'); var numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; @@ -692,7 +692,7 @@ assert.deepEqual(grouped['5'], ['three', 'seven', 'eight']); var context = {}; - _.groupBy([{}], function(){ assert.ok(this === context); }, context); + _.groupBy([{}], function(){ assert.strictEqual(this, context); }, context); grouped = _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; @@ -701,7 +701,7 @@ assert.equal(grouped.hasOwnProperty.length, 2); var array = [{}]; - _.groupBy(array, function(value, index, obj){ assert.ok(obj === array); }); + _.groupBy(array, function(value, index, obj){ assert.strictEqual(obj, array); }); array = [1, 2, 1, 2, 3]; grouped = _.groupBy(array); @@ -747,7 +747,7 @@ assert.equal(grouped['5'], 3); var context = {}; - _.countBy([{}], function(){ assert.ok(this === context); }, context); + _.countBy([{}], function(){ assert.strictEqual(this, context); }, context); grouped = _.countBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor'; @@ -756,7 +756,7 @@ assert.equal(grouped.hasOwnProperty, 2); var array = [{}]; - _.countBy(array, function(value, index, obj){ assert.ok(obj === array); }); + _.countBy(array, function(value, index, obj){ assert.strictEqual(obj, array); }); array = [1, 2, 1, 2, 3]; grouped = _.countBy(array); @@ -800,7 +800,7 @@ assert.ok(!_.isArray(arguments), 'arguments object is not an array'); assert.ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array'); var a = [1, 2, 3]; - assert.ok(_.toArray(a) !== a, 'array is cloned'); + assert.notStrictEqual(_.toArray(a), a, 'array is cloned'); assert.deepEqual(_.toArray(a), [1, 2, 3], 'cloned array contains same elements'); var numbers = _.toArray({one: 1, two: 2, three: 3}); diff --git a/test/objects.js b/test/objects.js index fa1d9e3e3..059a9b28c 100644 --- a/test/objects.js +++ b/test/objects.js @@ -958,8 +958,8 @@ assert.equal(_.matcher({})(null), true, 'Empty spec called with null object returns true'); assert.equal(_.matcher({a: 1})(null), false, 'Non-empty spec called with null object returns false'); - assert.ok(_.find(stooges, _.matcher({hair: false})) === curly, 'returns a predicate that can be used by finding functions.'); - assert.ok(_.find(stooges, _.matcher(moe)) === moe, 'can be used to locate an object exists in a collection.'); + assert.strictEqual(_.find(stooges, _.matcher({hair: false})), curly, 'returns a predicate that can be used by finding functions.'); + assert.strictEqual(_.find(stooges, _.matcher(moe)), moe, 'can be used to locate an object exists in a collection.'); assert.deepEqual(_.filter([null, void 0], _.matcher({a: 1})), [], 'Do not throw on null values.'); assert.deepEqual(_.filter([null, void 0], _.matcher(null)), [null, void 0], 'null matches null'); diff --git a/test/utility.js b/test/utility.js index fbd54df31..60d387597 100644 --- a/test/utility.js +++ b/test/utility.js @@ -52,8 +52,8 @@ QUnit.test('#750 - Return _ instance.', function(assert) { assert.expect(2); var instance = _([]); - assert.ok(_(instance) === instance); - assert.ok(new _(instance) === instance); + assert.strictEqual(_(instance), instance); + assert.strictEqual(new _(instance), instance); }); QUnit.test('identity', function(assert) { @@ -188,7 +188,7 @@ var str = 'some string & another string & yet another'; var escaped = _.escape(str); - assert.ok(escaped.indexOf('&') !== -1, 'handles & aka &'); + assert.notStrictEqual(escaped.indexOf('&'), -1, 'handles & aka &'); assert.equal(_.unescape(str), str, 'can unescape &'); }); From cc1cb526bc8d6d9d0e9ef6c6b2b3b0905cffe04e Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sun, 3 Apr 2016 21:58:52 -0700 Subject: [PATCH 170/263] Prefer `assert.notOk()` to `assert.ok(!)` In #2389 we upgraded our browser tests to QUnit 1.18.0 which means we can now use the `assert.notOk()` assertion. Using this gives a less confusing error message when the assertion fails. Assuming my `shouldBeFalse()` function is failing: assert.ok(!shouldBeFalse()); => failed, expected argument to be truthy, was: false assert.notOk(shouldBeFalse()); => failed, expected argument to be falsy, was: true --- test/collections.js | 40 +++--- test/cross-document.js | 20 +-- test/functions.js | 2 +- test/objects.js | 316 ++++++++++++++++++++--------------------- test/utility.js | 8 +- 5 files changed, 193 insertions(+), 193 deletions(-) diff --git a/test/collections.js b/test/collections.js index 320f323d0..76ed98c94 100644 --- a/test/collections.js +++ b/test/collections.js @@ -268,8 +268,8 @@ var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}]; assert.deepEqual(_.find(list, {a: 1}), {a: 1, b: 2}, 'can be used as findWhere'); assert.deepEqual(_.find(list, {b: 4}), {a: 1, b: 4}); - assert.ok(!_.find(list, {c: 1}), 'undefined when not found'); - assert.ok(!_.find([], {c: 1}), 'undefined when searching empty list'); + assert.notOk(_.find(list, {c: 1}), 'undefined when not found'); + assert.notOk(_.find([], {c: 1}), 'undefined when searching empty list'); var result = _.find([1, 2, 3], function(num){ return num * 2 === 4; }); assert.equal(result, 2, 'found the first "2" and broke the loop'); @@ -348,25 +348,25 @@ QUnit.test('every', function(assert) { assert.ok(_.every([], _.identity), 'the empty set'); assert.ok(_.every([true, true, true], _.identity), 'every true values'); - assert.ok(!_.every([true, false, true], _.identity), 'one false value'); + assert.notOk(_.every([true, false, true], _.identity), 'one false value'); assert.ok(_.every([0, 10, 28], function(num){ return num % 2 === 0; }), 'even numbers'); - assert.ok(!_.every([0, 11, 28], function(num){ return num % 2 === 0; }), 'an odd number'); + assert.notOk(_.every([0, 11, 28], function(num){ return num % 2 === 0; }), 'an odd number'); assert.strictEqual(_.every([1], _.identity), true, 'cast to boolean - true'); assert.strictEqual(_.every([0], _.identity), false, 'cast to boolean - false'); - assert.ok(!_.every([void 0, void 0, void 0], _.identity), 'works with arrays of undefined'); + assert.notOk(_.every([void 0, void 0, void 0], _.identity), 'works with arrays of undefined'); var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; - assert.ok(!_.every(list, {a: 1, b: 2}), 'Can be called with object'); + assert.notOk(_.every(list, {a: 1, b: 2}), 'Can be called with object'); assert.ok(_.every(list, 'a'), 'String mapped to object property'); list = [{a: 1, b: 2}, {a: 2, b: 2, c: true}]; assert.ok(_.every(list, {b: 2}), 'Can be called with object'); - assert.ok(!_.every(list, 'c'), 'String mapped to object property'); + assert.notOk(_.every(list, 'c'), 'String mapped to object property'); assert.ok(_.every({a: 1, b: 2, c: 3, d: 4}, _.isNumber), 'takes objects'); - assert.ok(!_.every({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects'); + assert.notOk(_.every({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects'); assert.ok(_.every(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); - assert.ok(!_.every(['a', 'b', 'c', 'd', 'f'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); + assert.notOk(_.every(['a', 'b', 'c', 'd', 'f'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); }); QUnit.test('all', function(assert) { @@ -374,29 +374,29 @@ }); QUnit.test('some', function(assert) { - assert.ok(!_.some([]), 'the empty set'); - assert.ok(!_.some([false, false, false]), 'all false values'); + assert.notOk(_.some([]), 'the empty set'); + assert.notOk(_.some([false, false, false]), 'all false values'); assert.ok(_.some([false, false, true]), 'one true value'); assert.ok(_.some([null, 0, 'yes', false]), 'a string'); - assert.ok(!_.some([null, 0, '', false]), 'falsy values'); - assert.ok(!_.some([1, 11, 29], function(num){ return num % 2 === 0; }), 'all odd numbers'); + assert.notOk(_.some([null, 0, '', false]), 'falsy values'); + assert.notOk(_.some([1, 11, 29], function(num){ return num % 2 === 0; }), 'all odd numbers'); assert.ok(_.some([1, 10, 29], function(num){ return num % 2 === 0; }), 'an even number'); assert.strictEqual(_.some([1], _.identity), true, 'cast to boolean - true'); assert.strictEqual(_.some([0], _.identity), false, 'cast to boolean - false'); assert.ok(_.some([false, false, true])); var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]; - assert.ok(!_.some(list, {a: 5, b: 2}), 'Can be called with object'); + assert.notOk(_.some(list, {a: 5, b: 2}), 'Can be called with object'); assert.ok(_.some(list, 'a'), 'String mapped to object property'); list = [{a: 1, b: 2}, {a: 2, b: 2, c: true}]; assert.ok(_.some(list, {b: 2}), 'Can be called with object'); - assert.ok(!_.some(list, 'd'), 'String mapped to object property'); + assert.notOk(_.some(list, 'd'), 'String mapped to object property'); assert.ok(_.some({a: '1', b: '2', c: '3', d: '4', e: 6}, _.isNumber), 'takes objects'); - assert.ok(!_.some({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects'); + assert.notOk(_.some({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects'); assert.ok(_.some(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); - assert.ok(!_.some(['x', 'y', 'z'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); + assert.notOk(_.some(['x', 'y', 'z'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works'); }); QUnit.test('any', function(assert) { @@ -408,7 +408,7 @@ assert.strictEqual(_.includes(val, 'hasOwnProperty'), false); }); assert.strictEqual(_.includes([1, 2, 3], 2), true, 'two is in the array'); - assert.ok(!_.includes([1, 3, 9], 2), 'two is not in the array'); + assert.notOk(_.includes([1, 3, 9], 2), 'two is not in the array'); assert.strictEqual(_.includes([5, 4, 3, 2, 1], 5, true), true, 'doesn\'t delegate to binary search'); @@ -797,7 +797,7 @@ }); QUnit.test('toArray', function(assert) { - assert.ok(!_.isArray(arguments), 'arguments object is not an array'); + assert.notOk(_.isArray(arguments), 'arguments object is not an array'); assert.ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array'); var a = [1, 2, 3]; assert.notStrictEqual(_.toArray(a), a, 'array is cloned'); @@ -882,7 +882,7 @@ assert.deepEqual(_.map(elementChildren, 'id'), ['id1', 'id2']); assert.deepEqual(_.map(parent.childNodes, 'nodeType'), [1, 3, 1]); - assert.ok(!_.every(parent.childNodes, _.isElement)); + assert.notOk(_.every(parent.childNodes, _.isElement)); assert.ok(_.some(parent.childNodes, _.isElement)); function compareNode(node) { diff --git a/test/cross-document.js b/test/cross-document.js index cb68a3d9b..bc3ab77f1 100644 --- a/test/cross-document.js +++ b/test/cross-document.js @@ -35,7 +35,7 @@ QUnit.test('isEqual', function(assert) { - assert.ok(!_.isEqual(iNumber, 101)); + assert.notOk(_.isEqual(iNumber, 101)); assert.ok(_.isEqual(iNumber, 100)); // Objects from another frame. @@ -46,13 +46,13 @@ }); QUnit.test('isEmpty', function(assert) { - assert.ok(!_([iNumber]).isEmpty(), '[1] is not empty'); - assert.ok(!_.isEmpty(iArray), '[] is empty'); + assert.notOk(_([iNumber]).isEmpty(), '[1] is not empty'); + assert.notOk(_.isEmpty(iArray), '[] is empty'); assert.ok(_.isEmpty(iObject), '{} is empty'); }); QUnit.test('isElement', function(assert) { - assert.ok(!_.isElement('div'), 'strings are not dom elements'); + assert.notOk(_.isElement('div'), 'strings are not dom elements'); assert.ok(_.isElement(document.body), 'the body tag is a DOM element'); assert.ok(_.isElement(iElement), 'even from another frame'); }); @@ -113,12 +113,12 @@ if (typeof ActiveXObject != 'undefined') { QUnit.test('IE host objects', function(assert) { var xml = new ActiveXObject('Msxml2.DOMDocument.3.0'); - assert.ok(!_.isNumber(xml)); - assert.ok(!_.isBoolean(xml)); - assert.ok(!_.isNaN(xml)); - assert.ok(!_.isFunction(xml)); - assert.ok(!_.isNull(xml)); - assert.ok(!_.isUndefined(xml)); + assert.notOk(_.isNumber(xml)); + assert.notOk(_.isBoolean(xml)); + assert.notOk(_.isNaN(xml)); + assert.notOk(_.isFunction(xml)); + assert.notOk(_.isNull(xml)); + assert.notOk(_.isUndefined(xml)); }); QUnit.test('#1621 IE 11 compat mode DOM elements are not functions', function(assert) { diff --git a/test/functions.js b/test/functions.js index e31d1d355..f73f5d382 100644 --- a/test/functions.js +++ b/test/functions.js @@ -180,7 +180,7 @@ var done = assert.async(); var delayed = false; _.delay(function(){ delayed = true; }, 100); - setTimeout(function(){ assert.ok(!delayed, "didn't delay the function quite yet"); }, 50); + setTimeout(function(){ assert.notOk(delayed, "didn't delay the function quite yet"); }, 50); setTimeout(function(){ assert.ok(delayed, 'delayed the function'); done(); }, 150); }); diff --git a/test/objects.js b/test/objects.js index 059a9b28c..91c49a4cc 100644 --- a/test/objects.js +++ b/test/objects.js @@ -123,7 +123,7 @@ subObj.c = 'd'; assert.deepEqual(_.extend({}, subObj), {a: 'b', c: 'd'}, 'extend copies all properties from source'); _.extend(subObj, {}); - assert.ok(!subObj.hasOwnProperty('a'), "extend does not convert destination object's 'in' properties to 'own' properties"); + assert.notOk(subObj.hasOwnProperty('a'), "extend does not convert destination object's 'in' properties to 'own' properties"); try { result = {}; @@ -205,7 +205,7 @@ return this[key] === 3 && this === instance; }, instance), {c: 3}, 'function is given context'); - assert.ok(!_.has(_.pick({}, 'foo'), 'foo'), 'does not set own property if property not in object'); + assert.notOk(_.has(_.pick({}, 'foo'), 'foo'), 'does not set own property if property not in object'); _.pick(data, function(value, key, obj) { assert.equal(obj, data, 'passes same object as third parameter of iteratee'); }); @@ -309,7 +309,7 @@ Child.prototype.foo = 'foo'; var created = _.create(Child.prototype, new Child); - assert.ok(!created.hasOwnProperty('foo'), 'should only add own properties'); + assert.notOk(created.hasOwnProperty('foo'), 'should only add own properties'); }); QUnit.test('isEqual', function(assert) { @@ -326,10 +326,10 @@ assert.ok(_.isEqual(null, null), '`null` is equal to `null`'); assert.ok(_.isEqual(), '`undefined` is equal to `undefined`'); - assert.ok(!_.isEqual(0, -0), '`0` is not equal to `-0`'); - assert.ok(!_.isEqual(-0, 0), 'Commutative equality is implemented for `0` and `-0`'); - assert.ok(!_.isEqual(null, void 0), '`null` is not equal to `undefined`'); - assert.ok(!_.isEqual(void 0, null), 'Commutative equality is implemented for `null` and `undefined`'); + assert.notOk(_.isEqual(0, -0), '`0` is not equal to `-0`'); + assert.notOk(_.isEqual(-0, 0), 'Commutative equality is implemented for `0` and `-0`'); + assert.notOk(_.isEqual(null, void 0), '`null` is not equal to `undefined`'); + assert.notOk(_.isEqual(void 0, null), 'Commutative equality is implemented for `null` and `undefined`'); // String object and primitive comparisons. assert.ok(_.isEqual('Curly', 'Curly'), 'Identical string primitives are equal'); @@ -337,76 +337,76 @@ assert.ok(_.isEqual(new String('Curly'), 'Curly'), 'String primitives and their corresponding object wrappers are equal'); assert.ok(_.isEqual('Curly', new String('Curly')), 'Commutative equality is implemented for string objects and primitives'); - assert.ok(!_.isEqual('Curly', 'Larry'), 'String primitives with different values are not equal'); - assert.ok(!_.isEqual(new String('Curly'), new String('Larry')), 'String objects with different primitive values are not equal'); - assert.ok(!_.isEqual(new String('Curly'), {toString: function(){ return 'Curly'; }}), 'String objects and objects with a custom `toString` method are not equal'); + assert.notOk(_.isEqual('Curly', 'Larry'), 'String primitives with different values are not equal'); + assert.notOk(_.isEqual(new String('Curly'), new String('Larry')), 'String objects with different primitive values are not equal'); + assert.notOk(_.isEqual(new String('Curly'), {toString: function(){ return 'Curly'; }}), 'String objects and objects with a custom `toString` method are not equal'); // Number object and primitive comparisons. assert.ok(_.isEqual(75, 75), 'Identical number primitives are equal'); assert.ok(_.isEqual(new Number(75), new Number(75)), 'Number objects with identical primitive values are equal'); assert.ok(_.isEqual(75, new Number(75)), 'Number primitives and their corresponding object wrappers are equal'); assert.ok(_.isEqual(new Number(75), 75), 'Commutative equality is implemented for number objects and primitives'); - assert.ok(!_.isEqual(new Number(0), -0), '`new Number(0)` and `-0` are not equal'); - assert.ok(!_.isEqual(0, new Number(-0)), 'Commutative equality is implemented for `new Number(0)` and `-0`'); + assert.notOk(_.isEqual(new Number(0), -0), '`new Number(0)` and `-0` are not equal'); + assert.notOk(_.isEqual(0, new Number(-0)), 'Commutative equality is implemented for `new Number(0)` and `-0`'); - assert.ok(!_.isEqual(new Number(75), new Number(63)), 'Number objects with different primitive values are not equal'); - assert.ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), 'Number objects and objects with a `valueOf` method are not equal'); + assert.notOk(_.isEqual(new Number(75), new Number(63)), 'Number objects with different primitive values are not equal'); + assert.notOk(_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), 'Number objects and objects with a `valueOf` method are not equal'); // Comparisons involving `NaN`. assert.ok(_.isEqual(NaN, NaN), '`NaN` is equal to `NaN`'); assert.ok(_.isEqual(new Number(NaN), NaN), 'Object(`NaN`) is equal to `NaN`'); - assert.ok(!_.isEqual(61, NaN), 'A number primitive is not equal to `NaN`'); - assert.ok(!_.isEqual(new Number(79), NaN), 'A number object is not equal to `NaN`'); - assert.ok(!_.isEqual(Infinity, NaN), '`Infinity` is not equal to `NaN`'); + assert.notOk(_.isEqual(61, NaN), 'A number primitive is not equal to `NaN`'); + assert.notOk(_.isEqual(new Number(79), NaN), 'A number object is not equal to `NaN`'); + assert.notOk(_.isEqual(Infinity, NaN), '`Infinity` is not equal to `NaN`'); // Boolean object and primitive comparisons. assert.ok(_.isEqual(true, true), 'Identical boolean primitives are equal'); assert.ok(_.isEqual(new Boolean, new Boolean), 'Boolean objects with identical primitive values are equal'); assert.ok(_.isEqual(true, new Boolean(true)), 'Boolean primitives and their corresponding object wrappers are equal'); assert.ok(_.isEqual(new Boolean(true), true), 'Commutative equality is implemented for booleans'); - assert.ok(!_.isEqual(new Boolean(true), new Boolean), 'Boolean objects with different primitive values are not equal'); + assert.notOk(_.isEqual(new Boolean(true), new Boolean), 'Boolean objects with different primitive values are not equal'); // Common type coercions. - assert.ok(!_.isEqual(new Boolean(false), true), '`new Boolean(false)` is not equal to `true`'); - assert.ok(!_.isEqual('75', 75), 'String and number primitives with like values are not equal'); - assert.ok(!_.isEqual(new Number(63), new String(63)), 'String and number objects with like values are not equal'); - assert.ok(!_.isEqual(75, '75'), 'Commutative equality is implemented for like string and number values'); - assert.ok(!_.isEqual(0, ''), 'Number and string primitives with like values are not equal'); - assert.ok(!_.isEqual(1, true), 'Number and boolean primitives with like values are not equal'); - assert.ok(!_.isEqual(new Boolean(false), new Number(0)), 'Boolean and number objects with like values are not equal'); - assert.ok(!_.isEqual(false, new String('')), 'Boolean primitives and string objects with like values are not equal'); - assert.ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), 'Dates and their corresponding numeric primitive values are not equal'); + assert.notOk(_.isEqual(new Boolean(false), true), '`new Boolean(false)` is not equal to `true`'); + assert.notOk(_.isEqual('75', 75), 'String and number primitives with like values are not equal'); + assert.notOk(_.isEqual(new Number(63), new String(63)), 'String and number objects with like values are not equal'); + assert.notOk(_.isEqual(75, '75'), 'Commutative equality is implemented for like string and number values'); + assert.notOk(_.isEqual(0, ''), 'Number and string primitives with like values are not equal'); + assert.notOk(_.isEqual(1, true), 'Number and boolean primitives with like values are not equal'); + assert.notOk(_.isEqual(new Boolean(false), new Number(0)), 'Boolean and number objects with like values are not equal'); + assert.notOk(_.isEqual(false, new String('')), 'Boolean primitives and string objects with like values are not equal'); + assert.notOk(_.isEqual(12564504e5, new Date(2009, 9, 25)), 'Dates and their corresponding numeric primitive values are not equal'); // Dates. assert.ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), 'Date objects referencing identical times are equal'); - assert.ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), 'Date objects referencing different times are not equal'); - assert.ok(!_.isEqual(new Date(2009, 11, 13), { + assert.notOk(_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), 'Date objects referencing different times are not equal'); + assert.notOk(_.isEqual(new Date(2009, 11, 13), { getTime: function(){ return 12606876e5; } }), 'Date objects and objects with a `getTime` method are not equal'); - assert.ok(!_.isEqual(new Date('Curly'), new Date('Curly')), 'Invalid dates are not equal'); + assert.notOk(_.isEqual(new Date('Curly'), new Date('Curly')), 'Invalid dates are not equal'); // Functions. - assert.ok(!_.isEqual(First, Second), 'Different functions with identical bodies and source code representations are not equal'); + assert.notOk(_.isEqual(First, Second), 'Different functions with identical bodies and source code representations are not equal'); // RegExps. assert.ok(_.isEqual(/(?:)/gim, /(?:)/gim), 'RegExps with equivalent patterns and flags are equal'); assert.ok(_.isEqual(/(?:)/gi, /(?:)/ig), 'Flag order is not significant'); - assert.ok(!_.isEqual(/(?:)/g, /(?:)/gi), 'RegExps with equivalent patterns and different flags are not equal'); - assert.ok(!_.isEqual(/Moe/gim, /Curly/gim), 'RegExps with different patterns and equivalent flags are not equal'); - assert.ok(!_.isEqual(/(?:)/gi, /(?:)/g), 'Commutative equality is implemented for RegExps'); - assert.ok(!_.isEqual(/Curly/g, {source: 'Larry', global: true, ignoreCase: false, multiline: false}), 'RegExps and RegExp-like objects are not equal'); + assert.notOk(_.isEqual(/(?:)/g, /(?:)/gi), 'RegExps with equivalent patterns and different flags are not equal'); + assert.notOk(_.isEqual(/Moe/gim, /Curly/gim), 'RegExps with different patterns and equivalent flags are not equal'); + assert.notOk(_.isEqual(/(?:)/gi, /(?:)/g), 'Commutative equality is implemented for RegExps'); + assert.notOk(_.isEqual(/Curly/g, {source: 'Larry', global: true, ignoreCase: false, multiline: false}), 'RegExps and RegExp-like objects are not equal'); // Empty arrays, array-like objects, and object literals. assert.ok(_.isEqual({}, {}), 'Empty object literals are equal'); assert.ok(_.isEqual([], []), 'Empty array literals are equal'); assert.ok(_.isEqual([{}], [{}]), 'Empty nested arrays and objects are equal'); - assert.ok(!_.isEqual({length: 0}, []), 'Array-like objects and arrays are not equal.'); - assert.ok(!_.isEqual([], {length: 0}), 'Commutative equality is implemented for array-like objects'); + assert.notOk(_.isEqual({length: 0}, []), 'Array-like objects and arrays are not equal.'); + assert.notOk(_.isEqual([], {length: 0}), 'Commutative equality is implemented for array-like objects'); - assert.ok(!_.isEqual({}, []), 'Object literals and array literals are not equal'); - assert.ok(!_.isEqual([], {}), 'Commutative equality is implemented for objects and arrays'); + assert.notOk(_.isEqual({}, []), 'Object literals and array literals are not equal'); + assert.notOk(_.isEqual([], {}), 'Commutative equality is implemented for objects and arrays'); // Arrays with primitive and object values. assert.ok(_.isEqual([1, 'Larry', true], [1, 'Larry', true]), 'Arrays containing identical primitives are equal'); @@ -424,14 +424,14 @@ // Array elements and properties. assert.ok(_.isEqual(a, b), 'Arrays containing equivalent elements and different non-numeric properties are equal'); a.push('White Rocks'); - assert.ok(!_.isEqual(a, b), 'Arrays of different lengths are not equal'); + assert.notOk(_.isEqual(a, b), 'Arrays of different lengths are not equal'); a.push('East Boulder'); b.push('Gunbarrel Ranch', 'Teller Farm'); - assert.ok(!_.isEqual(a, b), 'Arrays of identical lengths containing different elements are not equal'); + assert.notOk(_.isEqual(a, b), 'Arrays of identical lengths containing different elements are not equal'); // Sparse arrays. assert.ok(_.isEqual(Array(3), Array(3)), 'Sparse arrays of identical lengths are equal'); - assert.ok(!_.isEqual(Array(3), Array(6)), 'Sparse arrays of different lengths are not equal when both are empty'); + assert.notOk(_.isEqual(Array(3), Array(6)), 'Sparse arrays of different lengths are not equal when both are empty'); var sparse = []; sparse[1] = 5; @@ -440,11 +440,11 @@ // Simple objects. assert.ok(_.isEqual({a: 'Curly', b: 1, c: true}, {a: 'Curly', b: 1, c: true}), 'Objects containing identical primitives are equal'); assert.ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), 'Objects containing equivalent members are equal'); - assert.ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), 'Objects of identical sizes with different values are not equal'); - assert.ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), 'Objects of identical sizes with different property names are not equal'); - assert.ok(!_.isEqual({a: 1, b: 2}, {a: 1}), 'Objects of different sizes are not equal'); - assert.ok(!_.isEqual({a: 1}, {a: 1, b: 2}), 'Commutative equality is implemented for objects'); - assert.ok(!_.isEqual({x: 1, y: void 0}, {x: 1, z: 2}), 'Objects with identical keys and different values are not equivalent'); + assert.notOk(_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), 'Objects of identical sizes with different values are not equal'); + assert.notOk(_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), 'Objects of identical sizes with different property names are not equal'); + assert.notOk(_.isEqual({a: 1, b: 2}, {a: 1}), 'Objects of different sizes are not equal'); + assert.notOk(_.isEqual({a: 1}, {a: 1, b: 2}), 'Commutative equality is implemented for objects'); + assert.notOk(_.isEqual({x: 1, y: void 0}, {x: 1, z: 2}), 'Objects with identical keys and different values are not equivalent'); // `A` contains nested objects and arrays. a = { @@ -479,9 +479,9 @@ // Instances. assert.ok(_.isEqual(new First, new First), 'Object instances are equal'); - assert.ok(!_.isEqual(new First, new Second), 'Objects with different constructors and identical own properties are not equal'); - assert.ok(!_.isEqual({value: 1}, new First), 'Object instances and objects sharing equivalent properties are not equal'); - assert.ok(!_.isEqual({value: 2}, new Second), 'The prototype chain of objects should not be examined'); + assert.notOk(_.isEqual(new First, new Second), 'Objects with different constructors and identical own properties are not equal'); + assert.notOk(_.isEqual({value: 1}, new First), 'Object instances and objects sharing equivalent properties are not equal'); + assert.notOk(_.isEqual({value: 2}, new Second), 'The prototype chain of objects should not be examined'); // Circular Arrays. (a = []).push(a); @@ -492,13 +492,13 @@ assert.ok(_.isEqual(a, b), 'Arrays containing circular references and equivalent properties are equal'); a.push('Shemp'); b.push('Curly'); - assert.ok(!_.isEqual(a, b), 'Arrays containing circular references and different properties are not equal'); + assert.notOk(_.isEqual(a, b), 'Arrays containing circular references and different properties are not equal'); // More circular arrays #767. a = ['everything is checked but', 'this', 'is not']; a[1] = a; b = ['everything is checked but', ['this', 'array'], 'is not']; - assert.ok(!_.isEqual(a, b), 'Comparison of circular references with non-circular references are not equal'); + assert.notOk(_.isEqual(a, b), 'Comparison of circular references with non-circular references are not equal'); // Circular Objects. a = {abc: null}; @@ -511,13 +511,13 @@ assert.ok(_.isEqual(a, b), 'Objects containing circular references and equivalent properties are equal'); a.def = new Number(75); b.def = new Number(63); - assert.ok(!_.isEqual(a, b), 'Objects containing circular references and different properties are not equal'); + assert.notOk(_.isEqual(a, b), 'Objects containing circular references and different properties are not equal'); // More circular objects #767. a = {everything: 'is checked', but: 'this', is: 'not'}; a.but = a; b = {everything: 'is checked', but: {that: 'object'}, is: 'not'}; - assert.ok(!_.isEqual(a, b), 'Comparison of circular references with non-circular object references are not equal'); + assert.notOk(_.isEqual(a, b), 'Comparison of circular references with non-circular object references are not equal'); // Cyclic Structures. a = [{abc: null}]; @@ -530,7 +530,7 @@ assert.ok(_.isEqual(a, b), 'Cyclic structures containing equivalent properties are equal'); a[0].def = new String('Larry'); b[0].def = new String('Curly'); - assert.ok(!_.isEqual(a, b), 'Cyclic structures containing different properties are not equal'); + assert.notOk(_.isEqual(a, b), 'Cyclic structures containing different properties are not equal'); // Complex Circular References. a = {foo: {b: {foo: {c: {foo: null}}}}}; @@ -540,7 +540,7 @@ assert.ok(_.isEqual(a, b), 'Cyclic structures with nested and identically-named properties are equal'); // Chaining. - assert.ok(!_.isEqual(_({x: 1, y: void 0}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal'); + assert.notOk(_.isEqual(_({x: 1, y: void 0}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal'); a = _({x: 1, y: 2}).chain(); b = _({x: 1, y: 2}).chain(); @@ -576,15 +576,15 @@ }); QUnit.test('isEmpty', function(assert) { - assert.ok(!_([1]).isEmpty(), '[1] is not empty'); + assert.notOk(_([1]).isEmpty(), '[1] is not empty'); assert.ok(_.isEmpty([]), '[] is empty'); - assert.ok(!_.isEmpty({one: 1}), '{one: 1} is not empty'); + assert.notOk(_.isEmpty({one: 1}), '{one: 1} is not empty'); assert.ok(_.isEmpty({}), '{} is empty'); assert.ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty'); assert.ok(_.isEmpty(null), 'null is empty'); assert.ok(_.isEmpty(), 'undefined is empty'); assert.ok(_.isEmpty(''), 'the empty string is empty'); - assert.ok(!_.isEmpty('moe'), 'but other strings are not'); + assert.notOk(_.isEmpty('moe'), 'but other strings are not'); var obj = {one: 1}; delete obj.one; @@ -592,27 +592,27 @@ var args = function(){ return arguments; }; assert.ok(_.isEmpty(args()), 'empty arguments object is empty'); - assert.ok(!_.isEmpty(args('')), 'non-empty arguments object is not empty'); + assert.notOk(_.isEmpty(args('')), 'non-empty arguments object is not empty'); // covers collecting non-enumerable properties in IE < 9 var nonEnumProp = {toString: 5}; - assert.ok(!_.isEmpty(nonEnumProp), 'non-enumerable property is not empty'); + assert.notOk(_.isEmpty(nonEnumProp), 'non-enumerable property is not empty'); }); if (typeof document === 'object') { QUnit.test('isElement', function(assert) { - assert.ok(!_.isElement('div'), 'strings are not dom elements'); + assert.notOk(_.isElement('div'), 'strings are not dom elements'); assert.ok(_.isElement(testElement), 'an element is a DOM element'); }); } QUnit.test('isArguments', function(assert) { var args = (function(){ return arguments; }(1, 2, 3)); - assert.ok(!_.isArguments('string'), 'a string is not an arguments object'); - assert.ok(!_.isArguments(_.isArguments), 'a function is not an arguments object'); + assert.notOk(_.isArguments('string'), 'a string is not an arguments object'); + assert.notOk(_.isArguments(_.isArguments), 'a function is not an arguments object'); assert.ok(_.isArguments(args), 'but the arguments object is an arguments object'); - assert.ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array'); - assert.ok(!_.isArguments([1, 2, 3]), 'and not vanilla arrays.'); + assert.notOk(_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array'); + assert.notOk(_.isArguments([1, 2, 3]), 'and not vanilla arrays.'); }); QUnit.test('isObject', function(assert) { @@ -622,24 +622,24 @@ assert.ok(_.isObject(testElement), 'and DOM element'); } assert.ok(_.isObject(function() {}), 'and functions'); - assert.ok(!_.isObject(null), 'but not null'); - assert.ok(!_.isObject(void 0), 'and not undefined'); - assert.ok(!_.isObject('string'), 'and not string'); - assert.ok(!_.isObject(12), 'and not number'); - assert.ok(!_.isObject(true), 'and not boolean'); + assert.notOk(_.isObject(null), 'but not null'); + assert.notOk(_.isObject(void 0), 'and not undefined'); + assert.notOk(_.isObject('string'), 'and not string'); + assert.notOk(_.isObject(12), 'and not number'); + assert.notOk(_.isObject(true), 'and not boolean'); assert.ok(_.isObject(new String('string')), 'but new String()'); }); QUnit.test('isArray', function(assert) { - assert.ok(!_.isArray(void 0), 'undefined vars are not arrays'); - assert.ok(!_.isArray(arguments), 'the arguments object is not an array'); + assert.notOk(_.isArray(void 0), 'undefined vars are not arrays'); + assert.notOk(_.isArray(arguments), 'the arguments object is not an array'); assert.ok(_.isArray([1, 2, 3]), 'but arrays are'); }); QUnit.test('isString', function(assert) { var obj = new String('I am a string object'); if (testElement) { - assert.ok(!_.isString(testElement), 'an element is not a string'); + assert.notOk(_.isString(testElement), 'an element is not a string'); } assert.ok(_.isString([1, 2, 3].join(', ')), 'but strings are'); assert.strictEqual(_.isString('I am a string literal'), true, 'string literals are'); @@ -648,9 +648,9 @@ }); QUnit.test('isSymbol', function(assert) { - assert.ok(!_.isSymbol(0), 'numbers are not symbols'); - assert.ok(!_.isSymbol(''), 'strings are not symbols'); - assert.ok(!_.isSymbol(_.isSymbol), 'functions are not symbols'); + assert.notOk(_.isSymbol(0), 'numbers are not symbols'); + assert.notOk(_.isSymbol(''), 'strings are not symbols'); + assert.notOk(_.isSymbol(_.isSymbol), 'functions are not symbols'); if (typeof Symbol === 'function') { assert.ok(_.isSymbol(Symbol()), 'symbols are symbols'); assert.ok(_.isSymbol(Symbol('description')), 'described symbols are symbols'); @@ -659,43 +659,43 @@ }); QUnit.test('isNumber', function(assert) { - assert.ok(!_.isNumber('string'), 'a string is not a number'); - assert.ok(!_.isNumber(arguments), 'the arguments object is not a number'); - assert.ok(!_.isNumber(void 0), 'undefined is not a number'); + assert.notOk(_.isNumber('string'), 'a string is not a number'); + assert.notOk(_.isNumber(arguments), 'the arguments object is not a number'); + assert.notOk(_.isNumber(void 0), 'undefined is not a number'); assert.ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are'); assert.ok(_.isNumber(NaN), 'NaN *is* a number'); assert.ok(_.isNumber(Infinity), 'Infinity is a number'); - assert.ok(!_.isNumber('1'), 'numeric strings are not numbers'); + assert.notOk(_.isNumber('1'), 'numeric strings are not numbers'); }); QUnit.test('isBoolean', function(assert) { - assert.ok(!_.isBoolean(2), 'a number is not a boolean'); - assert.ok(!_.isBoolean('string'), 'a string is not a boolean'); - assert.ok(!_.isBoolean('false'), 'the string "false" is not a boolean'); - assert.ok(!_.isBoolean('true'), 'the string "true" is not a boolean'); - assert.ok(!_.isBoolean(arguments), 'the arguments object is not a boolean'); - assert.ok(!_.isBoolean(void 0), 'undefined is not a boolean'); - assert.ok(!_.isBoolean(NaN), 'NaN is not a boolean'); - assert.ok(!_.isBoolean(null), 'null is not a boolean'); + assert.notOk(_.isBoolean(2), 'a number is not a boolean'); + assert.notOk(_.isBoolean('string'), 'a string is not a boolean'); + assert.notOk(_.isBoolean('false'), 'the string "false" is not a boolean'); + assert.notOk(_.isBoolean('true'), 'the string "true" is not a boolean'); + assert.notOk(_.isBoolean(arguments), 'the arguments object is not a boolean'); + assert.notOk(_.isBoolean(void 0), 'undefined is not a boolean'); + assert.notOk(_.isBoolean(NaN), 'NaN is not a boolean'); + assert.notOk(_.isBoolean(null), 'null is not a boolean'); assert.ok(_.isBoolean(true), 'but true is'); assert.ok(_.isBoolean(false), 'and so is false'); }); QUnit.test('isMap', function(assert) { - assert.ok(!_.isMap('string'), 'a string is not a map'); - assert.ok(!_.isMap(2), 'a number is not a map'); - assert.ok(!_.isMap({}), 'an object is not a map'); - assert.ok(!_.isMap(false), 'a boolean is not a map'); - assert.ok(!_.isMap(void 0), 'undefined is not a map'); - assert.ok(!_.isMap([1, 2, 3]), 'an array is not a map'); + assert.notOk(_.isMap('string'), 'a string is not a map'); + assert.notOk(_.isMap(2), 'a number is not a map'); + assert.notOk(_.isMap({}), 'an object is not a map'); + assert.notOk(_.isMap(false), 'a boolean is not a map'); + assert.notOk(_.isMap(void 0), 'undefined is not a map'); + assert.notOk(_.isMap([1, 2, 3]), 'an array is not a map'); if (typeof Set === 'function') { - assert.ok(!_.isMap(new Set()), 'a set is not a map'); + assert.notOk(_.isMap(new Set()), 'a set is not a map'); } if (typeof WeakSet === 'function') { - assert.ok(!_.isMap(new WeakSet()), 'a weakset is not a map'); + assert.notOk(_.isMap(new WeakSet()), 'a weakset is not a map'); } if (typeof WeakMap === 'function') { - assert.ok(!_.isMap(new WeakMap()), 'a weakmap is not a map'); + assert.notOk(_.isMap(new WeakMap()), 'a weakmap is not a map'); } if (typeof Map === 'function') { var keyString = 'a string'; @@ -706,20 +706,20 @@ }); QUnit.test('isWeakMap', function(assert) { - assert.ok(!_.isWeakMap('string'), 'a string is not a weakmap'); - assert.ok(!_.isWeakMap(2), 'a number is not a weakmap'); - assert.ok(!_.isWeakMap({}), 'an object is not a weakmap'); - assert.ok(!_.isWeakMap(false), 'a boolean is not a weakmap'); - assert.ok(!_.isWeakMap(void 0), 'undefined is not a weakmap'); - assert.ok(!_.isWeakMap([1, 2, 3]), 'an array is not a weakmap'); + assert.notOk(_.isWeakMap('string'), 'a string is not a weakmap'); + assert.notOk(_.isWeakMap(2), 'a number is not a weakmap'); + assert.notOk(_.isWeakMap({}), 'an object is not a weakmap'); + assert.notOk(_.isWeakMap(false), 'a boolean is not a weakmap'); + assert.notOk(_.isWeakMap(void 0), 'undefined is not a weakmap'); + assert.notOk(_.isWeakMap([1, 2, 3]), 'an array is not a weakmap'); if (typeof Set === 'function') { - assert.ok(!_.isWeakMap(new Set()), 'a set is not a weakmap'); + assert.notOk(_.isWeakMap(new Set()), 'a set is not a weakmap'); } if (typeof WeakSet === 'function') { - assert.ok(!_.isWeakMap(new WeakSet()), 'a weakset is not a weakmap'); + assert.notOk(_.isWeakMap(new WeakSet()), 'a weakset is not a weakmap'); } if (typeof Map === 'function') { - assert.ok(!_.isWeakMap(new Map()), 'a map is not a weakmap'); + assert.notOk(_.isWeakMap(new Map()), 'a map is not a weakmap'); } if (typeof WeakMap === 'function') { var keyObj = {}, obj = new WeakMap(); @@ -729,20 +729,20 @@ }); QUnit.test('isSet', function(assert) { - assert.ok(!_.isSet('string'), 'a string is not a set'); - assert.ok(!_.isSet(2), 'a number is not a set'); - assert.ok(!_.isSet({}), 'an object is not a set'); - assert.ok(!_.isSet(false), 'a boolean is not a set'); - assert.ok(!_.isSet(void 0), 'undefined is not a set'); - assert.ok(!_.isSet([1, 2, 3]), 'an array is not a set'); + assert.notOk(_.isSet('string'), 'a string is not a set'); + assert.notOk(_.isSet(2), 'a number is not a set'); + assert.notOk(_.isSet({}), 'an object is not a set'); + assert.notOk(_.isSet(false), 'a boolean is not a set'); + assert.notOk(_.isSet(void 0), 'undefined is not a set'); + assert.notOk(_.isSet([1, 2, 3]), 'an array is not a set'); if (typeof Map === 'function') { - assert.ok(!_.isSet(new Map()), 'a map is not a set'); + assert.notOk(_.isSet(new Map()), 'a map is not a set'); } if (typeof WeakMap === 'function') { - assert.ok(!_.isSet(new WeakMap()), 'a weakmap is not a set'); + assert.notOk(_.isSet(new WeakMap()), 'a weakmap is not a set'); } if (typeof WeakSet === 'function') { - assert.ok(!_.isSet(new WeakSet()), 'a weakset is not a set'); + assert.notOk(_.isSet(new WeakSet()), 'a weakset is not a set'); } if (typeof Set === 'function') { var obj = new Set(); @@ -753,20 +753,20 @@ QUnit.test('isWeakSet', function(assert) { - assert.ok(!_.isWeakSet('string'), 'a string is not a weakset'); - assert.ok(!_.isWeakSet(2), 'a number is not a weakset'); - assert.ok(!_.isWeakSet({}), 'an object is not a weakset'); - assert.ok(!_.isWeakSet(false), 'a boolean is not a weakset'); - assert.ok(!_.isWeakSet(void 0), 'undefined is not a weakset'); - assert.ok(!_.isWeakSet([1, 2, 3]), 'an array is not a weakset'); + assert.notOk(_.isWeakSet('string'), 'a string is not a weakset'); + assert.notOk(_.isWeakSet(2), 'a number is not a weakset'); + assert.notOk(_.isWeakSet({}), 'an object is not a weakset'); + assert.notOk(_.isWeakSet(false), 'a boolean is not a weakset'); + assert.notOk(_.isWeakSet(void 0), 'undefined is not a weakset'); + assert.notOk(_.isWeakSet([1, 2, 3]), 'an array is not a weakset'); if (typeof Map === 'function') { - assert.ok(!_.isWeakSet(new Map()), 'a map is not a weakset'); + assert.notOk(_.isWeakSet(new Map()), 'a map is not a weakset'); } if (typeof WeakMap === 'function') { - assert.ok(!_.isWeakSet(new WeakMap()), 'a weakmap is not a weakset'); + assert.notOk(_.isWeakSet(new WeakMap()), 'a weakmap is not a weakset'); } if (typeof Set === 'function') { - assert.ok(!_.isWeakSet(new Set()), 'a set is not a weakset'); + assert.notOk(_.isWeakSet(new Set()), 'a set is not a weakset'); } if (typeof WeakSet === 'function') { var obj = new WeakSet(); @@ -776,19 +776,19 @@ }); QUnit.test('isFunction', function(assert) { - assert.ok(!_.isFunction(void 0), 'undefined vars are not functions'); - assert.ok(!_.isFunction([1, 2, 3]), 'arrays are not functions'); - assert.ok(!_.isFunction('moe'), 'strings are not functions'); + assert.notOk(_.isFunction(void 0), 'undefined vars are not functions'); + assert.notOk(_.isFunction([1, 2, 3]), 'arrays are not functions'); + assert.notOk(_.isFunction('moe'), 'strings are not functions'); assert.ok(_.isFunction(_.isFunction), 'but functions are'); assert.ok(_.isFunction(function(){}), 'even anonymous ones'); if (testElement) { - assert.ok(!_.isFunction(testElement), 'elements are not functions'); + assert.notOk(_.isFunction(testElement), 'elements are not functions'); } var nodelist = typeof document != 'undefined' && document.childNodes; if (nodelist) { - assert.ok(!_.isFunction(nodelist)); + assert.notOk(_.isFunction(nodelist)); } }); @@ -806,65 +806,65 @@ } QUnit.test('isDate', function(assert) { - assert.ok(!_.isDate(100), 'numbers are not dates'); - assert.ok(!_.isDate({}), 'objects are not dates'); + assert.notOk(_.isDate(100), 'numbers are not dates'); + assert.notOk(_.isDate({}), 'objects are not dates'); assert.ok(_.isDate(new Date()), 'but dates are'); }); QUnit.test('isRegExp', function(assert) { - assert.ok(!_.isRegExp(_.identity), 'functions are not RegExps'); + assert.notOk(_.isRegExp(_.identity), 'functions are not RegExps'); assert.ok(_.isRegExp(/identity/), 'but RegExps are'); }); QUnit.test('isFinite', function(assert) { - assert.ok(!_.isFinite(void 0), 'undefined is not finite'); - assert.ok(!_.isFinite(null), 'null is not finite'); - assert.ok(!_.isFinite(NaN), 'NaN is not finite'); - assert.ok(!_.isFinite(Infinity), 'Infinity is not finite'); - assert.ok(!_.isFinite(-Infinity), '-Infinity is not finite'); + assert.notOk(_.isFinite(void 0), 'undefined is not finite'); + assert.notOk(_.isFinite(null), 'null is not finite'); + assert.notOk(_.isFinite(NaN), 'NaN is not finite'); + assert.notOk(_.isFinite(Infinity), 'Infinity is not finite'); + assert.notOk(_.isFinite(-Infinity), '-Infinity is not finite'); assert.ok(_.isFinite('12'), 'Numeric strings are numbers'); - assert.ok(!_.isFinite('1a'), 'Non numeric strings are not numbers'); - assert.ok(!_.isFinite(''), 'Empty strings are not numbers'); + assert.notOk(_.isFinite('1a'), 'Non numeric strings are not numbers'); + assert.notOk(_.isFinite(''), 'Empty strings are not numbers'); var obj = new Number(5); assert.ok(_.isFinite(obj), 'Number instances can be finite'); assert.ok(_.isFinite(0), '0 is finite'); assert.ok(_.isFinite(123), 'Ints are finite'); assert.ok(_.isFinite(-12.44), 'Floats are finite'); if (typeof Symbol === 'function') { - assert.ok(!_.isFinite(Symbol()), 'symbols are not numbers'); - assert.ok(!_.isFinite(Symbol('description')), 'described symbols are not numbers'); - assert.ok(!_.isFinite(Object(Symbol())), 'boxed symbols are not numbers'); + assert.notOk(_.isFinite(Symbol()), 'symbols are not numbers'); + assert.notOk(_.isFinite(Symbol('description')), 'described symbols are not numbers'); + assert.notOk(_.isFinite(Object(Symbol())), 'boxed symbols are not numbers'); } }); QUnit.test('isNaN', function(assert) { - assert.ok(!_.isNaN(void 0), 'undefined is not NaN'); - assert.ok(!_.isNaN(null), 'null is not NaN'); - assert.ok(!_.isNaN(0), '0 is not NaN'); - assert.ok(!_.isNaN(new Number(0)), 'wrapped 0 is not NaN'); + assert.notOk(_.isNaN(void 0), 'undefined is not NaN'); + assert.notOk(_.isNaN(null), 'null is not NaN'); + assert.notOk(_.isNaN(0), '0 is not NaN'); + assert.notOk(_.isNaN(new Number(0)), 'wrapped 0 is not NaN'); assert.ok(_.isNaN(NaN), 'but NaN is'); assert.ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN'); }); QUnit.test('isNull', function(assert) { - assert.ok(!_.isNull(void 0), 'undefined is not null'); - assert.ok(!_.isNull(NaN), 'NaN is not null'); + assert.notOk(_.isNull(void 0), 'undefined is not null'); + assert.notOk(_.isNull(NaN), 'NaN is not null'); assert.ok(_.isNull(null), 'but null is'); }); QUnit.test('isUndefined', function(assert) { - assert.ok(!_.isUndefined(1), 'numbers are defined'); - assert.ok(!_.isUndefined(null), 'null is defined'); - assert.ok(!_.isUndefined(false), 'false is defined'); - assert.ok(!_.isUndefined(NaN), 'NaN is defined'); + assert.notOk(_.isUndefined(1), 'numbers are defined'); + assert.notOk(_.isUndefined(null), 'null is defined'); + assert.notOk(_.isUndefined(false), 'false is defined'); + assert.notOk(_.isUndefined(NaN), 'NaN is defined'); assert.ok(_.isUndefined(), 'nothing is undefined'); assert.ok(_.isUndefined(void 0), 'undefined is undefined'); }); QUnit.test('isError', function(assert) { - assert.ok(!_.isError(1), 'numbers are not Errors'); - assert.ok(!_.isError(null), 'null is not an Error'); - assert.ok(!_.isError(Error), 'functions are not Errors'); + assert.notOk(_.isError(1), 'numbers are not Errors'); + assert.notOk(_.isError(null), 'null is not an Error'); + assert.notOk(_.isError(Error), 'functions are not Errors'); assert.ok(_.isError(new Error()), 'Errors are Errors'); assert.ok(_.isError(new EvalError()), 'EvalErrors are Errors'); assert.ok(_.isError(new RangeError()), 'RangeErrors are Errors'); @@ -893,13 +893,13 @@ QUnit.test('has', function(assert) { var obj = {foo: 'bar', func: function(){}}; assert.ok(_.has(obj, 'foo'), 'has() checks that the object has a property.'); - assert.ok(!_.has(obj, 'baz'), "has() returns false if the object doesn't have the property."); + assert.notOk(_.has(obj, 'baz'), "has() returns false if the object doesn't have the property."); assert.ok(_.has(obj, 'func'), 'has() works for functions too.'); obj.hasOwnProperty = null; assert.ok(_.has(obj, 'foo'), 'has() works even when the hasOwnProperty method is deleted.'); var child = {}; child.prototype = obj; - assert.ok(!_.has(child, 'foo'), 'has() does not check the prototype chain for a property.'); + assert.notOk(_.has(child, 'foo'), 'has() does not check the prototype chain for a property.'); assert.strictEqual(_.has(null, 'foo'), false, 'has() returns false for null'); assert.strictEqual(_.has(void 0, 'foo'), false, 'has() returns false for undefined'); }); diff --git a/test/utility.js b/test/utility.js index 60d387597..b7ded62b1 100644 --- a/test/utility.js +++ b/test/utility.js @@ -370,9 +370,9 @@ }); QUnit.test('#547 - _.templateSettings is unchanged by custom settings.', function(assert) { - assert.ok(!_.templateSettings.variable); + assert.notOk(_.templateSettings.variable); _.template('', {}, {variable: 'x'}); - assert.ok(!_.templateSettings.variable); + assert.notOk(_.templateSettings.variable); }); QUnit.test('#556 - undefined template variables.', function(assert) { @@ -397,11 +397,11 @@ assert.expect(2); var count = 0; var template = _.template('<%= f() %>'); - template({f: function(){ assert.ok(!count++); }}); + template({f: function(){ assert.notOk(count++); }}); var countEscaped = 0; var templateEscaped = _.template('<%- f() %>'); - templateEscaped({f: function(){ assert.ok(!countEscaped++); }}); + templateEscaped({f: function(){ assert.notOk(countEscaped++); }}); }); QUnit.test('#746 - _.template settings are not modified.', function(assert) { From d988667b708592eecdc6fb3348c0f9848535c8d7 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Tue, 5 Apr 2016 10:37:00 -0700 Subject: [PATCH 171/263] Point users to Gitter instead of IRC --- index.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 68634baa0..366108f1a 100644 --- a/index.html +++ b/index.html @@ -396,8 +396,9 @@ The project is hosted on GitHub. You can report bugs and discuss features on the - issues page, or - on Freenode in the #documentcloud channel. + issues page, + on Freenode in the #documentcloud channel, or in our Gitter + channel. From 10d2d64dc92e8939e64ce38039051870139956ce Mon Sep 17 00:00:00 2001 From: marija
+ added to the Underscore object, as well as the OOP wrapper. Returns the + Underscore object to facilitate chaining.Date: Wed, 13 Apr 2016 15:09:28 +0200 Subject: [PATCH 172/263] optimization of _.isNaN --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 78c709bd3..b39f6733b 100644 --- a/underscore.js +++ b/underscore.js @@ -1316,7 +1316,7 @@ // Is the given value `NaN`? _.isNaN = function(obj) { - return _.isNumber(obj) && isNaN(obj); + return isNaN(obj) && _.isNumber(obj); }; // Is a given value a boolean? From 929fc74b880a87e669229597b9c5cf6cdd2dbf14 Mon Sep 17 00:00:00 2001 From: Amit Evron Date: Sat, 16 Apr 2016 00:03:17 +0300 Subject: [PATCH 173/263] Return self after using mixin() will allow user to chain mixin(), and most importantly use mixin() in the dependency section in the file. --- underscore.js | 1 + 1 file changed, 1 insertion(+) diff --git a/underscore.js b/underscore.js index ad065442b..1630b7286 100644 --- a/underscore.js +++ b/underscore.js @@ -1573,6 +1573,7 @@ return chainResult(this, func.apply(_, args)); }; }); + return _; }; // Add all of the Underscore functions to the wrapper object. From 8707c00bae6a264d58f90de15d67ba5b1aca737d Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Mon, 18 Apr 2016 20:22:11 -0700 Subject: [PATCH 174/263] Add tests and docs for `_.mixin` chaining This change was introduced in #2502 without tests or docs. This commit adds those two missing pieces. --- index.html | 4 ++-- test/utility.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 366108f1a..429f0a2d5 100644 --- a/index.html +++ b/index.html @@ -1886,8 +1886,8 @@ Utility Functions
Allows you to extend Underscore with your own utility functions. Pass a hash of {name: function} definitions to have your functions - added to the Underscore object, as well as the OOP wrapper. -_.mixin({ capitalize: function(string) { diff --git a/test/utility.js b/test/utility.js index b7ded62b1..6a81e8735 100644 --- a/test/utility.js +++ b/test/utility.js @@ -137,11 +137,12 @@ }); QUnit.test('mixin', function(assert) { - _.mixin({ + var ret = _.mixin({ myReverse: function(string) { return string.split('').reverse().join(''); } }); + assert.equal(ret, _, 'returns the _ object to facilitate chaining'); assert.equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _'); assert.equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper'); }); From e90055343e86122782cbcc7623dab0770e48c132 Mon Sep 17 00:00:00 2001 From: Jordan EldredgeDate: Sat, 23 Apr 2016 10:51:44 -0700 Subject: [PATCH 175/263] Cleanup docs for methods with multiple aliases Our formatting was a bit inconsistent. --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 366108f1a..69a53d139 100644 --- a/index.html +++ b/index.html @@ -499,7 +499,7 @@ Collection Functions (Arrays or Objects)
reduce
_.reduce(list, iteratee, [memo], [context])
- Aliases: inject, foldl + Aliases: inject, foldl
Also known as inject and foldl, reduce boils down a list of values into a single value. Memo is the initial state of the reduction, and each successive step of it should be returned by @@ -826,7 +826,7 @@Array Functions
first
_.first(array, [n])
- Alias: head, take + Aliases: head, take
Returns the first element of an array. Passing n will return the first n elements of the array. @@ -861,7 +861,7 @@Array Functions
rest
_.rest(array, [index])
- Alias: tail, drop + Aliases: tail, drop
Returns the rest of the elements in an array. Pass an index to return the values of the array from that index onward. From 507b858e0ba99d158b1ad61d97f260e7d7ec04f9 Mon Sep 17 00:00:00 2001 From: codefallingDate: Sun, 24 Apr 2016 18:59:51 +0800 Subject: [PATCH 176/263] check length in _.first and _.last, fix #2495 --- test/arrays.js | 8 ++++++++ underscore.js | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 748edea4f..319994aa1 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -15,6 +15,10 @@ result = _.map([[1, 2, 3], [1, 2, 3]], _.first); assert.deepEqual(result, [1, 1], 'works well with _.map'); assert.equal(_.first(null), void 0, 'returns undefined when called on null'); + + Array.prototype[0] = 'boo'; + assert.equal(_.first([]), void 0, 'return undefined when called on a empty array'); + delete Array.prototype[0]; }); QUnit.test('head', function(assert) { @@ -66,6 +70,10 @@ result = _.map([[1, 2, 3], [1, 2, 3]], _.last); assert.deepEqual(result, [3, 3], 'works well with _.map'); assert.equal(_.last(null), void 0, 'returns undefined when called on null'); + + var arr = []; + arr[-1] = 'boo'; + assert.equal(_.last(arr), void 0, 'return undefined when called on a empty array'); }); QUnit.test('compact', function(assert) { diff --git a/underscore.js b/underscore.js index 1630b7286..84713e688 100644 --- a/underscore.js +++ b/underscore.js @@ -467,7 +467,7 @@ // values in the array. Aliased as `head` and `take`. The **guard** check // allows it to work with `_.map`. _.first = _.head = _.take = function(array, n, guard) { - if (array == null) return void 0; + if (array == null || array.length < 1) return void 0; if (n == null || guard) return array[0]; return _.initial(array, array.length - n); }; @@ -482,7 +482,7 @@ // Get the last element of an array. Passing **n** will return the last N // values in the array. _.last = function(array, n, guard) { - if (array == null) return void 0; + if (array == null || array.length < 1) return void 0; if (n == null || guard) return array[array.length - 1]; return _.rest(array, Math.max(0, array.length - n)); }; From d484f8ff4486c6894684af2bbbb0834a38d69674 Mon Sep 17 00:00:00 2001 From: codefalling Date: Mon, 25 Apr 2016 17:19:25 +0800 Subject: [PATCH 177/263] safer _#toString, fix #2498 --- underscore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/underscore.js b/underscore.js index 84713e688..ab2f75f36 100644 --- a/underscore.js +++ b/underscore.js @@ -1608,7 +1608,7 @@ _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; _.prototype.toString = function() { - return '' + this._wrapped; + return String(this._wrapped); }; // AMD registration happens at the end for compatibility with AMD loaders From ef9ee4b7f54ecf4387f681d54dbca36ad0cb0e85 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sat, 23 Apr 2016 10:49:42 -0700 Subject: [PATCH 178/263] Make functions in docs filterable With a utility library like Underscore, it is very common to open the docs with the aim of locating the documentation for a specific function. Currently I use my browser's search functionality, but since many functions reference other functions, I frequently have to cycle through multiple matches before I arrive at the actual function's description. This patch aims to improve this common use case by offering a "filter" input above the list of functions. As a user types, the list of functions (and section titles) is reduced, leaving only the matching functions. If the user presses enter, they are jumped to the documentation for the first matching function. This functionality (and implementation) is greatly inspired by the implementation that is included in the [Ramda docs](http://ramdajs.com/0.21.0/docs/). You can read their source code [here](https://github.com/ramda/ramda.github.io/blob/master/main.js) --- docs/.eslintrc | 5 + docs/main.js | 58 +++++++++ index.html | 339 ++++++++++++++++++++++++++----------------------- 3 files changed, 246 insertions(+), 156 deletions(-) create mode 100644 docs/.eslintrc create mode 100644 docs/main.js diff --git a/docs/.eslintrc b/docs/.eslintrc new file mode 100644 index 000000000..aac42a91c --- /dev/null +++ b/docs/.eslintrc @@ -0,0 +1,5 @@ +{ + "globals": { + "_": true + } +} diff --git a/docs/main.js b/docs/main.js new file mode 100644 index 000000000..b46891fca --- /dev/null +++ b/docs/main.js @@ -0,0 +1,58 @@ +(function() { + var functions = document.querySelectorAll('[data-name]'); + var sections = document.querySelectorAll('.searchable_section'); + var searchInput = document.getElementById('function_filter'); + + function strIn(a, b) { + a = a.toLowerCase(); + b = b.toLowerCase(); + return b.indexOf(a) >= 0; + } + + function doesMatch(element) { + var name = element.getAttribute('data-name'); + var aliases = element.getAttribute('data-aliases') || ''; + return strIn(searchInput.value, name) || strIn(searchInput.value, aliases); + } + + function filterElement(element) { + element.style.display = doesMatch(element) ? '' : 'none'; + } + + function filterToc() { + _.each(functions, filterElement); + + var emptySearch = searchInput.value === ''; + + // Hide the titles of empty sections + _.each(sections, function(section) { + var sectionFunctions = section.querySelectorAll('[data-name]'); + var showSection = emptySearch || _.some(sectionFunctions, doesMatch); + section.style.display = showSection ? '' : 'none'; + }); + } + + function gotoFirst() { + var firstFunction = _.find(functions, doesMatch); + if(firstFunction) { + window.location.hash = firstFunction.getAttribute('data-name'); + searchInput.focus(); + } + } + + searchInput.addEventListener('input', filterToc, false); + + // Press "Enter" to jump to the first matching function + searchInput.addEventListener('keypress', function(e) { + if (e.which === 13) { + gotoFirst(); + } + }); + + // Press "/" to search + document.body.addEventListener('keyup', function(event) { + if (191 === event.which) { + searchInput.focus(); + } + }); +}()); diff --git a/index.html b/index.html index 366108f1a..79b72363f 100644 --- a/index.html +++ b/index.html @@ -64,6 +64,9 @@ .toc_section li a:hover { text-decoration: underline; } + input#function_filter { + width: 80%; + } div.container { width: 550px; margin: 40px 0 50px 260px; @@ -188,170 +191,193 @@ » Underscore-contrib - - Introduction - + - - Collections - --
+- - each
-- - map
-- - reduce
-- - reduceRight
-- - find
-- - filter
-- - where
-- - findWhere
-- - reject
-- - every
-- - some
-- - contains
-- - invoke
-- - pluck
-- - max
-- - min
-- - sortBy
-- - groupBy
-- - indexBy
-- - countBy
-- - shuffle
-- - sample
-- - toArray
-- - size
-- - partition
-+ + Introduction + +- - Arrays - --
+- - first
-- - initial
-- - last
-- - rest
-- - compact
-- - flatten
-- - without
-- - union
-- - intersection
-- - difference
-- - uniq
-- - zip
-- - unzip
-- - object
-- - indexOf
-- - lastIndexOf
-- - sortedIndex
-- - findIndex
-- - findLastIndex
-- - range
-+ + Collections + + +- - Functions - --
+- - bind
-- - bindAll
-- - partial
-- - memoize
-- - delay
-- - defer
-- - throttle
-- - debounce
-- - once
-- - after
-- - before
-- - wrap
-- - negate
-- - compose
-+ + Arrays + +- - Objects - -+
+- - first
+- - initial
+- - last
+- - rest
+- - compact
+- - flatten
+- - without
+- - union
+- - intersection
+- - difference
+- - uniq
+- - zip
+- - unzip
+- - object
+- - indexOf
+- - lastIndexOf
+- - sortedIndex
+- - findIndex
+- - findLastIndex
+- - range
+-
+- - keys
-- - allKeys
-- - values
-- - mapObject
-- - pairs
-- - invert
-- - create
-- - functions
-- - findKey
-- - extend
-- - extendOwn
-- - pick
-- - omit
-- - defaults
-- - clone
-- - tap
-- - has
-- - matcher
-- - property
-- - propertyOf
-- - isEqual
-- - isMatch
-- - isEmpty
-- - isElement
-- - isArray
-- - isObject
-- - isArguments
-- - isFunction
-- - isString
-- - isNumber
-- - isFinite
-- - isBoolean
-- - isDate
-- - isRegExp
-- - isError
-- - isSymbol
-- - isNaN
-- - isNull
-- - isUndefined
-+ + Functions + + +- - Utility - --
+- - noConflict
-- - identity
-- - constant
-- - noop
-- - times
-- - random
-- - mixin
-- - iteratee
-- - uniqueId
-- - escape
-- - unescape
-- - result
-- - now
-- - template
-+ + Objects + +- - OOP Style - - - Chaining - - ++
+- - keys
+- - allKeys
+- - values
+- - mapObject
+- - pairs
+- - invert
+- - create
+- - functions
+- - findKey
+- - extend
+- - extendOwn
+- - pick
+- - omit
+- - defaults
+- - clone
+- - tap
+- - has
+- - matcher
+- - property
+- - propertyOf
+- - isEqual
+- - isMatch
+- - isEmpty
+- - isElement
+- - isArray
+- - isObject
+- - isArguments
+- - isFunction
+- - isString
+- - isNumber
+- - isFinite
+- - isBoolean
+- - isDate
+- - isRegExp
+- - isError
+- - isSymbol
+- - isNaN
+- - isNull
+- - isUndefined
++ + Utility + + +- - Links - ++ + OOP Style + +- - Change Log - ++ + Chaining + + ++ ++ + Links + ++ ++ + Change Log + +@@ -3223,6 +3249,7 @@Change Log
+