mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-29 06:27:49 +00:00
Update benchmark and underscore vendor files.
This commit is contained in:
@@ -51,6 +51,7 @@
|
||||
'0'
|
||||
],
|
||||
'flatten': [
|
||||
'Flattens empty arrays',
|
||||
'can flatten nested arrays',
|
||||
'can shallowly flatten nested arrays',
|
||||
'works on an arguments object',
|
||||
@@ -83,6 +84,9 @@
|
||||
]
|
||||
},
|
||||
'Chaining': {
|
||||
'pop': true,
|
||||
'shift': true,
|
||||
'splice': true,
|
||||
'select/reject/sortBy': [
|
||||
'Died on test #1'
|
||||
],
|
||||
@@ -97,16 +101,14 @@
|
||||
'filter': [
|
||||
'OO-filter'
|
||||
],
|
||||
'invoke': [
|
||||
'handles null & undefined'
|
||||
],
|
||||
'map': [
|
||||
'OO-style doubled numbers'
|
||||
],
|
||||
'reduce': [
|
||||
'handles a null (without initial value) properly',
|
||||
'throws an error for empty arrays with no initial value'
|
||||
],
|
||||
'reduceRight': [
|
||||
'handles a null (without initial value) properly',
|
||||
'throws an error for empty arrays with no initial value'
|
||||
'Resistant to collection length and properties changing while iterating': [
|
||||
'Died on test #50'
|
||||
]
|
||||
},
|
||||
'Functions': {
|
||||
@@ -127,14 +129,23 @@
|
||||
'debounce asap': true
|
||||
},
|
||||
'Objects': {
|
||||
'isEqual': [
|
||||
'Died on test #60',
|
||||
'Died on test #63'
|
||||
'#1929 Typed Array constructors are functions': true,
|
||||
'allKeys': true,
|
||||
'extendOwn': true,
|
||||
'mapObject': true,
|
||||
'matcher': true,
|
||||
'matcher ': true,
|
||||
'extend': [
|
||||
'extend copies all properties from source'
|
||||
],
|
||||
'isFinite': [
|
||||
'Numeric strings are numbers',
|
||||
'Number instances can be finite'
|
||||
],
|
||||
'isMatch': [
|
||||
'inherited and own properties are checked on the test object',
|
||||
'doesnt falsey match constructor on undefined/null'
|
||||
],
|
||||
'keys': [
|
||||
'is not fooled by sparse arrays; see issue #95',
|
||||
'[]'
|
||||
@@ -145,9 +156,6 @@
|
||||
]
|
||||
},
|
||||
'Utility': {
|
||||
'now': [
|
||||
'Produces the correct time in milliseconds'
|
||||
],
|
||||
'_.templateSettings.variable': [
|
||||
'"x"'
|
||||
],
|
||||
|
||||
372
vendor/benchmark.js/benchmark.js
vendored
372
vendor/benchmark.js/benchmark.js
vendored
File diff suppressed because it is too large
Load Diff
2
vendor/underscore/LICENSE
vendored
2
vendor/underscore/LICENSE
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative
|
||||
Copyright (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative
|
||||
Reporters & Editors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
|
||||
207
vendor/underscore/test/arrays.js
vendored
207
vendor/underscore/test/arrays.js
vendored
@@ -1,6 +1,7 @@
|
||||
(function() {
|
||||
var _ = typeof require == 'function' ? require('..') : window._;
|
||||
|
||||
module('Arrays');
|
||||
QUnit.module('Arrays');
|
||||
|
||||
test('first', function() {
|
||||
equal(_.first([1, 2, 3]), 1, 'can pull out the first element of an array');
|
||||
@@ -79,6 +80,12 @@
|
||||
});
|
||||
|
||||
test('flatten', function() {
|
||||
deepEqual(_.flatten(null), [], 'Flattens supports null');
|
||||
deepEqual(_.flatten(void 0), [], 'Flattens supports undefined');
|
||||
|
||||
deepEqual(_.flatten([[], [[]], []]), [], 'Flattens empty arrays');
|
||||
deepEqual(_.flatten([[], [[]], []], true), [[]], 'Flattens empty arrays');
|
||||
|
||||
var list = [1, [2], [3, [[[4]]]]];
|
||||
deepEqual(_.flatten(list), [1, 2, 3, 4], 'can flatten nested arrays');
|
||||
deepEqual(_.flatten(list, true), [1, 2, 3, [[[4]]]], 'can shallowly flatten nested arrays');
|
||||
@@ -86,6 +93,11 @@
|
||||
deepEqual(result, [1, 2, 3, 4], 'works on an arguments object');
|
||||
list = [[1], [2], [3], [[4]]];
|
||||
deepEqual(_.flatten(list, true), [1, 2, 3, [4]], 'can shallowly flatten arrays containing only other arrays');
|
||||
|
||||
equal(_.flatten([_.range(10), _.range(10), 5, 1, 3], true).length, 23);
|
||||
equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23);
|
||||
equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'Flatten can handle massive collections');
|
||||
equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'Flatten can handle massive collections');
|
||||
});
|
||||
|
||||
test('without', function() {
|
||||
@@ -99,6 +111,32 @@
|
||||
equal(_.without(list, list[0]).length, 1, 'ditto.');
|
||||
});
|
||||
|
||||
test('sortedIndex', function() {
|
||||
var numbers = [10, 20, 30, 40, 50], num = 35;
|
||||
var indexForNum = _.sortedIndex(numbers, num);
|
||||
equal(indexForNum, 3, '35 should be inserted at index 3');
|
||||
|
||||
var indexFor30 = _.sortedIndex(numbers, 30);
|
||||
equal(indexFor30, 2, '30 should be inserted at index 2');
|
||||
|
||||
var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}];
|
||||
var iterator = function(obj){ return obj.x; };
|
||||
strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2);
|
||||
strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3);
|
||||
|
||||
var context = {1: 2, 2: 3, 3: 4};
|
||||
iterator = function(obj){ return this[obj]; };
|
||||
strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1);
|
||||
|
||||
var values = [0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647];
|
||||
var array = Array(Math.pow(2, 32) - 1);
|
||||
var length = values.length;
|
||||
while (length--) {
|
||||
array[values[length]] = values[length];
|
||||
}
|
||||
equal(_.sortedIndex(array, 2147483648), 2147483648, 'should work with large indexes');
|
||||
});
|
||||
|
||||
test('uniq', function() {
|
||||
var list = [1, 2, 1, 3, 1, 4];
|
||||
deepEqual(_.uniq(list), [1, 2, 3, 4], 'can find the unique values of an unsorted array');
|
||||
@@ -116,6 +154,20 @@
|
||||
list = [1, 2, 2, 3, 4, 4];
|
||||
deepEqual(_.uniq(list, true, iterator), [1, 2, 3, 4], 'iterator works with sorted array');
|
||||
|
||||
var kittens = [
|
||||
{kitten: 'Celery', cuteness: 8},
|
||||
{kitten: 'Juniper', cuteness: 10},
|
||||
{kitten: 'Spottis', cuteness: 10}
|
||||
];
|
||||
|
||||
var expected = [
|
||||
{kitten: 'Celery', cuteness: 8},
|
||||
{kitten: 'Juniper', cuteness: 10}
|
||||
];
|
||||
|
||||
deepEqual(_.uniq(kittens, true, 'cuteness'), expected, 'string iterator works with sorted array');
|
||||
|
||||
|
||||
var result = (function(){ return _.uniq(arguments); }(1, 2, 1, 3, 1, 4));
|
||||
deepEqual(result, [1, 2, 3, 4], 'works on an arguments object');
|
||||
|
||||
@@ -209,6 +261,19 @@
|
||||
deepEqual(_.zip(), [], '_.zip() returns []');
|
||||
});
|
||||
|
||||
test('unzip', function() {
|
||||
deepEqual(_.unzip(null), [], 'handles null');
|
||||
|
||||
deepEqual(_.unzip([['a', 'b'], [1, 2]]), [['a', 1], ['b', 2]]);
|
||||
|
||||
// complements zip
|
||||
var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
|
||||
deepEqual(_.unzip(zipped), [['fred', 'barney'], [30, 40], [true, false]]);
|
||||
|
||||
zipped = _.zip(['moe', 30], ['larry', 40], ['curly', 50, 'extra data']);
|
||||
deepEqual(_.unzip(zipped), [['moe', 30, void 0], ['larry', 40, void 0], ['curly', 50, 'extra data']], 'Uses length of largest array');
|
||||
});
|
||||
|
||||
test('object', function() {
|
||||
var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]);
|
||||
var shouldBe = {moe: 30, larry: 40, curly: 50};
|
||||
@@ -229,7 +294,14 @@
|
||||
equal(_.indexOf(numbers, 2), 1, 'can compute indexOf');
|
||||
var result = (function(){ return _.indexOf(arguments, 2); }(1, 2, 3));
|
||||
equal(result, 1, 'works on an arguments object');
|
||||
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
|
||||
|
||||
_.each([null, void 0, [], false], function(val) {
|
||||
var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val);
|
||||
equal(_.indexOf(val, 2), -1, msg);
|
||||
equal(_.indexOf(val, 2, -1), -1, msg);
|
||||
equal(_.indexOf(val, 2, -20), -1, msg);
|
||||
equal(_.indexOf(val, 2, 15), -1, msg);
|
||||
});
|
||||
|
||||
var num = 35;
|
||||
numbers = [10, 20, 30, 40, 50];
|
||||
@@ -263,6 +335,25 @@
|
||||
strictEqual(_.indexOf(array, 1, fromIndex), 0);
|
||||
});
|
||||
strictEqual(_.indexOf([1, 2, 3], 1, true), 0);
|
||||
|
||||
index = _.indexOf([], undefined, true);
|
||||
equal(index, -1, 'empty array with truthy `isSorted` returns -1');
|
||||
});
|
||||
|
||||
test('indexOf with NaN', function() {
|
||||
strictEqual(_.indexOf([1, 2, NaN, NaN], NaN), 2, 'Expected [1, 2, NaN] to contain NaN');
|
||||
strictEqual(_.indexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN');
|
||||
|
||||
(function() {
|
||||
strictEqual(_.indexOf(arguments, NaN), 2, 'Expected arguments [1, 2, NaN] to contain NaN');
|
||||
}(1, 2, NaN, NaN));
|
||||
});
|
||||
|
||||
test('indexOf with +- 0', function() {
|
||||
_.each([-0, +0], function(val) {
|
||||
strictEqual(_.indexOf([1, 2, val, val], val), 2);
|
||||
strictEqual(_.indexOf([1, 2, val, val], -val), 2);
|
||||
});
|
||||
});
|
||||
|
||||
test('lastIndexOf', function() {
|
||||
@@ -276,7 +367,14 @@
|
||||
equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
|
||||
var result = (function(){ return _.lastIndexOf(arguments, 1); }(1, 0, 1, 0, 0, 1, 0, 0, 0));
|
||||
equal(result, 5, 'works on an arguments object');
|
||||
equal(_.lastIndexOf(null, 2), -1, 'handles nulls properly');
|
||||
|
||||
_.each([null, void 0, [], false], function(val) {
|
||||
var msg = 'Handles: ' + (_.isArray(val) ? '[]' : val);
|
||||
equal(_.lastIndexOf(val, 2), -1, msg);
|
||||
equal(_.lastIndexOf(val, 2, -1), -1, msg);
|
||||
equal(_.lastIndexOf(val, 2, -20), -1, msg);
|
||||
equal(_.lastIndexOf(val, 2, 15), -1, msg);
|
||||
});
|
||||
|
||||
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
|
||||
var index = _.lastIndexOf(numbers, 2, 2);
|
||||
@@ -316,6 +414,109 @@
|
||||
}), [0, -1, -1]);
|
||||
});
|
||||
|
||||
test('lastIndexOf with NaN', function() {
|
||||
strictEqual(_.lastIndexOf([1, 2, NaN, NaN], NaN), 3, 'Expected [1, 2, NaN] to contain NaN');
|
||||
strictEqual(_.lastIndexOf([1, 2, Infinity], NaN), -1, 'Expected [1, 2, NaN] to contain NaN');
|
||||
|
||||
(function() {
|
||||
strictEqual(_.lastIndexOf(arguments, NaN), 3, 'Expected arguments [1, 2, NaN] to contain NaN');
|
||||
}(1, 2, NaN, NaN));
|
||||
});
|
||||
|
||||
test('lastIndexOf with +- 0', function() {
|
||||
_.each([-0, +0], function(val) {
|
||||
strictEqual(_.lastIndexOf([1, 2, val, val], val), 3);
|
||||
strictEqual(_.lastIndexOf([1, 2, val, val], -val), 3);
|
||||
strictEqual(_.lastIndexOf([-1, 1, 2], -val), -1);
|
||||
});
|
||||
});
|
||||
|
||||
test('findIndex', function() {
|
||||
var objects = [
|
||||
{'a': 0, 'b': 0},
|
||||
{'a': 1, 'b': 1},
|
||||
{'a': 2, 'b': 2},
|
||||
{'a': 0, 'b': 0}
|
||||
];
|
||||
|
||||
equal(_.findIndex(objects, function(obj) {
|
||||
return obj.a === 0;
|
||||
}), 0);
|
||||
|
||||
equal(_.findIndex(objects, function(obj) {
|
||||
return obj.b * obj.a === 4;
|
||||
}), 2);
|
||||
|
||||
equal(_.findIndex(objects, 'a'), 1, 'Uses lookupIterator');
|
||||
|
||||
equal(_.findIndex(objects, function(obj) {
|
||||
return obj.b * obj.a === 5;
|
||||
}), -1);
|
||||
|
||||
equal(_.findIndex(null, _.noop), -1);
|
||||
strictEqual(_.findIndex(objects, function(a) {
|
||||
return a.foo === null;
|
||||
}), -1);
|
||||
_.findIndex([{a: 1}], function(a, key, obj) {
|
||||
equal(key, 0);
|
||||
deepEqual(obj, [{a: 1}]);
|
||||
strictEqual(this, objects, 'called with context');
|
||||
}, objects);
|
||||
|
||||
var sparse = [];
|
||||
sparse[20] = {'a': 2, 'b': 2};
|
||||
equal(_.findIndex(sparse, function(obj) {
|
||||
return obj && obj.b * obj.a === 4;
|
||||
}), 20, 'Works with sparse arrays');
|
||||
|
||||
var array = [1, 2, 3, 4];
|
||||
array.match = 55;
|
||||
strictEqual(_.findIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys');
|
||||
});
|
||||
|
||||
test('findLastIndex', function() {
|
||||
var objects = [
|
||||
{'a': 0, 'b': 0},
|
||||
{'a': 1, 'b': 1},
|
||||
{'a': 2, 'b': 2},
|
||||
{'a': 0, 'b': 0}
|
||||
];
|
||||
|
||||
equal(_.findLastIndex(objects, function(obj) {
|
||||
return obj.a === 0;
|
||||
}), 3);
|
||||
|
||||
equal(_.findLastIndex(objects, function(obj) {
|
||||
return obj.b * obj.a === 4;
|
||||
}), 2);
|
||||
|
||||
equal(_.findLastIndex(objects, 'a'), 2, 'Uses lookupIterator');
|
||||
|
||||
equal(_.findLastIndex(objects, function(obj) {
|
||||
return obj.b * obj.a === 5;
|
||||
}), -1);
|
||||
|
||||
equal(_.findLastIndex(null, _.noop), -1);
|
||||
strictEqual(_.findLastIndex(objects, function(a) {
|
||||
return a.foo === null;
|
||||
}), -1);
|
||||
_.findLastIndex([{a: 1}], function(a, key, obj) {
|
||||
equal(key, 0);
|
||||
deepEqual(obj, [{a: 1}]);
|
||||
strictEqual(this, objects, 'called with context');
|
||||
}, objects);
|
||||
|
||||
var sparse = [];
|
||||
sparse[20] = {'a': 2, 'b': 2};
|
||||
equal(_.findLastIndex(sparse, function(obj) {
|
||||
return obj && obj.b * obj.a === 4;
|
||||
}), 20, 'Works with sparse arrays');
|
||||
|
||||
var array = [1, 2, 3, 4];
|
||||
array.match = 55;
|
||||
strictEqual(_.findLastIndex(array, function(x) { return x === 55; }), -1, 'doesn\'t match array-likes keys');
|
||||
});
|
||||
|
||||
test('range', function() {
|
||||
deepEqual(_.range(0), [], 'range with 0 as a first argument generates an empty array');
|
||||
deepEqual(_.range(4), [0, 1, 2, 3], 'range with a single positive argument generates an array of elements 0,1,2,...,n-1');
|
||||
|
||||
34
vendor/underscore/test/chaining.js
vendored
34
vendor/underscore/test/chaining.js
vendored
@@ -1,6 +1,7 @@
|
||||
(function() {
|
||||
var _ = typeof require == 'function' ? require('..') : window._;
|
||||
|
||||
module('Chaining');
|
||||
QUnit.module('Chaining');
|
||||
|
||||
test('map/flatten/reduce', function() {
|
||||
var lyrics = [
|
||||
@@ -57,10 +58,41 @@
|
||||
deepEqual(numbers, [34, 10, 8, 6, 4, 2, 10, 10], 'can chain together array functions.');
|
||||
});
|
||||
|
||||
test('splice', function() {
|
||||
var instance = _([1, 2, 3, 4, 5]).chain();
|
||||
deepEqual(instance.splice(1, 3).value(), [1, 5]);
|
||||
deepEqual(instance.splice(1, 0).value(), [1, 5]);
|
||||
deepEqual(instance.splice(1, 1).value(), [1]);
|
||||
deepEqual(instance.splice(0, 1).value(), [], '#397 Can create empty array');
|
||||
});
|
||||
|
||||
test('shift', function() {
|
||||
var instance = _([1, 2, 3]).chain();
|
||||
deepEqual(instance.shift().value(), [2, 3]);
|
||||
deepEqual(instance.shift().value(), [3]);
|
||||
deepEqual(instance.shift().value(), [], '#397 Can create empty array');
|
||||
});
|
||||
|
||||
test('pop', function() {
|
||||
var instance = _([1, 2, 3]).chain();
|
||||
deepEqual(instance.pop().value(), [1, 2]);
|
||||
deepEqual(instance.pop().value(), [1]);
|
||||
deepEqual(instance.pop().value(), [], '#397 Can create empty array');
|
||||
});
|
||||
|
||||
test('chaining works in small stages', function() {
|
||||
var o = _([1, 2, 3, 4]).chain();
|
||||
deepEqual(o.filter(function(i) { return i < 3; }).value(), [1, 2]);
|
||||
deepEqual(o.filter(function(i) { return i > 2; }).value(), [3, 4]);
|
||||
});
|
||||
|
||||
test('#1562: Engine proxies for chained functions', function() {
|
||||
var wrapped = _(512);
|
||||
strictEqual(wrapped.toJSON(), 512);
|
||||
strictEqual(wrapped.valueOf(), 512);
|
||||
strictEqual(+wrapped, 512);
|
||||
strictEqual(wrapped.toString(), '512');
|
||||
strictEqual('' + wrapped, '512');
|
||||
});
|
||||
|
||||
}());
|
||||
|
||||
245
vendor/underscore/test/collections.js
vendored
245
vendor/underscore/test/collections.js
vendored
@@ -1,6 +1,7 @@
|
||||
(function() {
|
||||
var _ = typeof require == 'function' ? require('..') : window._;
|
||||
|
||||
module('Collections');
|
||||
QUnit.module('Collections');
|
||||
|
||||
test('each', function() {
|
||||
_.each([1, 2, 3], function(num, i) {
|
||||
@@ -35,12 +36,6 @@
|
||||
var a = [1, 2, 3];
|
||||
strictEqual(_.each(a, function(){}), a);
|
||||
strictEqual(_.each(null, function(){}), null);
|
||||
|
||||
var b = [1, 2, 3];
|
||||
b.length = 100;
|
||||
answers = 0;
|
||||
_.each(b, function(){ ++answers; });
|
||||
equal(answers, 100, 'enumerates [0, length)');
|
||||
});
|
||||
|
||||
test('forEach', function() {
|
||||
@@ -55,6 +50,94 @@
|
||||
});
|
||||
});
|
||||
|
||||
test('Iterating objects with sketchy length properties', function() {
|
||||
var functions = [
|
||||
'each', 'map', 'filter', 'find',
|
||||
'some', 'every', 'max', 'min',
|
||||
'groupBy', 'countBy', 'partition', 'indexBy'
|
||||
];
|
||||
var reducers = ['reduce', 'reduceRight'];
|
||||
|
||||
var tricks = [
|
||||
{length: '5'},
|
||||
{
|
||||
length: {
|
||||
valueOf: _.constant(5)
|
||||
}
|
||||
},
|
||||
{length: Math.pow(2, 53) + 1},
|
||||
{length: Math.pow(2, 53)},
|
||||
{length: null},
|
||||
{length: -2},
|
||||
{length: new Number(15)}
|
||||
];
|
||||
|
||||
expect(tricks.length * (functions.length + reducers.length + 4));
|
||||
|
||||
_.each(tricks, function(trick) {
|
||||
var length = trick.length;
|
||||
strictEqual(_.size(trick), 1, 'size on obj with length: ' + length);
|
||||
deepEqual(_.toArray(trick), [length], 'toArray on obj with length: ' + length);
|
||||
deepEqual(_.shuffle(trick), [length], 'shuffle on obj with length: ' + length);
|
||||
deepEqual(_.sample(trick), length, 'sample on obj with length: ' + length);
|
||||
|
||||
|
||||
_.each(functions, function(method) {
|
||||
_[method](trick, function(val, key) {
|
||||
strictEqual(key, 'length', method + ': ran with length = ' + val);
|
||||
});
|
||||
});
|
||||
|
||||
_.each(reducers, function(method) {
|
||||
strictEqual(_[method](trick), trick.length, method);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('Resistant to collection length and properties changing while iterating', function() {
|
||||
|
||||
var collection = [
|
||||
'each', 'map', 'filter', 'find',
|
||||
'some', 'every', 'max', 'min', 'reject',
|
||||
'groupBy', 'countBy', 'partition', 'indexBy',
|
||||
'reduce', 'reduceRight'
|
||||
];
|
||||
var array = [
|
||||
'findIndex', 'findLastIndex'
|
||||
];
|
||||
var object = [
|
||||
'mapObject', 'findKey', 'pick', 'omit'
|
||||
];
|
||||
|
||||
_.each(collection.concat(array), function(method) {
|
||||
var sparseArray = [1, 2, 3];
|
||||
sparseArray.length = 100;
|
||||
var answers = 0;
|
||||
_[method](sparseArray, function(){
|
||||
++answers;
|
||||
return method === 'every' ? true : null;
|
||||
}, {});
|
||||
equal(answers, 100, method + ' enumerates [0, length)');
|
||||
|
||||
var growingCollection = [1, 2, 3], count = 0;
|
||||
_[method](growingCollection, function() {
|
||||
if (count < 10) growingCollection.push(count++);
|
||||
return method === 'every' ? true : null;
|
||||
}, {});
|
||||
equal(count, 3, method + ' is resistant to length changes');
|
||||
});
|
||||
|
||||
_.each(collection.concat(object), function(method) {
|
||||
var changingObject = {0: 0, 1: 1}, count = 0;
|
||||
_[method](changingObject, function(val) {
|
||||
if (count < 10) changingObject[++count] = val + 1;
|
||||
return method === 'every' ? true : null;
|
||||
}, {});
|
||||
|
||||
equal(count, 2, method + ' is resistant to property changes');
|
||||
});
|
||||
});
|
||||
|
||||
test('map', function() {
|
||||
var doubled = _.map([1, 2, 3], function(num){ return num * 2; });
|
||||
deepEqual(doubled, [2, 4, 6], 'doubled numbers');
|
||||
@@ -65,12 +148,7 @@
|
||||
doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
|
||||
deepEqual(doubled, [2, 4, 6], 'OO-style doubled numbers');
|
||||
|
||||
if (document.querySelectorAll) {
|
||||
var ids = _.map(document.querySelectorAll('#map-test *'), function(n){ return n.id; });
|
||||
deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on NodeLists.');
|
||||
}
|
||||
|
||||
ids = _.map({length: 2, 0: {id: '1'}, 1: {id: '2'}}, function(n){
|
||||
var ids = _.map({length: 2, 0: {id: '1'}, 1: {id: '2'}}, function(n){
|
||||
return n.id;
|
||||
});
|
||||
deepEqual(ids, ['1', '2'], 'Can use collection methods on Array-likes.');
|
||||
@@ -113,9 +191,7 @@
|
||||
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), _, 'collection of length one with no initial value returns the first item');
|
||||
|
||||
raises(function() { _.reduce([], _.noop); }, TypeError, 'throws an error for empty arrays with no initial value');
|
||||
raises(function() {_.reduce(null, _.noop);}, TypeError, 'handles a null (without initial value) properly');
|
||||
equal(_.reduce([], _.noop), undefined, 'returns undefined when collection is empty and no initial value');
|
||||
});
|
||||
|
||||
test('foldl', function() {
|
||||
@@ -136,9 +212,7 @@
|
||||
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');
|
||||
|
||||
raises(function() { _.reduceRight([], _.noop); }, TypeError, 'throws an error for empty arrays with no initial value');
|
||||
raises(function() {_.reduceRight(null, _.noop);}, TypeError, 'handles a null (without initial value) properly');
|
||||
equal(_.reduceRight([], _.noop), undefined, 'returns undefined when collection is empty and no initial value');
|
||||
|
||||
// Assert that the correct arguments are being passed.
|
||||
|
||||
@@ -183,6 +257,9 @@
|
||||
strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found `value`');
|
||||
strictEqual(_.find(array, function() { return false; }), void 0, 'should return `undefined` if `value` is not found');
|
||||
|
||||
array.dontmatch = 55;
|
||||
strictEqual(_.find(array, function(x) { return x === 55; }), void 0, 'iterates array-likes correctly');
|
||||
|
||||
// Matching an object like _.findWhere.
|
||||
var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}, {a: 2, b: 4}];
|
||||
deepEqual(_.find(list, {a: 1}), {a: 1, b: 2}, 'can be used as findWhere');
|
||||
@@ -192,6 +269,25 @@
|
||||
|
||||
var result = _.find([1, 2, 3], function(num){ return num * 2 === 4; });
|
||||
equal(result, 2, 'found the first "2" and broke the loop');
|
||||
|
||||
var obj = {
|
||||
a: {x: 1, z: 3},
|
||||
b: {x: 2, z: 2},
|
||||
c: {x: 3, z: 4},
|
||||
d: {x: 4, z: 1}
|
||||
};
|
||||
|
||||
deepEqual(_.find(obj, {x: 2}), {x: 2, z: 2}, 'works on objects');
|
||||
deepEqual(_.find(obj, {x: 2, z: 1}), void 0);
|
||||
deepEqual(_.find(obj, function(x) {
|
||||
return x.x === 4;
|
||||
}), {x: 4, z: 1});
|
||||
|
||||
_.findIndex([{a: 1}], function(a, key, obj) {
|
||||
equal(key, 0);
|
||||
deepEqual(obj, [{a: 1}]);
|
||||
strictEqual(this, _, 'called with context');
|
||||
}, _);
|
||||
});
|
||||
|
||||
test('detect', function() {
|
||||
@@ -303,22 +399,66 @@
|
||||
strictEqual(_.any, _.some, 'alias for any');
|
||||
});
|
||||
|
||||
test('contains', function() {
|
||||
ok(_.contains([1, 2, 3], 2), 'two is in the array');
|
||||
ok(!_.contains([1, 3, 9], 2), 'two is not in the array');
|
||||
ok(_.contains({moe: 1, larry: 3, curly: 9}, 3) === true, '_.contains on objects checks their values');
|
||||
ok(_([1, 2, 3]).contains(2), 'OO-style contains');
|
||||
test('includes', function() {
|
||||
_.each([null, void 0, 0, 1, NaN, {}, []], function(val) {
|
||||
strictEqual(_.includes(val, 'hasOwnProperty'), false);
|
||||
});
|
||||
strictEqual(_.includes([1, 2, 3], 2), true, 'two is in the array');
|
||||
ok(!_.includes([1, 3, 9], 2), 'two is not in the array');
|
||||
|
||||
strictEqual(_.includes([5, 4, 3, 2, 1], 5, true), true, 'doesn\'t delegate to binary search');
|
||||
|
||||
ok(_.includes({moe: 1, larry: 3, curly: 9}, 3) === true, '_.includes on objects checks their values');
|
||||
ok(_([1, 2, 3]).includes(2), 'OO-style includes');
|
||||
});
|
||||
|
||||
test('include', function() {
|
||||
strictEqual(_.contains, _.include, 'alias for contains');
|
||||
strictEqual(_.includes, _.include, 'alias for includes');
|
||||
});
|
||||
|
||||
test('invoke', function() {
|
||||
test('contains', function() {
|
||||
strictEqual(_.includes, _.contains, 'alias for includes');
|
||||
|
||||
var numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
|
||||
strictEqual(_.includes(numbers, 1, 1), true);
|
||||
strictEqual(_.includes(numbers, 1, -1), false);
|
||||
strictEqual(_.includes(numbers, 1, -2), false);
|
||||
strictEqual(_.includes(numbers, 1, -3), true);
|
||||
strictEqual(_.includes(numbers, 1, 6), true);
|
||||
strictEqual(_.includes(numbers, 1, 7), false);
|
||||
});
|
||||
|
||||
test('includes with NaN', function() {
|
||||
strictEqual(_.includes([1, 2, NaN, NaN], NaN), true, 'Expected [1, 2, NaN] to contain NaN');
|
||||
strictEqual(_.includes([1, 2, Infinity], NaN), false, 'Expected [1, 2, NaN] to contain NaN');
|
||||
});
|
||||
|
||||
test('includes with +- 0', function() {
|
||||
_.each([-0, +0], function(val) {
|
||||
strictEqual(_.includes([1, 2, val, val], val), true);
|
||||
strictEqual(_.includes([1, 2, val, val], -val), true);
|
||||
strictEqual(_.includes([-1, 1, 2], -val), false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('invoke', 5, function() {
|
||||
var list = [[5, 1, 7], [3, 2, 1]];
|
||||
var result = _.invoke(list, 'sort');
|
||||
deepEqual(result[0], [1, 5, 7], 'first array sorted');
|
||||
deepEqual(result[1], [1, 2, 3], 'second array sorted');
|
||||
|
||||
_.invoke([{
|
||||
method: function() {
|
||||
deepEqual(_.toArray(arguments), [1, 2, 3], 'called with arguments');
|
||||
}
|
||||
}], 'method', 1, 2, 3);
|
||||
|
||||
deepEqual(_.invoke([{a: null}, {}, {a: _.constant(1)}], 'a'), [null, void 0, 1], 'handles null & undefined');
|
||||
|
||||
throws(function() {
|
||||
_.invoke([{a: 1}], 'a');
|
||||
}, TypeError, 'throws for non-functions');
|
||||
});
|
||||
|
||||
test('invoke w/ function reference', function() {
|
||||
@@ -326,6 +466,10 @@
|
||||
var result = _.invoke(list, Array.prototype.sort);
|
||||
deepEqual(result[0], [1, 5, 7], 'first array sorted');
|
||||
deepEqual(result[1], [1, 2, 3], 'second array sorted');
|
||||
|
||||
deepEqual(_.invoke([1, 2, 3], function(a) {
|
||||
return a + this;
|
||||
}, 5), [6, 7, 8], 'receives params from invoke');
|
||||
});
|
||||
|
||||
// Relevant when using ClojureScript
|
||||
@@ -346,6 +490,7 @@
|
||||
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');
|
||||
//compat: most flexible handling of edge cases
|
||||
deepEqual(_.pluck([{'[object Object]': 1}], {}), [1]);
|
||||
});
|
||||
@@ -582,24 +727,6 @@
|
||||
equal(grouped['3'], 1);
|
||||
});
|
||||
|
||||
test('sortedIndex', function() {
|
||||
var numbers = [10, 20, 30, 40, 50], num = 35;
|
||||
var indexForNum = _.sortedIndex(numbers, num);
|
||||
equal(indexForNum, 3, '35 should be inserted at index 3');
|
||||
|
||||
var indexFor30 = _.sortedIndex(numbers, 30);
|
||||
equal(indexFor30, 2, '30 should be inserted at index 2');
|
||||
|
||||
var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}];
|
||||
var iterator = function(obj){ return obj.x; };
|
||||
strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2);
|
||||
strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3);
|
||||
|
||||
var context = {1: 2, 2: 3, 3: 4};
|
||||
iterator = function(obj){ return this[obj]; };
|
||||
strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1);
|
||||
});
|
||||
|
||||
test('shuffle', function() {
|
||||
var numbers = _.range(10);
|
||||
var shuffled = _.shuffle(numbers);
|
||||
@@ -637,12 +764,14 @@
|
||||
var numbers = _.toArray({one : 1, two : 2, three : 3});
|
||||
deepEqual(numbers, [1, 2, 3], 'object flattened into array');
|
||||
|
||||
if (typeof document != 'undefined') {
|
||||
// test in IE < 9
|
||||
var actual;
|
||||
try {
|
||||
var actual = _.toArray(document.childNodes);
|
||||
actual = _.toArray(document.childNodes);
|
||||
} catch(ex) { }
|
||||
|
||||
ok(_.isArray(actual), 'should not throw converting a node list');
|
||||
deepEqual(actual, _.map(document.childNodes, _.identity), 'works on NodeList');
|
||||
}
|
||||
});
|
||||
|
||||
test('size', function() {
|
||||
@@ -693,4 +822,26 @@
|
||||
}, predicate);
|
||||
});
|
||||
|
||||
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 elementChildren = _.filter(parent.childNodes, _.isElement);
|
||||
equal(elementChildren.length, 2);
|
||||
|
||||
deepEqual(_.map(elementChildren, 'id'), ['id1', 'id2']);
|
||||
deepEqual(_.map(parent.childNodes, 'nodeType'), [1, 3, 1]);
|
||||
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
}());
|
||||
|
||||
40
vendor/underscore/test/functions.js
vendored
40
vendor/underscore/test/functions.js
vendored
@@ -1,6 +1,8 @@
|
||||
(function() {
|
||||
var _ = typeof require == 'function' ? require('..') : window._;
|
||||
|
||||
module('Functions');
|
||||
QUnit.module('Functions');
|
||||
QUnit.config.asyncRetries = 3;
|
||||
|
||||
test('bind', function() {
|
||||
var context = {name : 'moe'};
|
||||
@@ -12,7 +14,9 @@
|
||||
equal(bound(), 'name: moe', 'can do OO-style binding');
|
||||
|
||||
bound = _.bind(func, null, 'curly');
|
||||
equal(bound(), 'name: curly', 'can bind without specifying a context');
|
||||
var result = bound();
|
||||
// Work around a PhantomJS bug when applying a function with null|undefined.
|
||||
ok(result === 'name: curly' || result === 'name: ' + window.name, 'can bind without specifying a context');
|
||||
|
||||
func = function(salutation, name) { return salutation + ': ' + name; };
|
||||
func = _.bind(func, this, 'hello');
|
||||
@@ -40,7 +44,7 @@
|
||||
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');
|
||||
|
||||
raises(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function');
|
||||
throws(function() { _.bind('notafunction'); }, TypeError, 'throws an error when binding to a non-function');
|
||||
});
|
||||
|
||||
test('partial', function() {
|
||||
@@ -59,6 +63,20 @@
|
||||
|
||||
func = _.partial(function() { return typeof arguments[2]; }, _, 'b', _, 'd');
|
||||
equal(func('a'), 'undefined', 'unfilled placeholders are undefined');
|
||||
|
||||
// passes context
|
||||
function MyWidget(name, options) {
|
||||
this.name = name;
|
||||
this.options = options;
|
||||
}
|
||||
MyWidget.prototype.get = function() {
|
||||
return this.name;
|
||||
};
|
||||
var MyWidgetWithCoolOpts = _.partial(MyWidget, _, {a: 1});
|
||||
var widget = new MyWidgetWithCoolOpts('foo');
|
||||
ok(widget instanceof MyWidget, 'Can partially bind a constructor');
|
||||
equal(widget.get(), 'foo', 'keeps prototype');
|
||||
deepEqual(widget.options, {a: 1});
|
||||
});
|
||||
|
||||
test('bindAll', function() {
|
||||
@@ -81,9 +99,9 @@
|
||||
sayLast : function() { return this.sayHi(_.last(arguments)); }
|
||||
};
|
||||
|
||||
raises(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named');
|
||||
raises(function() { _.bindAll(moe, 'sayBye'); }, TypeError, 'throws an error for bindAll if the given key is undefined');
|
||||
raises(function() { _.bindAll(moe, 'name'); }, TypeError, 'throws an error for bindAll if the given key is not a function');
|
||||
throws(function() { _.bindAll(moe); }, Error, 'throws an error for bindAll with no functions named');
|
||||
throws(function() { _.bindAll(moe, 'sayBye'); }, TypeError, 'throws an error for bindAll if the given key is undefined');
|
||||
throws(function() { _.bindAll(moe, 'name'); }, TypeError, 'throws an error for bindAll if the given key is not a function');
|
||||
|
||||
_.bindAll(moe, 'sayHi', 'sayLast');
|
||||
curly.sayHi = moe.sayHi;
|
||||
@@ -548,6 +566,16 @@
|
||||
test('iteratee', function() {
|
||||
var identity = _.iteratee();
|
||||
equal(identity, _.identity, '_.iteratee is exposed as an external function.');
|
||||
|
||||
function fn() {
|
||||
return arguments;
|
||||
}
|
||||
_.each([_.iteratee(fn), _.iteratee(fn, {})], function(cb) {
|
||||
equal(cb().length, 0);
|
||||
deepEqual(_.toArray(cb(1, 2, 3)), _.range(1, 4));
|
||||
deepEqual(_.toArray(cb(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), _.range(1, 11));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}());
|
||||
|
||||
428
vendor/underscore/test/objects.js
vendored
428
vendor/underscore/test/objects.js
vendored
@@ -1,7 +1,9 @@
|
||||
(function() {
|
||||
var _ = typeof require == 'function' ? require('..') : window._;
|
||||
|
||||
module('Objects');
|
||||
/* global iObject, iElement, iArguments, iFunction, iArray, iString, iNumber, iBoolean, iDate, iRegExp, iNaN, iNull, iUndefined, ActiveXObject */
|
||||
QUnit.module('Objects');
|
||||
|
||||
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');
|
||||
@@ -13,6 +15,62 @@
|
||||
deepEqual(_.keys(1), []);
|
||||
deepEqual(_.keys('a'), []);
|
||||
deepEqual(_.keys(true), []);
|
||||
|
||||
// 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__': []
|
||||
};
|
||||
var troubleKeys = ['constructor', 'valueOf', 'hasOwnProperty', 'toString', 'toLocaleString', 'propertyIsEnumerable',
|
||||
'isPrototypeOf', '__defineGetter__', '__defineSetter__', '__lookupSetter__', '__lookupGetter__'].sort();
|
||||
deepEqual(_.keys(trouble).sort(), troubleKeys, 'matches non-enumerable properties');
|
||||
});
|
||||
|
||||
test('allKeys', function() {
|
||||
deepEqual(_.allKeys({one : 1, two : 2}), ['one', 'two'], 'can extract the allKeys from an object');
|
||||
// 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');
|
||||
|
||||
a.a = a;
|
||||
deepEqual(_.allKeys(a), ['1', 'a'], 'is not fooled by sparse arrays with additional properties');
|
||||
|
||||
_.each([null, void 0, 1, 'a', true, NaN, {}, [], new Number(5), new Date(0)], function(val) {
|
||||
deepEqual(_.allKeys(val), []);
|
||||
});
|
||||
|
||||
// allKeys 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
|
||||
};
|
||||
var troubleKeys = ['constructor', 'valueOf', 'hasOwnProperty', 'toString', 'toLocaleString', 'propertyIsEnumerable',
|
||||
'isPrototypeOf'].sort();
|
||||
deepEqual(_.allKeys(trouble).sort(), troubleKeys, 'matches non-enumerable properties');
|
||||
|
||||
function A() {}
|
||||
A.prototype.foo = 'foo';
|
||||
var b = new A();
|
||||
b.bar = 'bar';
|
||||
deepEqual(_.allKeys(b).sort(), ['bar', 'foo'], 'should include inherited keys');
|
||||
|
||||
function y() {}
|
||||
y.x = 'z';
|
||||
deepEqual(_.allKeys(y), ['x'], 'should get keys from constructor');
|
||||
});
|
||||
|
||||
test('values', function() {
|
||||
@@ -63,7 +121,9 @@
|
||||
F.prototype = {a: 'b'};
|
||||
var subObj = new F();
|
||||
subObj.c = 'd';
|
||||
deepEqual(_.extend({}, subObj), {c: 'd'}, 'extend ignores any properties but own from source');
|
||||
deepEqual(_.extend({}, subObj), {a: 'b', c: 'd'}, 'extend copies all properties from source');
|
||||
_.extend(subObj, {});
|
||||
ok(!subObj.hasOwnProperty('a'), "extend does not convert destination object's 'in' properties to 'own' properties");
|
||||
|
||||
try {
|
||||
result = {};
|
||||
@@ -76,6 +136,36 @@
|
||||
strictEqual(_.extend(undefined, {a: 1}), undefined, 'extending undefined results in undefined');
|
||||
});
|
||||
|
||||
test('extendOwn', function() {
|
||||
var result;
|
||||
equal(_.extendOwn({}, {a: 'b'}).a, 'b', 'can assign an object with the attributes of another');
|
||||
equal(_.extendOwn({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination');
|
||||
equal(_.extendOwn({x: 'x'}, {a: 'b'}).x, 'x', "properties not in source don't get overriden");
|
||||
result = _.extendOwn({x: 'x'}, {a: 'a'}, {b: 'b'});
|
||||
deepEqual(result, {x: 'x', a: 'a', b: 'b'}, 'can assign from multiple source objects');
|
||||
result = _.assign({x: 'x'}, {a: 'a', x: 2}, {a: 'b'});
|
||||
deepEqual(result, {x: 2, a: 'b'}, 'assigning from multiple source objects last property trumps');
|
||||
deepEqual(_.extendOwn({}, {a: void 0, b: null}), {a: void 0, b: null}, 'assign copies undefined values');
|
||||
|
||||
var F = function() {};
|
||||
F.prototype = {a: 'b'};
|
||||
var subObj = new F();
|
||||
subObj.c = 'd';
|
||||
deepEqual(_.extendOwn({}, subObj), {c: 'd'}, 'assign copies own properties from source');
|
||||
|
||||
result = {};
|
||||
deepEqual(_.assign(result, null, undefined, {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');
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
test('pick', function() {
|
||||
var result;
|
||||
result = _.pick({a: 1, b: 2, c: 3}, 'a', 'c');
|
||||
@@ -87,8 +177,10 @@
|
||||
result = _.pick(['a', 'b'], 1);
|
||||
deepEqual(result, {1: 'b'}, 'can pick numeric properties');
|
||||
|
||||
deepEqual(_.pick(null, 'a', 'b'), {}, 'non objects return empty object');
|
||||
deepEqual(_.pick(undefined, 'toString'), {}, 'null/undefined return empty object');
|
||||
_.each([null, void 0], function(val) {
|
||||
deepEqual(_.pick(val, 'hasOwnProperty'), {}, 'Called with null/undefined');
|
||||
deepEqual(_.pick(val, _.constant(true)), {});
|
||||
});
|
||||
deepEqual(_.pick(5, 'toString', 'b'), {toString: Number.prototype.toString}, 'can iterate primitives');
|
||||
|
||||
var data = {a: 1, b: 2, c: 3};
|
||||
@@ -108,6 +200,11 @@
|
||||
deepEqual(_.pick(data, function(val, key) {
|
||||
return this[key] === 3 && this === instance;
|
||||
}, instance), {c: 3}, 'function is given context');
|
||||
|
||||
ok(!_.has(_.pick({}, 'foo'), 'foo'), 'does not set own property if property not in object');
|
||||
_.pick(data, function(value, key, obj) {
|
||||
equal(obj, data, 'passes same object as third parameter of iteratee');
|
||||
});
|
||||
});
|
||||
|
||||
test('omit', function() {
|
||||
@@ -419,9 +516,6 @@
|
||||
b = _({x: 1, y: 2}).chain();
|
||||
equal(_.isEqual(a.isEqual(b), _(true)), true, '`isEqual` can be chained');
|
||||
|
||||
// Objects from another frame.
|
||||
ok(_.isEqual({}, iObject));
|
||||
|
||||
// Objects without a `constructor` property
|
||||
if (Object.create) {
|
||||
a = Object.create(null, {x: {value: 1, enumerable: true}});
|
||||
@@ -454,37 +548,18 @@
|
||||
var args = function(){ return arguments; };
|
||||
ok(_.isEmpty(args()), 'empty arguments object is empty');
|
||||
ok(!_.isEmpty(args('')), 'non-empty arguments object is not empty');
|
||||
|
||||
// covers collecting non-enumerable properties in IE < 9
|
||||
var nonEnumProp = {'toString': 5};
|
||||
ok(!_.isEmpty(nonEnumProp), 'non-enumerable property is not empty');
|
||||
});
|
||||
|
||||
// Setup remote variables for iFrame tests.
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.frameBorder = iframe.height = iframe.width = 0;
|
||||
document.body.appendChild(iframe);
|
||||
var iDoc = (iDoc = iframe.contentDocument || iframe.contentWindow).document || iDoc;
|
||||
iDoc.write(
|
||||
'<script>' +
|
||||
' parent.iElement = document.createElement("div");' +
|
||||
' parent.iArguments = (function(){ return arguments; })(1, 2, 3);' +
|
||||
' parent.iArray = [1, 2, 3];' +
|
||||
' parent.iString = new String("hello");' +
|
||||
' parent.iNumber = new Number(100);' +
|
||||
' parent.iFunction = (function(){});' +
|
||||
' parent.iDate = new Date();' +
|
||||
' parent.iRegExp = /hi/;' +
|
||||
' parent.iNaN = NaN;' +
|
||||
' parent.iNull = null;' +
|
||||
' parent.iBoolean = new Boolean(false);' +
|
||||
' parent.iUndefined = undefined;' +
|
||||
' parent.iObject = {};' +
|
||||
'</script>'
|
||||
);
|
||||
iDoc.close();
|
||||
|
||||
if (typeof document === 'object') {
|
||||
test('isElement', function() {
|
||||
ok(!_.isElement('div'), 'strings are not dom elements');
|
||||
ok(_.isElement(document.body), 'the body tag is a DOM element');
|
||||
ok(_.isElement(iElement), 'even from another frame');
|
||||
ok(_.isElement(testElement), 'an element is a DOM element');
|
||||
});
|
||||
}
|
||||
|
||||
test('isArguments', function() {
|
||||
var args = (function(){ return arguments; }(1, 2, 3));
|
||||
@@ -493,16 +568,15 @@
|
||||
ok(_.isArguments(args), 'but the arguments object is an arguments object');
|
||||
ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array');
|
||||
ok(!_.isArguments([1, 2, 3]), 'and not vanilla arrays.');
|
||||
ok(_.isArguments(iArguments), 'even from another frame');
|
||||
});
|
||||
|
||||
test('isObject', function() {
|
||||
ok(_.isObject(arguments), 'the arguments object is object');
|
||||
ok(_.isObject([1, 2, 3]), 'and arrays');
|
||||
ok(_.isObject(document.body), 'and DOM element');
|
||||
ok(_.isObject(iElement), 'even from another frame');
|
||||
if (testElement) {
|
||||
ok(_.isObject(testElement), 'and DOM element');
|
||||
}
|
||||
ok(_.isObject(function () {}), 'and functions');
|
||||
ok(_.isObject(iFunction), 'even from another frame');
|
||||
ok(!_.isObject(null), 'but not null');
|
||||
ok(!_.isObject(undefined), 'and not undefined');
|
||||
ok(!_.isObject('string'), 'and not string');
|
||||
@@ -515,16 +589,17 @@
|
||||
ok(!_.isArray(undefined), 'undefined vars are not arrays');
|
||||
ok(!_.isArray(arguments), 'the arguments object is not an array');
|
||||
ok(_.isArray([1, 2, 3]), 'but arrays are');
|
||||
ok(_.isArray(iArray), 'even from another frame');
|
||||
});
|
||||
|
||||
test('isString', function() {
|
||||
var obj = new String('I am a string object');
|
||||
ok(!_.isString(document.body), 'the document body is not a string');
|
||||
if (testElement) {
|
||||
ok(!_.isString(testElement), 'an element is not a string');
|
||||
}
|
||||
ok(_.isString([1, 2, 3].join(', ')), 'but strings are');
|
||||
ok(_.isString(iString), 'even from another frame');
|
||||
ok(_.isString('I am a string literal'), 'string literals are');
|
||||
strictEqual(_.isString('I am a string literal'), true, 'string literals are');
|
||||
ok(_.isString(obj), 'so are String objects');
|
||||
strictEqual(_.isString(1), false);
|
||||
});
|
||||
|
||||
test('isNumber', function() {
|
||||
@@ -534,7 +609,6 @@
|
||||
ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are');
|
||||
ok(_.isNumber(NaN), 'NaN *is* a number');
|
||||
ok(_.isNumber(Infinity), 'Infinity is a number');
|
||||
ok(_.isNumber(iNumber), 'even from another frame');
|
||||
ok(!_.isNumber('1'), 'numeric strings are not numbers');
|
||||
});
|
||||
|
||||
@@ -549,7 +623,6 @@
|
||||
ok(!_.isBoolean(null), 'null is not a boolean');
|
||||
ok(_.isBoolean(true), 'but true is');
|
||||
ok(_.isBoolean(false), 'and so is false');
|
||||
ok(_.isBoolean(iBoolean), 'even from another frame');
|
||||
});
|
||||
|
||||
test('isFunction', function() {
|
||||
@@ -557,21 +630,35 @@
|
||||
ok(!_.isFunction([1, 2, 3]), 'arrays are not functions');
|
||||
ok(!_.isFunction('moe'), 'strings are not functions');
|
||||
ok(_.isFunction(_.isFunction), 'but functions are');
|
||||
ok(_.isFunction(iFunction), 'even from another frame');
|
||||
ok(_.isFunction(function(){}), 'even anonymous ones');
|
||||
|
||||
if (testElement) {
|
||||
ok(!_.isFunction(testElement), 'elements are not functions');
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof Int8Array !== 'undefined') {
|
||||
test('#1929 Typed Array constructors are functions', function() {
|
||||
_.chain(['Float32Array', 'Float64Array', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array'])
|
||||
.map(_.propertyOf(typeof GLOBAL != 'undefined' ? GLOBAL : window))
|
||||
.compact()
|
||||
.each(function(TypedArray) {
|
||||
// PhantomJS reports `typeof UInt8Array == 'object'` and doesn't report toString TypeArray
|
||||
// as a function
|
||||
strictEqual(_.isFunction(TypedArray), Object.prototype.toString.call(TypedArray) === '[object Function]');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test('isDate', function() {
|
||||
ok(!_.isDate(100), 'numbers are not dates');
|
||||
ok(!_.isDate({}), 'objects are not dates');
|
||||
ok(_.isDate(new Date()), 'but dates are');
|
||||
ok(_.isDate(iDate), 'even from another frame');
|
||||
});
|
||||
|
||||
test('isRegExp', function() {
|
||||
ok(!_.isRegExp(_.identity), 'functions are not RegExps');
|
||||
ok(_.isRegExp(/identity/), 'but RegExps are');
|
||||
ok(_.isRegExp(iRegExp), 'even from another frame');
|
||||
});
|
||||
|
||||
test('isFinite', function() {
|
||||
@@ -595,7 +682,6 @@
|
||||
ok(!_.isNaN(null), 'null is not NaN');
|
||||
ok(!_.isNaN(0), '0 is not NaN');
|
||||
ok(_.isNaN(NaN), 'but NaN is');
|
||||
ok(_.isNaN(iNaN), 'even from another frame');
|
||||
ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN');
|
||||
});
|
||||
|
||||
@@ -603,7 +689,6 @@
|
||||
ok(!_.isNull(undefined), 'undefined is not null');
|
||||
ok(!_.isNull(NaN), 'NaN is not null');
|
||||
ok(_.isNull(null), 'but null is');
|
||||
ok(_.isNull(iNull), 'even from another frame');
|
||||
});
|
||||
|
||||
test('isUndefined', function() {
|
||||
@@ -613,20 +698,20 @@
|
||||
ok(!_.isUndefined(NaN), 'NaN is defined');
|
||||
ok(_.isUndefined(), 'nothing is undefined');
|
||||
ok(_.isUndefined(undefined), 'undefined is undefined');
|
||||
ok(_.isUndefined(iUndefined), 'even from another frame');
|
||||
});
|
||||
|
||||
if (window.ActiveXObject) {
|
||||
test('IE host objects', function() {
|
||||
var xml = new ActiveXObject('Msxml2.DOMDocument.3.0');
|
||||
ok(!_.isNumber(xml));
|
||||
ok(!_.isBoolean(xml));
|
||||
ok(!_.isNaN(xml));
|
||||
ok(!_.isFunction(xml));
|
||||
ok(!_.isNull(xml));
|
||||
ok(!_.isUndefined(xml));
|
||||
test('isError', function() {
|
||||
ok(!_.isError(1), 'numbers are not Errors');
|
||||
ok(!_.isError(null), 'null is not an Error');
|
||||
ok(!_.isError(Error), 'functions are not Errors');
|
||||
ok(_.isError(new Error()), 'Errors are Errors');
|
||||
ok(_.isError(new EvalError()), 'EvalErrors are Errors');
|
||||
ok(_.isError(new RangeError()), 'RangeErrors are Errors');
|
||||
ok(_.isError(new ReferenceError()), 'ReferenceErrors are Errors');
|
||||
ok(_.isError(new SyntaxError()), 'SyntaxErrors are Errors');
|
||||
ok(_.isError(new TypeError()), 'TypeErrors are Errors');
|
||||
ok(_.isError(new URIError()), 'URIErrors are Errors');
|
||||
});
|
||||
}
|
||||
|
||||
test('tap', function() {
|
||||
var intercepted = null;
|
||||
@@ -658,22 +743,62 @@
|
||||
strictEqual(_.has(undefined, 'foo'), false, 'has() returns false for undefined');
|
||||
});
|
||||
|
||||
test('matches', function() {
|
||||
test('isMatch', function() {
|
||||
var moe = {name: 'Moe Howard', hair: true};
|
||||
var curly = {name: 'Curly Howard', hair: false};
|
||||
|
||||
equal(_.isMatch(moe, {hair: true}), true, 'Returns a boolean');
|
||||
equal(_.isMatch(curly, {hair: true}), false, 'Returns a boolean');
|
||||
|
||||
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(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([true, 5, NaN, null, undefined], function(item) {
|
||||
strictEqual(_.isMatch({a: 1}, item), true, 'treats primitives as empty');
|
||||
});
|
||||
|
||||
function Prototest() {}
|
||||
Prototest.prototype.x = 1;
|
||||
var specObj = new Prototest;
|
||||
equal(_.isMatch({x: 2}, specObj), true, 'spec is restricted to own properties');
|
||||
|
||||
specObj.y = 5;
|
||||
equal(_.isMatch({x: 1, y: 5}, specObj), true);
|
||||
equal(_.isMatch({x: 1, y: 4}, specObj), false);
|
||||
|
||||
ok(_.isMatch(specObj, {x: 1, y: 5}), 'inherited and own properties are checked on the test object');
|
||||
|
||||
Prototest.x = 5;
|
||||
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');
|
||||
});
|
||||
|
||||
test('matcher', function() {
|
||||
var moe = {name: 'Moe Howard', hair: true};
|
||||
var curly = {name: 'Curly Howard', hair: false};
|
||||
var stooges = [moe, curly];
|
||||
|
||||
equal(_.matches({hair: true})(moe), true, 'Returns a boolean');
|
||||
equal(_.matches({hair: true})(curly), false, 'Returns a boolean');
|
||||
equal(_.matcher({hair: true})(moe), true, 'Returns a boolean');
|
||||
equal(_.matcher({hair: true})(curly), false, 'Returns a boolean');
|
||||
|
||||
equal(_.matches({__x__: undefined})(5), false, 'can match undefined props on primitives');
|
||||
equal(_.matches({__x__: undefined})({__x__: undefined}), true, 'can match undefined props');
|
||||
equal(_.matcher({__x__: undefined})(5), false, 'can match undefined props on primitives');
|
||||
equal(_.matcher({__x__: undefined})({__x__: undefined}), true, 'can match undefined props');
|
||||
|
||||
equal(_.matches({})(null), true, 'Empty spec called with null object returns true');
|
||||
equal(_.matches({a: 1})(null), false, 'Non-empty spec called with null object returns false');
|
||||
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, _.matches({hair: false})) === curly, 'returns a predicate that can be used by finding functions.');
|
||||
ok(_.find(stooges, _.matches(moe)) === moe, 'can be used to locate an object exists in a collection.');
|
||||
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');
|
||||
@@ -687,22 +812,22 @@
|
||||
function Prototest() {}
|
||||
Prototest.prototype.x = 1;
|
||||
var specObj = new Prototest;
|
||||
var protospec = _.matches(specObj);
|
||||
var protospec = _.matcher(specObj);
|
||||
equal(protospec({x: 2}), true, 'spec is restricted to own properties');
|
||||
|
||||
specObj.y = 5;
|
||||
protospec = _.matches(specObj);
|
||||
protospec = _.matcher(specObj);
|
||||
equal(protospec({x: 1, y: 5}), true);
|
||||
equal(protospec({x: 1, y: 4}), false);
|
||||
|
||||
ok(_.matches({x: 1, y: 5})(specObj), 'inherited and own properties are checked on the test object');
|
||||
ok(_.matcher({x: 1, y: 5})(specObj), 'inherited and own properties are checked on the test object');
|
||||
|
||||
Prototest.x = 5;
|
||||
ok(_.matches(Prototest)({x: 5, y: 1}), 'spec can be a function');
|
||||
ok(_.matcher(Prototest)({x: 5, y: 1}), 'spec can be a function');
|
||||
|
||||
// #1729
|
||||
var o = {'b': 1};
|
||||
var m = _.matches(o);
|
||||
var m = _.matcher(o);
|
||||
|
||||
equal(m({'b': 1}), true);
|
||||
o.b = 2;
|
||||
@@ -711,8 +836,159 @@
|
||||
|
||||
|
||||
//null edge cases
|
||||
var oCon = _.matches({'constructor': Object});
|
||||
deepEqual(_.map([null, undefined, 5, {}], oCon), [false, false, false, true], 'doesnt fasley match constructor on undefined/null');
|
||||
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');
|
||||
});
|
||||
|
||||
test('findKey', function() {
|
||||
var objects = {
|
||||
a: {'a': 0, 'b': 0},
|
||||
b: {'a': 1, 'b': 1},
|
||||
c: {'a': 2, 'b': 2}
|
||||
};
|
||||
|
||||
equal(_.findKey(objects, function(obj) {
|
||||
return obj.a === 0;
|
||||
}), 'a');
|
||||
|
||||
equal(_.findKey(objects, function(obj) {
|
||||
return obj.b * obj.a === 4;
|
||||
}), 'c');
|
||||
|
||||
equal(_.findKey(objects, 'a'), 'b', 'Uses lookupIterator');
|
||||
|
||||
equal(_.findKey(objects, function(obj) {
|
||||
return obj.b * obj.a === 5;
|
||||
}), undefined);
|
||||
|
||||
strictEqual(_.findKey([1, 2, 3, 4, 5, 6], function(obj) {
|
||||
return obj === 3;
|
||||
}), '2', 'Keys are strings');
|
||||
|
||||
strictEqual(_.findKey(objects, function(a) {
|
||||
return a.foo === null;
|
||||
}), undefined);
|
||||
|
||||
_.findKey({a: {a: 1}}, function(a, key, obj) {
|
||||
equal(key, 'a');
|
||||
deepEqual(obj, {a: {a: 1}});
|
||||
strictEqual(this, objects, 'called with context');
|
||||
}, objects);
|
||||
|
||||
var array = [1, 2, 3, 4];
|
||||
array.match = 55;
|
||||
strictEqual(_.findKey(array, function(x) { return x === 55; }), 'match', 'matches array-likes keys');
|
||||
});
|
||||
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
deepEqual(_.mapObject(obj, function(val) {
|
||||
return val * 2;
|
||||
}), {'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');
|
||||
|
||||
deepEqual(_.mapObject(obj, function(val,key,obj) {
|
||||
return obj[key] * 2;
|
||||
}), {'a': 2, 'b': 4}, 'correct keys');
|
||||
|
||||
deepEqual(_.mapObject([1,2], function(val) {
|
||||
return val * 2;
|
||||
}), {'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');
|
||||
|
||||
deepEqual(_.mapObject({a: 1}, function() {
|
||||
return this.length;
|
||||
}, [1,2]), {'a': 2}, 'called with context');
|
||||
|
||||
var ids = _.mapObject({length: 2, 0: {id: '1'}, 1: {id: '2'}}, function(n){
|
||||
return n.id;
|
||||
});
|
||||
deepEqual(ids, {'length': undefined, '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');
|
||||
|
||||
_.each([null, void 0, 1, 'abc', [], {}, undefined], function(val){
|
||||
deepEqual(_.mapObject(val, _.identity), {}, 'mapValue identity');
|
||||
});
|
||||
|
||||
var Proto = function(){this.a = 1;};
|
||||
Proto.prototype.b = 1;
|
||||
var protoObj = new Proto();
|
||||
deepEqual(_.mapObject(protoObj, _.identity), {a: 1}, 'ignore inherited values from prototypes');
|
||||
|
||||
});
|
||||
}());
|
||||
|
||||
71
vendor/underscore/test/utility.js
vendored
71
vendor/underscore/test/utility.js
vendored
@@ -1,8 +1,8 @@
|
||||
(function() {
|
||||
|
||||
var _ = typeof require == 'function' ? require('..') : window._;
|
||||
var templateSettings;
|
||||
|
||||
module('Utility', {
|
||||
QUnit.module('Utility', {
|
||||
|
||||
setup: function() {
|
||||
templateSettings = _.clone(_.templateSettings);
|
||||
@@ -21,13 +21,13 @@
|
||||
});
|
||||
|
||||
test('identity', function() {
|
||||
var moe = {name : 'moe'};
|
||||
equal(_.identity(moe), moe, 'moe is the same as his identity');
|
||||
var stooge = {name : 'moe'};
|
||||
equal(_.identity(stooge), stooge, 'stooge is the same as his identity');
|
||||
});
|
||||
|
||||
test('constant', function() {
|
||||
var moe = {name : 'moe'};
|
||||
equal(_.constant(moe)(), moe, 'should create a function that returns moe');
|
||||
var stooge = {name : 'moe'};
|
||||
equal(_.constant(stooge)(), stooge, 'should create a function that returns stooge');
|
||||
});
|
||||
|
||||
test('noop', function() {
|
||||
@@ -35,8 +35,28 @@
|
||||
});
|
||||
|
||||
test('property', function() {
|
||||
var moe = {name : 'moe'};
|
||||
equal(_.property('name')(moe), 'moe', 'should return the property with the given name');
|
||||
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');
|
||||
});
|
||||
|
||||
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');
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
test('random', function() {
|
||||
@@ -268,6 +288,41 @@
|
||||
strictEqual(_.result(null, 'x'), undefined);
|
||||
});
|
||||
|
||||
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(''.match('missing'), 1, 'default'), 'default');
|
||||
});
|
||||
|
||||
test('result returns a default value if property of object is missing', function() {
|
||||
strictEqual(_.result({d: null}, 'd', 'default'), null);
|
||||
strictEqual(_.result({e: false}, 'e', 'default'), false);
|
||||
});
|
||||
|
||||
test('result only returns the default value if the object does not have the property or is undefined', function() {
|
||||
strictEqual(_.result({}, 'b', 'default'), 'default');
|
||||
strictEqual(_.result({d: undefined}, 'd', 'default'), 'default');
|
||||
});
|
||||
|
||||
test('result does not return the default if the property of an object is found in the prototype', function() {
|
||||
var Foo = function(){};
|
||||
Foo.prototype.bar = 1;
|
||||
strictEqual(_.result(new Foo, 'bar', 2), 1);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
test('result fallback can use a function', function() {
|
||||
var obj = {a: [1, 2, 3]};
|
||||
strictEqual(_.result(obj, 'b', _.constant(5)), 5);
|
||||
strictEqual(_.result(obj, 'b', function() {
|
||||
return this.a;
|
||||
}), obj.a, 'called with context');
|
||||
});
|
||||
|
||||
test('_.templateSettings.variable', function() {
|
||||
var s = '<%=data.x%>';
|
||||
var data = {x: 'x'};
|
||||
|
||||
6
vendor/underscore/underscore-min.js
vendored
6
vendor/underscore/underscore-min.js
vendored
File diff suppressed because one or more lines are too long
669
vendor/underscore/underscore.js
vendored
669
vendor/underscore/underscore.js
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user