1(function() { 2 var _ = typeof require == 'function' ? require('..') : window._; 3 4 QUnit.module('Arrays'); 5 6 QUnit.test('first', function(assert) { 7 assert.equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array'); 8 assert.equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"'); 9 assert.deepEqual(_.first([1, 2, 3], 0), [], 'returns an empty array when n <= 0 (0 case)'); 10 assert.deepEqual(_.first([1, 2, 3], -1), [], 'returns an empty array when n <= 0 (negative case)'); 11 assert.deepEqual(_.first([1, 2, 3], 2), [1, 2], 'can fetch the first n elements'); 12 assert.deepEqual(_.first([1, 2, 3], 5), [1, 2, 3], 'returns the whole array if n > length'); 13 var result = (function(){ return _.first(arguments); }(4, 3, 2, 1)); 14 assert.equal(result, 4, 'works on an arguments object'); 15 result = _.map([[1, 2, 3], [1, 2, 3]], _.first); 16 assert.deepEqual(result, [1, 1], 'works well with _.map'); 17 assert.equal(_.first(null), void 0, 'returns undefined when called on null'); 18 19 Array.prototype[0] = 'boo'; 20 assert.equal(_.first([]), void 0, 'return undefined when called on a empty array'); 21 delete Array.prototype[0]; 22 }); 23 24 QUnit.test('head', function(assert) { 25 assert.strictEqual(_.head, _.first, 'is an alias for first'); 26 }); 27 28 QUnit.test('take', function(assert) { 29 assert.strictEqual(_.take, _.first, 'is an alias for first'); 30 }); 31 32 QUnit.test('rest', function(assert) { 33 var numbers = [1, 2, 3, 4]; 34 assert.deepEqual(_.rest(numbers), [2, 3, 4], 'fetches all but the first element'); 35 assert.deepEqual(_.rest(numbers, 0), [1, 2, 3, 4], 'returns the whole array when index is 0'); 36 assert.deepEqual(_.rest(numbers, 2), [3, 4], 'returns elements starting at the given index'); 37 var result = (function(){ return _(arguments).rest(); }(1, 2, 3, 4)); 38 assert.deepEqual(result, [2, 3, 4], 'works on an arguments object'); 39 result = _.map([[1, 2, 3], [1, 2, 3]], _.rest); 40 assert.deepEqual(_.flatten(result), [2, 3, 2, 3], 'works well with _.map'); 41 }); 42 43 QUnit.test('tail', function(assert) { 44 assert.strictEqual(_.tail, _.rest, 'is an alias for rest'); 45 }); 46 47 QUnit.test('drop', function(assert) { 48 assert.strictEqual(_.drop, _.rest, 'is an alias for rest'); 49 }); 50 51 QUnit.test('initial', function(assert) { 52 assert.deepEqual(_.initial([1, 2, 3, 4, 5]), [1, 2, 3, 4], 'returns all but the last element'); 53 assert.deepEqual(_.initial([1, 2, 3, 4], 2), [1, 2], 'returns all but the last n elements'); 54 assert.deepEqual(_.initial([1, 2, 3, 4], 6), [], 'returns an empty array when n > length'); 55 var result = (function(){ return _(arguments).initial(); }(1, 2, 3, 4)); 56 assert.deepEqual(result, [1, 2, 3], 'works on an arguments object'); 57 result = _.map([[1, 2, 3], [1, 2, 3]], _.initial); 58 assert.deepEqual(_.flatten(result), [1, 2, 1, 2], 'works well with _.map'); 59 }); 60 61 QUnit.test('last', function(assert) { 62 assert.equal(_.last([1, 2, 3]), 3, 'can pull out the last element of an array'); 63 assert.equal(_([1, 2, 3]).last(), 3, 'can perform OO-style "last()"'); 64 assert.deepEqual(_.last([1, 2, 3], 0), [], 'returns an empty array when n <= 0 (0 case)'); 65 assert.deepEqual(_.last([1, 2, 3], -1), [], 'returns an empty array when n <= 0 (negative case)'); 66 assert.deepEqual(_.last([1, 2, 3], 2), [2, 3], 'can fetch the last n elements'); 67 assert.deepEqual(_.last([1, 2, 3], 5), [1, 2, 3], 'returns the whole array if n > length'); 68 var result = (function(){ return _(arguments).last(); }(1, 2, 3, 4)); 69 assert.equal(result, 4, 'works on an arguments object'); 70 result = _.map([[1, 2, 3], [1, 2, 3]], _.last); 71 assert.deepEqual(result, [3, 3], 'works well with _.map'); 72 assert.equal(_.last(null), void 0, 'returns undefined when called on null'); 73 74 var arr = []; 75 arr[-1] = 'boo'; 76 assert.equal(_.last(arr), void 0, 'return undefined when called on a empty array'); 77 }); 78 79 QUnit.test('compact', function(assert) { 80 assert.deepEqual(_.compact([1, false, null, 0, '', void 0, NaN, 2]), [1, 2], 'removes all falsy values'); 81 var result = (function(){ return _.compact(arguments); }(0, 1, false, 2, false, 3)); 82 assert.deepEqual(result, [1, 2, 3], 'works on an arguments object'); 83 result = _.map([[1, false, false], [false, false, 3]], _.compact); 84 assert.deepEqual(result, [[1], [3]], 'works well with _.map'); 85 }); 86 87 QUnit.test('flatten', function(assert) { 88 assert.deepEqual(_.flatten(null), [], 'supports null'); 89 assert.deepEqual(_.flatten(void 0), [], 'supports undefined'); 90 91 assert.deepEqual(_.flatten([[], [[]], []]), [], 'supports empty arrays'); 92 assert.deepEqual(_.flatten([[], [[]], []], true), [[]], 'can shallowly flatten empty arrays'); 93 94 var list = [1, [2], [3, [[[4]]]]]; 95 assert.deepEqual(_.flatten(list), [1, 2, 3, 4], 'can flatten nested arrays'); 96 assert.deepEqual(_.flatten(list, true), [1, 2, 3, [[[4]]]], 'can shallowly flatten nested arrays'); 97 var result = (function(){ return _.flatten(arguments); }(1, [2], [3, [[[4]]]])); 98 assert.deepEqual(result, [1, 2, 3, 4], 'works on an arguments object'); 99 list = [[1], [2], [3], [[4]]]; 100 assert.deepEqual(_.flatten(list, true), [1, 2, 3, [4]], 'can shallowly flatten arrays containing only other arrays'); 101 102 assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3], true).length, 23, 'can flatten medium length arrays'); 103 assert.equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23, 'can shallowly flatten medium length arrays'); 104 assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'can handle massive arrays'); 105 assert.equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'can handle massive arrays in shallow mode'); 106 107 var x = _.range(100000); 108 for (var i = 0; i < 1000; i++) x = [x]; 109 assert.deepEqual(_.flatten(x), _.range(100000), 'can handle very deep arrays'); 110 assert.deepEqual(_.flatten(x, true), x[0], 'can handle very deep arrays in shallow mode'); 111 }); 112 113 QUnit.test('without', function(assert) { 114 var list = [1, 2, 1, 0, 3, 1, 4]; 115 assert.deepEqual(_.without(list, 0, 1), [2, 3, 4], 'removes all instances of the given values'); 116 var result = (function(){ return _.without(arguments, 0, 1); }(1, 2, 1, 0, 3, 1, 4)); 117 assert.deepEqual(result, [2, 3, 4], 'works on an arguments object'); 118 119 list = [{one: 1}, {two: 2}]; 120 assert.deepEqual(_.without(list, {one: 1}), list, 'compares objects by reference (value case)'); 121 assert.deepEqual(_.without(list, list[0]), [{two: 2}], 'compares objects by reference (reference case)'); 122 }); 123 124 QUnit.test('sortedIndex', function(assert) { 125 var numbers = [10, 20, 30, 40, 50]; 126 var indexFor35 = _.sortedIndex(numbers, 35); 127 assert.equal(indexFor35, 3, 'finds the index at which a value should be inserted to retain order'); 128 var indexFor30 = _.sortedIndex(numbers, 30); 129 assert.equal(indexFor30, 2, 'finds the smallest index at which a value could be inserted to retain order'); 130 131 var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}]; 132 var iterator = function(obj){ return obj.x; }; 133 assert.strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2, 'uses the result of `iterator` for order comparisons'); 134 assert.strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3, 'when `iterator` is a string, uses that key for order comparisons'); 135 136 var context = {1: 2, 2: 3, 3: 4}; 137 iterator = function(obj){ return this[obj]; }; 138 assert.strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1, 'can execute its iterator in the given context'); 139 140 var values = [0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 141 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647]; 142 var largeArray = Array(Math.pow(2, 32) - 1); 143 var length = values.length; 144 // Sparsely populate `array` 145 while (length--) { 146 largeArray[values[length]] = values[length]; 147 } 148 assert.equal(_.sortedIndex(largeArray, 2147483648), 2147483648, 'works with large indexes'); 149 }); 150 151 QUnit.test('uniq', function(assert) { 152 var list = [1, 2, 1, 3, 1, 4]; 153 assert.deepEqual(_.uniq(list), [1, 2, 3, 4], 'can find the unique values of an unsorted array'); 154 list = [1, 1, 1, 2, 2, 3]; 155 assert.deepEqual(_.uniq(list, true), [1, 2, 3], 'can find the unique values of a sorted array faster'); 156 157 list = [{name: 'Moe'}, {name: 'Curly'}, {name: 'Larry'}, {name: 'Curly'}]; 158 var expected = [{name: 'Moe'}, {name: 'Curly'}, {name: 'Larry'}]; 159 var iterator = function(stooge) { return stooge.name; }; 160 assert.deepEqual(_.uniq(list, false, iterator), expected, 'uses the result of `iterator` for uniqueness comparisons (unsorted case)'); 161 assert.deepEqual(_.uniq(list, iterator), expected, '`sorted` argument defaults to false when omitted'); 162 assert.deepEqual(_.uniq(list, 'name'), expected, 'when `iterator` is a string, uses that key for comparisons (unsorted case)'); 163 164 list = [{score: 8}, {score: 10}, {score: 10}]; 165 expected = [{score: 8}, {score: 10}]; 166 iterator = function(item) { return item.score; }; 167 assert.deepEqual(_.uniq(list, true, iterator), expected, 'uses the result of `iterator` for uniqueness comparisons (sorted case)'); 168 assert.deepEqual(_.uniq(list, true, 'score'), expected, 'when `iterator` is a string, uses that key for comparisons (sorted case)'); 169 170 assert.deepEqual(_.uniq([{0: 1}, {0: 1}, {0: 1}, {0: 2}], 0), [{0: 1}, {0: 2}], 'can use falsey pluck like iterator'); 171 172 var result = (function(){ return _.uniq(arguments); }(1, 2, 1, 3, 1, 4)); 173 assert.deepEqual(result, [1, 2, 3, 4], 'works on an arguments object'); 174 175 var a = {}, b = {}, c = {}; 176 assert.deepEqual(_.uniq([a, b, a, b, c]), [a, b, c], 'works on values that can be tested for equivalency but not ordered'); 177 178 assert.deepEqual(_.uniq(null), [], 'returns an empty array when `array` is not iterable'); 179 180 var context = {}; 181 list = [3]; 182 _.uniq(list, function(value, index, array) { 183 assert.strictEqual(this, context, 'executes its iterator in the given context'); 184 assert.strictEqual(value, 3, 'passes its iterator the value'); 185 assert.strictEqual(index, 0, 'passes its iterator the index'); 186 assert.strictEqual(array, list, 'passes its iterator the entire array'); 187 }, context); 188 189 }); 190 191 QUnit.test('unique', function(assert) { 192 assert.strictEqual(_.unique, _.uniq, 'is an alias for uniq'); 193 }); 194 195 QUnit.test('intersection', function(assert) { 196 var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho']; 197 assert.deepEqual(_.intersection(stooges, leaders), ['moe'], 'can find the set intersection of two arrays'); 198 assert.deepEqual(_(stooges).intersection(leaders), ['moe'], 'can perform an OO-style intersection'); 199 var result = (function(){ return _.intersection(arguments, leaders); }('moe', 'curly', 'larry')); 200 assert.deepEqual(result, ['moe'], 'works on an arguments object'); 201 var theSixStooges = ['moe', 'moe', 'curly', 'curly', 'larry', 'larry']; 202 assert.deepEqual(_.intersection(theSixStooges, leaders), ['moe'], 'returns a duplicate-free array'); 203 result = _.intersection([2, 4, 3, 1], [1, 2, 3]); 204 assert.deepEqual(result, [2, 3, 1], 'preserves the order of the first array'); 205 result = _.intersection(null, [1, 2, 3]); 206 assert.deepEqual(result, [], 'returns an empty array when passed null as the first argument'); 207 result = _.intersection([1, 2, 3], null); 208 assert.deepEqual(result, [], 'returns an empty array when passed null as an argument beyond the first'); 209 }); 210 211 QUnit.test('union', function(assert) { 212 var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]); 213 assert.deepEqual(result, [1, 2, 3, 30, 40], 'can find the union of a list of arrays'); 214 215 result = _([1, 2, 3]).union([2, 30, 1], [1, 40]); 216 assert.deepEqual(result, [1, 2, 3, 30, 40], 'can perform an OO-style union'); 217 218 result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]); 219 assert.deepEqual(result, [1, 2, 3, 30, 40, [1]], 'can find the union of a list of nested arrays'); 220 221 result = _.union([10, 20], [1, 30, 10], [0, 40]); 222 assert.deepEqual(result, [10, 20, 1, 30, 0, 40], 'orders values by their first encounter'); 223 224 result = (function(){ return _.union(arguments, [2, 30, 1], [1, 40]); }(1, 2, 3)); 225 assert.deepEqual(result, [1, 2, 3, 30, 40], 'works on an arguments object'); 226 227 assert.deepEqual(_.union([1, 2, 3], 4), [1, 2, 3], 'restricts the union to arrays only'); 228 }); 229 230 QUnit.test('difference', function(assert) { 231 var result = _.difference([1, 2, 3], [2, 30, 40]); 232 assert.deepEqual(result, [1, 3], 'can find the difference of two arrays'); 233 234 result = _([1, 2, 3]).difference([2, 30, 40]); 235 assert.deepEqual(result, [1, 3], 'can perform an OO-style difference'); 236 237 result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]); 238 assert.deepEqual(result, [3, 4], 'can find the difference of three arrays'); 239 240 result = _.difference([8, 9, 3, 1], [3, 8]); 241 assert.deepEqual(result, [9, 1], 'preserves the order of the first array'); 242 243 result = (function(){ return _.difference(arguments, [2, 30, 40]); }(1, 2, 3)); 244 assert.deepEqual(result, [1, 3], 'works on an arguments object'); 245 246 result = _.difference([1, 2, 3], 1); 247 assert.deepEqual(result, [1, 2, 3], 'restrict the difference to arrays only'); 248 }); 249 250 QUnit.test('zip', function(assert) { 251 var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true]; 252 assert.deepEqual(_.zip(names, ages, leaders), [ 253 ['moe', 30, true], 254 ['larry', 40, void 0], 255 ['curly', 50, void 0] 256 ], 'zipped together arrays of different lengths'); 257 258 var stooges = _.zip(['moe', 30, 'stooge 1'], ['larry', 40, 'stooge 2'], ['curly', 50, 'stooge 3']); 259 assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], ['stooge 1', 'stooge 2', 'stooge 3']], 'zipped pairs'); 260 261 // In the case of different lengths of the tuples, undefined values 262 // should be used as placeholder 263 stooges = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); 264 assert.deepEqual(stooges, [['moe', 'larry', 'curly'], [30, 40, 50], [void 0, void 0, 'extra data']], 'zipped pairs with empties'); 265 266 var empty = _.zip([]); 267 assert.deepEqual(empty, [], 'unzipped empty'); 268 269 assert.deepEqual(_.zip(null), [], 'handles null'); 270 assert.deepEqual(_.zip(), [], '_.zip() returns []'); 271 }); 272 273 QUnit.test('unzip', function(assert) { 274 assert.deepEqual(_.unzip(null), [], 'handles null'); 275 276 assert.deepEqual(_.unzip([['a', 'b'], [1, 2]]), [['a', 1], ['b', 2]]); 277 278 // complements zip 279 var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); 280 assert.deepEqual(_.unzip(zipped), [['fred', 'barney'], [30, 40], [true, false]]); 281 282 zipped = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']); 283 assert.deepEqual(_.unzip(zipped), [['moe', 30, void 0], ['larry', 40, void 0], ['curly', 50, 'extra data']], 'Uses length of largest array'); 284 }); 285 286 QUnit.test('object', function(assert) { 287 var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]); 288 var shouldBe = {moe: 30, larry: 40, curly: 50}; 289 assert.deepEqual(result, shouldBe, 'two arrays zipped together into an object'); 290 291 result = _.object([['one', 1], ['two', 2], ['three', 3]]); 292 shouldBe = {one: 1, two: 2, three: 3}; 293 assert.deepEqual(result, shouldBe, 'an array of pairs zipped together into an object'); 294 295 var stooges = {moe: 30, larry: 40, curly: 50}; 296 assert.deepEqual(_.object(_.pairs(stooges)), stooges, 'an object converted to pairs and back to an object'); 297 298 assert.deepEqual(_.object(null), {}, 'handles nulls'); 299 }); 300 301 QUnit.test('indexOf', function(assert) { 302 var numbers = [1, 2, 3]; 303 assert.equal(_.indexOf(numbers, 2), 1, 'can compute indexOf'); 304 var result = (function(){ return _.indexOf(arguments, 2); }(1, 2, 3)); 305 assert.equal(result, 1, 'works on an arguments object'); 306 307 _.each([null, void 0, [], false], function(val) { 308 var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val); 309 assert.equal(_.indexOf(val, 2), -1, msg); 310 assert.equal(_.indexOf(val, 2, -1), -1, msg); 311 assert.equal(_.indexOf(val, 2, -20), -1, msg); 312 assert.equal(_.indexOf(val, 2, 15), -1, msg); 313 }); 314 315 var num = 35; 316 numbers = [10, 20, 30, 40, 50]; 317 var index = _.indexOf(numbers, num, true); 318 assert.equal(index, -1, '35 is not in the list'); 319 320 numbers = [10, 20, 30, 40, 50]; num = 40; 321 index = _.indexOf(numbers, num, true); 322 assert.equal(index, 3, '40 is in the list'); 323 324 numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40; 325 assert.equal(_.indexOf(numbers, num, true), 1, '40 is in the list'); 326 assert.equal(_.indexOf(numbers, 6, true), -1, '6 isnt in the list'); 327 assert.equal(_.indexOf([1, 2, 5, 4, 6, 7], 5, true), -1, 'sorted indexOf doesn\'t uses binary search'); 328 assert.ok(_.every(['1', [], {}, null], function() { 329 return _.indexOf(numbers, num, {}) === 1; 330 }), 'non-nums as fromIndex make indexOf assume sorted'); 331 332 numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; 333 index = _.indexOf(numbers, 2, 5); 334 assert.equal(index, 7, 'supports the fromIndex argument'); 335 336 index = _.indexOf([,,, 0], void 0); 337 assert.equal(index, 0, 'treats sparse arrays as if they were dense'); 338 339 var array = [1, 2, 3, 1, 2, 3]; 340 assert.strictEqual(_.indexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index'); 341 assert.strictEqual(_.indexOf(array, 1, -2), -1, 'neg `fromIndex` starts at the right index'); 342 assert.strictEqual(_.indexOf(array, 2, -3), 4); 343 _.each([-6, -8, -Infinity], function(fromIndex) { 344 assert.strictEqual(_.indexOf(array, 1, fromIndex), 0); 345 }); 346 assert.strictEqual(_.indexOf([1, 2, 3], 1, true), 0); 347 348 index = _.indexOf([], void 0, true); 349 assert.equal(index, -1, 'empty array with truthy `isSorted` returns -1'); 350 }); 351 352 QUnit.test('indexOf with NaN', function(assert) { 353 assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN), 2, 'Expected [1, 2, NaN] to contain NaN'); 354 assert.strictEqual(_.indexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); 355 356 assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, 1), 2, 'startIndex does not affect result'); 357 assert.strictEqual(_.indexOf([1, 2, NaN, NaN], NaN, -2), 2, 'startIndex does not affect result'); 358 359 (function() { 360 assert.strictEqual(_.indexOf(arguments, NaN), 2, 'Expected arguments [1, 2, NaN] to contain NaN'); 361 }(1, 2, NaN, NaN)); 362 }); 363 364 QUnit.test('indexOf with +- 0', function(assert) { 365 _.each([-0, +0], function(val) { 366 assert.strictEqual(_.indexOf([1, 2, val, val], val), 2); 367 assert.strictEqual(_.indexOf([1, 2, val, val], -val), 2); 368 }); 369 }); 370 371 QUnit.test('lastIndexOf', function(assert) { 372 var numbers = [1, 0, 1]; 373 var falsey = [void 0, '', 0, false, NaN, null, void 0]; 374 assert.equal(_.lastIndexOf(numbers, 1), 2); 375 376 numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0]; 377 numbers.lastIndexOf = null; 378 assert.equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function'); 379 assert.equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element'); 380 var result = (function(){ return _.lastIndexOf(arguments, 1); }(1, 0, 1, 0, 0, 1, 0, 0, 0)); 381 assert.equal(result, 5, 'works on an arguments object'); 382 383 _.each([null, void 0, [], false], function(val) { 384 var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val); 385 assert.equal(_.lastIndexOf(val, 2), -1, msg); 386 assert.equal(_.lastIndexOf(val, 2, -1), -1, msg); 387 assert.equal(_.lastIndexOf(val, 2, -20), -1, msg); 388 assert.equal(_.lastIndexOf(val, 2, 15), -1, msg); 389 }); 390 391 numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3]; 392 var index = _.lastIndexOf(numbers, 2, 2); 393 assert.equal(index, 1, 'supports the fromIndex argument'); 394 395 var array = [1, 2, 3, 1, 2, 3]; 396 397 assert.strictEqual(_.lastIndexOf(array, 1, 0), 0, 'starts at the correct from idx'); 398 assert.strictEqual(_.lastIndexOf(array, 3), 5, 'should return the index of the last matched value'); 399 assert.strictEqual(_.lastIndexOf(array, 4), -1, 'should return `-1` for an unmatched value'); 400 401 assert.strictEqual(_.lastIndexOf(array, 1, 2), 0, 'should work with a positive `fromIndex`'); 402 403 _.each([6, 8, Math.pow(2, 32), Infinity], function(fromIndex) { 404 assert.strictEqual(_.lastIndexOf(array, void 0, fromIndex), -1); 405 assert.strictEqual(_.lastIndexOf(array, 1, fromIndex), 3); 406 assert.strictEqual(_.lastIndexOf(array, '', fromIndex), -1); 407 }); 408 409 var expected = _.map(falsey, function(value) { 410 return typeof value == 'number' ? -1 : 5; 411 }); 412 413 var actual = _.map(falsey, function(fromIndex) { 414 return _.lastIndexOf(array, 3, fromIndex); 415 }); 416 417 assert.deepEqual(actual, expected, 'should treat falsey `fromIndex` values, except `0` and `NaN`, as `array.length`'); 418 assert.strictEqual(_.lastIndexOf(array, 3, '1'), 5, 'should treat non-number `fromIndex` values as `array.length`'); 419 assert.strictEqual(_.lastIndexOf(array, 3, true), 5, 'should treat non-number `fromIndex` values as `array.length`'); 420 421 assert.strictEqual(_.lastIndexOf(array, 2, -3), 1, 'should work with a negative `fromIndex`'); 422 assert.strictEqual(_.lastIndexOf(array, 1, -3), 3, 'neg `fromIndex` starts at the right index'); 423 424 assert.deepEqual(_.map([-6, -8, -Infinity], function(fromIndex) { 425 return _.lastIndexOf(array, 1, fromIndex); 426 }), [0, -1, -1]); 427 }); 428 429 QUnit.test('lastIndexOf with NaN', function(assert) { 430 assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN), 3, 'Expected [1, 2, NaN] to contain NaN'); 431 assert.strictEqual(_.lastIndexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN'); 432 433 assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, 2), 2, 'fromIndex does not affect result'); 434 assert.strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN, -2), 2, 'fromIndex does not affect result'); 435 436 (function() { 437 assert.strictEqual(_.lastIndexOf(arguments, NaN), 3, 'Expected arguments [1, 2, NaN] to contain NaN'); 438 }(1, 2, NaN, NaN)); 439 }); 440 441 QUnit.test('lastIndexOf with +- 0', function(assert) { 442 _.each([-0, +0], function(val) { 443 assert.strictEqual(_.lastIndexOf([1, 2, val, val], val), 3); 444 assert.strictEqual(_.lastIndexOf([1, 2, val, val], -val), 3); 445 assert.strictEqual(_.lastIndexOf([-1, 1, 2], -val), -1); 446 }); 447 }); 448 449 QUnit.test('findIndex', function(assert) { 450 var objects = [ 451 {a: 0, b: 0}, 452 {a: 1, b: 1}, 453 {a: 2, b: 2}, 454 {a: 0, b: 0} 455 ]; 456 457 assert.equal(_.findIndex(objects, function(obj) { 458 return obj.a === 0; 459 }), 0); 460 461 assert.equal(_.findIndex(objects, function(obj) { 462 return obj.b * obj.a === 4; 463 }), 2); 464 465 assert.equal(_.findIndex(objects, 'a'), 1, 'Uses lookupIterator'); 466 467 assert.equal(_.findIndex(objects, function(obj) { 468 return obj.b * obj.a === 5; 469 }), -1); 470 471 assert.equal(_.findIndex(null, _.noop), -1); 472 assert.strictEqual(_.findIndex(objects, function(a) { 473 return a.foo === null; 474 }), -1); 475 _.findIndex([{a: 1}], function(a, key, obj) { 476 assert.equal(key, 0); 477 assert.deepEqual(obj, [{a: 1}]); 478 assert.strictEqual(this, objects, 'called with context'); 479 }, objects); 480 481 var sparse = []; 482 sparse[20] = {a: 2, b: 2}; 483 assert.equal(_.findIndex(sparse, function(obj) { 484 return obj && obj.b * obj.a === 4; 485 }), 20, 'Works with sparse arrays'); 486 487 var array = [1, 2, 3, 4]; 488 array.match = 55; 489 assert.strictEqual(_.findIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); 490 }); 491 492 QUnit.test('findLastIndex', function(assert) { 493 var objects = [ 494 {a: 0, b: 0}, 495 {a: 1, b: 1}, 496 {a: 2, b: 2}, 497 {a: 0, b: 0} 498 ]; 499 500 assert.equal(_.findLastIndex(objects, function(obj) { 501 return obj.a === 0; 502 }), 3); 503 504 assert.equal(_.findLastIndex(objects, function(obj) { 505 return obj.b * obj.a === 4; 506 }), 2); 507 508 assert.equal(_.findLastIndex(objects, 'a'), 2, 'Uses lookupIterator'); 509 510 assert.equal(_.findLastIndex(objects, function(obj) { 511 return obj.b * obj.a === 5; 512 }), -1); 513 514 assert.equal(_.findLastIndex(null, _.noop), -1); 515 assert.strictEqual(_.findLastIndex(objects, function(a) { 516 return a.foo === null; 517 }), -1); 518 _.findLastIndex([{a: 1}], function(a, key, obj) { 519 assert.equal(key, 0); 520 assert.deepEqual(obj, [{a: 1}]); 521 assert.strictEqual(this, objects, 'called with context'); 522 }, objects); 523 524 var sparse = []; 525 sparse[20] = {a: 2, b: 2}; 526 assert.equal(_.findLastIndex(sparse, function(obj) { 527 return obj && obj.b * obj.a === 4; 528 }), 20, 'Works with sparse arrays'); 529 530 var array = [1, 2, 3, 4]; 531 array.match = 55; 532 assert.strictEqual(_.findLastIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys'); 533 }); 534 535 QUnit.test('range', function(assert) { 536 assert.deepEqual(_.range(0), [], 'range with 0 as a first argument generates an empty array'); 537 assert.deepEqual(_.range(4), [0, 1, 2, 3], 'range with a single positive argument generates an array of elements 0,1,2,...,n-1'); 538 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 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'); 540 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'); 541 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'); 542 assert.deepEqual(_.range(0, -10, -1), [0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 'final example in the Python docs'); 543 assert.strictEqual(1 / _.range(-0, 1)[0], -Infinity, 'should preserve -0'); 544 assert.deepEqual(_.range(8, 5), [8, 7, 6], 'negative range generates descending array'); 545 assert.deepEqual(_.range(-3), [0, -1, -2], 'negative range generates descending array'); 546 }); 547 548 QUnit.test('chunk', function(assert) { 549 assert.deepEqual(_.chunk([], 2), [], 'chunk for empty array returns an empty array'); 550 551 assert.deepEqual(_.chunk([1, 2, 3], 0), [], 'chunk into parts of 0 elements returns empty array'); 552 assert.deepEqual(_.chunk([1, 2, 3], -1), [], 'chunk into parts of negative amount of elements returns an empty array'); 553 assert.deepEqual(_.chunk([1, 2, 3]), [], 'defaults to empty array (chunk size 0)'); 554 555 assert.deepEqual(_.chunk([1, 2, 3], 1), [[1], [2], [3]], 'chunk into parts of 1 elements returns original array'); 556 557 assert.deepEqual(_.chunk([1, 2, 3], 3), [[1, 2, 3]], 'chunk into parts of current array length elements returns the original array'); 558 assert.deepEqual(_.chunk([1, 2, 3], 5), [[1, 2, 3]], 'chunk into parts of more then current array length elements returns the original array'); 559 560 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'); 561 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'); 562 }); 563}()); 564