nexus site path corrected
[portal.git] / ecomp-portal-FE / client / bower_components / lodash / vendor / underscore / test / collections.js
1 (function() {
2   var _ = typeof require == 'function' ? require('..') : window._;
3
4   QUnit.module('Collections');
5
6   QUnit.test('each', function(assert) {
7     _.each([1, 2, 3], function(num, i) {
8       assert.equal(num, i + 1, 'each iterators provide value and iteration count');
9     });
10
11     var answers = [];
12     _.each([1, 2, 3], function(num){ answers.push(num * this.multiplier); }, {multiplier: 5});
13     assert.deepEqual(answers, [5, 10, 15], 'context object property accessed');
14
15     answers = [];
16     _.each([1, 2, 3], function(num){ answers.push(num); });
17     assert.deepEqual(answers, [1, 2, 3], 'can iterate a simple array');
18
19     answers = [];
20     var obj = {one: 1, two: 2, three: 3};
21     obj.constructor.prototype.four = 4;
22     _.each(obj, function(value, key){ answers.push(key); });
23     assert.deepEqual(answers, ['one', 'two', 'three'], 'iterating over objects works, and ignores the object prototype.');
24     delete obj.constructor.prototype.four;
25
26     // ensure the each function is JITed
27     _(1000).times(function() { _.each([], function(){}); });
28     var count = 0;
29     obj = {1: 'foo', 2: 'bar', 3: 'baz'};
30     _.each(obj, function(){ count++; });
31     assert.equal(count, 3, 'the fun should be called only 3 times');
32
33     var answer = null;
34     _.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; });
35     assert.ok(answer, 'can reference the original collection from inside the iterator');
36
37     answers = 0;
38     _.each(null, function(){ ++answers; });
39     assert.equal(answers, 0, 'handles a null properly');
40
41     _.each(false, function(){});
42
43     var a = [1, 2, 3];
44     assert.strictEqual(_.each(a, function(){}), a);
45     assert.strictEqual(_.each(null, function(){}), null);
46   });
47
48   QUnit.test('forEach', function(assert) {
49     assert.strictEqual(_.forEach, _.each, 'is an alias for each');
50   });
51
52   QUnit.test('lookupIterator with contexts', function(assert) {
53     _.each([true, false, 'yes', '', 0, 1, {}], function(context) {
54       _.each([1], function() {
55         assert.equal(this, context);
56       }, context);
57     });
58   });
59
60   QUnit.test('Iterating objects with sketchy length properties', function(assert) {
61     var functions = [
62       'each', 'map', 'filter', 'find',
63       'some', 'every', 'max', 'min',
64       'groupBy', 'countBy', 'partition', 'indexBy'
65     ];
66     var reducers = ['reduce', 'reduceRight'];
67
68     var tricks = [
69       {length: '5'},
70       {length: {valueOf: _.constant(5)}},
71       {length: Math.pow(2, 53) + 1},
72       {length: Math.pow(2, 53)},
73       {length: null},
74       {length: -2},
75       {length: new Number(15)}
76     ];
77
78     assert.expect(tricks.length * (functions.length + reducers.length + 4));
79
80     _.each(tricks, function(trick) {
81       var length = trick.length;
82       assert.strictEqual(_.size(trick), 1, 'size on obj with length: ' + length);
83       assert.deepEqual(_.toArray(trick), [length], 'toArray on obj with length: ' + length);
84       assert.deepEqual(_.shuffle(trick), [length], 'shuffle on obj with length: ' + length);
85       assert.deepEqual(_.sample(trick), length, 'sample on obj with length: ' + length);
86
87
88       _.each(functions, function(method) {
89         _[method](trick, function(val, key) {
90           assert.strictEqual(key, 'length', method + ': ran with length = ' + val);
91         });
92       });
93
94       _.each(reducers, function(method) {
95         assert.strictEqual(_[method](trick), trick.length, method);
96       });
97     });
98   });
99
100   QUnit.test('Resistant to collection length and properties changing while iterating', function(assert) {
101
102     var collection = [
103       'each', 'map', 'filter', 'find',
104       'some', 'every', 'max', 'min', 'reject',
105       'groupBy', 'countBy', 'partition', 'indexBy',
106       'reduce', 'reduceRight'
107     ];
108     var array = [
109       'findIndex', 'findLastIndex'
110     ];
111     var object = [
112       'mapObject', 'findKey', 'pick', 'omit'
113     ];
114
115     _.each(collection.concat(array), function(method) {
116       var sparseArray = [1, 2, 3];
117       sparseArray.length = 100;
118       var answers = 0;
119       _[method](sparseArray, function(){
120         ++answers;
121         return method === 'every' ? true : null;
122       }, {});
123       assert.equal(answers, 100, method + ' enumerates [0, length)');
124
125       var growingCollection = [1, 2, 3], count = 0;
126       _[method](growingCollection, function() {
127         if (count < 10) growingCollection.push(count++);
128         return method === 'every' ? true : null;
129       }, {});
130       assert.equal(count, 3, method + ' is resistant to length changes');
131     });
132
133     _.each(collection.concat(object), function(method) {
134       var changingObject = {0: 0, 1: 1}, count = 0;
135       _[method](changingObject, function(val) {
136         if (count < 10) changingObject[++count] = val + 1;
137         return method === 'every' ? true : null;
138       }, {});
139
140       assert.equal(count, 2, method + ' is resistant to property changes');
141     });
142   });
143
144   QUnit.test('map', function(assert) {
145     var doubled = _.map([1, 2, 3], function(num){ return num * 2; });
146     assert.deepEqual(doubled, [2, 4, 6], 'doubled numbers');
147
148     var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier: 3});
149     assert.deepEqual(tripled, [3, 6, 9], 'tripled numbers with context');
150
151     doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
152     assert.deepEqual(doubled, [2, 4, 6], 'OO-style doubled numbers');
153
154     var ids = _.map({length: 2, 0: {id: '1'}, 1: {id: '2'}}, function(n){
155       return n.id;
156     });
157     assert.deepEqual(ids, ['1', '2'], 'Can use collection methods on Array-likes.');
158
159     assert.deepEqual(_.map(null, _.noop), [], 'handles a null properly');
160
161     assert.deepEqual(_.map([1], function() {
162       return this.length;
163     }, [5]), [1], 'called with context');
164
165     // Passing a property name like _.pluck.
166     var people = [{name: 'moe', age: 30}, {name: 'curly', age: 50}];
167     assert.deepEqual(_.map(people, 'name'), ['moe', 'curly'], 'predicate string map to object properties');
168   });
169
170   QUnit.test('collect', function(assert) {
171     assert.strictEqual(_.collect, _.map, 'is an alias for map');
172   });
173
174   QUnit.test('reduce', function(assert) {
175     var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
176     assert.equal(sum, 6, 'can sum up an array');
177
178     var context = {multiplier: 3};
179     sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num * this.multiplier; }, 0, context);
180     assert.equal(sum, 18, 'can reduce with a context object');
181
182     sum = _([1, 2, 3]).reduce(function(memo, num){ return memo + num; }, 0);
183     assert.equal(sum, 6, 'OO-style reduce');
184
185     sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; });
186     assert.equal(sum, 6, 'default initial value');
187
188     var prod = _.reduce([1, 2, 3, 4], function(memo, num){ return memo * num; });
189     assert.equal(prod, 24, 'can reduce via multiplication');
190
191     assert.ok(_.reduce(null, _.noop, 138) === 138, 'handles a null (with initial value) properly');
192     assert.equal(_.reduce([], _.noop, void 0), void 0, 'undefined can be passed as a special case');
193     assert.equal(_.reduce([_], _.noop), _, 'collection of length one with no initial value returns the first item');
194     assert.equal(_.reduce([], _.noop), void 0, 'returns undefined when collection is empty and no initial value');
195   });
196
197   QUnit.test('foldl', function(assert) {
198     assert.strictEqual(_.foldl, _.reduce, 'is an alias for reduce');
199   });
200
201   QUnit.test('inject', function(assert) {
202     assert.strictEqual(_.inject, _.reduce, 'is an alias for reduce');
203   });
204
205   QUnit.test('reduceRight', function(assert) {
206     var list = _.reduceRight(['foo', 'bar', 'baz'], function(memo, str){ return memo + str; }, '');
207     assert.equal(list, 'bazbarfoo', 'can perform right folds');
208
209     list = _.reduceRight(['foo', 'bar', 'baz'], function(memo, str){ return memo + str; });
210     assert.equal(list, 'bazbarfoo', 'default initial value');
211
212     var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(memo, num){ return memo + num; });
213     assert.equal(sum, 6, 'default initial value on object');
214
215     assert.ok(_.reduceRight(null, _.noop, 138) === 138, 'handles a null (with initial value) properly');
216     assert.equal(_.reduceRight([_], _.noop), _, 'collection of length one with no initial value returns the first item');
217
218     assert.equal(_.reduceRight([], _.noop, void 0), void 0, 'undefined can be passed as a special case');
219     assert.equal(_.reduceRight([], _.noop), void 0, 'returns undefined when collection is empty and no initial value');
220
221     // Assert that the correct arguments are being passed.
222
223     var args,
224         init = {},
225         object = {a: 1, b: 2},
226         lastKey = _.keys(object).pop();
227
228     var expected = lastKey === 'a'
229       ? [init, 1, 'a', object]
230       : [init, 2, 'b', object];
231
232     _.reduceRight(object, function() {
233       if (!args) args = _.toArray(arguments);
234     }, init);
235
236     assert.deepEqual(args, expected);
237
238     // And again, with numeric keys.
239
240     object = {2: 'a', 1: 'b'};
241     lastKey = _.keys(object).pop();
242     args = null;
243
244     expected = lastKey === '2'
245       ? [init, 'a', '2', object]
246       : [init, 'b', '1', object];
247
248     _.reduceRight(object, function() {
249       if (!args) args = _.toArray(arguments);
250     }, init);
251
252     assert.deepEqual(args, expected);
253   });
254
255   QUnit.test('foldr', function(assert) {
256     assert.strictEqual(_.foldr, _.reduceRight, 'is an alias for reduceRight');
257   });
258
259   QUnit.test('find', function(assert) {
260     var array = [1, 2, 3, 4];
261     assert.strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found `value`');
262     assert.strictEqual(_.find(array, function() { return false; }), void 0, 'should return `undefined` if `value` is not found');
263
264     array.dontmatch = 55;
265     assert.strictEqual(_.find(array, function(x) { return x === 55; }), void 0, 'iterates array-likes correctly');
266
267     // Matching an object like _.findWhere.
268     var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}];
269     assert.deepEqual(_.find(list, {a: 1}), {a: 1, b: 2}, 'can be used as findWhere');
270     assert.deepEqual(_.find(list, {b: 4}), {a: 1, b: 4});
271     assert.ok(!_.find(list, {c: 1}), 'undefined when not found');
272     assert.ok(!_.find([], {c: 1}), 'undefined when searching empty list');
273
274     var result = _.find([1, 2, 3], function(num){ return num * 2 === 4; });
275     assert.equal(result, 2, 'found the first "2" and broke the loop');
276
277     var obj = {
278       a: {x: 1, z: 3},
279       b: {x: 2, z: 2},
280       c: {x: 3, z: 4},
281       d: {x: 4, z: 1}
282     };
283
284     assert.deepEqual(_.find(obj, {x: 2}), {x: 2, z: 2}, 'works on objects');
285     assert.deepEqual(_.find(obj, {x: 2, z: 1}), void 0);
286     assert.deepEqual(_.find(obj, function(x) {
287       return x.x === 4;
288     }), {x: 4, z: 1});
289
290     _.findIndex([{a: 1}], function(a, key, o) {
291       assert.equal(key, 0);
292       assert.deepEqual(o, [{a: 1}]);
293       assert.strictEqual(this, _, 'called with context');
294     }, _);
295   });
296
297   QUnit.test('detect', function(assert) {
298     assert.strictEqual(_.detect, _.find, 'is an alias for find');
299   });
300
301   QUnit.test('filter', function(assert) {
302     var evenArray = [1, 2, 3, 4, 5, 6];
303     var evenObject = {one: 1, two: 2, three: 3};
304     var isEven = function(num){ return num % 2 === 0; };
305
306     assert.deepEqual(_.filter(evenArray, isEven), [2, 4, 6]);
307     assert.deepEqual(_.filter(evenObject, isEven), [2], 'can filter objects');
308     assert.deepEqual(_.filter([{}, evenObject, []], 'two'), [evenObject], 'predicate string map to object properties');
309
310     _.filter([1], function() {
311       assert.equal(this, evenObject, 'given context');
312     }, evenObject);
313
314     // Can be used like _.where.
315     var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
316     assert.deepEqual(_.filter(list, {a: 1}), [{a: 1, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}]);
317     assert.deepEqual(_.filter(list, {b: 2}), [{a: 1, b: 2}, {a: 2, b: 2}]);
318     assert.deepEqual(_.filter(list, {}), list, 'Empty object accepts all items');
319     assert.deepEqual(_(list).filter({}), list, 'OO-filter');
320   });
321
322   QUnit.test('select', function(assert) {
323     assert.strictEqual(_.select, _.filter, 'is an alias for filter');
324   });
325
326   QUnit.test('reject', function(assert) {
327     var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 === 0; });
328     assert.deepEqual(odds, [1, 3, 5], 'rejected each even number');
329
330     var context = 'obj';
331
332     var evens = _.reject([1, 2, 3, 4, 5, 6], function(num){
333       assert.equal(context, 'obj');
334       return num % 2 !== 0;
335     }, context);
336     assert.deepEqual(evens, [2, 4, 6], 'rejected each odd number');
337
338     assert.deepEqual(_.reject([odds, {one: 1, two: 2, three: 3}], 'two'), [odds], 'predicate string map to object properties');
339
340     // Can be used like _.where.
341     var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
342     assert.deepEqual(_.reject(list, {a: 1}), [{a: 2, b: 2}]);
343     assert.deepEqual(_.reject(list, {b: 2}), [{a: 1, b: 3}, {a: 1, b: 4}]);
344     assert.deepEqual(_.reject(list, {}), [], 'Returns empty list given empty object');
345     assert.deepEqual(_.reject(list, []), [], 'Returns empty list given empty array');
346   });
347
348   QUnit.test('every', function(assert) {
349     assert.ok(_.every([], _.identity), 'the empty set');
350     assert.ok(_.every([true, true, true], _.identity), 'every true values');
351     assert.ok(!_.every([true, false, true], _.identity), 'one false value');
352     assert.ok(_.every([0, 10, 28], function(num){ return num % 2 === 0; }), 'even numbers');
353     assert.ok(!_.every([0, 11, 28], function(num){ return num % 2 === 0; }), 'an odd number');
354     assert.ok(_.every([1], _.identity) === true, 'cast to boolean - true');
355     assert.ok(_.every([0], _.identity) === false, 'cast to boolean - false');
356     assert.ok(!_.every([void 0, void 0, void 0], _.identity), 'works with arrays of undefined');
357
358     var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
359     assert.ok(!_.every(list, {a: 1, b: 2}), 'Can be called with object');
360     assert.ok(_.every(list, 'a'), 'String mapped to object property');
361
362     list = [{a: 1, b: 2}, {a: 2, b: 2, c: true}];
363     assert.ok(_.every(list, {b: 2}), 'Can be called with object');
364     assert.ok(!_.every(list, 'c'), 'String mapped to object property');
365
366     assert.ok(_.every({a: 1, b: 2, c: 3, d: 4}, _.isNumber), 'takes objects');
367     assert.ok(!_.every({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects');
368     assert.ok(_.every(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works');
369     assert.ok(!_.every(['a', 'b', 'c', 'd', 'f'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works');
370   });
371
372   QUnit.test('all', function(assert) {
373     assert.strictEqual(_.all, _.every, 'is an alias for every');
374   });
375
376   QUnit.test('some', function(assert) {
377     assert.ok(!_.some([]), 'the empty set');
378     assert.ok(!_.some([false, false, false]), 'all false values');
379     assert.ok(_.some([false, false, true]), 'one true value');
380     assert.ok(_.some([null, 0, 'yes', false]), 'a string');
381     assert.ok(!_.some([null, 0, '', false]), 'falsy values');
382     assert.ok(!_.some([1, 11, 29], function(num){ return num % 2 === 0; }), 'all odd numbers');
383     assert.ok(_.some([1, 10, 29], function(num){ return num % 2 === 0; }), 'an even number');
384     assert.ok(_.some([1], _.identity) === true, 'cast to boolean - true');
385     assert.ok(_.some([0], _.identity) === false, 'cast to boolean - false');
386     assert.ok(_.some([false, false, true]));
387
388     var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
389     assert.ok(!_.some(list, {a: 5, b: 2}), 'Can be called with object');
390     assert.ok(_.some(list, 'a'), 'String mapped to object property');
391
392     list = [{a: 1, b: 2}, {a: 2, b: 2, c: true}];
393     assert.ok(_.some(list, {b: 2}), 'Can be called with object');
394     assert.ok(!_.some(list, 'd'), 'String mapped to object property');
395
396     assert.ok(_.some({a: '1', b: '2', c: '3', d: '4', e: 6}, _.isNumber), 'takes objects');
397     assert.ok(!_.some({a: 1, b: 2, c: 3, d: 4}, _.isObject), 'takes objects');
398     assert.ok(_.some(['a', 'b', 'c', 'd'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works');
399     assert.ok(!_.some(['x', 'y', 'z'], _.hasOwnProperty, {a: 1, b: 2, c: 3, d: 4}), 'context works');
400   });
401
402   QUnit.test('any', function(assert) {
403     assert.strictEqual(_.any, _.some, 'is an alias for some');
404   });
405
406   QUnit.test('includes', function(assert) {
407     _.each([null, void 0, 0, 1, NaN, {}, []], function(val) {
408       assert.strictEqual(_.includes(val, 'hasOwnProperty'), false);
409     });
410     assert.strictEqual(_.includes([1, 2, 3], 2), true, 'two is in the array');
411     assert.ok(!_.includes([1, 3, 9], 2), 'two is not in the array');
412
413     assert.strictEqual(_.includes([5, 4, 3, 2, 1], 5, true), true, 'doesn\'t delegate to binary search');
414
415     assert.ok(_.includes({moe: 1, larry: 3, curly: 9}, 3) === true, '_.includes on objects checks their values');
416     assert.ok(_([1, 2, 3]).includes(2), 'OO-style includes');
417
418     var numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
419     assert.strictEqual(_.includes(numbers, 1, 1), true, 'takes a fromIndex');
420     assert.strictEqual(_.includes(numbers, 1, -1), false, 'takes a fromIndex');
421     assert.strictEqual(_.includes(numbers, 1, -2), false, 'takes a fromIndex');
422     assert.strictEqual(_.includes(numbers, 1, -3), true, 'takes a fromIndex');
423     assert.strictEqual(_.includes(numbers, 1, 6), true, 'takes a fromIndex');
424     assert.strictEqual(_.includes(numbers, 1, 7), false, 'takes a fromIndex');
425
426     assert.ok(_.every([1, 2, 3], _.partial(_.includes, numbers)), 'fromIndex is guarded');
427   });
428
429   QUnit.test('include', function(assert) {
430     assert.strictEqual(_.include, _.includes, 'is an alias for includes');
431   });
432
433   QUnit.test('contains', function(assert) {
434     assert.strictEqual(_.contains, _.includes, 'is an alias for includes');
435
436   });
437
438   QUnit.test('includes with NaN', function(assert) {
439     assert.strictEqual(_.includes([1, 2, NaN, NaN], NaN), true, 'Expected [1, 2, NaN] to contain NaN');
440     assert.strictEqual(_.includes([1, 2, Infinity], NaN), false, 'Expected [1, 2, NaN] to contain NaN');
441   });
442
443   QUnit.test('includes with +- 0', function(assert) {
444     _.each([-0, +0], function(val) {
445       assert.strictEqual(_.includes([1, 2, val, val], val), true);
446       assert.strictEqual(_.includes([1, 2, val, val], -val), true);
447       assert.strictEqual(_.includes([-1, 1, 2], -val), false);
448     });
449   });
450
451
452   QUnit.test('invoke', function(assert) {
453     assert.expect(5);
454     var list = [[5, 1, 7], [3, 2, 1]];
455     var result = _.invoke(list, 'sort');
456     assert.deepEqual(result[0], [1, 5, 7], 'first array sorted');
457     assert.deepEqual(result[1], [1, 2, 3], 'second array sorted');
458
459     _.invoke([{
460       method: function() {
461         assert.deepEqual(_.toArray(arguments), [1, 2, 3], 'called with arguments');
462       }
463     }], 'method', 1, 2, 3);
464
465     assert.deepEqual(_.invoke([{a: null}, {}, {a: _.constant(1)}], 'a'), [null, void 0, 1], 'handles null & undefined');
466
467     assert.raises(function() {
468       _.invoke([{a: 1}], 'a');
469     }, TypeError, 'throws for non-functions');
470   });
471
472   QUnit.test('invoke w/ function reference', function(assert) {
473     var list = [[5, 1, 7], [3, 2, 1]];
474     var result = _.invoke(list, Array.prototype.sort);
475     assert.deepEqual(result[0], [1, 5, 7], 'first array sorted');
476     assert.deepEqual(result[1], [1, 2, 3], 'second array sorted');
477
478     assert.deepEqual(_.invoke([1, 2, 3], function(a) {
479       return a + this;
480     }, 5), [6, 7, 8], 'receives params from invoke');
481   });
482
483   // Relevant when using ClojureScript
484   QUnit.test('invoke when strings have a call method', function(assert) {
485     String.prototype.call = function() {
486       return 42;
487     };
488     var list = [[5, 1, 7], [3, 2, 1]];
489     var s = 'foo';
490     assert.equal(s.call(), 42, 'call function exists');
491     var result = _.invoke(list, 'sort');
492     assert.deepEqual(result[0], [1, 5, 7], 'first array sorted');
493     assert.deepEqual(result[1], [1, 2, 3], 'second array sorted');
494     delete String.prototype.call;
495     assert.equal(s.call, void 0, 'call function removed');
496   });
497
498   QUnit.test('pluck', function(assert) {
499     var people = [{name: 'moe', age: 30}, {name: 'curly', age: 50}];
500     assert.deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'pulls names out of objects');
501     assert.deepEqual(_.pluck(people, 'address'), [void 0, void 0], 'missing properties are returned as undefined');
502     //compat: most flexible handling of edge cases
503     assert.deepEqual(_.pluck([{'[object Object]': 1}], {}), [1]);
504   });
505
506   QUnit.test('where', function(assert) {
507     var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
508     var result = _.where(list, {a: 1});
509     assert.equal(result.length, 3);
510     assert.equal(result[result.length - 1].b, 4);
511     result = _.where(list, {b: 2});
512     assert.equal(result.length, 2);
513     assert.equal(result[0].a, 1);
514     result = _.where(list, {});
515     assert.equal(result.length, list.length);
516
517     function test() {}
518     test.map = _.map;
519     assert.deepEqual(_.where([_, {a: 1, b: 2}, _], test), [_, _], 'checks properties given function');
520   });
521
522   QUnit.test('findWhere', function(assert) {
523     var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}];
524     var result = _.findWhere(list, {a: 1});
525     assert.deepEqual(result, {a: 1, b: 2});
526     result = _.findWhere(list, {b: 4});
527     assert.deepEqual(result, {a: 1, b: 4});
528
529     result = _.findWhere(list, {c: 1});
530     assert.ok(_.isUndefined(result), 'undefined when not found');
531
532     result = _.findWhere([], {c: 1});
533     assert.ok(_.isUndefined(result), 'undefined when searching empty list');
534
535     function test() {}
536     test.map = _.map;
537     assert.equal(_.findWhere([_, {a: 1, b: 2}, _], test), _, 'checks properties given function');
538
539     function TestClass() {
540       this.y = 5;
541       this.x = 'foo';
542     }
543     var expect = {c: 1, x: 'foo', y: 5};
544     assert.deepEqual(_.findWhere([{y: 5, b: 6}, expect], new TestClass()), expect, 'uses class instance properties');
545   });
546
547   QUnit.test('max', function(assert) {
548     assert.equal(-Infinity, _.max(null), 'can handle null/undefined');
549     assert.equal(-Infinity, _.max(void 0), 'can handle null/undefined');
550     assert.equal(-Infinity, _.max(null, _.identity), 'can handle null/undefined');
551
552     assert.equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max');
553
554     var neg = _.max([1, 2, 3], function(num){ return -num; });
555     assert.equal(neg, 1, 'can perform a computation-based max');
556
557     assert.equal(-Infinity, _.max({}), 'Maximum value of an empty object');
558     assert.equal(-Infinity, _.max([]), 'Maximum value of an empty array');
559     assert.equal(_.max({a: 'a'}), -Infinity, 'Maximum value of a non-numeric collection');
560
561     assert.equal(299999, _.max(_.range(1, 300000)), 'Maximum value of a too-big array');
562
563     assert.equal(3, _.max([1, 2, 3, 'test']), 'Finds correct max in array starting with num and containing a NaN');
564     assert.equal(3, _.max(['test', 1, 2, 3]), 'Finds correct max in array starting with NaN');
565
566     assert.equal(3, _.max([1, 2, 3, null]), 'Finds correct max in array starting with num and containing a `null`');
567     assert.equal(3, _.max([null, 1, 2, 3]), 'Finds correct max in array starting with a `null`');
568
569     assert.equal(3, _.max([1, 2, 3, '']), 'Finds correct max in array starting with num and containing an empty string');
570     assert.equal(3, _.max(['', 1, 2, 3]), 'Finds correct max in array starting with an empty string');
571
572     assert.equal(3, _.max([1, 2, 3, false]), 'Finds correct max in array starting with num and containing a false');
573     assert.equal(3, _.max([false, 1, 2, 3]), 'Finds correct max in array starting with a false');
574
575     assert.equal(4, _.max([0, 1, 2, 3, 4]), 'Finds correct max in array containing a zero');
576     assert.equal(0, _.max([-3, -2, -1, 0]), 'Finds correct max in array containing negative numbers');
577
578     assert.deepEqual([3, 6], _.map([[1, 2, 3], [4, 5, 6]], _.max), 'Finds correct max in array when mapping through multiple arrays');
579
580     var a = {x: -Infinity};
581     var b = {x: -Infinity};
582     var iterator = function(o){ return o.x; };
583     assert.equal(_.max([a, b], iterator), a, 'Respects iterator return value of -Infinity');
584
585     assert.deepEqual(_.max([{a: 1}, {a: 0, b: 3}, {a: 4}, {a: 2}], 'a'), {a: 4}, 'String keys use property iterator');
586
587     assert.deepEqual(_.max([0, 2], function(c){ return c * this.x; }, {x: 1}), 2, 'Iterator context');
588     assert.deepEqual(_.max([[1], [2, 3], [-1, 4], [5]], 0), [5], 'Lookup falsy iterator');
589     assert.deepEqual(_.max([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: 2}, 'Lookup falsy iterator');
590   });
591
592   QUnit.test('min', function(assert) {
593     assert.equal(Infinity, _.min(null), 'can handle null/undefined');
594     assert.equal(Infinity, _.min(void 0), 'can handle null/undefined');
595     assert.equal(Infinity, _.min(null, _.identity), 'can handle null/undefined');
596
597     assert.equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min');
598
599     var neg = _.min([1, 2, 3], function(num){ return -num; });
600     assert.equal(neg, 3, 'can perform a computation-based min');
601
602     assert.equal(Infinity, _.min({}), 'Minimum value of an empty object');
603     assert.equal(Infinity, _.min([]), 'Minimum value of an empty array');
604     assert.equal(_.min({a: 'a'}), Infinity, 'Minimum value of a non-numeric collection');
605
606     assert.deepEqual([1, 4], _.map([[1, 2, 3], [4, 5, 6]], _.min), 'Finds correct min in array when mapping through multiple arrays');
607
608     var now = new Date(9999999999);
609     var then = new Date(0);
610     assert.equal(_.min([now, then]), then);
611
612     assert.equal(1, _.min(_.range(1, 300000)), 'Minimum value of a too-big array');
613
614     assert.equal(1, _.min([1, 2, 3, 'test']), 'Finds correct min in array starting with num and containing a NaN');
615     assert.equal(1, _.min(['test', 1, 2, 3]), 'Finds correct min in array starting with NaN');
616
617     assert.equal(1, _.min([1, 2, 3, null]), 'Finds correct min in array starting with num and containing a `null`');
618     assert.equal(1, _.min([null, 1, 2, 3]), 'Finds correct min in array starting with a `null`');
619
620     assert.equal(0, _.min([0, 1, 2, 3, 4]), 'Finds correct min in array containing a zero');
621     assert.equal(-3, _.min([-3, -2, -1, 0]), 'Finds correct min in array containing negative numbers');
622
623     var a = {x: Infinity};
624     var b = {x: Infinity};
625     var iterator = function(o){ return o.x; };
626     assert.equal(_.min([a, b], iterator), a, 'Respects iterator return value of Infinity');
627
628     assert.deepEqual(_.min([{a: 1}, {a: 0, b: 3}, {a: 4}, {a: 2}], 'a'), {a: 0, b: 3}, 'String keys use property iterator');
629
630     assert.deepEqual(_.min([0, 2], function(c){ return c * this.x; }, {x: -1}), 2, 'Iterator context');
631     assert.deepEqual(_.min([[1], [2, 3], [-1, 4], [5]], 0), [-1, 4], 'Lookup falsy iterator');
632     assert.deepEqual(_.min([{0: 1}, {0: 2}, {0: -1}, {a: 1}], 0), {0: -1}, 'Lookup falsy iterator');
633   });
634
635   QUnit.test('sortBy', function(assert) {
636     var people = [{name: 'curly', age: 50}, {name: 'moe', age: 30}];
637     people = _.sortBy(people, function(person){ return person.age; });
638     assert.deepEqual(_.pluck(people, 'name'), ['moe', 'curly'], 'stooges sorted by age');
639
640     var list = [void 0, 4, 1, void 0, 3, 2];
641     assert.deepEqual(_.sortBy(list, _.identity), [1, 2, 3, 4, void 0, void 0], 'sortBy with undefined values');
642
643     list = ['one', 'two', 'three', 'four', 'five'];
644     var sorted = _.sortBy(list, 'length');
645     assert.deepEqual(sorted, ['one', 'two', 'four', 'five', 'three'], 'sorted by length');
646
647     function Pair(x, y) {
648       this.x = x;
649       this.y = y;
650     }
651
652     var stableArray = [
653       new Pair(1, 1), new Pair(1, 2),
654       new Pair(1, 3), new Pair(1, 4),
655       new Pair(1, 5), new Pair(1, 6),
656       new Pair(2, 1), new Pair(2, 2),
657       new Pair(2, 3), new Pair(2, 4),
658       new Pair(2, 5), new Pair(2, 6),
659       new Pair(void 0, 1), new Pair(void 0, 2),
660       new Pair(void 0, 3), new Pair(void 0, 4),
661       new Pair(void 0, 5), new Pair(void 0, 6)
662     ];
663
664     var stableObject = _.object('abcdefghijklmnopqr'.split(''), stableArray);
665
666     var actual = _.sortBy(stableArray, function(pair) {
667       return pair.x;
668     });
669
670     assert.deepEqual(actual, stableArray, 'sortBy should be stable for arrays');
671     assert.deepEqual(_.sortBy(stableArray, 'x'), stableArray, 'sortBy accepts property string');
672
673     actual = _.sortBy(stableObject, function(pair) {
674       return pair.x;
675     });
676
677     assert.deepEqual(actual, stableArray, 'sortBy should be stable for objects');
678
679     list = ['q', 'w', 'e', 'r', 't', 'y'];
680     assert.deepEqual(_.sortBy(list), ['e', 'q', 'r', 't', 'w', 'y'], 'uses _.identity if iterator is not specified');
681   });
682
683   QUnit.test('groupBy', function(assert) {
684     var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
685     assert.ok('0' in parity && '1' in parity, 'created a group for each value');
686     assert.deepEqual(parity[0], [2, 4, 6], 'put each even number in the right group');
687
688     var list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'];
689     var grouped = _.groupBy(list, 'length');
690     assert.deepEqual(grouped['3'], ['one', 'two', 'six', 'ten']);
691     assert.deepEqual(grouped['4'], ['four', 'five', 'nine']);
692     assert.deepEqual(grouped['5'], ['three', 'seven', 'eight']);
693
694     var context = {};
695     _.groupBy([{}], function(){ assert.ok(this === context); }, context);
696
697     grouped = _.groupBy([4.2, 6.1, 6.4], function(num) {
698       return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
699     });
700     assert.equal(grouped.constructor.length, 1);
701     assert.equal(grouped.hasOwnProperty.length, 2);
702
703     var array = [{}];
704     _.groupBy(array, function(value, index, obj){ assert.ok(obj === array); });
705
706     array = [1, 2, 1, 2, 3];
707     grouped = _.groupBy(array);
708     assert.equal(grouped['1'].length, 2);
709     assert.equal(grouped['3'].length, 1);
710
711     var matrix = [
712       [1, 2],
713       [1, 3],
714       [2, 3]
715     ];
716     assert.deepEqual(_.groupBy(matrix, 0), {1: [[1, 2], [1, 3]], 2: [[2, 3]]});
717     assert.deepEqual(_.groupBy(matrix, 1), {2: [[1, 2]], 3: [[1, 3], [2, 3]]});
718   });
719
720   QUnit.test('indexBy', function(assert) {
721     var parity = _.indexBy([1, 2, 3, 4, 5], function(num){ return num % 2 === 0; });
722     assert.equal(parity['true'], 4);
723     assert.equal(parity['false'], 5);
724
725     var list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'];
726     var grouped = _.indexBy(list, 'length');
727     assert.equal(grouped['3'], 'ten');
728     assert.equal(grouped['4'], 'nine');
729     assert.equal(grouped['5'], 'eight');
730
731     var array = [1, 2, 1, 2, 3];
732     grouped = _.indexBy(array);
733     assert.equal(grouped['1'], 1);
734     assert.equal(grouped['2'], 2);
735     assert.equal(grouped['3'], 3);
736   });
737
738   QUnit.test('countBy', function(assert) {
739     var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 === 0; });
740     assert.equal(parity['true'], 2);
741     assert.equal(parity['false'], 3);
742
743     var list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'];
744     var grouped = _.countBy(list, 'length');
745     assert.equal(grouped['3'], 4);
746     assert.equal(grouped['4'], 3);
747     assert.equal(grouped['5'], 3);
748
749     var context = {};
750     _.countBy([{}], function(){ assert.ok(this === context); }, context);
751
752     grouped = _.countBy([4.2, 6.1, 6.4], function(num) {
753       return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
754     });
755     assert.equal(grouped.constructor, 1);
756     assert.equal(grouped.hasOwnProperty, 2);
757
758     var array = [{}];
759     _.countBy(array, function(value, index, obj){ assert.ok(obj === array); });
760
761     array = [1, 2, 1, 2, 3];
762     grouped = _.countBy(array);
763     assert.equal(grouped['1'], 2);
764     assert.equal(grouped['3'], 1);
765   });
766
767   QUnit.test('shuffle', function(assert) {
768     assert.deepEqual(_.shuffle([1]), [1], 'behaves correctly on size 1 arrays');
769     var numbers = _.range(20);
770     var shuffled = _.shuffle(numbers);
771     assert.notDeepEqual(numbers, shuffled, 'does change the order'); // Chance of false negative: 1 in ~2.4*10^18
772     assert.notStrictEqual(numbers, shuffled, 'original object is unmodified');
773     assert.deepEqual(numbers, _.sortBy(shuffled), 'contains the same members before and after shuffle');
774
775     shuffled = _.shuffle({a: 1, b: 2, c: 3, d: 4});
776     assert.equal(shuffled.length, 4);
777     assert.deepEqual(shuffled.sort(), [1, 2, 3, 4], 'works on objects');
778   });
779
780   QUnit.test('sample', function(assert) {
781     assert.strictEqual(_.sample([1]), 1, 'behaves correctly when no second parameter is given');
782     assert.deepEqual(_.sample([1, 2, 3], -2), [], 'behaves correctly on negative n');
783     var numbers = _.range(10);
784     var allSampled = _.sample(numbers, 10).sort();
785     assert.deepEqual(allSampled, numbers, 'contains the same members before and after sample');
786     allSampled = _.sample(numbers, 20).sort();
787     assert.deepEqual(allSampled, numbers, 'also works when sampling more objects than are present');
788     assert.ok(_.contains(numbers, _.sample(numbers)), 'sampling a single element returns something from the array');
789     assert.strictEqual(_.sample([]), void 0, 'sampling empty array with no number returns undefined');
790     assert.notStrictEqual(_.sample([], 5), [], 'sampling empty array with a number returns an empty array');
791     assert.notStrictEqual(_.sample([1, 2, 3], 0), [], 'sampling an array with 0 picks returns an empty array');
792     assert.deepEqual(_.sample([1, 2], -1), [], 'sampling a negative number of picks returns an empty array');
793     assert.ok(_.contains([1, 2, 3], _.sample({a: 1, b: 2, c: 3})), 'sample one value from an object');
794     var partialSample = _.sample(_.range(1000), 10);
795     var partialSampleSorted = partialSample.sort();
796     assert.notDeepEqual(partialSampleSorted, _.range(10), 'samples from the whole array, not just the beginning');
797   });
798
799   QUnit.test('toArray', function(assert) {
800     assert.ok(!_.isArray(arguments), 'arguments object is not an array');
801     assert.ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array');
802     var a = [1, 2, 3];
803     assert.ok(_.toArray(a) !== a, 'array is cloned');
804     assert.deepEqual(_.toArray(a), [1, 2, 3], 'cloned array contains same elements');
805
806     var numbers = _.toArray({one: 1, two: 2, three: 3});
807     assert.deepEqual(numbers, [1, 2, 3], 'object flattened into array');
808
809     var hearts = '\uD83D\uDC95';
810     var pair = hearts.split('');
811     var expected = [pair[0], hearts, '&', hearts, pair[1]];
812     assert.deepEqual(_.toArray(expected.join('')), expected, 'maintains astral characters');
813     assert.deepEqual(_.toArray(''), [], 'empty string into empty array');
814
815     if (typeof document != 'undefined') {
816       // test in IE < 9
817       var actual;
818       try {
819         actual = _.toArray(document.childNodes);
820       } catch (e) { /* ignored */ }
821       assert.deepEqual(actual, _.map(document.childNodes, _.identity), 'works on NodeList');
822     }
823   });
824
825   QUnit.test('size', function(assert) {
826     assert.equal(_.size({one: 1, two: 2, three: 3}), 3, 'can compute the size of an object');
827     assert.equal(_.size([1, 2, 3]), 3, 'can compute the size of an array');
828     assert.equal(_.size({length: 3, 0: 0, 1: 0, 2: 0}), 3, 'can compute the size of Array-likes');
829
830     var func = function() {
831       return _.size(arguments);
832     };
833
834     assert.equal(func(1, 2, 3, 4), 4, 'can test the size of the arguments object');
835
836     assert.equal(_.size('hello'), 5, 'can compute the size of a string literal');
837     assert.equal(_.size(new String('hello')), 5, 'can compute the size of string object');
838
839     assert.equal(_.size(null), 0, 'handles nulls');
840     assert.equal(_.size(0), 0, 'handles numbers');
841   });
842
843   QUnit.test('partition', function(assert) {
844     var list = [0, 1, 2, 3, 4, 5];
845     assert.deepEqual(_.partition(list, function(x) { return x < 4; }), [[0, 1, 2, 3], [4, 5]], 'handles bool return values');
846     assert.deepEqual(_.partition(list, function(x) { return x & 1; }), [[1, 3, 5], [0, 2, 4]], 'handles 0 and 1 return values');
847     assert.deepEqual(_.partition(list, function(x) { return x - 3; }), [[0, 1, 2, 4, 5], [3]], 'handles other numeric return values');
848     assert.deepEqual(_.partition(list, function(x) { return x > 1 ? null : true; }), [[0, 1], [2, 3, 4, 5]], 'handles null return values');
849     assert.deepEqual(_.partition(list, function(x) { if (x < 2) return true; }), [[0, 1], [2, 3, 4, 5]], 'handles undefined return values');
850     assert.deepEqual(_.partition({a: 1, b: 2, c: 3}, function(x) { return x > 1; }), [[2, 3], [1]], 'handles objects');
851
852     assert.deepEqual(_.partition(list, function(x, index) { return index % 2; }), [[1, 3, 5], [0, 2, 4]], 'can reference the array index');
853     assert.deepEqual(_.partition(list, function(x, index, arr) { return x === arr.length - 1; }), [[5], [0, 1, 2, 3, 4]], 'can reference the collection');
854
855     // Default iterator
856     assert.deepEqual(_.partition([1, false, true, '']), [[1, true], [false, '']], 'Default iterator');
857     assert.deepEqual(_.partition([{x: 1}, {x: 0}, {x: 1}], 'x'), [[{x: 1}, {x: 1}], [{x: 0}]], 'Takes a string');
858
859     // Context
860     var predicate = function(x){ return x === this.x; };
861     assert.deepEqual(_.partition([1, 2, 3], predicate, {x: 2}), [[2], [1, 3]], 'partition takes a context argument');
862
863     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');
864
865     var object = {a: 1};
866     _.partition(object, function(val, key, obj) {
867       assert.equal(val, 1);
868       assert.equal(key, 'a');
869       assert.equal(obj, object);
870       assert.equal(this, predicate);
871     }, predicate);
872   });
873
874   if (typeof document != 'undefined') {
875     QUnit.test('Can use various collection methods on NodeLists', function(assert) {
876       var parent = document.createElement('div');
877       parent.innerHTML = '<span id=id1></span>textnode<span id=id2></span>';
878
879       var elementChildren = _.filter(parent.childNodes, _.isElement);
880       assert.equal(elementChildren.length, 2);
881
882       assert.deepEqual(_.map(elementChildren, 'id'), ['id1', 'id2']);
883       assert.deepEqual(_.map(parent.childNodes, 'nodeType'), [1, 3, 1]);
884
885       assert.ok(!_.every(parent.childNodes, _.isElement));
886       assert.ok(_.some(parent.childNodes, _.isElement));
887
888       function compareNode(node) {
889         return _.isElement(node) ? node.id.charAt(2) : void 0;
890       }
891       assert.equal(_.max(parent.childNodes, compareNode), _.last(parent.childNodes));
892       assert.equal(_.min(parent.childNodes, compareNode), _.first(parent.childNodes));
893     });
894   }
895
896 }());