Add arrayWithExactContents asymmetric matcher

- Fixes #817
This commit is contained in:
Gregg Van Hove
2017-08-04 12:07:09 -07:00
parent 8c0a8a1b33
commit 8ad9abb19a
7 changed files with 149 additions and 8 deletions

View File

@@ -63,6 +63,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.matchersUtil = jRequire.matchersUtil(j$);
j$.ObjectContaining = jRequire.ObjectContaining(j$);
j$.ArrayContaining = jRequire.ArrayContaining(j$);
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
j$.pp = jRequire.pp(j$);
j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher();
@@ -280,6 +281,17 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return new j$.ArrayContaining(sample);
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
* @name jasmine.arrayWithExactContents
* @function
* @param {Array} sample
*/
j$.arrayWithExactContents = function(sample) {
return new j$.ArrayWithExactContents(sample);
};
/**
* Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
* @name jasmine.createSpy
@@ -1417,8 +1429,9 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
}
ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
var className = Object.prototype.toString.call(this.sample);
if (className !== '[object Array]') { throw new Error('You must provide an array to arrayContaining, not \'' + this.sample + '\'.'); }
if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.');
}
for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i];
@@ -1437,6 +1450,38 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
return ArrayContaining;
};
getJasmineRequireObj().ArrayWithExactContents = function(j$) {
function ArrayWithExactContents(sample) {
this.sample = sample;
}
ArrayWithExactContents.prototype.asymmetricMatch = function(other, customTesters) {
if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.');
}
if (this.sample.length !== other.length) {
return false;
}
for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i];
if (!j$.matchersUtil.contains(other, item, customTesters)) {
return false;
}
}
return true;
};
ArrayWithExactContents.prototype.jasmineToString = function() {
return '<jasmine.arrayWithExactContents ' + j$.pp(this.sample) + '>';
};
return ArrayWithExactContents;
};
getJasmineRequireObj().ObjectContaining = function(j$) {
function ObjectContaining(sample) {
@@ -2391,13 +2436,17 @@ getJasmineRequireObj().matchersUtil = function(j$) {
if (asymmetricA) {
result = a.asymmetricMatch(b, customTesters);
diffBuilder.record(a, b);
if (!result) {
diffBuilder.record(a, b);
}
return result;
}
if (asymmetricB) {
result = b.asymmetricMatch(a, customTesters);
diffBuilder.record(a, b);
if (!result) {
diffBuilder.record(a, b);
}
return result;
}
}

View File

@@ -0,0 +1,47 @@
describe("ArrayWithExactContents", function() {
it("matches an array with the same items in a different order", function() {
var matcher = new jasmineUnderTest.ArrayWithExactContents(['a', 2, /a/]);
expect(matcher.asymmetricMatch([2, 'a', /a/])).toBe(true);
});
it("does not work when not passed an array", function() {
var matcher = new jasmineUnderTest.ArrayWithExactContents("foo");
expect(function() {
matcher.asymmetricMatch([]);
}).toThrowError(/not 'foo'/);
});
it("does not match when an item is missing", function() {
var matcher = new jasmineUnderTest.ArrayWithExactContents(['a', 2, /a/]);
expect(matcher.asymmetricMatch(['a', 2])).toBe(false);
expect(matcher.asymmetricMatch(['a', 2, undefined])).toBe(false);
});
it("does not match when there is an extra item", function() {
var matcher = new jasmineUnderTest.ArrayWithExactContents(['a']);
expect(matcher.asymmetricMatch(['a', 2])).toBe(false);
});
it("jasmineToStrings itself", function() {
var matcher = new jasmineUnderTest.ArrayWithExactContents([]);
expect(matcher.jasmineToString()).toMatch("<jasmine.arrayWithExactContents");
});
it("uses custom equality testers", function() {
var tester = function(a, b) {
// All "foo*" strings match each other.
if (typeof a == "string" && typeof b == "string" &&
a.substr(0, 3) == "foo" && b.substr(0, 3) == "foo") {
return true;
}
};
var matcher = new jasmineUnderTest.ArrayWithExactContents(["fooVal"]);
expect(matcher.asymmetricMatch(["fooBar"], [tester])).toBe(true);
});
});

View File

@@ -67,8 +67,9 @@ describe("Custom Matchers (Integration)", function() {
};
env.addCustomEqualityTester(customEqualityFn);
env.expect({foo: 'fooValue'}).toEqual(jasmine.objectContaining({foo: 'fooBar'}));
env.expect(['fooValue']).toEqual(jasmine.arrayContaining(['fooBar']));
env.expect({foo: 'fooValue'}).toEqual(jasmineUnderTest.objectContaining({foo: 'fooBar'}));
env.expect(['fooValue', 'things']).toEqual(jasmineUnderTest.arrayContaining(['fooBar']));
env.expect(['fooValue']).toEqual(jasmineUnderTest.arrayWithExactContents(['fooBar']));
});
var specExpectations = function(result) {

View File

@@ -4,8 +4,9 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
}
ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
var className = Object.prototype.toString.call(this.sample);
if (className !== '[object Array]') { throw new Error('You must provide an array to arrayContaining, not \'' + this.sample + '\'.'); }
if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.');
}
for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i];

View File

@@ -0,0 +1,31 @@
getJasmineRequireObj().ArrayWithExactContents = function(j$) {
function ArrayWithExactContents(sample) {
this.sample = sample;
}
ArrayWithExactContents.prototype.asymmetricMatch = function(other, customTesters) {
if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.');
}
if (this.sample.length !== other.length) {
return false;
}
for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i];
if (!j$.matchersUtil.contains(other, item, customTesters)) {
return false;
}
}
return true;
};
ArrayWithExactContents.prototype.jasmineToString = function() {
return '<jasmine.arrayWithExactContents ' + j$.pp(this.sample) + '>';
};
return ArrayWithExactContents;
};

View File

@@ -152,6 +152,17 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return new j$.ArrayContaining(sample);
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
* @name jasmine.arrayWithExactContents
* @function
* @param {Array} sample
*/
j$.arrayWithExactContents = function(sample) {
return new j$.ArrayWithExactContents(sample);
};
/**
* Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
* @name jasmine.createSpy

View File

@@ -41,6 +41,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.matchersUtil = jRequire.matchersUtil(j$);
j$.ObjectContaining = jRequire.ObjectContaining(j$);
j$.ArrayContaining = jRequire.ArrayContaining(j$);
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
j$.pp = jRequire.pp(j$);
j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher();