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
+450 -445
View File
@@ -4925,117 +4925,116 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
}; };
getJasmineRequireObj().DiffBuilder = function(j$) { getJasmineRequireObj().DiffBuilder = function(j$) {
return function DiffBuilder(config) { class DiffBuilder {
const prettyPrinter = constructor(config) {
(config || {}).prettyPrinter || j$.makePrettyPrinter(); this.prettyPrinter_ =
const mismatches = new j$.MismatchTree(); (config || {}).prettyPrinter || j$.makePrettyPrinter();
let path = new j$.ObjectPath(); this.mismatches_ = new j$.MismatchTree();
let actualRoot = undefined; this.path_ = new j$.ObjectPath();
let expectedRoot = undefined; this.actualRoot_ = 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) {
messages.push(formatter(actual, expected, path, prettyPrinter));
return true;
}
const actualCustom = prettyPrinter.customFormat_(actual);
const expectedCustom = prettyPrinter.customFormat_(expected);
const useCustom = !(
j$.util.isUndefined(actualCustom) &&
j$.util.isUndefined(expectedCustom)
);
if (useCustom) {
messages.push(
wrapPrettyPrinted(actualCustom, expectedCustom, path)
);
return false; // don't recurse further
}
if (isLeaf) {
messages.push(
defaultFormatter(actual, expected, path, prettyPrinter)
);
}
if (formatter) {
messages.push(formatter(actual, expected, path, this.prettyPrinter_));
return true; return true;
}); }
return messages.join('\n'); const actualCustom = this.prettyPrinter_.customFormat_(actual);
}, const expectedCustom = this.prettyPrinter_.customFormat_(expected);
const useCustom = !(
j$.util.isUndefined(actualCustom) &&
j$.util.isUndefined(expectedCustom)
);
withPath: function(pathComponent, block) { if (useCustom) {
const oldPath = path; messages.push(wrapPrettyPrinted(actualCustom, expectedCustom, path));
path = path.add(pathComponent); return false; // don't recurse further
block(); }
path = oldPath;
if (isLeaf) {
messages.push(this.defaultFormatter_(actual, expected, path));
}
return true;
});
return messages.join('\n');
}
withPath(pathComponent, block) {
const oldPath = this.path_;
this.path_ = this.path_.add(pathComponent);
block();
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;
}
};
handleAsymmetricExpected();
for (const pc of objectPath.components) {
actual = actual[pc];
expected = expected[pc];
handleAsymmetricExpected();
} }
};
function defaultFormatter(actual, expected, path, prettyPrinter) { 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) {
return (
'Expected ' +
path +
(path.depth() ? ' = ' : '') +
actual +
' to equal ' +
expected +
'.'
);
}
};
function dereferencePath(objectPath, actual, expected, pp) {
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 };
} }
function wrapPrettyPrinted(actual, expected, path) {
return (
'Expected ' +
path +
(path.depth() ? ' = ' : '') +
actual +
' to equal ' +
expected +
'.'
);
}
return DiffBuilder;
}; };
getJasmineRequireObj().MatchersUtil = function(j$) { getJasmineRequireObj().MatchersUtil = function(j$) {
@@ -5735,49 +5734,51 @@ 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 {
this.path = path || new j$.ObjectPath([]); constructor(path) {
this.formatter = undefined; this.path = path || new j$.ObjectPath([]);
this.children = []; this.formatter = undefined;
this.isMismatch = false; this.children = [];
} this.isMismatch = false;
MismatchTree.prototype.add = function(path, formatter) {
if (path.depth() === 0) {
this.formatter = formatter;
this.isMismatch = true;
} else {
const key = path.components[0];
path = path.shift();
let child = this.child(key);
if (!child) {
child = new MismatchTree(this.path.add(key));
this.children.push(child);
}
child.add(path, formatter);
} }
};
MismatchTree.prototype.traverse = function(visit) { add(path, formatter) {
const hasChildren = this.children.length > 0; if (path.depth() === 0) {
this.formatter = formatter;
this.isMismatch = true;
} else {
const key = path.components[0];
path = path.shift();
let child = this.child(key);
if (this.isMismatch || hasChildren) { if (!child) {
if (visit(this.path, !hasChildren, this.formatter)) { child = new MismatchTree(this.path.add(key));
for (const child of this.children) { this.children.push(child);
child.traverse(visit); }
child.add(path, formatter);
}
}
traverse(visit) {
const hasChildren = this.children.length > 0;
if (this.isMismatch || hasChildren) {
if (visit(this.path, !hasChildren, this.formatter)) {
for (const child of this.children) {
child.traverse(visit);
}
} }
} }
} }
};
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 {
this.components = components || []; constructor(components) {
} this.components = components || [];
ObjectPath.prototype.toString = function() {
if (this.components.length) {
return '$' + this.components.map(formatPropertyAccess).join('');
} else {
return '';
} }
};
ObjectPath.prototype.add = function(component) { toString() {
return new ObjectPath(this.components.concat([component])); if (this.components.length) {
}; return '$' + this.components.map(formatPropertyAccess).join('');
} else {
return '';
}
}
ObjectPath.prototype.shift = function() { add(component) {
return new ObjectPath(this.components.slice(1)); return new ObjectPath(this.components.concat([component]));
}; }
ObjectPath.prototype.depth = function() { shift() {
return this.components.length; return new ObjectPath(this.components.slice(1));
}; }
depth() {
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,13 +7524,300 @@ getJasmineRequireObj().NeverSkipPolicy = function(j$) {
}; };
getJasmineRequireObj().makePrettyPrinter = function(j$) { getJasmineRequireObj().makePrettyPrinter = function(j$) {
function SinglePrettyPrintRun(customObjectFormatters, pp) { class SinglePrettyPrintRun {
this.customObjectFormatters_ = customObjectFormatters; constructor(customObjectFormatters, pp) {
this.ppNestLevel_ = 0; this.customObjectFormatters_ = customObjectFormatters;
this.seen = []; this.ppNestLevel_ = 0;
this.length = 0; this.seen = [];
this.stringParts = []; this.length = 0;
this.pp_ = pp; this.stringParts = [];
this.pp_ = pp;
}
format(value) {
this.ppNestLevel_++;
try {
const customFormatResult = this.applyCustomFormatters_(value);
if (customFormatResult) {
this.emitScalar(customFormatResult);
} else if (j$.util.isUndefined(value)) {
this.emitScalar('undefined');
} else if (value === null) {
this.emitScalar('null');
} else if (value === 0 && 1 / value === -Infinity) {
this.emitScalar('-0');
} else if (value === j$.getGlobal()) {
this.emitScalar('<global>');
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString(this.pp_));
} else if (j$.isString_(value)) {
this.emitString(value);
} else if (j$.isSpy(value)) {
this.emitScalar('spy on ' + value.and.identity);
} else if (j$.isSpy(value.toString)) {
this.emitScalar('spy on ' + value.toString.and.identity);
} else if (value instanceof RegExp) {
this.emitScalar(value.toString());
} else if (typeof value === 'function') {
this.emitScalar('Function');
} else if (j$.isDomNode(value)) {
if (value.tagName) {
this.emitDomElement(value);
} else {
this.emitScalar('HTMLNode');
}
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (j$.isSet(value)) {
this.emitSet(value);
} else if (j$.isMap(value)) {
this.emitMap(value);
} else if (j$.isTypedArray_(value)) {
this.emitTypedArray(value);
} else if (
value.toString &&
typeof value === 'object' &&
!j$.isArray_(value) &&
hasCustomToString(value)
) {
try {
this.emitScalar(value.toString());
} catch (e) {
this.emitScalar('has-invalid-toString-method');
}
} else if (j$.util.arrayContains(this.seen, value)) {
this.emitScalar(
'<circular reference: ' +
(j$.isArray_(value) ? 'Array' : 'Object') +
'>'
);
} else if (j$.isArray_(value) || j$.isA_('Object', value)) {
this.seen.push(value);
if (j$.isArray_(value)) {
this.emitArray(value);
} else {
this.emitObject(value);
}
this.seen.pop();
} else {
this.emitScalar(value.toString());
}
} catch (e) {
if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
throw e;
}
} finally {
this.ppNestLevel_--;
}
}
applyCustomFormatters_(value) {
return customFormat(value, this.customObjectFormatters_);
}
iterateObject(obj, fn) {
const objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj));
const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
for (let i = 0; i < length; i++) {
fn(objKeys[i]);
}
return objKeys.length > length;
}
emitScalar(value) {
this.append(value);
}
emitString(value) {
this.append("'" + value + "'");
}
emitArray(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array');
return;
}
const length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
this.append('[ ');
for (let i = 0; i < length; i++) {
if (i > 0) {
this.append(', ');
}
this.format(array[i]);
}
if (array.length > length) {
this.append(', ...');
}
let first = array.length === 0;
const wasTruncated = this.iterateObject(array, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(array, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' ]');
}
emitSet(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set');
return;
}
this.append('Set( ');
const size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
set.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(value);
i++;
}, this);
if (set.size > size) {
this.append(', ...');
}
this.append(' )');
}
emitMap(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
const size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
map.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format([key, value]);
i++;
}, this);
if (map.size > size) {
this.append(', ...');
}
this.append(' )');
}
emitObject(obj) {
const ctor = obj.constructor;
const constructorName =
typeof ctor === 'function' && obj instanceof ctor
? j$.fnNameFor(obj.constructor)
: 'null';
this.append(constructorName);
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
return;
}
this.append('({ ');
let first = true;
const wasTruncated = this.iterateObject(obj, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(obj, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' })');
}
emitTypedArray(arr) {
const constructorName = j$.fnNameFor(arr.constructor);
const limitedArray = Array.prototype.slice.call(
arr,
0,
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH
);
let itemsString = Array.prototype.join.call(limitedArray, ', ');
if (limitedArray.length !== arr.length) {
itemsString += ', ...';
}
this.append(constructorName + ' [ ' + itemsString + ' ]');
}
emitDomElement(el) {
const tagName = el.tagName.toLowerCase();
let out = '<' + tagName;
for (const attr of el.attributes) {
out += ' ' + attr.name;
if (attr.value !== '') {
out += '="' + attr.value + '"';
}
}
out += '>';
if (el.childElementCount !== 0 || el.textContent !== '') {
out += '...</' + tagName + '>';
}
this.append(out);
}
formatProperty(obj, property) {
if (typeof property === 'symbol') {
this.append(property.toString());
} else {
this.append(property);
}
this.append(': ');
this.format(obj[property]);
}
append(value) {
// This check protects us from the rare case where an object has overriden
// `toString()` with an invalid implementation (returning a non-string).
if (typeof value !== 'string') {
value = Object.prototype.toString.call(value);
}
const result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
this.length += result.value.length;
this.stringParts.push(result.value);
if (result.truncated) {
throw new MaxCharsReachedError();
}
}
} }
function hasCustomToString(value) { function hasCustomToString(value) {
@@ -7545,291 +7835,6 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
} }
SinglePrettyPrintRun.prototype.format = function(value) {
this.ppNestLevel_++;
try {
const customFormatResult = this.applyCustomFormatters_(value);
if (customFormatResult) {
this.emitScalar(customFormatResult);
} else if (j$.util.isUndefined(value)) {
this.emitScalar('undefined');
} else if (value === null) {
this.emitScalar('null');
} else if (value === 0 && 1 / value === -Infinity) {
this.emitScalar('-0');
} else if (value === j$.getGlobal()) {
this.emitScalar('<global>');
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString(this.pp_));
} else if (j$.isString_(value)) {
this.emitString(value);
} else if (j$.isSpy(value)) {
this.emitScalar('spy on ' + value.and.identity);
} else if (j$.isSpy(value.toString)) {
this.emitScalar('spy on ' + value.toString.and.identity);
} else if (value instanceof RegExp) {
this.emitScalar(value.toString());
} else if (typeof value === 'function') {
this.emitScalar('Function');
} else if (j$.isDomNode(value)) {
if (value.tagName) {
this.emitDomElement(value);
} else {
this.emitScalar('HTMLNode');
}
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (j$.isSet(value)) {
this.emitSet(value);
} else if (j$.isMap(value)) {
this.emitMap(value);
} else if (j$.isTypedArray_(value)) {
this.emitTypedArray(value);
} else if (
value.toString &&
typeof value === 'object' &&
!j$.isArray_(value) &&
hasCustomToString(value)
) {
try {
this.emitScalar(value.toString());
} catch (e) {
this.emitScalar('has-invalid-toString-method');
}
} else if (j$.util.arrayContains(this.seen, value)) {
this.emitScalar(
'<circular reference: ' +
(j$.isArray_(value) ? 'Array' : 'Object') +
'>'
);
} else if (j$.isArray_(value) || j$.isA_('Object', value)) {
this.seen.push(value);
if (j$.isArray_(value)) {
this.emitArray(value);
} else {
this.emitObject(value);
}
this.seen.pop();
} else {
this.emitScalar(value.toString());
}
} catch (e) {
if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
throw e;
}
} finally {
this.ppNestLevel_--;
}
};
SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) {
return customFormat(value, this.customObjectFormatters_);
};
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
const objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj));
const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
for (let i = 0; i < length; i++) {
fn(objKeys[i]);
}
return objKeys.length > length;
};
SinglePrettyPrintRun.prototype.emitScalar = function(value) {
this.append(value);
};
SinglePrettyPrintRun.prototype.emitString = function(value) {
this.append("'" + value + "'");
};
SinglePrettyPrintRun.prototype.emitArray = function(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array');
return;
}
const length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
this.append('[ ');
for (let i = 0; i < length; i++) {
if (i > 0) {
this.append(', ');
}
this.format(array[i]);
}
if (array.length > length) {
this.append(', ...');
}
let first = array.length === 0;
const wasTruncated = this.iterateObject(array, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(array, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' ]');
};
SinglePrettyPrintRun.prototype.emitSet = function(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set');
return;
}
this.append('Set( ');
const size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
set.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(value);
i++;
}, this);
if (set.size > size) {
this.append(', ...');
}
this.append(' )');
};
SinglePrettyPrintRun.prototype.emitMap = function(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
const size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
map.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format([key, value]);
i++;
}, this);
if (map.size > size) {
this.append(', ...');
}
this.append(' )');
};
SinglePrettyPrintRun.prototype.emitObject = function(obj) {
const ctor = obj.constructor;
const constructorName =
typeof ctor === 'function' && obj instanceof ctor
? j$.fnNameFor(obj.constructor)
: 'null';
this.append(constructorName);
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
return;
}
this.append('({ ');
let first = true;
const wasTruncated = this.iterateObject(obj, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(obj, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' })');
};
SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) {
const constructorName = j$.fnNameFor(arr.constructor);
const limitedArray = Array.prototype.slice.call(
arr,
0,
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH
);
let itemsString = Array.prototype.join.call(limitedArray, ', ');
if (limitedArray.length !== arr.length) {
itemsString += ', ...';
}
this.append(constructorName + ' [ ' + itemsString + ' ]');
};
SinglePrettyPrintRun.prototype.emitDomElement = function(el) {
const tagName = el.tagName.toLowerCase();
let out = '<' + tagName;
for (const attr of el.attributes) {
out += ' ' + attr.name;
if (attr.value !== '') {
out += '="' + attr.value + '"';
}
}
out += '>';
if (el.childElementCount !== 0 || el.textContent !== '') {
out += '...</' + tagName + '>';
}
this.append(out);
};
SinglePrettyPrintRun.prototype.formatProperty = function(obj, property) {
if (typeof property === 'symbol') {
this.append(property.toString());
} else {
this.append(property);
}
this.append(': ');
this.format(obj[property]);
};
SinglePrettyPrintRun.prototype.append = function(value) {
// This check protects us from the rare case where an object has overriden
// `toString()` with an invalid implementation (returning a non-string).
if (typeof value !== 'string') {
value = Object.prototype.toString.call(value);
}
const result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
this.length += result.value.length;
this.stringParts.push(result.value);
if (result.truncated) {
throw new MaxCharsReachedError();
}
};
function truncate(s, maxlen) { function truncate(s, maxlen) {
if (s.length <= maxlen) { if (s.length <= maxlen) {
return { value: s, truncated: false }; return { value: s, truncated: false };
+6 -6
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() {};
+294 -292
View File
@@ -1,11 +1,298 @@
getJasmineRequireObj().makePrettyPrinter = function(j$) { getJasmineRequireObj().makePrettyPrinter = function(j$) {
function SinglePrettyPrintRun(customObjectFormatters, pp) { class SinglePrettyPrintRun {
this.customObjectFormatters_ = customObjectFormatters; constructor(customObjectFormatters, pp) {
this.ppNestLevel_ = 0; this.customObjectFormatters_ = customObjectFormatters;
this.seen = []; this.ppNestLevel_ = 0;
this.length = 0; this.seen = [];
this.stringParts = []; this.length = 0;
this.pp_ = pp; this.stringParts = [];
this.pp_ = pp;
}
format(value) {
this.ppNestLevel_++;
try {
const customFormatResult = this.applyCustomFormatters_(value);
if (customFormatResult) {
this.emitScalar(customFormatResult);
} else if (j$.util.isUndefined(value)) {
this.emitScalar('undefined');
} else if (value === null) {
this.emitScalar('null');
} else if (value === 0 && 1 / value === -Infinity) {
this.emitScalar('-0');
} else if (value === j$.getGlobal()) {
this.emitScalar('<global>');
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString(this.pp_));
} else if (j$.isString_(value)) {
this.emitString(value);
} else if (j$.isSpy(value)) {
this.emitScalar('spy on ' + value.and.identity);
} else if (j$.isSpy(value.toString)) {
this.emitScalar('spy on ' + value.toString.and.identity);
} else if (value instanceof RegExp) {
this.emitScalar(value.toString());
} else if (typeof value === 'function') {
this.emitScalar('Function');
} else if (j$.isDomNode(value)) {
if (value.tagName) {
this.emitDomElement(value);
} else {
this.emitScalar('HTMLNode');
}
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (j$.isSet(value)) {
this.emitSet(value);
} else if (j$.isMap(value)) {
this.emitMap(value);
} else if (j$.isTypedArray_(value)) {
this.emitTypedArray(value);
} else if (
value.toString &&
typeof value === 'object' &&
!j$.isArray_(value) &&
hasCustomToString(value)
) {
try {
this.emitScalar(value.toString());
} catch (e) {
this.emitScalar('has-invalid-toString-method');
}
} else if (j$.util.arrayContains(this.seen, value)) {
this.emitScalar(
'<circular reference: ' +
(j$.isArray_(value) ? 'Array' : 'Object') +
'>'
);
} else if (j$.isArray_(value) || j$.isA_('Object', value)) {
this.seen.push(value);
if (j$.isArray_(value)) {
this.emitArray(value);
} else {
this.emitObject(value);
}
this.seen.pop();
} else {
this.emitScalar(value.toString());
}
} catch (e) {
if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
throw e;
}
} finally {
this.ppNestLevel_--;
}
}
applyCustomFormatters_(value) {
return customFormat(value, this.customObjectFormatters_);
}
iterateObject(obj, fn) {
const objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj));
const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
for (let i = 0; i < length; i++) {
fn(objKeys[i]);
}
return objKeys.length > length;
}
emitScalar(value) {
this.append(value);
}
emitString(value) {
this.append("'" + value + "'");
}
emitArray(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array');
return;
}
const length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
this.append('[ ');
for (let i = 0; i < length; i++) {
if (i > 0) {
this.append(', ');
}
this.format(array[i]);
}
if (array.length > length) {
this.append(', ...');
}
let first = array.length === 0;
const wasTruncated = this.iterateObject(array, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(array, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' ]');
}
emitSet(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set');
return;
}
this.append('Set( ');
const size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
set.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(value);
i++;
}, this);
if (set.size > size) {
this.append(', ...');
}
this.append(' )');
}
emitMap(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
const size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
map.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format([key, value]);
i++;
}, this);
if (map.size > size) {
this.append(', ...');
}
this.append(' )');
}
emitObject(obj) {
const ctor = obj.constructor;
const constructorName =
typeof ctor === 'function' && obj instanceof ctor
? j$.fnNameFor(obj.constructor)
: 'null';
this.append(constructorName);
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
return;
}
this.append('({ ');
let first = true;
const wasTruncated = this.iterateObject(obj, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(obj, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' })');
}
emitTypedArray(arr) {
const constructorName = j$.fnNameFor(arr.constructor);
const limitedArray = Array.prototype.slice.call(
arr,
0,
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH
);
let itemsString = Array.prototype.join.call(limitedArray, ', ');
if (limitedArray.length !== arr.length) {
itemsString += ', ...';
}
this.append(constructorName + ' [ ' + itemsString + ' ]');
}
emitDomElement(el) {
const tagName = el.tagName.toLowerCase();
let out = '<' + tagName;
for (const attr of el.attributes) {
out += ' ' + attr.name;
if (attr.value !== '') {
out += '="' + attr.value + '"';
}
}
out += '>';
if (el.childElementCount !== 0 || el.textContent !== '') {
out += '...</' + tagName + '>';
}
this.append(out);
}
formatProperty(obj, property) {
if (typeof property === 'symbol') {
this.append(property.toString());
} else {
this.append(property);
}
this.append(': ');
this.format(obj[property]);
}
append(value) {
// This check protects us from the rare case where an object has overriden
// `toString()` with an invalid implementation (returning a non-string).
if (typeof value !== 'string') {
value = Object.prototype.toString.call(value);
}
const result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
this.length += result.value.length;
this.stringParts.push(result.value);
if (result.truncated) {
throw new MaxCharsReachedError();
}
}
} }
function hasCustomToString(value) { function hasCustomToString(value) {
@@ -23,291 +310,6 @@ getJasmineRequireObj().makePrettyPrinter = function(j$) {
} }
} }
SinglePrettyPrintRun.prototype.format = function(value) {
this.ppNestLevel_++;
try {
const customFormatResult = this.applyCustomFormatters_(value);
if (customFormatResult) {
this.emitScalar(customFormatResult);
} else if (j$.util.isUndefined(value)) {
this.emitScalar('undefined');
} else if (value === null) {
this.emitScalar('null');
} else if (value === 0 && 1 / value === -Infinity) {
this.emitScalar('-0');
} else if (value === j$.getGlobal()) {
this.emitScalar('<global>');
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString(this.pp_));
} else if (j$.isString_(value)) {
this.emitString(value);
} else if (j$.isSpy(value)) {
this.emitScalar('spy on ' + value.and.identity);
} else if (j$.isSpy(value.toString)) {
this.emitScalar('spy on ' + value.toString.and.identity);
} else if (value instanceof RegExp) {
this.emitScalar(value.toString());
} else if (typeof value === 'function') {
this.emitScalar('Function');
} else if (j$.isDomNode(value)) {
if (value.tagName) {
this.emitDomElement(value);
} else {
this.emitScalar('HTMLNode');
}
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (j$.isSet(value)) {
this.emitSet(value);
} else if (j$.isMap(value)) {
this.emitMap(value);
} else if (j$.isTypedArray_(value)) {
this.emitTypedArray(value);
} else if (
value.toString &&
typeof value === 'object' &&
!j$.isArray_(value) &&
hasCustomToString(value)
) {
try {
this.emitScalar(value.toString());
} catch (e) {
this.emitScalar('has-invalid-toString-method');
}
} else if (j$.util.arrayContains(this.seen, value)) {
this.emitScalar(
'<circular reference: ' +
(j$.isArray_(value) ? 'Array' : 'Object') +
'>'
);
} else if (j$.isArray_(value) || j$.isA_('Object', value)) {
this.seen.push(value);
if (j$.isArray_(value)) {
this.emitArray(value);
} else {
this.emitObject(value);
}
this.seen.pop();
} else {
this.emitScalar(value.toString());
}
} catch (e) {
if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
throw e;
}
} finally {
this.ppNestLevel_--;
}
};
SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) {
return customFormat(value, this.customObjectFormatters_);
};
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
const objKeys = j$.MatchersUtil.keys(obj, j$.isArray_(obj));
const length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
for (let i = 0; i < length; i++) {
fn(objKeys[i]);
}
return objKeys.length > length;
};
SinglePrettyPrintRun.prototype.emitScalar = function(value) {
this.append(value);
};
SinglePrettyPrintRun.prototype.emitString = function(value) {
this.append("'" + value + "'");
};
SinglePrettyPrintRun.prototype.emitArray = function(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array');
return;
}
const length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
this.append('[ ');
for (let i = 0; i < length; i++) {
if (i > 0) {
this.append(', ');
}
this.format(array[i]);
}
if (array.length > length) {
this.append(', ...');
}
let first = array.length === 0;
const wasTruncated = this.iterateObject(array, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(array, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' ]');
};
SinglePrettyPrintRun.prototype.emitSet = function(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set');
return;
}
this.append('Set( ');
const size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
set.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format(value);
i++;
}, this);
if (set.size > size) {
this.append(', ...');
}
this.append(' )');
};
SinglePrettyPrintRun.prototype.emitMap = function(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
const size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
let i = 0;
map.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format([key, value]);
i++;
}, this);
if (map.size > size) {
this.append(', ...');
}
this.append(' )');
};
SinglePrettyPrintRun.prototype.emitObject = function(obj) {
const ctor = obj.constructor;
const constructorName =
typeof ctor === 'function' && obj instanceof ctor
? j$.fnNameFor(obj.constructor)
: 'null';
this.append(constructorName);
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
return;
}
this.append('({ ');
let first = true;
const wasTruncated = this.iterateObject(obj, property => {
if (first) {
first = false;
} else {
this.append(', ');
}
this.formatProperty(obj, property);
});
if (wasTruncated) {
this.append(', ...');
}
this.append(' })');
};
SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) {
const constructorName = j$.fnNameFor(arr.constructor);
const limitedArray = Array.prototype.slice.call(
arr,
0,
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH
);
let itemsString = Array.prototype.join.call(limitedArray, ', ');
if (limitedArray.length !== arr.length) {
itemsString += ', ...';
}
this.append(constructorName + ' [ ' + itemsString + ' ]');
};
SinglePrettyPrintRun.prototype.emitDomElement = function(el) {
const tagName = el.tagName.toLowerCase();
let out = '<' + tagName;
for (const attr of el.attributes) {
out += ' ' + attr.name;
if (attr.value !== '') {
out += '="' + attr.value + '"';
}
}
out += '>';
if (el.childElementCount !== 0 || el.textContent !== '') {
out += '...</' + tagName + '>';
}
this.append(out);
};
SinglePrettyPrintRun.prototype.formatProperty = function(obj, property) {
if (typeof property === 'symbol') {
this.append(property.toString());
} else {
this.append(property);
}
this.append(': ');
this.format(obj[property]);
};
SinglePrettyPrintRun.prototype.append = function(value) {
// This check protects us from the rare case where an object has overriden
// `toString()` with an invalid implementation (returning a non-string).
if (typeof value !== 'string') {
value = Object.prototype.toString.call(value);
}
const result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
this.length += result.value.length;
this.stringParts.push(result.value);
if (result.truncated) {
throw new MaxCharsReachedError();
}
};
function truncate(s, maxlen) { function truncate(s, maxlen) {
if (s.length <= maxlen) { if (s.length <= maxlen) {
return { value: s, truncated: false }; return { value: s, truncated: false };
+95 -96
View File
@@ -1,113 +1,112 @@
getJasmineRequireObj().DiffBuilder = function(j$) { getJasmineRequireObj().DiffBuilder = function(j$) {
return function DiffBuilder(config) { class DiffBuilder {
const prettyPrinter = constructor(config) {
(config || {}).prettyPrinter || j$.makePrettyPrinter(); this.prettyPrinter_ =
const mismatches = new j$.MismatchTree(); (config || {}).prettyPrinter || j$.makePrettyPrinter();
let path = new j$.ObjectPath(); this.mismatches_ = new j$.MismatchTree();
let actualRoot = undefined; this.path_ = new j$.ObjectPath();
let expectedRoot = undefined; this.actualRoot_ = 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) {
messages.push(formatter(actual, expected, path, prettyPrinter));
return true;
}
const actualCustom = prettyPrinter.customFormat_(actual);
const expectedCustom = prettyPrinter.customFormat_(expected);
const useCustom = !(
j$.util.isUndefined(actualCustom) &&
j$.util.isUndefined(expectedCustom)
);
if (useCustom) {
messages.push(
wrapPrettyPrinted(actualCustom, expectedCustom, path)
);
return false; // don't recurse further
}
if (isLeaf) {
messages.push(
defaultFormatter(actual, expected, path, prettyPrinter)
);
}
if (formatter) {
messages.push(formatter(actual, expected, path, this.prettyPrinter_));
return true; return true;
}); }
return messages.join('\n'); const actualCustom = this.prettyPrinter_.customFormat_(actual);
}, const expectedCustom = this.prettyPrinter_.customFormat_(expected);
const useCustom = !(
j$.util.isUndefined(actualCustom) &&
j$.util.isUndefined(expectedCustom)
);
withPath: function(pathComponent, block) { if (useCustom) {
const oldPath = path; messages.push(wrapPrettyPrinted(actualCustom, expectedCustom, path));
path = path.add(pathComponent); return false; // don't recurse further
block(); }
path = oldPath;
if (isLeaf) {
messages.push(this.defaultFormatter_(actual, expected, path));
}
return true;
});
return messages.join('\n');
}
withPath(pathComponent, block) {
const oldPath = this.path_;
this.path_ = this.path_.add(pathComponent);
block();
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;
}
};
handleAsymmetricExpected();
for (const pc of objectPath.components) {
actual = actual[pc];
expected = expected[pc];
handleAsymmetricExpected();
} }
};
function defaultFormatter(actual, expected, path, prettyPrinter) { 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) {
return (
'Expected ' +
path +
(path.depth() ? ' = ' : '') +
actual +
' to equal ' +
expected +
'.'
);
}
};
function dereferencePath(objectPath, actual, expected, pp) {
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 };
} }
function wrapPrettyPrinted(actual, expected, path) {
return (
'Expected ' +
path +
(path.depth() ? ' = ' : '') +
actual +
' to equal ' +
expected +
'.'
);
}
return DiffBuilder;
}; };
+38 -36
View File
@@ -6,49 +6,51 @@ 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 {
this.path = path || new j$.ObjectPath([]); constructor(path) {
this.formatter = undefined; this.path = path || new j$.ObjectPath([]);
this.children = []; this.formatter = undefined;
this.isMismatch = false; this.children = [];
} this.isMismatch = false;
MismatchTree.prototype.add = function(path, formatter) {
if (path.depth() === 0) {
this.formatter = formatter;
this.isMismatch = true;
} else {
const key = path.components[0];
path = path.shift();
let child = this.child(key);
if (!child) {
child = new MismatchTree(this.path.add(key));
this.children.push(child);
}
child.add(path, formatter);
} }
};
MismatchTree.prototype.traverse = function(visit) { add(path, formatter) {
const hasChildren = this.children.length > 0; if (path.depth() === 0) {
this.formatter = formatter;
this.isMismatch = true;
} else {
const key = path.components[0];
path = path.shift();
let child = this.child(key);
if (this.isMismatch || hasChildren) { if (!child) {
if (visit(this.path, !hasChildren, this.formatter)) { child = new MismatchTree(this.path.add(key));
for (const child of this.children) { this.children.push(child);
child.traverse(visit); }
child.add(path, formatter);
}
}
traverse(visit) {
const hasChildren = this.children.length > 0;
if (this.isMismatch || hasChildren) {
if (visit(this.path, !hasChildren, this.formatter)) {
for (const child of this.children) {
child.traverse(visit);
}
} }
} }
} }
};
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;
}; };
+22 -20
View File
@@ -1,27 +1,29 @@
getJasmineRequireObj().ObjectPath = function(j$) { getJasmineRequireObj().ObjectPath = function(j$) {
function ObjectPath(components) { class ObjectPath {
this.components = components || []; constructor(components) {
} this.components = components || [];
ObjectPath.prototype.toString = function() {
if (this.components.length) {
return '$' + this.components.map(formatPropertyAccess).join('');
} else {
return '';
} }
};
ObjectPath.prototype.add = function(component) { toString() {
return new ObjectPath(this.components.concat([component])); if (this.components.length) {
}; return '$' + this.components.map(formatPropertyAccess).join('');
} else {
return '';
}
}
ObjectPath.prototype.shift = function() { add(component) {
return new ObjectPath(this.components.slice(1)); return new ObjectPath(this.components.concat([component]));
}; }
ObjectPath.prototype.depth = function() { shift() {
return this.components.length; return new ObjectPath(this.components.slice(1));
}; }
depth() {
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) {
+1 -1
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);