Merge branch 'tobe-tostring' of https://github.com/johnjbarton/jasmine into johnjbarton-tobe-tostring
- Merges #1718 from @johnjbarton - Fixes #1726
This commit is contained in:
@@ -77,6 +77,8 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
|||||||
j$.ObjectContaining = jRequire.ObjectContaining(j$);
|
j$.ObjectContaining = jRequire.ObjectContaining(j$);
|
||||||
j$.ArrayContaining = jRequire.ArrayContaining(j$);
|
j$.ArrayContaining = jRequire.ArrayContaining(j$);
|
||||||
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
|
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
|
||||||
|
j$.MapContaining = jRequire.MapContaining(j$);
|
||||||
|
j$.SetContaining = jRequire.SetContaining(j$);
|
||||||
j$.pp = jRequire.pp(j$);
|
j$.pp = jRequire.pp(j$);
|
||||||
j$.QueueRunner = jRequire.QueueRunner(j$);
|
j$.QueueRunner = jRequire.QueueRunner(j$);
|
||||||
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
||||||
@@ -283,6 +285,8 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
|||||||
|
|
||||||
j$.isMap = function(obj) {
|
j$.isMap = function(obj) {
|
||||||
return (
|
return (
|
||||||
|
obj !== null &&
|
||||||
|
typeof obj !== 'undefined' &&
|
||||||
typeof jasmineGlobal.Map !== 'undefined' &&
|
typeof jasmineGlobal.Map !== 'undefined' &&
|
||||||
obj.constructor === jasmineGlobal.Map
|
obj.constructor === jasmineGlobal.Map
|
||||||
);
|
);
|
||||||
@@ -290,6 +294,8 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
|||||||
|
|
||||||
j$.isSet = function(obj) {
|
j$.isSet = function(obj) {
|
||||||
return (
|
return (
|
||||||
|
obj !== null &&
|
||||||
|
typeof obj !== 'undefined' &&
|
||||||
typeof jasmineGlobal.Set !== 'undefined' &&
|
typeof jasmineGlobal.Set !== 'undefined' &&
|
||||||
obj.constructor === jasmineGlobal.Set
|
obj.constructor === jasmineGlobal.Set
|
||||||
);
|
);
|
||||||
@@ -434,6 +440,32 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
|||||||
return new j$.ArrayWithExactContents(sample);
|
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) {
|
j$.isSpy = function(putativeSpy) {
|
||||||
if (!putativeSpy) {
|
if (!putativeSpy) {
|
||||||
return false;
|
return false;
|
||||||
@@ -580,6 +612,25 @@ 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;
|
return util;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2247,6 +2298,48 @@ getJasmineRequireObj().Falsy = function(j$) {
|
|||||||
return Falsy;
|
return Falsy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().NotEmpty = function (j$) {
|
getJasmineRequireObj().NotEmpty = function (j$) {
|
||||||
|
|
||||||
function NotEmpty() {}
|
function NotEmpty() {}
|
||||||
@@ -2324,6 +2417,46 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
|
|||||||
return ObjectContaining;
|
return ObjectContaining;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().StringMatching = function(j$) {
|
getJasmineRequireObj().StringMatching = function(j$) {
|
||||||
|
|
||||||
function StringMatching(expected) {
|
function StringMatching(expected) {
|
||||||
@@ -3860,7 +3993,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
|
|||||||
contains: function(haystack, needle, customTesters) {
|
contains: function(haystack, needle, customTesters) {
|
||||||
customTesters = customTesters || [];
|
customTesters = customTesters || [];
|
||||||
|
|
||||||
if ((Object.prototype.toString.apply(haystack) === '[object Set]')) {
|
if (j$.isSet(haystack)) {
|
||||||
return haystack.has(needle);
|
return haystack.has(needle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5624,11 +5757,16 @@ getJasmineRequireObj().pp = function(j$) {
|
|||||||
function hasCustomToString(value) {
|
function hasCustomToString(value) {
|
||||||
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
|
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
|
||||||
// iframe, web worker)
|
// iframe, web worker)
|
||||||
return (
|
try {
|
||||||
j$.isFunction_(value.toString) &&
|
return (
|
||||||
value.toString !== Object.prototype.toString &&
|
j$.isFunction_(value.toString) &&
|
||||||
value.toString() !== Object.prototype.toString.call(value)
|
value.toString !== Object.prototype.toString &&
|
||||||
);
|
value.toString() !== Object.prototype.toString.call(value)
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// The custom toString() threw.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrettyPrinter.prototype.format = function(value) {
|
PrettyPrinter.prototype.format = function(value) {
|
||||||
@@ -5674,7 +5812,11 @@ getJasmineRequireObj().pp = function(j$) {
|
|||||||
!j$.isArray_(value) &&
|
!j$.isArray_(value) &&
|
||||||
hasCustomToString(value)
|
hasCustomToString(value)
|
||||||
) {
|
) {
|
||||||
this.emitScalar(value.toString());
|
try {
|
||||||
|
this.emitScalar(value.toString());
|
||||||
|
} catch (e) {
|
||||||
|
this.emitScalar('has-invalid-toString-method');
|
||||||
|
}
|
||||||
} else if (j$.util.arrayContains(this.seen, value)) {
|
} else if (j$.util.arrayContains(this.seen, value)) {
|
||||||
this.emitScalar(
|
this.emitScalar(
|
||||||
'<circular reference: ' +
|
'<circular reference: ' +
|
||||||
|
|||||||
@@ -457,11 +457,17 @@ describe('jasmineUnderTest.pp', function() {
|
|||||||
// Valid: an actual number
|
// Valid: an actual number
|
||||||
baz: 3,
|
baz: 3,
|
||||||
// Valid: an actual Error object
|
// Valid: an actual Error object
|
||||||
qux: new Error('bar')
|
qux: new Error('bar'),
|
||||||
|
//
|
||||||
|
baddy: {
|
||||||
|
toString: function() {
|
||||||
|
throw new Error('I am a bad toString');
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(jasmineUnderTest.pp(obj)).toEqual(
|
expect(jasmineUnderTest.pp(obj)).toEqual(
|
||||||
'Object({ foo: [object Number], bar: [object Object], baz: 3, qux: Error: bar })'
|
'Object({ foo: [object Number], bar: [object Object], baz: 3, qux: Error: bar, baddy: has-invalid-toString-method })'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,11 +9,16 @@ getJasmineRequireObj().pp = function(j$) {
|
|||||||
function hasCustomToString(value) {
|
function hasCustomToString(value) {
|
||||||
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
|
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
|
||||||
// iframe, web worker)
|
// iframe, web worker)
|
||||||
return (
|
try {
|
||||||
j$.isFunction_(value.toString) &&
|
return (
|
||||||
value.toString !== Object.prototype.toString &&
|
j$.isFunction_(value.toString) &&
|
||||||
value.toString() !== Object.prototype.toString.call(value)
|
value.toString !== Object.prototype.toString &&
|
||||||
);
|
value.toString() !== Object.prototype.toString.call(value)
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// The custom toString() threw.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PrettyPrinter.prototype.format = function(value) {
|
PrettyPrinter.prototype.format = function(value) {
|
||||||
@@ -59,7 +64,11 @@ getJasmineRequireObj().pp = function(j$) {
|
|||||||
!j$.isArray_(value) &&
|
!j$.isArray_(value) &&
|
||||||
hasCustomToString(value)
|
hasCustomToString(value)
|
||||||
) {
|
) {
|
||||||
this.emitScalar(value.toString());
|
try {
|
||||||
|
this.emitScalar(value.toString());
|
||||||
|
} catch (e) {
|
||||||
|
this.emitScalar('has-invalid-toString-method');
|
||||||
|
}
|
||||||
} else if (j$.util.arrayContains(this.seen, value)) {
|
} else if (j$.util.arrayContains(this.seen, value)) {
|
||||||
this.emitScalar(
|
this.emitScalar(
|
||||||
'<circular reference: ' +
|
'<circular reference: ' +
|
||||||
|
|||||||
Reference in New Issue
Block a user