Array equality treats undefined elements as equal however they got in there

- Fixes #786
This commit is contained in:
Gregg Van Hove
2016-02-22 11:06:59 -08:00
parent 602f5bc08a
commit 5458f2f18d
3 changed files with 95 additions and 48 deletions

View File

@@ -2879,14 +2879,22 @@ getJasmineRequireObj().matchersUtil = function(j$) {
var size = 0; var size = 0;
// Recursively compare objects and arrays. // Recursively compare objects and arrays.
// Compare array lengths to determine if a deep comparison is necessary. // Compare array lengths to determine if a deep comparison is necessary.
if (className == '[object Array]' && a.length !== b.length) { if (className == '[object Array]') {
result = false; size = a.length;
if (size !== b.length) {
return false;
} }
if (result) { while (size--) {
result = eq(a[size], b[size], aStack, bStack, customTesters);
if (!result) {
return false;
}
}
} else {
// Objects with different constructors are not equivalent, but `Object`s // Objects with different constructors are not equivalent, but `Object`s
// or `Array`s from different frames are. // or `Array`s from different frames are.
if (className !== '[object Array]') {
var aCtor = a.constructor, bCtor = b.constructor; var aCtor = a.constructor, bCtor = b.constructor;
if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor &&
isFunction(bCtor) && bCtor instanceof bCtor)) { isFunction(bCtor) && bCtor instanceof bCtor)) {
@@ -2895,11 +2903,11 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
// Deep compare objects. // Deep compare objects.
var aKeys = keys(a), key; var aKeys = keys(a, className == '[object Array]'), key;
size = aKeys.length; size = aKeys.length;
// Ensure that both objects contain the same number of properties before comparing deep equality. // Ensure that both objects contain the same number of properties before comparing deep equality.
if (keys(b).length !== size) { return false; } if (keys(b, className == '[object Array]').length !== size) { return false; }
while (size--) { while (size--) {
key = aKeys[size]; key = aKeys[size];
@@ -2910,15 +2918,14 @@ getJasmineRequireObj().matchersUtil = function(j$) {
return false; return false;
} }
} }
}
// Remove the first object from the stack of traversed objects. // Remove the first object from the stack of traversed objects.
aStack.pop(); aStack.pop();
bStack.pop(); bStack.pop();
return result; return result;
function keys(obj) { function keys(obj, isArray) {
return Object.keys ? Object.keys(obj) : var allKeys = Object.keys ? Object.keys(obj) :
(function(o) { (function(o) {
var keys = []; var keys = [];
for (var key in o) { for (var key in o) {
@@ -2928,6 +2935,19 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
return keys; return keys;
})(obj); })(obj);
if (!isArray) {
return allKeys;
}
var extraKeys = [];
for (var i in allKeys) {
if (!allKeys[i].match(/^[0-9]+$/)) {
extraKeys.push(key);
}
}
return extraKeys;
} }
function has(obj, key) { function has(obj, key) {

View File

@@ -54,6 +54,13 @@ describe("matchersUtil", function() {
expect(jasmineUnderTest.matchersUtil.equals([1, 2], [1, 2])).toBe(true); expect(jasmineUnderTest.matchersUtil.equals([1, 2], [1, 2])).toBe(true);
}); });
it("passes for Arrays that are equivalent, with elements added by changing length", function() {
var foo = [];
foo.length = 1;
expect(jasmineUnderTest.matchersUtil.equals(foo, [undefined])).toBe(true);
});
it("fails for Arrays that are not equivalent", function() { it("fails for Arrays that are not equivalent", function() {
expect(jasmineUnderTest.matchersUtil.equals([1, 2], [1, 2, 3])).toBe(false); expect(jasmineUnderTest.matchersUtil.equals([1, 2], [1, 2, 3])).toBe(false);
}); });

View File

@@ -161,14 +161,22 @@ getJasmineRequireObj().matchersUtil = function(j$) {
var size = 0; var size = 0;
// Recursively compare objects and arrays. // Recursively compare objects and arrays.
// Compare array lengths to determine if a deep comparison is necessary. // Compare array lengths to determine if a deep comparison is necessary.
if (className == '[object Array]' && a.length !== b.length) { if (className == '[object Array]') {
result = false; size = a.length;
if (size !== b.length) {
return false;
} }
if (result) { while (size--) {
result = eq(a[size], b[size], aStack, bStack, customTesters);
if (!result) {
return false;
}
}
} else {
// Objects with different constructors are not equivalent, but `Object`s // Objects with different constructors are not equivalent, but `Object`s
// or `Array`s from different frames are. // or `Array`s from different frames are.
if (className !== '[object Array]') {
var aCtor = a.constructor, bCtor = b.constructor; var aCtor = a.constructor, bCtor = b.constructor;
if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor &&
isFunction(bCtor) && bCtor instanceof bCtor)) { isFunction(bCtor) && bCtor instanceof bCtor)) {
@@ -177,11 +185,11 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
// Deep compare objects. // Deep compare objects.
var aKeys = keys(a), key; var aKeys = keys(a, className == '[object Array]'), key;
size = aKeys.length; size = aKeys.length;
// Ensure that both objects contain the same number of properties before comparing deep equality. // Ensure that both objects contain the same number of properties before comparing deep equality.
if (keys(b).length !== size) { return false; } if (keys(b, className == '[object Array]').length !== size) { return false; }
while (size--) { while (size--) {
key = aKeys[size]; key = aKeys[size];
@@ -192,15 +200,14 @@ getJasmineRequireObj().matchersUtil = function(j$) {
return false; return false;
} }
} }
}
// Remove the first object from the stack of traversed objects. // Remove the first object from the stack of traversed objects.
aStack.pop(); aStack.pop();
bStack.pop(); bStack.pop();
return result; return result;
function keys(obj) { function keys(obj, isArray) {
return Object.keys ? Object.keys(obj) : var allKeys = Object.keys ? Object.keys(obj) :
(function(o) { (function(o) {
var keys = []; var keys = [];
for (var key in o) { for (var key in o) {
@@ -210,6 +217,19 @@ getJasmineRequireObj().matchersUtil = function(j$) {
} }
return keys; return keys;
})(obj); })(obj);
if (!isArray) {
return allKeys;
}
var extraKeys = [];
for (var i in allKeys) {
if (!allKeys[i].match(/^[0-9]+$/)) {
extraKeys.push(key);
}
}
return extraKeys;
} }
function has(obj, key) { function has(obj, key) {