Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

WIP: a parallel toEqual2, moves to underscore's toEqual as it doesn't…

… touch existing objects. Also, more explict tests for toEqual2 (existing toEqual is tested far too indirectly for a refactor
  • Loading branch information...
commit 1854b1b65132d062af43946f5052719e2e2ffd7f 1 parent a378ed3
Davis W. Frank authored
Showing with 176 additions and 104 deletions.
  1. +26 −17 lib/jasmine-core/jasmine.js
  2. +126 −78 spec/core/ToEqualSpec.js
  3. +24 −9 src/core/Env.js
View
43 lib/jasmine-core/jasmine.js
@@ -986,26 +986,22 @@ jasmine.Env.prototype.addEqualityTester = function (equalityTester) {
jasmine.Env.prototype.equals2_ = function eq(a, b, stack) {
stack = stack || [];
- function hasKey(obj, keyName) {
- return obj !== null && obj[keyName] !== jasmine.undefined;
- }
-
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
- if (a === b) return a !== 0 || 1 / a == 1 / b;
+ if (a === b) {
+ return a !== 0 || 1 / a == 1 / b;
+ }
// A strict comparison is necessary because `null == undefined`.
- if (a == null || b == null) return a === b;
-
- // Unwrap any wrapped objects.
-// if (a._chain) a = a._wrapped;
-// if (b._chain) b = b._wrapped;
-// // Invoke a custom `isEqual` method if one is provided.
-// if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
-// if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
- // Compare `[[Class]]` names.
+ if (a == null || b == null) {
+ return a === b;
+ }
+ // Compare `[[Class]]` names.
var className = toString.call(a);
- if (className != toString.call(b)) return false;
+ if (className != toString.call(b)) {
+ return false;
+ }
+
switch (className) {
// Strings, numbers, dates, and booleans are compared by value.
case '[object String]':
@@ -1029,7 +1025,11 @@ jasmine.Env.prototype.equals2_ = function eq(a, b, stack) {
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase;
}
- if (typeof a != 'object' || typeof b != 'object') return false;
+
+ if (typeof a != 'object' || typeof b != 'object') {
+ return false;
+ }
+
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = stack.length;
@@ -1054,8 +1054,16 @@ jasmine.Env.prototype.equals2_ = function eq(a, b, stack) {
}
}
} else {
+
// Objects with different constructors are not equivalent.
- if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
+ if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) {
+ return false;
+ }
+
+ function hasKey(obj, keyName) {
+ return obj !== null && obj[keyName] !== jasmine.undefined;
+ }
+
// Deep compare objects.
for (var key in a) {
if (hasKey(a, key)) {
@@ -1075,6 +1083,7 @@ jasmine.Env.prototype.equals2_ = function eq(a, b, stack) {
}
// Remove the first object from the stack of traversed objects.
stack.pop();
+
return result;
};
/** No-op base class for Jasmine reporters.
View
204 spec/core/ToEqualSpec.js
@@ -1,20 +1,8 @@
-// TODO: This is a nice replacement for toEqual
-//
-// * Consider moving to jsDiff for differencing objects
-// *
-
describe("Matchers", function() {
var env, suite, spec;
- // TODO: move this to SpecHelper?
-
- function match(value) {
- return spec.expect(value);
- }
-
- // TODO: this test has WAY too much knowledge of how matchers work - proof tha the results object is hard to use and should have a better interface
function lastResult() {
- return spec.addMatcherResult.mostRecentCall.args[0];
+ return (spec.addMatcherResult.mostRecentCall.args[0]).passed();
}
describe("toEqual2", function() {
@@ -27,93 +15,144 @@ describe("Matchers", function() {
});
});
spyOn(spec, 'addMatcherResult');
-
- // TODO: if the results object is easier to use, this could go away?
- this.addMatchers({
- toPass:function() {
- return lastResult().passed();
- },
- toFail:function() {
- return !lastResult().passed();
- }
- });
});
it("should compare against null", function() {
- expect(match(null).toEqual2(null)).toPass();
- expect(match(null).not.toEqual2(null)).toFail();
+ spec.expect(null).toEqual2(null);
+ expect(lastResult()).toEqual2(true);
- expect(match(null).toEqual2({})).toFail();
- expect(match(null).not.toEqual2({})).toPass();
+ spec.expect(null).not.toEqual2(null);
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect(null).toEqual2({});
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect(null).not.toEqual2({});
+ expect(lastResult()).toEqual2(true);
});
it("should compare against undefined", function() {
- expect(match(undefined).toEqual2(undefined)).toPass();
- expect(match(undefined).not.toEqual2(undefined)).toFail();
+ spec.expect(undefined).toEqual2(undefined);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect(undefined).not.toEqual2(undefined);
+ expect(lastResult()).toEqual2(false);
- expect(match(undefined).toEqual2({})).toFail();
- expect(match(undefined).not.toEqual2({})).toPass();
+ spec.expect(undefined).toEqual2({});
+ expect(lastResult()).toEqual2(false);
- expect(match(undefined).not.toEqual2(null)).toPass();
- expect(match(undefined).toEqual2(null)).toFail();
+ spec.expect(undefined).not.toEqual2({});
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect(undefined).not.toEqual2(null);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect(undefined).toEqual2(null);
+ expect(lastResult()).toEqual2(false);
});
it("should compare Booleans", function() {
- expect(match(true).toEqual2(true)).toPass();
- expect(match(true).not.toEqual2(false)).toPass();
+ spec.expect(true).toEqual2(true);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect(true).not.toEqual2(false);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect(false).toEqual2(true);
+ expect(lastResult()).toEqual2(false);
- expect(match(false).toEqual2(true)).toFail();
- expect(match(false).not.toEqual2(false)).toFail();
+ spec.expect(false).not.toEqual2(false);
+ expect(lastResult()).toEqual2(false);
});
it("should compare Strings", function() {
- expect((match("cat").toEqual("cat"))).toPass();
- expect((match("cat").not.toEqual("cat"))).toFail();
+ spec.expect("cat").toEqual2("cat");
+ expect(lastResult()).toEqual2(true);
- expect((match("cat").toEqual("123"))).toFail();
- expect((match("cat").not.toEqual("123"))).toPass();
+ spec.expect("cat").not.toEqual2("cat");
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect("cat").toEqual2("123");
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect("cat").not.toEqual2("123");
+ expect(lastResult()).toEqual2(true);
});
it("should compare Dates", function() {
- expect((match(new Date(2008, 1, 3, 15, 17, 19, 1234)).toEqual(new Date(2009, 1, 3, 15, 17, 19, 1234)))).toFail();
- expect((match(new Date(2008, 1, 3, 15, 17, 19, 1234)).not.toEqual(new Date(2009, 1, 3, 15, 17, 19, 1234)))).toPass();
+ var date = new Date(2008, 1, 3, 15, 17, 19, 1234);
+ var anotherDate = new Date(2009, 1, 3, 15, 17, 19, 1234);
+
+ spec.expect(date).toEqual2(date);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect(date).not.toEqual2(date);
+ expect(lastResult()).toEqual2(false);
- expect((match(new Date(2008, 1, 3, 15, 17, 19, 1234)).toEqual(new Date(2008, 1, 3, 15, 17, 19, 1234)))).toPass();
- expect((match(new Date(2008, 1, 3, 15, 17, 19, 1234)).not.toEqual(new Date(2008, 1, 3, 15, 17, 19, 1234)))).toFail();
+ spec.expect(date).toEqual2(anotherDate);
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect(date).not.toEqual2(anotherDate);
+ expect(lastResult()).toEqual2(true);
});
it("should compare Numbers", function() {
- expect((match(5).toEqual(5))).toPass();
- expect((match(5).not.toEqual(5))).toFail();
+ spec.expect(5).toEqual2(5);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect(5).not.toEqual2(5);
+ expect(lastResult()).toEqual2(false);
- expect((match(5).toEqual(3276.7))).toFail();
- expect((match(5).not.toEqual(3276.7))).toPass();
+ spec.expect(5).toEqual2(3276.7);
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect(5).not.toEqual2(3276.7);
+ expect(lastResult()).toEqual2(true);
});
it("should compare objects", function() {
- expect(match({a:1}).toEqual({a:1})).toPass();
- expect(match({a:1}).not.toEqual({a:1})).toFail();
- expect(match({a:1}).toEqual({a:2})).toFail();
- expect(match({a:1}).not.toEqual({a:2})).toPass();
+ spec.expect({a:1}).toEqual2({a:1});
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect({a:1}).not.toEqual2({a:1});
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect({a:1}).toEqual2({a:2});
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect({a:1}).not.toEqual2({a:2});
+ expect(lastResult()).toEqual2(true);
});
it("should compare objects with cycles", function() {
var circularGraph = {};
circularGraph.referenceToSelf = circularGraph;
- expect((match(circularGraph).toEqual2(circularGraph))).toPass();
- expect((match(circularGraph).not.toEqual2(circularGraph))).toFail();
+ spec.expect(circularGraph).toEqual2(circularGraph);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect(circularGraph).not.toEqual2(circularGraph);
+ expect(lastResult()).toEqual2(false);
});
it("should compare Arrays", function() {
- expect(match([1, 2, 3]).toEqual2([1, 2, 3])).toPass();
- expect(match([1, 2, 3]).not.toEqual2([1, 2, 3])).toFail();
+ spec.expect([1, 2, 3]).toEqual2([1, 2, 3]);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect([1, 2, 3]).not.toEqual2([1, 2, 3]);
+ expect(lastResult()).toEqual2(false);
- expect(match([1, 2, 3]).toEqual2([3, 2, 1])).toFail();
- expect(match([1, 2, 3]).not.toEqual2([3, 2, 1])).toPass();
+ spec.expect([1, 2, 3]).toEqual2([3, 2, 1]);
+ expect(lastResult()).toEqual2(false);
- expect(match([1]).toEqual2([3, 2, 1])).toFail();
- expect(match([1]).not.toEqual2([3, 2, 1])).toPass();
+ spec.expect([1, 2, 3]).not.toEqual2([3, 2, 1]);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect([1]).toEqual2([3, 2, 1]);
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect([1]).not.toEqual2([3, 2, 1]);
+ expect(lastResult()).toEqual2(true);
});
it("should compare functions", function() {
@@ -124,30 +163,39 @@ describe("Matchers", function() {
return 0;
};
- expect(match(functionA).toEqual2(functionB)).toFail();
- expect(match(functionA).not.toEqual2(functionB)).toPass();
+ spec.expect(functionA).toEqual2(functionB);
+ expect(lastResult()).toEqual2(false);
+
+ spec.expect(functionA).not.toEqual2(functionB);
+ expect(lastResult()).toEqual2(true);
var functionC = functionB;
- expect(match(functionC).toEqual2(functionB)).toPass();
- expect(match(functionC).not.toEqual2(functionB)).toFail();
+ spec.expect(functionC).toEqual2(functionB);
+ expect(lastResult()).toEqual2(true);
+
+ spec.expect(functionC).not.toEqual2(functionB);
+ expect(lastResult()).toEqual2(false);
});
- it("should report its message", function() {
- var actual = 'a';
- var matcher = match(actual);
- var expected = 'b';
- matcher.toEqual2(expected);
+ describe("message on failure", function() {
- var result = lastResult();
+ it("should explain the object's differences", function() {
+ var actual = {
+ foo: 'a',
+ bar: 'b',
+ baz: 'c'
+ };
+ var expected = {
+ bar: 'b',
+ quux: 'd'
+ };
- expect(result.matcherName).toEqual("toEqual2");
- expect(result.passed()).toFail();
- expect(result.message).toMatch(jasmine.pp(actual));
- expect(result.message).toMatch(jasmine.pp(expected));
- expect(result.expected).toEqual(expected);
- expect(result.actual).toEqual(actual);
- });
+ spec.expect(actual).toEqual2(expected);
+ var result = spec.addMatcherResult.mostRecentCall.args[0];
+ expect(result.message).toEqual2("Expected { foo : 'a', bar : 'b', baz : 'c' } to equal2 { bar : 'b', quux : 'd' }.");
+ });
+ });
});
});
View
33 src/core/Env.js
@@ -280,19 +280,21 @@ jasmine.Env.prototype.addEqualityTester = function (equalityTester) {
jasmine.Env.prototype.equals2_ = function eq(a, b, stack) {
stack = stack || [];
- function hasKey(obj, keyName) {
- return obj !== null && obj[keyName] !== jasmine.undefined;
- }
-
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
- if (a === b) return a !== 0 || 1 / a == 1 / b;
+ if (a === b) {
+ return a !== 0 || 1 / a == 1 / b;
+ }
// A strict comparison is necessary because `null == undefined`.
- if (a == null || b == null) return a === b;
+ if (a == null || b == null) {
+ return a === b;
+ }
// Compare `[[Class]]` names.
var className = toString.call(a);
- if (className != toString.call(b)) return false;
+ if (className != toString.call(b)) {
+ return false;
+ }
switch (className) {
// Strings, numbers, dates, and booleans are compared by value.
@@ -317,7 +319,11 @@ jasmine.Env.prototype.equals2_ = function eq(a, b, stack) {
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase;
}
- if (typeof a != 'object' || typeof b != 'object') return false;
+
+ if (typeof a != 'object' || typeof b != 'object') {
+ return false;
+ }
+
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = stack.length;
@@ -342,8 +348,16 @@ jasmine.Env.prototype.equals2_ = function eq(a, b, stack) {
}
}
} else {
+
// Objects with different constructors are not equivalent.
- if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
+ if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) {
+ return false;
+ }
+
+ function hasKey(obj, keyName) {
+ return obj !== null && obj[keyName] !== jasmine.undefined;
+ }
+
// Deep compare objects.
for (var key in a) {
if (hasKey(a, key)) {
@@ -363,5 +377,6 @@ jasmine.Env.prototype.equals2_ = function eq(a, b, stack) {
}
// Remove the first object from the stack of traversed objects.
stack.pop();
+
return result;
};
Please sign in to comment.
Something went wrong with that request. Please try again.