Converted DiffBuilder, ObjectPath, MismatchTree, and SinglePrettyPrintRun to ES6 classes

This commit is contained in:
Steve Gravrock
2022-05-14 11:07:37 -07:00
parent 2fd76c954c
commit 751cf6ab5b
7 changed files with 906 additions and 896 deletions

View File

@@ -4925,81 +4925,102 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
}; };
getJasmineRequireObj().DiffBuilder = function(j$) { getJasmineRequireObj().DiffBuilder = function(j$) {
return function DiffBuilder(config) { class DiffBuilder {
const prettyPrinter = constructor(config) {
this.prettyPrinter_ =
(config || {}).prettyPrinter || j$.makePrettyPrinter(); (config || {}).prettyPrinter || j$.makePrettyPrinter();
const mismatches = new j$.MismatchTree(); this.mismatches_ = new j$.MismatchTree();
let path = new j$.ObjectPath(); this.path_ = new j$.ObjectPath();
let actualRoot = undefined; this.actualRoot_ = undefined;
let expectedRoot = undefined; this.expectedRoot_ = undefined;
}
return { setRoots(actual, expected) {
setRoots: function(actual, expected) { this.actualRoot_ = actual;
actualRoot = actual; this.expectedRoot_ = expected;
expectedRoot = expected; }
},
recordMismatch: function(formatter) { recordMismatch(formatter) {
mismatches.add(path, formatter); this.mismatches_.add(this.path_, formatter);
}, }
getMessage: function() { getMessage() {
const messages = []; const messages = [];
mismatches.traverse(function(path, isLeaf, formatter) { this.mismatches_.traverse((path, isLeaf, formatter) => {
const { actual, expected } = dereferencePath( const { actual, expected } = this.dereferencePath_(path);
path,
actualRoot,
expectedRoot,
prettyPrinter
);
if (formatter) { if (formatter) {
messages.push(formatter(actual, expected, path, prettyPrinter)); messages.push(formatter(actual, expected, path, this.prettyPrinter_));
return true; return true;
} }
const actualCustom = prettyPrinter.customFormat_(actual); const actualCustom = this.prettyPrinter_.customFormat_(actual);
const expectedCustom = prettyPrinter.customFormat_(expected); const expectedCustom = this.prettyPrinter_.customFormat_(expected);
const useCustom = !( const useCustom = !(
j$.util.isUndefined(actualCustom) && j$.util.isUndefined(actualCustom) &&
j$.util.isUndefined(expectedCustom) j$.util.isUndefined(expectedCustom)
); );
if (useCustom) { if (useCustom) {
messages.push( messages.push(wrapPrettyPrinted(actualCustom, expectedCustom, path));
wrapPrettyPrinted(actualCustom, expectedCustom, path)
);
return false; // don't recurse further return false; // don't recurse further
} }
if (isLeaf) { if (isLeaf) {
messages.push( messages.push(this.defaultFormatter_(actual, expected, path));
defaultFormatter(actual, expected, path, prettyPrinter)
);
} }
return true; return true;
}); });
return messages.join('\n'); return messages.join('\n');
}, }
withPath: function(pathComponent, block) { withPath(pathComponent, block) {
const oldPath = path; const oldPath = this.path_;
path = path.add(pathComponent); this.path_ = this.path_.add(pathComponent);
block(); block();
path = oldPath; this.path_ = oldPath;
}
dereferencePath_(objectPath) {
let actual = this.actualRoot_;
let expected = this.expectedRoot_;
const handleAsymmetricExpected = () => {
if (
j$.isAsymmetricEqualityTester_(expected) &&
j$.isFunction_(expected.valuesForDiff_)
) {
const asymmetricResult = expected.valuesForDiff_(
actual,
this.prettyPrinter_
);
expected = asymmetricResult.self;
actual = asymmetricResult.other;
} }
}; };
function defaultFormatter(actual, expected, path, prettyPrinter) { handleAsymmetricExpected();
for (const pc of objectPath.components) {
actual = actual[pc];
expected = expected[pc];
handleAsymmetricExpected();
}
return { actual: actual, expected: expected };
}
defaultFormatter_(actual, expected, path) {
return wrapPrettyPrinted( return wrapPrettyPrinted(
prettyPrinter(actual), this.prettyPrinter_(actual),
prettyPrinter(expected), this.prettyPrinter_(expected),
path path
); );
} }
}
function wrapPrettyPrinted(actual, expected, path) { function wrapPrettyPrinted(actual, expected, path) {
return ( return (
@@ -5012,30 +5033,8 @@ getJasmineRequireObj().DiffBuilder = function(j$) {
'.' '.'
); );
} }
};
function dereferencePath(objectPath, actual, expected, pp) { return DiffBuilder;
function handleAsymmetricExpected() {
if (
j$.isAsymmetricEqualityTester_(expected) &&
j$.isFunction_(expected.valuesForDiff_)
) {
const asymmetricResult = expected.valuesForDiff_(actual, pp);
expected = asymmetricResult.self;
actual = asymmetricResult.other;
}
}
handleAsymmetricExpected();
for (const pc of objectPath.components) {
actual = actual[pc];
expected = expected[pc];
handleAsymmetricExpected();
}
return { actual: actual, expected: expected };
}
}; };
getJasmineRequireObj().MatchersUtil = function(j$) { getJasmineRequireObj().MatchersUtil = function(j$) {
@@ -5735,14 +5734,15 @@ getJasmineRequireObj().MismatchTree = function(j$) {
the expected and actual object graphs. MismatchTree maintains that context the expected and actual object graphs. MismatchTree maintains that context
and provides it via the traverse method. and provides it via the traverse method.
*/ */
function MismatchTree(path) { class MismatchTree {
constructor(path) {
this.path = path || new j$.ObjectPath([]); this.path = path || new j$.ObjectPath([]);
this.formatter = undefined; this.formatter = undefined;
this.children = []; this.children = [];
this.isMismatch = false; this.isMismatch = false;
} }
MismatchTree.prototype.add = function(path, formatter) { add(path, formatter) {
if (path.depth() === 0) { if (path.depth() === 0) {
this.formatter = formatter; this.formatter = formatter;
this.isMismatch = true; this.isMismatch = true;
@@ -5758,9 +5758,9 @@ getJasmineRequireObj().MismatchTree = function(j$) {
child.add(path, formatter); child.add(path, formatter);
} }
}; }
MismatchTree.prototype.traverse = function(visit) { traverse(visit) {
const hasChildren = this.children.length > 0; const hasChildren = this.children.length > 0;
if (this.isMismatch || hasChildren) { if (this.isMismatch || hasChildren) {
@@ -5770,14 +5770,15 @@ getJasmineRequireObj().MismatchTree = function(j$) {
} }
} }
} }
}; }
MismatchTree.prototype.child = function(key) { child(key) {
return this.children.find(child => { return this.children.find(child => {
const pathEls = child.path.components; const pathEls = child.path.components;
return pathEls[pathEls.length - 1] === key; return pathEls[pathEls.length - 1] === key;
}); });
}; }
}
return MismatchTree; return MismatchTree;
}; };
@@ -5817,29 +5818,31 @@ getJasmineRequireObj().NullDiffBuilder = function(j$) {
}; };
getJasmineRequireObj().ObjectPath = function(j$) { getJasmineRequireObj().ObjectPath = function(j$) {
function ObjectPath(components) { class ObjectPath {
constructor(components) {
this.components = components || []; this.components = components || [];
} }
ObjectPath.prototype.toString = function() { toString() {
if (this.components.length) { if (this.components.length) {
return '$' + this.components.map(formatPropertyAccess).join(''); return '$' + this.components.map(formatPropertyAccess).join('');
} else { } else {
return ''; return '';
} }
}; }
ObjectPath.prototype.add = function(component) { add(component) {
return new ObjectPath(this.components.concat([component])); return new ObjectPath(this.components.concat([component]));
}; }
ObjectPath.prototype.shift = function() { shift() {
return new ObjectPath(this.components.slice(1)); return new ObjectPath(this.components.slice(1));
}; }
ObjectPath.prototype.depth = function() { depth() {
return this.components.length; return this.components.length;
}; }
}
function formatPropertyAccess(prop) { function formatPropertyAccess(prop) {
if (typeof prop === 'number' || typeof prop === 'symbol') { if (typeof prop === 'number' || typeof prop === 'symbol') {
@@ -5850,7 +5853,7 @@ getJasmineRequireObj().ObjectPath = function(j$) {
return '.' + prop; return '.' + prop;
} }
return "['" + prop + "']"; return `['${prop}']`;
} }
function isValidIdentifier(string) { function isValidIdentifier(string) {
@@ -6415,7 +6418,7 @@ getJasmineRequireObj().toEqual = function(j$) {
var result = { var result = {
pass: false pass: false
}, },
diffBuilder = j$.DiffBuilder({ prettyPrinter: matchersUtil.pp }); diffBuilder = new j$.DiffBuilder({ prettyPrinter: matchersUtil.pp });
result.pass = matchersUtil.equals(actual, expected, diffBuilder); result.pass = matchersUtil.equals(actual, expected, diffBuilder);
@@ -7521,7 +7524,8 @@ getJasmineRequireObj().NeverSkipPolicy = function(j$) {
}; };
getJasmineRequireObj().makePrettyPrinter = function(j$) { getJasmineRequireObj().makePrettyPrinter = function(j$) {
function SinglePrettyPrintRun(customObjectFormatters, pp) { class SinglePrettyPrintRun {
constructor(customObjectFormatters, pp) {
this.customObjectFormatters_ = customObjectFormatters; this.customObjectFormatters_ = customObjectFormatters;
this.ppNestLevel_ = 0; this.ppNestLevel_ = 0;
this.seen = []; this.seen = [];
@@ -7530,22 +7534,7 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
this.pp_ = pp; this.pp_ = pp;
} }
function hasCustomToString(value) { format(value) {
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
// iframe, web worker)
try {
return (
j$.isFunction_(value.toString) &&
value.toString !== Object.prototype.toString &&
value.toString() !== Object.prototype.toString.call(value)
);
} catch (e) {
// The custom toString() threw.
return true;
}
}
SinglePrettyPrintRun.prototype.format = function(value) {
this.ppNestLevel_++; this.ppNestLevel_++;
try { try {
const customFormatResult = this.applyCustomFormatters_(value); const customFormatResult = this.applyCustomFormatters_(value);
@@ -7621,13 +7610,13 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} finally { } finally {
this.ppNestLevel_--; this.ppNestLevel_--;
} }
}; }
SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) { applyCustomFormatters_(value) {
return customFormat(value, this.customObjectFormatters_); return customFormat(value, this.customObjectFormatters_);
}; }
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) { iterateObject(obj, fn) {
const objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj)); const objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj));
const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
@@ -7636,17 +7625,17 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
return objKeys.length > length; return objKeys.length > length;
}; }
SinglePrettyPrintRun.prototype.emitScalar = function(value) { emitScalar(value) {
this.append(value); this.append(value);
}; }
SinglePrettyPrintRun.prototype.emitString = function(value) { emitString(value) {
this.append("'" + value + "'"); this.append("'" + value + "'");
}; }
SinglePrettyPrintRun.prototype.emitArray = function(array) { emitArray(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array'); this.append('Array');
return; return;
@@ -7681,9 +7670,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
this.append(' ]'); this.append(' ]');
}; }
SinglePrettyPrintRun.prototype.emitSet = function(set) { emitSet(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set'); this.append('Set');
return; return;
@@ -7706,9 +7695,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
this.append(', ...'); this.append(', ...');
} }
this.append(' )'); this.append(' )');
}; }
SinglePrettyPrintRun.prototype.emitMap = function(map) { emitMap(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map'); this.append('Map');
return; return;
@@ -7731,9 +7720,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
this.append(', ...'); this.append(', ...');
} }
this.append(' )'); this.append(' )');
}; }
SinglePrettyPrintRun.prototype.emitObject = function(obj) { emitObject(obj) {
const ctor = obj.constructor; const ctor = obj.constructor;
const constructorName = const constructorName =
typeof ctor === 'function' && obj instanceof ctor typeof ctor === 'function' && obj instanceof ctor
@@ -7764,9 +7753,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
this.append(' })'); this.append(' })');
}; }
SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) { emitTypedArray(arr) {
const constructorName = j$.fnNameFor(arr.constructor); const constructorName = j$.fnNameFor(arr.constructor);
const limitedArray = Array.prototype.slice.call( const limitedArray = Array.prototype.slice.call(
arr, arr,
@@ -7780,9 +7769,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
this.append(constructorName + ' [ ' + itemsString + ' ]'); this.append(constructorName + ' [ ' + itemsString + ' ]');
}; }
SinglePrettyPrintRun.prototype.emitDomElement = function(el) { emitDomElement(el) {
const tagName = el.tagName.toLowerCase(); const tagName = el.tagName.toLowerCase();
let out = '<' + tagName; let out = '<' + tagName;
@@ -7801,9 +7790,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
this.append(out); this.append(out);
}; }
SinglePrettyPrintRun.prototype.formatProperty = function(obj, property) { formatProperty(obj, property) {
if (typeof property === 'symbol') { if (typeof property === 'symbol') {
this.append(property.toString()); this.append(property.toString());
} else { } else {
@@ -7812,9 +7801,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
this.append(': '); this.append(': ');
this.format(obj[property]); this.format(obj[property]);
}; }
SinglePrettyPrintRun.prototype.append = function(value) { append(value) {
// This check protects us from the rare case where an object has overriden // This check protects us from the rare case where an object has overriden
// `toString()` with an invalid implementation (returning a non-string). // `toString()` with an invalid implementation (returning a non-string).
if (typeof value !== 'string') { if (typeof value !== 'string') {
@@ -7828,7 +7817,23 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
if (result.truncated) { if (result.truncated) {
throw new MaxCharsReachedError(); throw new MaxCharsReachedError();
} }
}; }
}
function hasCustomToString(value) {
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
// iframe, web worker)
try {
return (
j$.isFunction_(value.toString) &&
value.toString !== Object.prototype.toString &&
value.toString() !== Object.prototype.toString.call(value)
);
} catch (e) {
// The custom toString() threw.
return true;
}
}
function truncate(s, maxlen) { function truncate(s, maxlen) {
if (s.length <= maxlen) { if (s.length <= maxlen) {

View File

@@ -1,6 +1,6 @@
describe('DiffBuilder', function() { describe('DiffBuilder', function() {
it('records the actual and expected objects', function() { it('records the actual and expected objects', function() {
const diffBuilder = jasmineUnderTest.DiffBuilder(); const diffBuilder = new jasmineUnderTest.DiffBuilder();
diffBuilder.setRoots({ x: 'actual' }, { x: 'expected' }); diffBuilder.setRoots({ x: 'actual' }, { x: 'expected' });
diffBuilder.recordMismatch(); diffBuilder.recordMismatch();
@@ -10,7 +10,7 @@ describe('DiffBuilder', function() {
}); });
it('prints the path at which the difference was found', function() { it('prints the path at which the difference was found', function() {
const diffBuilder = jasmineUnderTest.DiffBuilder(); const diffBuilder = new jasmineUnderTest.DiffBuilder();
diffBuilder.setRoots({ foo: { x: 'actual' } }, { foo: { x: 'expected' } }); diffBuilder.setRoots({ foo: { x: 'actual' } }, { foo: { x: 'expected' } });
diffBuilder.withPath('foo', function() { diffBuilder.withPath('foo', function() {
@@ -23,7 +23,7 @@ describe('DiffBuilder', function() {
}); });
it('prints multiple messages, separated by newlines', function() { it('prints multiple messages, separated by newlines', function() {
const diffBuilder = jasmineUnderTest.DiffBuilder(); const diffBuilder = new jasmineUnderTest.DiffBuilder();
diffBuilder.setRoots({ foo: 1, bar: 3 }, { foo: 2, bar: 4 }); diffBuilder.setRoots({ foo: 1, bar: 3 }, { foo: 2, bar: 4 });
diffBuilder.withPath('foo', function() { diffBuilder.withPath('foo', function() {
@@ -40,7 +40,7 @@ describe('DiffBuilder', function() {
}); });
it('allows customization of the message', function() { it('allows customization of the message', function() {
const diffBuilder = jasmineUnderTest.DiffBuilder(); const diffBuilder = new jasmineUnderTest.DiffBuilder();
diffBuilder.setRoots({ x: 'bar' }, { x: 'foo' }); diffBuilder.setRoots({ x: 'bar' }, { x: 'foo' });
function darthVaderFormatter(actual, expected, path) { function darthVaderFormatter(actual, expected, path) {
@@ -68,7 +68,7 @@ describe('DiffBuilder', function() {
const prettyPrinter = function(val) { const prettyPrinter = function(val) {
return '|' + val + '|'; return '|' + val + '|';
}, },
diffBuilder = jasmineUnderTest.DiffBuilder({ diffBuilder = new jasmineUnderTest.DiffBuilder({
prettyPrinter: prettyPrinter prettyPrinter: prettyPrinter
}); });
prettyPrinter.customFormat_ = function() {}; prettyPrinter.customFormat_ = function() {};
@@ -86,7 +86,7 @@ describe('DiffBuilder', function() {
it('passes the injected pretty-printer to the diff formatter', function() { it('passes the injected pretty-printer to the diff formatter', function() {
const diffFormatter = jasmine.createSpy('diffFormatter'), const diffFormatter = jasmine.createSpy('diffFormatter'),
prettyPrinter = function() {}, prettyPrinter = function() {},
diffBuilder = jasmineUnderTest.DiffBuilder({ diffBuilder = new jasmineUnderTest.DiffBuilder({
prettyPrinter: prettyPrinter prettyPrinter: prettyPrinter
}); });
prettyPrinter.customFormat_ = function() {}; prettyPrinter.customFormat_ = function() {};

View File

@@ -1,5 +1,6 @@
getJasmineRequireObj().makePrettyPrinter = function(j$) { getJasmineRequireObj().makePrettyPrinter = function(j$) {
function SinglePrettyPrintRun(customObjectFormatters, pp) { class SinglePrettyPrintRun {
constructor(customObjectFormatters, pp) {
this.customObjectFormatters_ = customObjectFormatters; this.customObjectFormatters_ = customObjectFormatters;
this.ppNestLevel_ = 0; this.ppNestLevel_ = 0;
this.seen = []; this.seen = [];
@@ -8,22 +9,7 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
this.pp_ = pp; this.pp_ = pp;
} }
function hasCustomToString(value) { format(value) {
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
// iframe, web worker)
try {
return (
j$.isFunction_(value.toString) &&
value.toString !== Object.prototype.toString &&
value.toString() !== Object.prototype.toString.call(value)
);
} catch (e) {
// The custom toString() threw.
return true;
}
}
SinglePrettyPrintRun.prototype.format = function(value) {
this.ppNestLevel_++; this.ppNestLevel_++;
try { try {
const customFormatResult = this.applyCustomFormatters_(value); const customFormatResult = this.applyCustomFormatters_(value);
@@ -99,13 +85,13 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} finally { } finally {
this.ppNestLevel_--; this.ppNestLevel_--;
} }
}; }
SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) { applyCustomFormatters_(value) {
return customFormat(value, this.customObjectFormatters_); return customFormat(value, this.customObjectFormatters_);
}; }
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) { iterateObject(obj, fn) {
const objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj)); const objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj));
const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH); const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
@@ -114,17 +100,17 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
return objKeys.length > length; return objKeys.length > length;
}; }
SinglePrettyPrintRun.prototype.emitScalar = function(value) { emitScalar(value) {
this.append(value); this.append(value);
}; }
SinglePrettyPrintRun.prototype.emitString = function(value) { emitString(value) {
this.append("'" + value + "'"); this.append("'" + value + "'");
}; }
SinglePrettyPrintRun.prototype.emitArray = function(array) { emitArray(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array'); this.append('Array');
return; return;
@@ -159,9 +145,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
this.append(' ]'); this.append(' ]');
}; }
SinglePrettyPrintRun.prototype.emitSet = function(set) { emitSet(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set'); this.append('Set');
return; return;
@@ -184,9 +170,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
this.append(', ...'); this.append(', ...');
} }
this.append(' )'); this.append(' )');
}; }
SinglePrettyPrintRun.prototype.emitMap = function(map) { emitMap(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map'); this.append('Map');
return; return;
@@ -209,9 +195,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
this.append(', ...'); this.append(', ...');
} }
this.append(' )'); this.append(' )');
}; }
SinglePrettyPrintRun.prototype.emitObject = function(obj) { emitObject(obj) {
const ctor = obj.constructor; const ctor = obj.constructor;
const constructorName = const constructorName =
typeof ctor === 'function' && obj instanceof ctor typeof ctor === 'function' && obj instanceof ctor
@@ -242,9 +228,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
this.append(' })'); this.append(' })');
}; }
SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) { emitTypedArray(arr) {
const constructorName = j$.fnNameFor(arr.constructor); const constructorName = j$.fnNameFor(arr.constructor);
const limitedArray = Array.prototype.slice.call( const limitedArray = Array.prototype.slice.call(
arr, arr,
@@ -258,9 +244,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
this.append(constructorName + ' [ ' + itemsString + ' ]'); this.append(constructorName + ' [ ' + itemsString + ' ]');
}; }
SinglePrettyPrintRun.prototype.emitDomElement = function(el) { emitDomElement(el) {
const tagName = el.tagName.toLowerCase(); const tagName = el.tagName.toLowerCase();
let out = '<' + tagName; let out = '<' + tagName;
@@ -279,9 +265,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
this.append(out); this.append(out);
}; }
SinglePrettyPrintRun.prototype.formatProperty = function(obj, property) { formatProperty(obj, property) {
if (typeof property === 'symbol') { if (typeof property === 'symbol') {
this.append(property.toString()); this.append(property.toString());
} else { } else {
@@ -290,9 +276,9 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
this.append(': '); this.append(': ');
this.format(obj[property]); this.format(obj[property]);
}; }
SinglePrettyPrintRun.prototype.append = function(value) { append(value) {
// This check protects us from the rare case where an object has overriden // This check protects us from the rare case where an object has overriden
// `toString()` with an invalid implementation (returning a non-string). // `toString()` with an invalid implementation (returning a non-string).
if (typeof value !== 'string') { if (typeof value !== 'string') {
@@ -306,7 +292,23 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
if (result.truncated) { if (result.truncated) {
throw new MaxCharsReachedError(); throw new MaxCharsReachedError();
} }
}; }
}
function hasCustomToString(value) {
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
// iframe, web worker)
try {
return (
j$.isFunction_(value.toString) &&
value.toString !== Object.prototype.toString &&
value.toString() !== Object.prototype.toString.call(value)
);
} catch (e) {
// The custom toString() threw.
return true;
}
}
function truncate(s, maxlen) { function truncate(s, maxlen) {
if (s.length <= maxlen) { if (s.length <= maxlen) {

View File

@@ -1,79 +1,100 @@
getJasmineRequireObj().DiffBuilder = function(j$) { getJasmineRequireObj().DiffBuilder = function(j$) {
return function DiffBuilder(config) { class DiffBuilder {
const prettyPrinter = constructor(config) {
this.prettyPrinter_ =
(config || {}).prettyPrinter || j$.makePrettyPrinter(); (config || {}).prettyPrinter || j$.makePrettyPrinter();
const mismatches = new j$.MismatchTree(); this.mismatches_ = new j$.MismatchTree();
let path = new j$.ObjectPath(); this.path_ = new j$.ObjectPath();
let actualRoot = undefined; this.actualRoot_ = undefined;
let expectedRoot = undefined; this.expectedRoot_ = undefined;
}
return { setRoots(actual, expected) {
setRoots: function(actual, expected) { this.actualRoot_ = actual;
actualRoot = actual; this.expectedRoot_ = expected;
expectedRoot = expected; }
},
recordMismatch: function(formatter) { recordMismatch(formatter) {
mismatches.add(path, formatter); this.mismatches_.add(this.path_, formatter);
}, }
getMessage: function() { getMessage() {
const messages = []; const messages = [];
mismatches.traverse(function(path, isLeaf, formatter) { this.mismatches_.traverse((path, isLeaf, formatter) => {
const { actual, expected } = dereferencePath( const { actual, expected } = this.dereferencePath_(path);
path,
actualRoot,
expectedRoot,
prettyPrinter
);
if (formatter) { if (formatter) {
messages.push(formatter(actual, expected, path, prettyPrinter)); messages.push(formatter(actual, expected, path, this.prettyPrinter_));
return true; return true;
} }
const actualCustom = prettyPrinter.customFormat_(actual); const actualCustom = this.prettyPrinter_.customFormat_(actual);
const expectedCustom = prettyPrinter.customFormat_(expected); const expectedCustom = this.prettyPrinter_.customFormat_(expected);
const useCustom = !( const useCustom = !(
j$.util.isUndefined(actualCustom) && j$.util.isUndefined(actualCustom) &&
j$.util.isUndefined(expectedCustom) j$.util.isUndefined(expectedCustom)
); );
if (useCustom) { if (useCustom) {
messages.push( messages.push(wrapPrettyPrinted(actualCustom, expectedCustom, path));
wrapPrettyPrinted(actualCustom, expectedCustom, path)
);
return false; // don't recurse further return false; // don't recurse further
} }
if (isLeaf) { if (isLeaf) {
messages.push( messages.push(this.defaultFormatter_(actual, expected, path));
defaultFormatter(actual, expected, path, prettyPrinter)
);
} }
return true; return true;
}); });
return messages.join('\n'); return messages.join('\n');
}, }
withPath: function(pathComponent, block) { withPath(pathComponent, block) {
const oldPath = path; const oldPath = this.path_;
path = path.add(pathComponent); this.path_ = this.path_.add(pathComponent);
block(); block();
path = oldPath; this.path_ = oldPath;
}
dereferencePath_(objectPath) {
let actual = this.actualRoot_;
let expected = this.expectedRoot_;
const handleAsymmetricExpected = () => {
if (
j$.isAsymmetricEqualityTester_(expected) &&
j$.isFunction_(expected.valuesForDiff_)
) {
const asymmetricResult = expected.valuesForDiff_(
actual,
this.prettyPrinter_
);
expected = asymmetricResult.self;
actual = asymmetricResult.other;
} }
}; };
function defaultFormatter(actual, expected, path, prettyPrinter) { handleAsymmetricExpected();
for (const pc of objectPath.components) {
actual = actual[pc];
expected = expected[pc];
handleAsymmetricExpected();
}
return { actual: actual, expected: expected };
}
defaultFormatter_(actual, expected, path) {
return wrapPrettyPrinted( return wrapPrettyPrinted(
prettyPrinter(actual), this.prettyPrinter_(actual),
prettyPrinter(expected), this.prettyPrinter_(expected),
path path
); );
} }
}
function wrapPrettyPrinted(actual, expected, path) { function wrapPrettyPrinted(actual, expected, path) {
return ( return (
@@ -86,28 +107,6 @@ getJasmineRequireObj().DiffBuilder = function(j$) {
'.' '.'
); );
} }
};
function dereferencePath(objectPath, actual, expected, pp) { return DiffBuilder;
function handleAsymmetricExpected() {
if (
j$.isAsymmetricEqualityTester_(expected) &&
j$.isFunction_(expected.valuesForDiff_)
) {
const asymmetricResult = expected.valuesForDiff_(actual, pp);
expected = asymmetricResult.self;
actual = asymmetricResult.other;
}
}
handleAsymmetricExpected();
for (const pc of objectPath.components) {
actual = actual[pc];
expected = expected[pc];
handleAsymmetricExpected();
}
return { actual: actual, expected: expected };
}
}; };

View File

@@ -6,14 +6,15 @@ getJasmineRequireObj().MismatchTree = function(j$) {
the expected and actual object graphs. MismatchTree maintains that context the expected and actual object graphs. MismatchTree maintains that context
and provides it via the traverse method. and provides it via the traverse method.
*/ */
function MismatchTree(path) { class MismatchTree {
constructor(path) {
this.path = path || new j$.ObjectPath([]); this.path = path || new j$.ObjectPath([]);
this.formatter = undefined; this.formatter = undefined;
this.children = []; this.children = [];
this.isMismatch = false; this.isMismatch = false;
} }
MismatchTree.prototype.add = function(path, formatter) { add(path, formatter) {
if (path.depth() === 0) { if (path.depth() === 0) {
this.formatter = formatter; this.formatter = formatter;
this.isMismatch = true; this.isMismatch = true;
@@ -29,9 +30,9 @@ getJasmineRequireObj().MismatchTree = function(j$) {
child.add(path, formatter); child.add(path, formatter);
} }
}; }
MismatchTree.prototype.traverse = function(visit) { traverse(visit) {
const hasChildren = this.children.length > 0; const hasChildren = this.children.length > 0;
if (this.isMismatch || hasChildren) { if (this.isMismatch || hasChildren) {
@@ -41,14 +42,15 @@ getJasmineRequireObj().MismatchTree = function(j$) {
} }
} }
} }
}; }
MismatchTree.prototype.child = function(key) { child(key) {
return this.children.find(child => { return this.children.find(child => {
const pathEls = child.path.components; const pathEls = child.path.components;
return pathEls[pathEls.length - 1] === key; return pathEls[pathEls.length - 1] === key;
}); });
}; }
}
return MismatchTree; return MismatchTree;
}; };

View File

@@ -1,27 +1,29 @@
getJasmineRequireObj().ObjectPath = function(j$) { getJasmineRequireObj().ObjectPath = function(j$) {
function ObjectPath(components) { class ObjectPath {
constructor(components) {
this.components = components || []; this.components = components || [];
} }
ObjectPath.prototype.toString = function() { toString() {
if (this.components.length) { if (this.components.length) {
return '$' + this.components.map(formatPropertyAccess).join(''); return '$' + this.components.map(formatPropertyAccess).join('');
} else { } else {
return ''; return '';
} }
}; }
ObjectPath.prototype.add = function(component) { add(component) {
return new ObjectPath(this.components.concat([component])); return new ObjectPath(this.components.concat([component]));
}; }
ObjectPath.prototype.shift = function() { shift() {
return new ObjectPath(this.components.slice(1)); return new ObjectPath(this.components.slice(1));
}; }
ObjectPath.prototype.depth = function() { depth() {
return this.components.length; return this.components.length;
}; }
}
function formatPropertyAccess(prop) { function formatPropertyAccess(prop) {
if (typeof prop === 'number' || typeof prop === 'symbol') { if (typeof prop === 'number' || typeof prop === 'symbol') {
@@ -32,7 +34,7 @@ getJasmineRequireObj().ObjectPath = function(j$) {
return '.' + prop; return '.' + prop;
} }
return "['" + prop + "']"; return `['${prop}']`;
} }
function isValidIdentifier(string) { function isValidIdentifier(string) {

View File

@@ -14,7 +14,7 @@ getJasmineRequireObj().toEqual = function(j$) {
var result = { var result = {
pass: false pass: false
}, },
diffBuilder = j$.DiffBuilder({ prettyPrinter: matchersUtil.pp }); diffBuilder = new j$.DiffBuilder({ prettyPrinter: matchersUtil.pp });
result.pass = matchersUtil.equals(actual, expected, diffBuilder); result.pass = matchersUtil.equals(actual, expected, diffBuilder);