Add more unit tests to increase coverage.

This commit is contained in:
John-David Dalton
2013-11-29 20:54:18 -06:00
parent 2afbe9514b
commit 97490b272f
2 changed files with 202 additions and 40 deletions

View File

@@ -22,6 +22,9 @@
Array._isArray = Array.isArray; Array._isArray = Array.isArray;
Array.isArray = function() { return false; }; Array.isArray = function() { return false; };
Date._now = Date.now;
Date.now = function() {};
Function.prototype._bind = Function.prototype.bind; Function.prototype._bind = Function.prototype.bind;
Function.prototype.bind = function() { return function() {}; }; Function.prototype.bind = function() { return function() {}; };
@@ -34,7 +37,7 @@
Object._keys = Object.keys; Object._keys = Object.keys;
Object.keys = function() { return []; }; Object.keys = function() { return []; };
// load Lo-Dash and expose it to the bad `Object.keys` shim // load Lo-Dash and expose it to the bad shims
document.write('<script src="' + (ui.isModularize ? '../lodash.js' : ui.buildPath) + '"><\/script>'); document.write('<script src="' + (ui.isModularize ? '../lodash.js' : ui.buildPath) + '"><\/script>');
</script> </script>
<script> <script>
@@ -47,6 +50,11 @@
} else { } else {
delete Array.isArray; delete Array.isArray;
} }
if (Date._now) {
Date.now = Date._now;
} else {
delete Date.now;
}
if (Function.prototype._bind) { if (Function.prototype._bind) {
Function.prototype.bind = Function.prototype._bind; Function.prototype.bind = Function.prototype._bind;
} else { } else {
@@ -68,6 +76,7 @@
delete Object.keys; delete Object.keys;
} }
delete Array._isArray; delete Array._isArray;
delete Date._now;
delete Function.prototype._bind; delete Function.prototype._bind;
delete Object._create; delete Object._create;
delete Object._defineProperty; delete Object._defineProperty;

View File

@@ -1,6 +1,9 @@
;(function(root, undefined) { ;(function(root, undefined) {
'use strict'; 'use strict';
/** Used to store Lo-Dash to test for bad shim detection */
var lodashBadShim;
/** Method and object shortcuts */ /** Method and object shortcuts */
var phantom = root.phantom, var phantom = root.phantom,
amd = root.define && define.amd, amd = root.define && define.amd,
@@ -176,6 +179,18 @@
/** Used to check problem JScript properties too */ /** Used to check problem JScript properties too */
var shadowedObject = _.invert(shadowedProps); var shadowedObject = _.invert(shadowedProps);
/**
* Removes all own enumerable properties from a given object.
*
* @private
* @param {Object} object The object to empty.
*/
function emptyObject(object) {
_.forOwn(object, function(value, key, object) {
delete object[key];
});
}
/** /**
* Skips a given number of tests with a passing result. * Skips a given number of tests with a passing result.
* *
@@ -195,6 +210,8 @@
(function() { (function() {
if (!amd) { if (!amd) {
try { try {
emptyObject(require.cache);
_.extend(_, require('vm').runInNewContext([ _.extend(_, require('vm').runInNewContext([
'({', '({',
"'_arguments': (function() { return arguments; }(1, 2, 3)),", "'_arguments': (function() { return arguments; }(1, 2, 3)),",
@@ -211,6 +228,42 @@
"'_undefined': undefined,", "'_undefined': undefined,",
'})' '})'
].join('\n'))); ].join('\n')));
// set bad shims
Array._isArray = Array.isArray;
Array.isArray = function() { return false; };
Date._now = Date.now;
Date.now = function() {};
Function.prototype._bind = Function.prototype.bind;
Function.prototype.bind = function() { return function() {}; };
Object._create = Object.create;
Object.create = function() {};
Object._defineProperty = Object.defineProperty;
Object.defineProperty = function() {};
Object._keys = Object.keys;
Object.keys = function() { return []; };
// load Lo-Dash and expose it to the bad shims
lodashBadShim = require(filePath);
// restore native methods
Array.isArray = Array._isArray;
Date.now = Date._now;
Function.prototype.bind = Function.prototype._bind;
Object.create = Object._create;
Object.defineProperty = Object._defineProperty;
Object.keys = Object._keys;
delete Array._isArray;
delete Function.prototype._bind;
delete Object._create;
delete Object._defineProperty;
delete Object._keys;
} catch(e) { } } catch(e) { }
} }
if (!_._object && document) { if (!_._object && document) {
@@ -307,14 +360,16 @@
} }
}); });
test('avoids overwritten native methods', 4, function() { test('avoids overwritten native methods', 5, function() {
function Foo() {}
function message(methodName) { function message(methodName) {
return '`_.' + methodName + '` should avoid overwritten native methods'; return '`_.' + methodName + '` should avoid overwritten native methods';
} }
var object = { 'a': true }; var object = { 'a': true };
if (document) { if (lodashBadShim) {
try { try {
var actual = lodashBadShim.bind(function() { return this.a; }, object)(); var actual = lodashBadShim.bind(function() { return this.a; }, object)();
} catch(e) { } catch(e) {
@@ -322,6 +377,13 @@
} }
ok(actual, message('bind')); ok(actual, message('bind'));
try {
actual = lodashBadShim.create(Foo.prototype, object);
} catch(e) {
actual = null;
}
ok(actual instanceof Foo, message('create'));
try { try {
actual = lodashBadShim.isArray([]); actual = lodashBadShim.isArray([]);
} catch(e) { } catch(e) {
@@ -337,20 +399,14 @@
deepEqual(actual, ['a'], message('keys')); deepEqual(actual, ['a'], message('keys'));
try { try {
var Foo = function() { actual = lodashBadShim.now();
this.a = 2;
};
var actual = _.transform(new Foo, function(result, value, key) {
result[key] = value * value;
});
} catch(e) { } catch(e) {
actual = null; actual = null;
} }
ok(actual instanceof Foo, message('transform')); ok(typeof actual == 'number', message('now'));
} }
else { else {
skipTest(4); skipTest(5);
} }
}); });
}()); }());
@@ -585,7 +641,6 @@
function Foo() { function Foo() {
return this; return this;
} }
var bound = _.bind(Foo, { 'a': 1 }), var bound = _.bind(Foo, { 'a': 1 }),
newBound = new bound; newBound = new bound;
@@ -594,10 +649,15 @@
ok(newBound instanceof Foo); ok(newBound instanceof Foo);
}); });
test('ensure `new bound` is an instance of `func`', 1, function() { test('ensure `new bound` is an instance of `func`', 2, function() {
var bound = _.bind(noop, {}); function Foo(value) {
return value && object;
}
var bound = _.bind(Foo),
object = {};
ok(new bound instanceof noop); ok(new bound instanceof Foo);
strictEqual(new bound(true), object);
}); });
test('should append array arguments to partially applied arguments (test in IE < 9)', 1, function() { test('should append array arguments to partially applied arguments (test in IE < 9)', 1, function() {
@@ -1276,11 +1336,12 @@
test('should return the function provided if already bound with `Function#bind`', 1, function() { test('should return the function provided if already bound with `Function#bind`', 1, function() {
function a() {} function a() {}
var object = {};
var bound = a.bind && a.bind({}); var bound = a.bind && a.bind(object);
if (bound && !('prototype' in bound)) { if (bound && !('prototype' in bound)) {
var bound = a.bind({}); var bound = a.bind(object);
strictEqual(_.createCallback(bound, {}), bound); strictEqual(_.createCallback(bound, object), bound);
} }
else { else {
skipTest(); skipTest();
@@ -1291,28 +1352,43 @@
function a() {} function a() {}
function b() { return this.b; } function b() { return this.b; }
var object = {};
if (_.support.funcDecomp) { if (_.support.funcDecomp) {
strictEqual(_.createCallback(a, {}), a); strictEqual(_.createCallback(a, object), a);
notStrictEqual(_.createCallback(b, {}), b); notStrictEqual(_.createCallback(b, object), b);
} }
else { else {
skipTest(2); skipTest(2);
} }
}); });
test('should only write `__bindData__` to named functions', 2, function() { test('should only write `__bindData__` to named functions', 3, function() {
function a() {}; function a() {};
var b = function() {}; function c() {};
var b = function() {},
object = {};
if (defineProperty && _.support.funcDecomp) { if (defineProperty && _.support.funcDecomp) {
_.createCallback(a, {}); _.createCallback(a, object);
ok('__bindData__' in a) ok('__bindData__' in a)
_.createCallback(b, {}); _.createCallback(b, object);
ok(!('__bindData__' in b)); ok(!('__bindData__' in b));
if (_.support.funcNames) {
_.support.funcNames = false;
_.createCallback(c, object);
ok('__bindData__' in c);
_.support.funcNames = true;
}
else {
skipTest();
}
} }
else { else {
skipTest(2); skipTest(3);
} }
}); });
}()); }());
@@ -1354,6 +1430,17 @@
}); });
}); });
test('ensure `new bound` is an instance of `func`', 2, function() {
function Foo(value) {
return value && object;
}
var bound = _.curry(Foo),
object = {};
ok(new bound(false) instanceof Foo);
strictEqual(new bound(true), object);
});
test('should not alter the `this` binding', 9, function() { test('should not alter the `this` binding', 9, function() {
function func(a, b, c) { function func(a, b, c) {
var value = this || {}; var value = this || {};
@@ -1797,6 +1884,16 @@
deepEqual(_.difference(array1, array2), []); deepEqual(_.difference(array1, array2), []);
}); });
test('should work with large arrays of objects', 1, function() {
var object = {};
var largeArray = _.times(largeArraySize, function() {
return object;
});
deepEqual(_.difference(largeArray, [object]), []);
});
test('should ignore individual secondary values', 1, function() { test('should ignore individual secondary values', 1, function() {
var array = [1, null, 3]; var array = [1, null, 3];
deepEqual(_.difference(array, null, 3), array); deepEqual(_.difference(array, null, 3), array);
@@ -2004,6 +2101,14 @@
strictEqual(func(objects, function(object) { return object.a == 3; }), expected[1]); strictEqual(func(objects, function(object) { return object.a == 3; }), expected[1]);
}); });
test('should work with an object for `collection`', 1, function() {
var actual = _.find({ 'a': 1, 'b': 2, 'c': 3 }, function(num) {
return num > 2;
});
equal(actual, 3);
});
test('should work with an object for `callback`', 1, function() { test('should work with an object for `callback`', 1, function() {
strictEqual(func(objects, { 'b': 2 }), expected[2]); strictEqual(func(objects, { 'b': 2 }), expected[2]);
}); });
@@ -2688,19 +2793,19 @@
QUnit.module('`__proto__` property bugs'); QUnit.module('`__proto__` property bugs');
(function() { (function() {
var stringLiteral = '__proto__',
stringObject = Object(stringLiteral),
expected = [stringLiteral, stringObject];
var array = _.times(largeArraySize, function(count) {
return count % 2 ? stringObject : stringLiteral;
});
test('internal data objects should work with the `__proto__` key', 4, function() { test('internal data objects should work with the `__proto__` key', 4, function() {
deepEqual(_.difference(array, array), []); var stringLiteral = '__proto__',
deepEqual(_.intersection(array, array), expected); stringObject = Object(stringLiteral),
deepEqual(_.uniq(array), expected); expected = [stringLiteral, stringObject];
deepEqual(_.without.apply(_, [array].concat(array)), []);
var largeArray = _.times(largeArraySize, function(count) {
return count % 2 ? stringObject : stringLiteral;
});
deepEqual(_.difference(largeArray, largeArray), []);
deepEqual(_.intersection(largeArray, largeArray), expected);
deepEqual(_.uniq(largeArray), expected);
deepEqual(_.without.apply(_, [largeArray].concat(largeArray)), []);
}); });
test('lodash.memoize should memoize values resolved to the `__proto__` key', 1, function() { test('lodash.memoize should memoize values resolved to the `__proto__` key', 1, function() {
@@ -3123,6 +3228,17 @@
deepEqual(actual, [1, 2]); deepEqual(actual, [1, 2]);
}); });
test('should work with large arrays of objects', 1, function() {
var object = {},
expected = [object];
var largeArray = _.times(largeArraySize, function() {
return object;
});
deepEqual(_.intersection(expected, largeArray), expected);
});
test('should return a wrapped value when chaining', 2, function() { test('should return a wrapped value when chaining', 2, function() {
if (!isNpm) { if (!isNpm) {
var actual = _([1, 3, 2]).intersection([5, 2, 1, 4]); var actual = _([1, 3, 2]).intersection([5, 2, 1, 4]);
@@ -4208,6 +4324,8 @@
QUnit.module('lodash.isPlainObject'); QUnit.module('lodash.isPlainObject');
(function() { (function() {
var element = document && document.createElement('div');
test('should detect plain objects', 5, function() { test('should detect plain objects', 5, function() {
function Foo(a) { function Foo(a) {
this.a = 1; this.a = 1;
@@ -4222,13 +4340,27 @@
} else { } else {
skipTest(); skipTest();
} }
if (document) { if (element) {
strictEqual(_.isPlainObject(body), false); strictEqual(_.isPlainObject(element), false);
} else { } else {
skipTest(); skipTest();
} }
}); });
test('should return `true` for plain objects with a custom `valueOf` property', 2, function() {
strictEqual(_.isPlainObject({ 'valueOf': 0 }), true);
if (element) {
var valueOf = element.valueOf;
element.valueOf = 0;
strictEqual(_.isPlainObject(element), false);
element.valueOf = valueOf;
}
else {
skipTest();
}
});
test('should return `true` for empty objects', 1, function() { test('should return `true` for empty objects', 1, function() {
strictEqual(_.isPlainObject({}), true); strictEqual(_.isPlainObject({}), true);
}); });
@@ -5502,6 +5634,17 @@
strictEqual(actual.length, 0); strictEqual(actual.length, 0);
}); });
test('ensure `new bound` is an instance of `func`', 2, function() {
function Foo(value) {
return value && object;
}
var bound = func(Foo),
object = {};
ok(new bound instanceof Foo);
strictEqual(new bound(true), object);
});
test('`_.' + methodName + '` should clone `__bindData__` for created functions', 3, function() { test('`_.' + methodName + '` should clone `__bindData__` for created functions', 3, function() {
function greet(greeting, name) { function greet(greeting, name) {
return greeting + ' ' + name; return greeting + ' ' + name;
@@ -7642,6 +7785,16 @@
deepEqual(_.uniq(array), [1, 2, 3]); deepEqual(_.uniq(array), [1, 2, 3]);
}); });
test('should work with large arrays of objects', 1, function() {
var object = {};
var largeArray = _.times(largeArraySize, function() {
return object;
});
deepEqual(_.uniq(largeArray), [object]);
});
test('should work with a `callback`', 1, function() { test('should work with a `callback`', 1, function() {
var actual = _.uniq(objects, false, function(object) { var actual = _.uniq(objects, false, function(object) {
return object.a; return object.a;