diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index 446e42b0..55efa172 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -2879,36 +2879,43 @@ getJasmineRequireObj().matchersUtil = function(j$) { var size = 0; // Recursively compare objects and arrays. // Compare array lengths to determine if a deep comparison is necessary. - if (className == '[object Array]' && a.length !== b.length) { - result = false; - } + if (className == '[object Array]') { + size = a.length; + if (size !== b.length) { + return false; + } - if (result) { - // Objects with different constructors are not equivalent, but `Object`s - // or `Array`s from different frames are. - if (className !== '[object Array]') { - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && - isFunction(bCtor) && bCtor instanceof bCtor)) { + while (size--) { + result = eq(a[size], b[size], aStack, bStack, customTesters); + if (!result) { return false; } } + } else { - // Deep compare objects. - var aKeys = keys(a), key; - size = aKeys.length; + // Objects with different constructors are not equivalent, but `Object`s + // or `Array`s from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && + isFunction(bCtor) && bCtor instanceof bCtor)) { + return false; + } + } - // Ensure that both objects contain the same number of properties before comparing deep equality. - if (keys(b).length !== size) { return false; } + // Deep compare objects. + var aKeys = keys(a, className == '[object Array]'), key; + size = aKeys.length; - while (size--) { - key = aKeys[size]; - // Deep compare each member - result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters); + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (keys(b, className == '[object Array]').length !== size) { return false; } - if (!result) { - return false; - } + while (size--) { + key = aKeys[size]; + // Deep compare each member + result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters); + + if (!result) { + return false; } } // Remove the first object from the stack of traversed objects. @@ -2917,8 +2924,8 @@ getJasmineRequireObj().matchersUtil = function(j$) { return result; - function keys(obj) { - return Object.keys ? Object.keys(obj) : + function keys(obj, isArray) { + var allKeys = Object.keys ? Object.keys(obj) : (function(o) { var keys = []; for (var key in o) { @@ -2928,6 +2935,19 @@ getJasmineRequireObj().matchersUtil = function(j$) { } return keys; })(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) { diff --git a/spec/core/matchers/matchersUtilSpec.js b/spec/core/matchers/matchersUtilSpec.js index 1ad5b210..3f0deac1 100644 --- a/spec/core/matchers/matchersUtilSpec.js +++ b/spec/core/matchers/matchersUtilSpec.js @@ -54,6 +54,13 @@ describe("matchersUtil", function() { 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() { expect(jasmineUnderTest.matchersUtil.equals([1, 2], [1, 2, 3])).toBe(false); }); diff --git a/src/core/matchers/matchersUtil.js b/src/core/matchers/matchersUtil.js index 2c9b716c..50b376c8 100644 --- a/src/core/matchers/matchersUtil.js +++ b/src/core/matchers/matchersUtil.js @@ -161,36 +161,43 @@ getJasmineRequireObj().matchersUtil = function(j$) { var size = 0; // Recursively compare objects and arrays. // Compare array lengths to determine if a deep comparison is necessary. - if (className == '[object Array]' && a.length !== b.length) { - result = false; - } + if (className == '[object Array]') { + size = a.length; + if (size !== b.length) { + return false; + } - if (result) { - // Objects with different constructors are not equivalent, but `Object`s - // or `Array`s from different frames are. - if (className !== '[object Array]') { - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && - isFunction(bCtor) && bCtor instanceof bCtor)) { + while (size--) { + result = eq(a[size], b[size], aStack, bStack, customTesters); + if (!result) { return false; } } + } else { - // Deep compare objects. - var aKeys = keys(a), key; - size = aKeys.length; + // Objects with different constructors are not equivalent, but `Object`s + // or `Array`s from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && + isFunction(bCtor) && bCtor instanceof bCtor)) { + return false; + } + } - // Ensure that both objects contain the same number of properties before comparing deep equality. - if (keys(b).length !== size) { return false; } + // Deep compare objects. + var aKeys = keys(a, className == '[object Array]'), key; + size = aKeys.length; - while (size--) { - key = aKeys[size]; - // Deep compare each member - result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters); + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (keys(b, className == '[object Array]').length !== size) { return false; } - if (!result) { - return false; - } + while (size--) { + key = aKeys[size]; + // Deep compare each member + result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters); + + if (!result) { + return false; } } // Remove the first object from the stack of traversed objects. @@ -199,8 +206,8 @@ getJasmineRequireObj().matchersUtil = function(j$) { return result; - function keys(obj) { - return Object.keys ? Object.keys(obj) : + function keys(obj, isArray) { + var allKeys = Object.keys ? Object.keys(obj) : (function(o) { var keys = []; for (var key in o) { @@ -210,6 +217,19 @@ getJasmineRequireObj().matchersUtil = function(j$) { } return keys; })(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) {