Update Underscore/Backbone tests and make them passable.

This commit is contained in:
John-David Dalton
2015-08-08 16:52:47 -07:00
parent de5c2b906e
commit bd9b38665d
13 changed files with 843 additions and 550 deletions

View File

@@ -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);
});
@@ -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() {
@@ -106,8 +111,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 +247,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 +257,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 +329,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 +341,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 +366,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 +397,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 +444,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 +475,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 +487,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 +518,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');
@@ -534,4 +539,19 @@
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([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], 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');
});
}());

View File

@@ -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');
});

View File

@@ -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,28 +557,30 @@
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');
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; };
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 +590,9 @@
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');
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);
@@ -604,20 +608,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');
@@ -628,25 +632,32 @@
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),
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) {
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');
deepEqual(_.sortBy(collection, 'x'), collection, 'sortBy accepts property string');
actual = _.sortBy(stableObject, function(pair) {
return pair.x;
});
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');
@@ -737,12 +748,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,17 +761,22 @@
});
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');
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');
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() {
@@ -770,7 +786,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') {
@@ -778,13 +794,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');
@@ -834,23 +850,23 @@
if (typeof document != 'undefined') {
test('Can use various collection methods on NodeLists', function() {
var parent = document.createElement('div');
parent.innerHTML = '<span id=id1></span>textnode<span id=id2></span>';
var parent = document.createElement('div');
parent.innerHTML = '<span id=id1></span>textnode<span id=id2></span>';
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));
});
}

View File

@@ -138,4 +138,4 @@
});
}
}());
}());

View File

@@ -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');
@@ -77,13 +77,23 @@
ok(widget instanceof MyWidget, 'Can partially bind a constructor');
equal(widget.get(), 'foo', 'keeps prototype');
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');
_.partial.placeholder = {};
func = _.partial(function() { return arguments.length; }, obj, 'b', obj, 'd');
equal(func('a'), 5, 'swapping the placeholder preserves previously bound arguments');
_.partial.placeholder = _;
});
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');
@@ -91,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');
@@ -109,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() {
@@ -145,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) {
@@ -155,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');
});
@@ -346,7 +360,7 @@
throttledIncr();
equal(counter, 1);
_.now = function () {
_.now = function() {
return new Date(2013, 0, 1, 1, 1, 1);
};
@@ -427,7 +441,7 @@
debouncedIncr();
equal(counter, 1, 'incr was called immediately');
_.now = function () {
_.now = function() {
return new Date(2013, 0, 1, 1, 1, 1);
};
@@ -485,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']);
});
@@ -575,7 +589,35 @@
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));
});
});
test('restArgs', 10, function() {
_.restArgs(function(a, args) {
strictEqual(a, 1);
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');
})();
_.restArgs(function(a, b, c, args) {
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');
}).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);
}, 0)(1, 2, 3, 4);
});
}());

View File

@@ -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');
@@ -54,7 +54,7 @@
valueOf: _.noop,
hasOwnProperty: null,
toString: 5,
toLocaleString: undefined,
toLocaleString: void 0,
propertyIsEnumerable: /a/,
isPrototypeOf: this
};
@@ -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');
deepEqual(_.defaults(null, {a: 1}), {a: 1}, 'defaults skips nulls');
deepEqual(_.defaults(void 0, {a: 1}), {a: 1}, 'defaults skips 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,7 +440,7 @@
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 = {
@@ -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; }
@@ -554,12 +554,19 @@
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() {
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');
@@ -567,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');
@@ -576,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');
});
@@ -602,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');
@@ -612,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');
});
@@ -631,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');
@@ -644,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');
@@ -652,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');
@@ -661,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') {
@@ -669,9 +681,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]');
});
});
}
@@ -688,7 +700,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');
@@ -704,15 +716,16 @@
});
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(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(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');
});
@@ -723,7 +736,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() {
@@ -755,7 +768,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.");
@@ -766,7 +779,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() {
@@ -776,17 +789,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');
});
@@ -805,8 +818,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() {
@@ -817,21 +830,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');
});
@@ -852,82 +865,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');
});
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__: undefined})(5), false, 'can match undefined props on primitives');
equal(_.matcher({__x__: undefined})({__x__: undefined}), 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, 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)');
_.each([true, 5, NaN, null, undefined], 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, 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) {
@@ -942,7 +898,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;
@@ -950,7 +906,7 @@
strictEqual(_.findKey(objects, function(a) {
return a.foo === null;
}), undefined);
}), void 0);
_.findKey({a: {a: 1}}, function(a, key, obj) {
equal(key, 'a');
@@ -965,53 +921,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');

View File

@@ -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);
@@ -21,42 +52,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 +117,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 +158,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 +189,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 +204,7 @@
var fancyTemplate = _.template('<ul><% ' +
' for (var key in people) { ' +
'%><li><%= people[key] %></li><% } %></ul>');
result = fancyTemplate({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}});
result = fancyTemplate({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}});
equal(result, '<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>', 'can run arbitrary javascript in templates');
var escapedCharsInJavascriptTemplate = _.template('<ul><% _.each(numbers.split("\\n"), function(item) { %><li><%= item %></li><% }) %></ul>');
@@ -222,15 +253,15 @@
' if (data) { data += 12345; }; %>\n ' +
' <li><%= data %></li>\n '
);
equal(template({data : 12345}).replace(/\s/g, ''), '<li>24690</li>');
equal(template({data: 12345}).replace(/\s/g, ''), '<li>24690</li>');
_.templateSettings = {
evaluate : /\{\{([\s\S]+?)\}\}/g,
interpolate : /\{\{=([\s\S]+?)\}\}/g
evaluate: /\{\{([\s\S]+?)\}\}/g,
interpolate: /\{\{=([\s\S]+?)\}\}/g
};
var custom = _.template('<ul>{{ for (var key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>');
result = custom({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}});
result = custom({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}});
equal(result, '<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>', 'can run arbitrary javascript in templates');
var customQuote = _.template("It's its, not it's");
@@ -240,12 +271,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('<ul><? for (var key in people) { ?><li><?= people[key] ?></li><? } ?></ul>');
result = customWithSpecialChars({people : {moe : 'Moe', larry : 'Larry', curly : 'Curly'}});
result = customWithSpecialChars({people: {moe: 'Moe', larry: 'Larry', curly: 'Curly'}});
equal(result, '<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>', 'can run arbitrary javascript in templates');
var customWithSpecialCharsQuote = _.template("It's its, not it's");
@@ -255,21 +286,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('<b><%= if x %></b>');
} catch (ex) {
var source = ex.source;
source = ex.source;
}
ok(/__p/.test(source));
});
@@ -284,13 +316,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 +333,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 +344,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 +373,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: {}}), '');