mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-03 00:27:50 +00:00
Add coverage for Set for environments w/o native support.
This commit is contained in:
134
test/asset/set.js
Normal file
134
test/asset/set.js
Normal file
@@ -0,0 +1,134 @@
|
||||
;(function() {
|
||||
|
||||
/** Used to determine if values are of the language type Object */
|
||||
var objectTypes = {
|
||||
'function': true,
|
||||
'object': true
|
||||
};
|
||||
|
||||
/** Used as the `Set#toString` return value */
|
||||
var nativeString = String(Object.prototype.toString).replace(/toString/g, 'Set');
|
||||
|
||||
/** Used as a reference to the global object */
|
||||
var root = (objectTypes[typeof window] && window) || this;
|
||||
|
||||
/** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
|
||||
var freeGlobal = objectTypes[typeof global] && global;
|
||||
if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
|
||||
root = freeGlobal;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Creates a Set object to optimize linear searches of large arrays.
|
||||
*/
|
||||
function Set() {
|
||||
this.__cache__ = {};
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Gets the index at which the first occurrence of `value` is found using
|
||||
* strict equality for comparisons, i.e. `===`.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to search.
|
||||
* @param {*} value The value to search for.
|
||||
* @returns {number} Returns the index of the matched value or `-1`.
|
||||
*/
|
||||
function indexOf(array, value) {
|
||||
var index = -1,
|
||||
length = array.length;
|
||||
|
||||
while (++index < length) {
|
||||
if (array[index] === value) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Checks if `value` is in the set.
|
||||
*
|
||||
* @memberOf Set
|
||||
* @param {*} value The value to search for.
|
||||
* @returns {boolean} Returns `true` if `value` is found, else `false`.
|
||||
*/
|
||||
function has(value) {
|
||||
var type = typeof value,
|
||||
cache = this.__cache__;
|
||||
|
||||
if (type == 'boolean' || value == null) {
|
||||
return cache[value] || false;
|
||||
}
|
||||
if (type != 'number' && type != 'string') {
|
||||
type = 'object';
|
||||
}
|
||||
var key = type == 'number' ? value : '_' + value;
|
||||
cache = (cache = cache[type]) && cache[key];
|
||||
|
||||
return type == 'object'
|
||||
? (cache && indexOf(cache, value) > -1 ? true : false)
|
||||
: (cache || false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds `value` to the set.
|
||||
*
|
||||
* @memberOf Set
|
||||
* @param {*} value The value to add to the set.
|
||||
*/
|
||||
function add(value) {
|
||||
var cache = this.__cache__,
|
||||
type = typeof value;
|
||||
|
||||
if (type == 'boolean' || value == null) {
|
||||
cache[value] = true;
|
||||
} else {
|
||||
if (type != 'number' && type != 'string') {
|
||||
type = 'object';
|
||||
}
|
||||
var key = type == 'number' ? value : '_' + value,
|
||||
typeCache = cache[type] || (cache[type] = {});
|
||||
|
||||
if (type == 'object') {
|
||||
var array = typeCache[key];
|
||||
if (array) {
|
||||
array.push(value);
|
||||
} else {
|
||||
typeCache[key] = [value];
|
||||
}
|
||||
} else {
|
||||
typeCache[key] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces the `toString` result of `Set`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf Set
|
||||
* @returns {string} Returns the string result.
|
||||
*/
|
||||
function toString() {
|
||||
return nativeString;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
Set.toString = toString;
|
||||
Set.prototype.add = add;
|
||||
Set.prototype.has = has;
|
||||
|
||||
// expose `Set`
|
||||
if (!root.Set) {
|
||||
root.Set = Set;
|
||||
}
|
||||
}.call(this));
|
||||
118
test/index.html
118
test/index.html
@@ -18,78 +18,122 @@
|
||||
<div id="qunit"></div>
|
||||
<div id="exports"></div>
|
||||
<script>
|
||||
var setProperty = (function() {
|
||||
var defineProperty = (function() {
|
||||
try {
|
||||
var o = {},
|
||||
func = Object.defineProperty,
|
||||
result = func(o, o, o) && func;
|
||||
} catch(e) { }
|
||||
return result;
|
||||
}());
|
||||
|
||||
if (!defineProperty) {
|
||||
return function(object, key, value) {
|
||||
object[key] = value;
|
||||
};
|
||||
}
|
||||
return function(object, key, value) {
|
||||
// avoid a bug where overwriting non-enumerable built-ins makes them enumerable
|
||||
// https://code.google.com/p/v8/issues/detail?id=1623
|
||||
defineProperty(object, key, {
|
||||
'configurable': true,
|
||||
'enumerable': false,
|
||||
'writable': true,
|
||||
'value': value
|
||||
});
|
||||
|
||||
}
|
||||
}());
|
||||
|
||||
function addBizarroMethods() {
|
||||
// add extensions
|
||||
Function.prototype._method = function() {};
|
||||
|
||||
// allow bypassing native checks
|
||||
setProperty(Function.prototype, '_toString', _fnToString);
|
||||
setProperty(Function.prototype, 'toString', (function() {
|
||||
var func = Function.prototype.toString;
|
||||
function toString() {
|
||||
return this.toString !== toString ? this.toString() : func.call(this);
|
||||
}
|
||||
return toString;
|
||||
}()));
|
||||
|
||||
// set bad shims
|
||||
Array._isArray = Array.isArray;
|
||||
Array.isArray = function() {};
|
||||
setProperty(Array, '_isArray', Array.isArray);
|
||||
setProperty(Array, 'isArray', function() {});
|
||||
|
||||
Date._now = Date.now;
|
||||
Date.now = function() {};
|
||||
setProperty(Date, '_now', Date.now);
|
||||
setProperty(Date, 'now', function() {});
|
||||
|
||||
Object._create = Object.create;
|
||||
Object.create = function() {};
|
||||
setProperty(Object, '_create', Object.create);
|
||||
setProperty(Object, 'create', function() {});
|
||||
|
||||
Object._defineProperty = Object.defineProperty;
|
||||
Object.defineProperty = function() {};
|
||||
setProperty(Object, '_defineProperty', Object.defineProperty);
|
||||
setProperty(Object, 'defineProperty', function() {});
|
||||
|
||||
Object._getPrototypeOf = Object.getPrototypeOf;
|
||||
Object.getPrototypeOf = function() {};
|
||||
setProperty(Object, '_getPrototypeOf', Object.getPrototypeOf);
|
||||
setProperty(Object, 'getPrototypeOf', function() {});
|
||||
|
||||
Object._keys = Object.keys;
|
||||
Object.keys = function() {};
|
||||
setProperty(Object, '_keys', Object.keys);
|
||||
setProperty(Object, 'keys', function() {});
|
||||
|
||||
String.prototype._contains = String.prototype.contains;
|
||||
String.prototype.contains = String.prototype._contains ? function() {} : Boolean;
|
||||
setProperty(String.prototype, '_contains', String.prototype.contains);
|
||||
setProperty(String.prototype, 'contains', String.prototype._contains ? function() {} : Boolean);
|
||||
|
||||
String.prototype._trim = String.prototype.trim;
|
||||
String.prototype.trim = String.prototype._trim ? function() {} : String;
|
||||
setProperty(String.prototype, '_trim', String.prototype.trim);
|
||||
setProperty(String.prototype, 'trim', String.prototype._trim ? function() {} : String);
|
||||
|
||||
String.prototype._trimLeft = String.prototype.trimLeft;
|
||||
String.prototype.trimLeft = String.prototype._trimLeft ? function() {} : String;
|
||||
setProperty(String.prototype, '_trimLeft', String.prototype.trimLeft);
|
||||
setProperty(String.prototype, 'trimLeft', String.prototype._trimLeft ? function() {} : String);
|
||||
|
||||
String.prototype._trimRight = String.prototype.trimRight;
|
||||
String.prototype.trimRight = String.prototype._trimRight ? function() {} : String;
|
||||
setProperty(String.prototype, '_trimRight', String.prototype.trimRight);
|
||||
setProperty(String.prototype, 'trimRight', String.prototype._trimRight ? function() {} : String);
|
||||
|
||||
window.WinRTError = Error;
|
||||
setProperty(window, '_Set', window.Set);
|
||||
setProperty(window, 'WinRTError', Error);
|
||||
|
||||
document._createDocumentFragment = document.createDocumentFragment;
|
||||
setProperty(document, '_createDocumentFragment', document.createDocumentFragment);
|
||||
document.createDocumentFragment = function() {};
|
||||
}
|
||||
|
||||
function removeBizarroMethods() {
|
||||
if (Array._isArray) {
|
||||
Array.isArray = Array._isArray;
|
||||
setProperty(Array, 'isArray', Array._isArray);
|
||||
} else {
|
||||
delete Array.isArray;
|
||||
}
|
||||
if (Date._now) {
|
||||
Date.now = Date._now;
|
||||
setProperty(Date, 'now', Date._now);
|
||||
} else {
|
||||
delete Date.now;
|
||||
}
|
||||
if (Object._create) {
|
||||
Object.create = Object._create;
|
||||
setProperty(Object, 'create', Object._create);
|
||||
} else {
|
||||
delete Object.create;
|
||||
}
|
||||
if (Object._defineProperty) {
|
||||
Object.defineProperty = Object._defineProperty;
|
||||
setProperty(Object, 'defineProperty', Object._defineProperty);
|
||||
} else {
|
||||
delete Object.defineProperty;
|
||||
}
|
||||
if (Object._getPrototypeOf) {
|
||||
Object.getPrototypeOf = Object._getPrototypeOf;
|
||||
setProperty(Object, 'getPrototypeOf', Object._getPrototypeOf);
|
||||
} else {
|
||||
delete Object.getPrototypeOf;
|
||||
}
|
||||
if (Object._keys) {
|
||||
Object.keys = Object._keys;
|
||||
setProperty(Object, 'keys', Object._keys);
|
||||
} else {
|
||||
delete Object.keys;
|
||||
}
|
||||
if (window._Set) {
|
||||
setProperty(window, 'Set', _Set);
|
||||
} else {
|
||||
setProperty(window, 'Set', undefined);
|
||||
}
|
||||
for (var key in {
|
||||
'contains': true,
|
||||
'trim': true,
|
||||
@@ -98,29 +142,22 @@
|
||||
}) {
|
||||
var func = String.prototype['_' + key];
|
||||
if (func) {
|
||||
if (Object.defineProperty) {
|
||||
Object.defineProperty(String.prototype, key, {
|
||||
'configurable': true,
|
||||
'enumerable': false,
|
||||
'writable': true,
|
||||
'value': func
|
||||
});
|
||||
} else {
|
||||
String.prototype[key] = func;
|
||||
}
|
||||
setProperty(String.prototype, key, func);
|
||||
} else {
|
||||
delete String.prototype[key];
|
||||
}
|
||||
delete String.prototype['_' + key];
|
||||
}
|
||||
window.WinRTError = undefined;
|
||||
setProperty(window, 'WinRTError', undefined);
|
||||
setProperty(Function.prototype, 'toString', Function.prototype._toString);
|
||||
|
||||
document.createDocumentFragment = document._createDocumentFragment;
|
||||
document._createDocumentFragment = undefined;
|
||||
setProperty(document, '_createDocumentFragment', undefined);
|
||||
|
||||
delete Array._isArray;
|
||||
delete Date._now;
|
||||
delete Function.prototype._method;
|
||||
delete Function.prototype._toString;
|
||||
delete Object._create;
|
||||
delete Object._defineProperty;
|
||||
delete Object._getPrototypeOf;
|
||||
@@ -130,6 +167,7 @@
|
||||
addBizarroMethods();
|
||||
|
||||
// load Lo-Dash and expose it to the bad extensions/shims
|
||||
document.write('<script src="./asset/set.js"><\/script>');
|
||||
document.write('<script src="' + (ui.isModularize ? '../lodash.js' : ui.buildPath) + '"><\/script>');
|
||||
</script>
|
||||
<script>
|
||||
|
||||
119
test/test.js
119
test/test.js
@@ -151,7 +151,7 @@
|
||||
var empties = [[], {}].concat(falsey.slice(1));
|
||||
|
||||
/** Used as the size when optimizations are enabled for large arrays */
|
||||
var largeArraySize = 75;
|
||||
var LARGE_ARRAY_SIZE = 75;
|
||||
|
||||
/** Used to set property descriptors */
|
||||
var defineProperty = (function() {
|
||||
@@ -192,6 +192,32 @@
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a non-enumerable property value on `object`.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The object augment.
|
||||
* @param {string} key The name of the property to set.
|
||||
* @param {*} value The property value.
|
||||
*/
|
||||
var setProperty = (function() {
|
||||
if (!defineProperty) {
|
||||
return function(object, key, value) {
|
||||
object[key] = value;
|
||||
};
|
||||
}
|
||||
return function(object, key, value) {
|
||||
// avoid a bug where overwriting non-enumerable built-ins makes them enumerable
|
||||
// https://code.google.com/p/v8/issues/detail?id=1623
|
||||
defineProperty(object, key, {
|
||||
'configurable': true,
|
||||
'enumerable': false,
|
||||
'writable': true,
|
||||
'value': value
|
||||
});
|
||||
};
|
||||
}());
|
||||
|
||||
/**
|
||||
* Skips a given number of tests with a passing result.
|
||||
*
|
||||
@@ -211,8 +237,6 @@
|
||||
(function() {
|
||||
if (!amd) {
|
||||
try {
|
||||
emptyObject(require.cache);
|
||||
|
||||
_.extend(_, require('vm').runInNewContext([
|
||||
'({',
|
||||
"'_arguments': (function() { return arguments; }(1, 2, 3)),",
|
||||
@@ -231,61 +255,60 @@
|
||||
].join('\n')));
|
||||
|
||||
// fake `WinRTError`
|
||||
global.WinRTError = Error;
|
||||
setProperty(global, 'WinRTError', Error);
|
||||
|
||||
// fake DOM
|
||||
global.window = {
|
||||
'document': {
|
||||
'createDocumentFragment': function() {
|
||||
return { 'nodeType': 11 };
|
||||
}
|
||||
}
|
||||
};
|
||||
setProperty(global, 'window', {});
|
||||
setProperty(global.window, 'document', {});
|
||||
setProperty(global.window.document, 'createDocumentFragment', function() {
|
||||
return { 'nodeType': 11 };
|
||||
});
|
||||
|
||||
// add extensions
|
||||
Function.prototype._method = function() {};
|
||||
|
||||
// set bad shims
|
||||
var _isArray = Array.isArray;
|
||||
Array.isArray = function() {};
|
||||
setProperty(Array, 'isArray', function() {});
|
||||
|
||||
var _now = Date.now;
|
||||
Date.now = function() {};
|
||||
setProperty(Date, 'now', function() {});
|
||||
|
||||
var _create = Object.create;
|
||||
Object.create = function() {};
|
||||
setProperty(Object, 'create', function() {});
|
||||
|
||||
var _defineProperty = Object.defineProperty;
|
||||
Object.defineProperty = function() {};
|
||||
setProperty(Object, 'defineProperty', function() {});
|
||||
|
||||
var _getPrototypeOf = Object.getPrototypeOf;
|
||||
Object.getPrototypeOf = function() {};
|
||||
setProperty(Object, 'getPrototypeOf', function() {});
|
||||
|
||||
var _keys = Object.keys;
|
||||
Object.keys = function() {};
|
||||
setProperty(Object, 'keys', function() {});
|
||||
|
||||
var _contains = String.prototype.contains;
|
||||
String.prototype.contains = _contains ? function() {} : Boolean;
|
||||
setProperty(String.prototype, 'contains', _contains ? function() {} : Boolean);
|
||||
|
||||
var _trim = String.prototype.trim;
|
||||
String.prototype.trim = _trim ? function() {} : String;
|
||||
setProperty(String.prototype, 'trim', _trim ? function() {} : String);
|
||||
|
||||
var _trimLeft = String.prototype.trimLeft;
|
||||
String.prototype.trimLeft = _trimLeft ? function() {} : String;
|
||||
setProperty(String.prototype, 'trimLeft', _trimLeft ? function() {} : String);
|
||||
|
||||
var _trimRight = String.prototype.trimRight;
|
||||
String.prototype.trimRight = _trimRight ? function() {} : String;
|
||||
setProperty(String.prototype, 'trimRight', _trimRight ? function() {} : String);
|
||||
|
||||
// load Lo-Dash and expose it to the bad extensions/shims
|
||||
emptyObject(require.cache);
|
||||
lodashBizarro = (lodashBizarro = require(filePath))._ || lodashBizarro;
|
||||
|
||||
// restore native methods
|
||||
Array.isArray = _isArray;
|
||||
Date.now = _now;
|
||||
Object.create = _create;
|
||||
Object.defineProperty = _defineProperty;
|
||||
Object.getPrototypeOf = _getPrototypeOf;
|
||||
Object.keys = _keys;
|
||||
setProperty(Array, 'isArray', _isArray);
|
||||
setProperty(Date, 'now', _now);
|
||||
setProperty(Object, 'create', _create);
|
||||
setProperty(Object, 'defineProperty', _defineProperty);
|
||||
setProperty(Object, 'getPrototypeOf', _getPrototypeOf);
|
||||
setProperty(Object, 'keys', _keys);
|
||||
|
||||
_.forOwn({
|
||||
'contains': _contains,
|
||||
@@ -295,14 +318,7 @@
|
||||
},
|
||||
function(func, key) {
|
||||
if (func) {
|
||||
// avoid a bug where overwriting non-enumerable built-ins makes them enumerable
|
||||
// https://code.google.com/p/v8/issues/detail?id=1623
|
||||
defineProperty(String.prototype, key, {
|
||||
'configurable': true,
|
||||
'enumerable': false,
|
||||
'writable': true,
|
||||
'value': func
|
||||
});
|
||||
setProperty(String.prototype, key, func);
|
||||
} else {
|
||||
delete String.prototype[key];
|
||||
}
|
||||
@@ -2030,7 +2046,7 @@
|
||||
});
|
||||
|
||||
test('should work with large arrays', 1, function() {
|
||||
var array1 = _.range(largeArraySize),
|
||||
var array1 = _.range(LARGE_ARRAY_SIZE),
|
||||
array2 = array1.slice(),
|
||||
a = {},
|
||||
b = {},
|
||||
@@ -2045,7 +2061,7 @@
|
||||
test('should work with large arrays of objects', 1, function() {
|
||||
var object = {};
|
||||
|
||||
var largeArray = _.times(largeArraySize, function() {
|
||||
var largeArray = _.times(LARGE_ARRAY_SIZE, function() {
|
||||
return object;
|
||||
});
|
||||
|
||||
@@ -2948,7 +2964,7 @@
|
||||
stringObject = Object(stringLiteral),
|
||||
expected = [stringLiteral, stringObject];
|
||||
|
||||
var largeArray = _.times(largeArraySize, function(count) {
|
||||
var largeArray = _.times(LARGE_ARRAY_SIZE, function(count) {
|
||||
return count % 2 ? stringObject : stringLiteral;
|
||||
});
|
||||
|
||||
@@ -3227,6 +3243,10 @@
|
||||
var array = [1, new Foo, 3, new Foo],
|
||||
indexOf = _.indexOf;
|
||||
|
||||
var largeArray = _.times(LARGE_ARRAY_SIZE, function() {
|
||||
return new Foo;
|
||||
});
|
||||
|
||||
test('`_.contains` should work with a custom `_.indexOf` method', 1, function() {
|
||||
if (!isModularize) {
|
||||
_.indexOf = custom;
|
||||
@@ -3238,25 +3258,27 @@
|
||||
}
|
||||
});
|
||||
|
||||
test('`_.difference` should work with a custom `_.indexOf` method', 1, function() {
|
||||
test('`_.difference` should work with a custom `_.indexOf` method', 2, function() {
|
||||
if (!isModularize) {
|
||||
_.indexOf = custom;
|
||||
deepEqual(_.difference(array, [new Foo]), [1, 3]);
|
||||
deepEqual(_.difference(array, largeArray), [1, 3]);
|
||||
_.indexOf = indexOf;
|
||||
}
|
||||
else {
|
||||
skipTest();
|
||||
skipTest(2);
|
||||
}
|
||||
});
|
||||
|
||||
test('`_.intersection` should work with a custom `_.indexOf` method', 1, function() {
|
||||
test('`_.intersection` should work with a custom `_.indexOf` method', 2, function() {
|
||||
if (!isModularize) {
|
||||
_.indexOf = custom;
|
||||
deepEqual(_.intersection(array, [new Foo]), [array[1]]);
|
||||
deepEqual(_.intersection(largeArray, [new Foo]), [array[1]]);
|
||||
_.indexOf = indexOf;
|
||||
}
|
||||
else {
|
||||
skipTest();
|
||||
skipTest(2);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3264,11 +3286,6 @@
|
||||
if (!isModularize) {
|
||||
_.indexOf = custom;
|
||||
deepEqual(_.uniq(array), array.slice(0, 3));
|
||||
|
||||
var largeArray = _.times(largeArraySize, function() {
|
||||
return new Foo;
|
||||
});
|
||||
|
||||
deepEqual(_.uniq(largeArray), [largeArray[0]]);
|
||||
_.indexOf = indexOf;
|
||||
}
|
||||
@@ -3388,7 +3405,7 @@
|
||||
var object = {},
|
||||
expected = [object];
|
||||
|
||||
var largeArray = _.times(largeArraySize, function() {
|
||||
var largeArray = _.times(LARGE_ARRAY_SIZE, function() {
|
||||
return object;
|
||||
});
|
||||
|
||||
@@ -8202,7 +8219,7 @@
|
||||
test('should work with large arrays', 1, function() {
|
||||
var object = {};
|
||||
|
||||
var largeArray = _.times(largeArraySize, function(index) {
|
||||
var largeArray = _.times(LARGE_ARRAY_SIZE, function(index) {
|
||||
switch (index % 3) {
|
||||
case 0: return 0;
|
||||
case 1: return 'a';
|
||||
@@ -8247,7 +8264,7 @@
|
||||
test('should work with large arrays of boolean, `null`, and `undefined` values', 1, function() {
|
||||
var array = [],
|
||||
expected = [true, false, null, undefined],
|
||||
count = Math.ceil(largeArraySize / expected.length);
|
||||
count = Math.ceil(LARGE_ARRAY_SIZE / expected.length);
|
||||
|
||||
_.times(count, function() {
|
||||
push.apply(array, expected);
|
||||
@@ -8258,7 +8275,7 @@
|
||||
test('should distinguish between numbers and numeric strings', 1, function() {
|
||||
var array = [],
|
||||
expected = ['2', 2, Object('2'), Object(2)],
|
||||
count = Math.ceil(largeArraySize / expected.length);
|
||||
count = Math.ceil(LARGE_ARRAY_SIZE / expected.length);
|
||||
|
||||
_.times(count, function() {
|
||||
push.apply(array, expected);
|
||||
|
||||
Reference in New Issue
Block a user