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

@@ -1,113 +1,112 @@
getJasmineRequireObj().DiffBuilder = function(j$) {
return function DiffBuilder(config) {
const prettyPrinter =
(config || {}).prettyPrinter || j$.makePrettyPrinter();
const mismatches = new j$.MismatchTree();
let path = new j$.ObjectPath();
let actualRoot = undefined;
let expectedRoot = undefined;
class DiffBuilder {
constructor(config) {
this.prettyPrinter_ =
(config || {}).prettyPrinter || j$.makePrettyPrinter();
this.mismatches_ = new j$.MismatchTree();
this.path_ = new j$.ObjectPath();
this.actualRoot_ = undefined;
this.expectedRoot_ = undefined;
}
return {
setRoots: function(actual, expected) {
actualRoot = actual;
expectedRoot = expected;
},
setRoots(actual, expected) {
this.actualRoot_ = actual;
this.expectedRoot_ = expected;
}
recordMismatch: function(formatter) {
mismatches.add(path, formatter);
},
recordMismatch(formatter) {
this.mismatches_.add(this.path_, formatter);
}
getMessage: function() {
const messages = [];
getMessage() {
const messages = [];
mismatches.traverse(function(path, isLeaf, formatter) {
const { actual, expected } = dereferencePath(
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)
);
}
this.mismatches_.traverse((path, isLeaf, formatter) => {
const { actual, expected } = this.dereferencePath_(path);
if (formatter) {
messages.push(formatter(actual, expected, path, this.prettyPrinter_));
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) {
const oldPath = path;
path = path.add(pathComponent);
block();
path = oldPath;
if (useCustom) {
messages.push(wrapPrettyPrinted(actualCustom, expectedCustom, path));
return false; // don't recurse further
}
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(
prettyPrinter(actual),
prettyPrinter(expected),
this.prettyPrinter_(actual),
this.prettyPrinter_(expected),
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;
};

View File

@@ -6,49 +6,51 @@ getJasmineRequireObj().MismatchTree = function(j$) {
the expected and actual object graphs. MismatchTree maintains that context
and provides it via the traverse method.
*/
function MismatchTree(path) {
this.path = path || new j$.ObjectPath([]);
this.formatter = undefined;
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);
class MismatchTree {
constructor(path) {
this.path = path || new j$.ObjectPath([]);
this.formatter = undefined;
this.children = [];
this.isMismatch = false;
}
};
MismatchTree.prototype.traverse = function(visit) {
const hasChildren = this.children.length > 0;
add(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 (this.isMismatch || hasChildren) {
if (visit(this.path, !hasChildren, this.formatter)) {
for (const child of this.children) {
child.traverse(visit);
if (!child) {
child = new MismatchTree(this.path.add(key));
this.children.push(child);
}
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) {
return this.children.find(child => {
const pathEls = child.path.components;
return pathEls[pathEls.length - 1] === key;
});
};
child(key) {
return this.children.find(child => {
const pathEls = child.path.components;
return pathEls[pathEls.length - 1] === key;
});
}
}
return MismatchTree;
};

View File

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

View File

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