mapContaining and setContaining asymmetric matchers
This commit is contained in:
41
src/core/asymmetric_equality/MapContaining.js
Normal file
41
src/core/asymmetric_equality/MapContaining.js
Normal file
@@ -0,0 +1,41 @@
|
||||
getJasmineRequireObj().MapContaining = function(j$) {
|
||||
function MapContaining(sample) {
|
||||
if (!j$.isMap(sample)) {
|
||||
throw new Error('You must provide a map to `mapContaining`, not ' + j$.pp(sample));
|
||||
}
|
||||
|
||||
this.sample = sample;
|
||||
}
|
||||
|
||||
MapContaining.prototype.asymmetricMatch = function(other, customTesters) {
|
||||
if (!j$.isMap(other)) return false;
|
||||
|
||||
var hasAllMatches = true;
|
||||
j$.util.forEachBreakable(this.sample, function(breakLoop, value, key) {
|
||||
// for each key/value pair in `sample`
|
||||
// there should be at least one pair in `other` whose key and value both match
|
||||
var hasMatch = false;
|
||||
j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) {
|
||||
if (
|
||||
j$.matchersUtil.equals(oKey, key, customTesters)
|
||||
&& j$.matchersUtil.equals(oValue, value, customTesters)
|
||||
) {
|
||||
hasMatch = true;
|
||||
oBreakLoop();
|
||||
}
|
||||
});
|
||||
if (!hasMatch) {
|
||||
hasAllMatches = false;
|
||||
breakLoop();
|
||||
}
|
||||
});
|
||||
|
||||
return hasAllMatches;
|
||||
};
|
||||
|
||||
MapContaining.prototype.jasmineToString = function() {
|
||||
return '<jasmine.mapContaining(' + j$.pp(this.sample) + ')>';
|
||||
};
|
||||
|
||||
return MapContaining;
|
||||
};
|
||||
39
src/core/asymmetric_equality/SetContaining.js
Normal file
39
src/core/asymmetric_equality/SetContaining.js
Normal file
@@ -0,0 +1,39 @@
|
||||
getJasmineRequireObj().SetContaining = function(j$) {
|
||||
function SetContaining(sample) {
|
||||
if (!j$.isSet(sample)) {
|
||||
throw new Error('You must provide a set to `setContaining`, not ' + j$.pp(sample));
|
||||
}
|
||||
|
||||
this.sample = sample;
|
||||
}
|
||||
|
||||
SetContaining.prototype.asymmetricMatch = function(other, customTesters) {
|
||||
if (!j$.isSet(other)) return false;
|
||||
|
||||
var hasAllMatches = true;
|
||||
j$.util.forEachBreakable(this.sample, function(breakLoop, item) {
|
||||
// for each item in `sample` there should be at least one matching item in `other`
|
||||
// (not using `j$.matchersUtil.contains` because it compares set members by reference,
|
||||
// not by deep value equality)
|
||||
var hasMatch = false;
|
||||
j$.util.forEachBreakable(other, function(oBreakLoop, oItem) {
|
||||
if (j$.matchersUtil.equals(oItem, item, customTesters)) {
|
||||
hasMatch = true;
|
||||
oBreakLoop();
|
||||
}
|
||||
});
|
||||
if (!hasMatch) {
|
||||
hasAllMatches = false;
|
||||
breakLoop();
|
||||
}
|
||||
});
|
||||
|
||||
return hasAllMatches;
|
||||
};
|
||||
|
||||
SetContaining.prototype.jasmineToString = function() {
|
||||
return '<jasmine.setContaining(' + j$.pp(this.sample) + ')>';
|
||||
};
|
||||
|
||||
return SetContaining;
|
||||
};
|
||||
@@ -128,6 +128,8 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
|
||||
j$.isMap = function(obj) {
|
||||
return (
|
||||
obj !== null &&
|
||||
typeof obj !== 'undefined' &&
|
||||
typeof jasmineGlobal.Map !== 'undefined' &&
|
||||
obj.constructor === jasmineGlobal.Map
|
||||
);
|
||||
@@ -135,6 +137,8 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
|
||||
j$.isSet = function(obj) {
|
||||
return (
|
||||
obj !== null &&
|
||||
typeof obj !== 'undefined' &&
|
||||
typeof jasmineGlobal.Set !== 'undefined' &&
|
||||
obj.constructor === jasmineGlobal.Set
|
||||
);
|
||||
@@ -279,6 +283,32 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
||||
return new j$.ArrayWithExactContents(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 every key/value pair in the sample passes the deep equality comparison
|
||||
* with at least one key/value pair in the actual value being compared
|
||||
* @name jasmine.mapContaining
|
||||
* @since
|
||||
* @function
|
||||
* @param {Map} sample - The subset of items that _must_ be in the actual.
|
||||
*/
|
||||
j$.mapContaining = function(sample) {
|
||||
return new j$.MapContaining(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 every item in the sample passes the deep equality comparison
|
||||
* with at least one item in the actual value being compared
|
||||
* @name jasmine.mapContaining
|
||||
* @since
|
||||
* @function
|
||||
* @param {Set} sample - The subset of items that _must_ be in the actual.
|
||||
*/
|
||||
j$.setContaining = function(sample) {
|
||||
return new j$.SetContaining(sample);
|
||||
};
|
||||
|
||||
j$.isSpy = function(putativeSpy) {
|
||||
if (!putativeSpy) {
|
||||
return false;
|
||||
|
||||
@@ -7,7 +7,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
||||
contains: function(haystack, needle, customTesters) {
|
||||
customTesters = customTesters || [];
|
||||
|
||||
if ((Object.prototype.toString.apply(haystack) === '[object Set]')) {
|
||||
if (j$.isSet(haystack)) {
|
||||
return haystack.has(needle);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
||||
j$.ObjectContaining = jRequire.ObjectContaining(j$);
|
||||
j$.ArrayContaining = jRequire.ArrayContaining(j$);
|
||||
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
|
||||
j$.MapContaining = jRequire.MapContaining(j$);
|
||||
j$.SetContaining = jRequire.SetContaining(j$);
|
||||
j$.pp = jRequire.pp(j$);
|
||||
j$.QueueRunner = jRequire.QueueRunner(j$);
|
||||
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
||||
|
||||
@@ -133,5 +133,24 @@ getJasmineRequireObj().util = function(j$) {
|
||||
};
|
||||
})();
|
||||
|
||||
function StopIteration() {}
|
||||
StopIteration.prototype = Object.create(Error.prototype);
|
||||
StopIteration.prototype.constructor = StopIteration;
|
||||
|
||||
// useful for maps and sets since `forEach` is the only IE11-compatible way to iterate them
|
||||
util.forEachBreakable = function(iterable, iteratee) {
|
||||
function breakLoop() {
|
||||
throw new StopIteration();
|
||||
}
|
||||
|
||||
try {
|
||||
iterable.forEach(function(value, key) {
|
||||
iteratee(breakLoop, value, key, iterable);
|
||||
});
|
||||
} catch (error) {
|
||||
if (!(error instanceof StopIteration)) throw error;
|
||||
}
|
||||
};
|
||||
|
||||
return util;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user