Ensure _.where returns elements that contain all source array values. [closes #583]

This commit is contained in:
John-David Dalton
2014-06-11 09:26:21 -07:00
parent ec89382e35
commit e5ccfc4446
2 changed files with 44 additions and 33 deletions

View File

@@ -1867,28 +1867,27 @@
length = value.length; length = value.length;
result = length == othLength; result = length == othLength;
if (result || isWhere) { if (result || (isWhere && othLength > length)) {
// deep compare the contents, ignoring non-numeric properties // deep compare the contents, ignoring non-numeric properties
while (++index < length) { while (++index < length) {
var valValue = value[index]; var valValue = value[index];
if (isWhere) { if (isWhere) {
var othIndex = -1; var othIndex = othLength;
while (++othIndex < othLength) { while (othIndex--) {
var othValue = other[othIndex]; result = baseIsEqual(valValue, other[othIndex], callback, isWhere, stackA, stackB);
result = baseIsEqual(valValue, othValue, callback, isWhere, stackA, stackB);
if (result) { if (result) {
break; break;
} }
} }
} else { } else {
othValue = other[index]; var othValue = other[index];
result = callback ? callback(valValue, othValue, index) : undefined; result = callback ? callback(valValue, othValue, index) : undefined;
if (typeof result == 'undefined') { if (typeof result == 'undefined') {
result = baseIsEqual(valValue, othValue, callback, isWhere, stackA, stackB); result = baseIsEqual(valValue, othValue, callback, isWhere, stackA, stackB);
} }
if (!result) { }
break; if (!result) {
} break;
} }
} }
} }
@@ -1911,8 +1910,8 @@
var key = valProps[index]; var key = valProps[index];
result = hasOwnProperty.call(other, key); result = hasOwnProperty.call(other, key);
if (result) { if (result) {
othValue = other[key];
valValue = value[key]; valValue = value[key];
othValue = other[key];
result = callback ? callback(valValue, othValue, key) : undefined; result = callback ? callback(valValue, othValue, key) : undefined;
if (typeof result == 'undefined') { if (typeof result == 'undefined') {
result = baseIsEqual(valValue, othValue, callback, isWhere, stackA, stackB); result = baseIsEqual(valValue, othValue, callback, isWhere, stackA, stackB);

View File

@@ -10138,16 +10138,24 @@
{ 'a': 3 } { 'a': 3 }
]; ];
test('should filter by `source` properties', 6, function() { test('should filter by `source` properties', 12, function() {
deepEqual(_.where(objects, { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }]); var pairs = [
deepEqual(_.where(objects, { 'a': 2 }), [{ 'a': 2, 'b': 2 }]); [{ 'a': 1 }, [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }]],
deepEqual(_.where(objects, { 'a': 3 }), [{ 'a': 3 }]); [{ 'a': 2 }, [{ 'a': 2, 'b': 2 }]],
deepEqual(_.where(objects, { 'b': 1 }), []); [{ 'a': 3 }, [{ 'a': 3 }]],
deepEqual(_.where(objects, { 'b': 2 }), [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]); [{ 'b': 1 }, []],
deepEqual(_.where(objects, { 'a': 1, 'b': 2 }), [{ 'a': 1, 'b': 2 }]); [{ 'b': 2 }, [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]],
[{ 'a': 1, 'b': 2 }, [{ 'a': 1, 'b': 2 }]]
];
_.each(pairs, function(pair) {
var actual = _.where(objects, pair[0]);
deepEqual(actual, pair[1]);
ok(_.isEmpty(_.difference(actual, objects)));
});
}); });
test('should not filter by inherited `source` properties', 2, function() { test('should not filter by inherited `source` properties', 1, function() {
function Foo() {} function Foo() {}
Foo.prototype = { 'a': 2 }; Foo.prototype = { 'a': 2 };
@@ -10158,7 +10166,6 @@
actual = _.where(objects, source); actual = _.where(objects, source);
deepEqual(actual, expected); deepEqual(actual, expected);
ok(_.isEmpty(_.difference(actual, objects)));
}); });
test('should filter by problem JScript properties (test in IE < 9)', 1, function() { test('should filter by problem JScript properties (test in IE < 9)', 1, function() {
@@ -10166,7 +10173,7 @@
deepEqual(_.where(collection, shadowedObject), [shadowedObject]); deepEqual(_.where(collection, shadowedObject), [shadowedObject]);
}); });
test('should work with an object for `collection`', 2, function() { test('should work with an object for `collection`', 1, function() {
var collection = { var collection = {
'x': { 'a': 1 }, 'x': { 'a': 1 },
'y': { 'a': 3 }, 'y': { 'a': 3 },
@@ -10177,7 +10184,6 @@
actual = _.where(collection, { 'a': 1 }); actual = _.where(collection, { 'a': 1 });
deepEqual(actual, expected); deepEqual(actual, expected);
ok(_.isEmpty(_.difference(actual, _.values(collection))));
}); });
test('should work with a function for `source`', 1, function() { test('should work with a function for `source`', 1, function() {
@@ -10198,32 +10204,38 @@
deepEqual(actual, expected); deepEqual(actual, expected);
}); });
test('should perform a deep partial comparison of `source`', 2, function() { test('should perform a deep partial comparison of `source`', 1, function() {
var collection = [{ 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }], var collection = [{ 'a': { 'b': { 'c': 1, 'd': 2 }, 'e': 3 }, 'f': 4 }],
expected = collection.slice(), expected = collection.slice(),
actual = _.where(collection, { 'a': { 'b': { 'c': 1 } } }); actual = _.where(collection, { 'a': { 'b': { 'c': 1 } } });
deepEqual(actual, expected); deepEqual(actual, expected);
ok(_.isEmpty(_.difference(actual, collection)));
}); });
test('should search of arrays for values', 2, function() { test('should search arrays of `source` for values', 4, function() {
var collection = [{ 'a': [1, 2] }], var collection = [{ 'a': ['b'] }, { 'a': ['c', 'd'] }],
expected = collection.slice(); actual = _.where(collection, { 'a': ['d'] });
deepEqual(_.where(collection, { 'a': [] }), []); deepEqual(actual, [collection[1]]);
deepEqual(_.where(collection, { 'a': [2] }), expected);
actual = _.where(collection, { 'a': [] });
deepEqual(actual, []);
actual = _.where(collection, { 'a': ['b', 'd'] });
deepEqual(actual, []);
actual = _.where(collection, { 'a': ['d', 'b'] });
deepEqual(actual, []);
}); });
test('should perform a partial comparison of *all* objects within arrays of `source`', 2, function() { test('should perform a partial comparison of all objects within arrays of `source`', 1, function() {
var collection = [ var collection = [
{ 'a': [{ 'b': 1, 'c': 2, 'd': 3 }, { 'b': 4, 'c': 5, 'd': 6 }] }, { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5, 'd': 6 }] },
{ 'a': [{ 'b': 1, 'c': 2, 'd': 3 }, { 'b': 4, 'c': 6, 'd': 7 }] } { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 6, 'd': 7 }] }
]; ];
var actual = _.where(collection, { 'a': [{ 'b': 1, 'c': 2 }, { 'b': 4, 'c': 5 }] }); var actual = _.where(collection, { 'a': [{ 'b': 1 }, { 'b': 4, 'c': 5 }] });
deepEqual(actual, [collection[0]]); deepEqual(actual, [collection[0]]);
ok(_.isEmpty(_.difference(actual, collection)));
}); });
test('should handle a `source` with `undefined` values', 4, function() { test('should handle a `source` with `undefined` values', 4, function() {