Ensure _.isEqual works on error objects and add tests for cloning and comparing errors and typed arrays.

This commit is contained in:
John-David Dalton
2014-05-25 23:10:08 -07:00
parent 7da022ebb4
commit cd8d9bf07c
2 changed files with 60 additions and 10 deletions

View File

@@ -157,9 +157,10 @@
/** Used to identify object classifications that `_.clone` supports */ /** Used to identify object classifications that `_.clone` supports */
var cloneableClasses = {}; var cloneableClasses = {};
cloneableClasses[argsClass] = cloneableClasses[arrayClass] = cloneableClasses[argsClass] =
cloneableClasses[arrayBufferClass] = cloneableClasses[boolClass] = cloneableClasses[arrayClass] = cloneableClasses[arrayBufferClass] =
cloneableClasses[dateClass] = cloneableClasses[errorClass] = cloneableClasses[boolClass] = cloneableClasses[dateClass] =
cloneableClasses[errorClass] = cloneableClasses[float32Class] =
cloneableClasses[float64Class] = cloneableClasses[int8Class] = cloneableClasses[float64Class] = cloneableClasses[int8Class] =
cloneableClasses[int16Class] = cloneableClasses[int32Class] = cloneableClasses[int16Class] = cloneableClasses[int32Class] =
cloneableClasses[numberClass] = cloneableClasses[objectClass] = cloneableClasses[numberClass] = cloneableClasses[objectClass] =
@@ -606,12 +607,10 @@
/** Native constructor references */ /** Native constructor references */
var Array = context.Array, var Array = context.Array,
Boolean = context.Boolean,
Date = context.Date, Date = context.Date,
Error = context.Error, Error = context.Error,
Function = context.Function, Function = context.Function,
Math = context.Math, Math = context.Math,
Number = context.Number,
Object = context.Object, Object = context.Object,
RegExp = context.RegExp, RegExp = context.RegExp,
String = context.String, String = context.String,
@@ -1786,9 +1785,11 @@
// but treat `-0` vs. `+0` as not equal // but treat `-0` vs. `+0` as not equal
: (value == 0 ? (1 / value == 1 / other) : value == +other); : (value == 0 ? (1 / value == 1 / other) : value == +other);
case errorClass:
case regexpClass: case regexpClass:
case stringClass: case stringClass:
// coerce regexes to strings (http://es5.github.io/#x15.10.6.4) // coerce errors (http://es5.github.io/#x15.11.4.4)
// and regexes (http://es5.github.io/#x15.10.6.4) to strings
// treat string primitives and their corresponding object instances as equal // treat string primitives and their corresponding object instances as equal
return value == String(other); return value == String(other);
} }

View File

@@ -206,6 +206,18 @@
/** Used to check problem JScript properties too */ /** Used to check problem JScript properties too */
var shadowedObject = _.invert(shadowedProps); var shadowedObject = _.invert(shadowedProps);
/** Used to check whether methods support typed arrays */
var typedArrays = [
'Float32Array',
'Int8Array',
'Int16Array',
'Int32Array',
'Uint8Array',
'Uint8ClampedArray',
'Uint16Array',
'Uint32Array'
];
/** Used to check for problems removing whitespace */ /** Used to check for problems removing whitespace */
var whitespace = ' \t\x0B\f\xA0\ufeff\n\r\u2028\u2029\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'; var whitespace = ' \t\x0B\f\xA0\ufeff\n\r\u2028\u2029\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000';
@@ -1183,6 +1195,13 @@
'an array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 }, 'an array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 },
'boolean': false, 'boolean': false,
'boolean object': Object(false), 'boolean object': Object(false),
'an Error object': new Error('text'),
'an EvalError object': new EvalError('text'),
'a RangeError object': new RangeError('text'),
'a ReferenceError object': new ReferenceError('text'),
'a SyntaxError object': new SyntaxError('text'),
'a TypeError object': new TypeError('text'),
'a URIError object': new URIError('text'),
'a Klass instance': new Klass, 'a Klass instance': new Klass,
'an object': { 'a': 0, 'b': 1, 'c': 3 }, 'an object': { 'a': 0, 'b': 1, 'c': 3 },
'an object with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } }, 'an object with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } },
@@ -1243,9 +1262,22 @@
}); });
}); });
_.each(typedArrays, function(type) {
test('`_.' + methodName + '` should clone ' + type + ' arrays', 2, function() {
var Ctor = root[type] || Array,
buffer = Ctor == Array ? 4 : new ArrayBuffer(4),
array = new Ctor(buffer),
actual = func(array);
deepEqual(actual, array);
notStrictEqual(actual, array);
});
});
test('`_.' + methodName + '` should clone problem JScript properties (test in IE < 9)', 2, function() { test('`_.' + methodName + '` should clone problem JScript properties (test in IE < 9)', 2, function() {
deepEqual(func(shadowedObject), shadowedObject); var actual = func(shadowedObject);
notStrictEqual(func(shadowedObject), shadowedObject); deepEqual(actual, shadowedObject);
notStrictEqual(actual, shadowedObject);
}); });
test('`_.' + methodName + '` should perform a ' + (isDeep ? 'deep' : 'shallow') + ' clone when used as a callback for `_.map`', 2, function() { test('`_.' + methodName + '` should perform a ' + (isDeep ? 'deep' : 'shallow') + ' clone when used as a callback for `_.map`', 2, function() {
@@ -1284,7 +1316,7 @@
deepEqual(actual, { 'a': { 'b': 'c' } }); deepEqual(actual, { 'a': { 'b': 'c' } });
}); });
test('`_.' + methodName + '` should deep clone `index` and `input` array properties', 2, function() { test('`_.' + methodName + '` should clone `index` and `input` array properties', 2, function() {
var array = /x/.exec('vwxyz'), var array = /x/.exec('vwxyz'),
actual = func(array); actual = func(array);
@@ -1292,7 +1324,7 @@
strictEqual(actual.input, 'vwxyz'); strictEqual(actual.input, 'vwxyz');
}); });
test('`_.' + methodName + '` should deep clone `lastIndex` regexp property', 1, function() { test('`_.' + methodName + '` should clone `lastIndex` regexp property', 1, function() {
// avoid a regexp literal for older Opera and use `exec` for older Safari // avoid a regexp literal for older Opera and use `exec` for older Safari
var regexp = RegExp('x', 'g'); var regexp = RegExp('x', 'g');
regexp.exec('vwxyz'); regexp.exec('vwxyz');
@@ -4779,6 +4811,23 @@
} }
}); });
test('should perform comparisons between typed arrays', 1, function() {
var pairs = _.map(typedArrays, function(type) {
var Ctor = root[type] || Array,
buffer = Ctor == Array ? 4 : new ArrayBuffer(4);
return [new Ctor(buffer), new Ctor(buffer)];
});
var expected = _.times(pairs.length, _.constant(true));
var actual = _.map(pairs, function(pair) {
return _.isEqual(pair[0], pair[1]);
});
deepEqual(actual, expected);
});
test('should perform comparisons between wrapped values', 4, function() { test('should perform comparisons between wrapped values', 4, function() {
if (!isNpm) { if (!isNpm) {
var object1 = _({ 'a': 1, 'b': 2 }), var object1 = _({ 'a': 1, 'b': 2 }),