Commit 5704f86c authored by Leszek Swirski's avatar Leszek Swirski Committed by V8 LUCI CQ

[test] Pretty print object properties on assert failure

Because I don't get much out of "Object() != Object()"

Change-Id: I5a765b9cb0a272d30edcd834ec7b60d2fd03190b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3497352Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79370}
parent d05a38f9
...@@ -3,7 +3,7 @@ test/mjsunit/mjsunit.js:{NUMBER}: Failure: expected <not same as 1> found <1> ...@@ -3,7 +3,7 @@ test/mjsunit/mjsunit.js:{NUMBER}: Failure: expected <not same as 1> found <1>
Stack: MjsUnitAssertionError Stack: MjsUnitAssertionError
at assertNotSame *mjsunit.js {NUMBER}:{NUMBER} at assertNotSame *mjsunit.js {NUMBER}:{NUMBER}
at *%(basename)s 7:1 at *%(basename)s 7:1
throw new MjsUnitAssertionError(message); throw new MjsUnitAssertionError(
^ ^
MjsUnitAssertionError MjsUnitAssertionError
at assertNotSame *mjsunit.js {NUMBER}:{NUMBER} at assertNotSame *mjsunit.js {NUMBER}:{NUMBER}
......
...@@ -3,7 +3,7 @@ test/mjsunit/mjsunit.js:{NUMBER}: Failure: expected <true> found <false> ...@@ -3,7 +3,7 @@ test/mjsunit/mjsunit.js:{NUMBER}: Failure: expected <true> found <false>
Stack: MjsUnitAssertionError Stack: MjsUnitAssertionError
at assertTrue *mjsunit.js {NUMBER}:{NUMBER} at assertTrue *mjsunit.js {NUMBER}:{NUMBER}
at *%(basename)s 7:1 at *%(basename)s 7:1
throw new MjsUnitAssertionError(message); throw new MjsUnitAssertionError(
^ ^
MjsUnitAssertionError MjsUnitAssertionError
at assertTrue *mjsunit.js {NUMBER}:{NUMBER} at assertTrue *mjsunit.js {NUMBER}:{NUMBER}
......
...@@ -25,18 +25,34 @@ ...@@ -25,18 +25,34 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function MjsUnitAssertionError(message) { var MjsUnitAssertionError = class MjsUnitAssertionError {
this.message = message; #cached_message = undefined;
// Temporarily install a custom stack trace formatter and restore the #message_func = undefined;
// previous value.
let prevPrepareStackTrace = Error.prepareStackTrace; constructor(message_func) {
try { this.#message_func = message_func;
Error.prepareStackTrace = MjsUnitAssertionError.prepareStackTrace; // Temporarily install a custom stack trace formatter and restore the
// This allows fetching the stack trace using TryCatch::StackTrace. // previous value.
this.stack = new Error("MjsUnitAssertionError").stack; let prevPrepareStackTrace = Error.prepareStackTrace;
} finally { try {
Error.prepareStackTrace = prevPrepareStackTrace; Error.prepareStackTrace = MjsUnitAssertionError.prepareStackTrace;
// This allows fetching the stack trace using TryCatch::StackTrace.
this.stack = new Error("MjsUnitAssertionError").stack;
} finally {
Error.prepareStackTrace = prevPrepareStackTrace;
}
}
get message() {
if (this.#cached_message === undefined) {
this.#cached_message = this.#message_func();
}
return this.#cached_message
} }
toString() {
return this.message + "\n\nStack: " + this.stack;
};
} }
/* /*
...@@ -45,11 +61,6 @@ function MjsUnitAssertionError(message) { ...@@ -45,11 +61,6 @@ function MjsUnitAssertionError(message) {
* the f-word and ignore all other lines. * the f-word and ignore all other lines.
*/ */
MjsUnitAssertionError.prototype.toString = function () {
return this.message + "\n\nStack: " + this.stack;
};
// Expected and found values the same objects, or the same primitive // Expected and found values the same objects, or the same primitive
// values. // values.
// For known primitive values, please use assertEquals. // For known primitive values, please use assertEquals.
...@@ -258,69 +269,82 @@ var prettyPrinted; ...@@ -258,69 +269,82 @@ var prettyPrinted;
prettyPrinted = function prettyPrinted(value) { prettyPrinted = function prettyPrinted(value) {
switch (typeof value) { let visited = new Set();
case "string": function prettyPrint(value) {
return JSONStringify(value); try {
case "bigint": switch (typeof value) {
return String(value) + "n"; case "string":
case "number": return JSONStringify(value);
if (value === 0 && (1 / value) < 0) return "-0"; case "bigint":
// FALLTHROUGH. return String(value) + "n";
case "boolean": case "number":
case "undefined": if (value === 0 && (1 / value) < 0) return "-0";
case "function": // FALLTHROUGH.
case "symbol": case "boolean":
return String(value); case "undefined":
case "object": case "function":
if (value === null) return "null"; case "symbol":
var objectClass = classOf(value); return String(value);
switch (objectClass) { case "object":
case "Number": if (value === null) return "null";
case "BigInt": // Guard against re-visiting.
case "String": if (visited.has(value)) return "<...>";
case "Boolean": visited.add(value);
case "Date": var objectClass = classOf(value);
return objectClass + "(" + prettyPrinted(ValueOf(value)) + ")"; switch (objectClass) {
case "RegExp": case "Number":
return RegExpPrototypeToString.call(value); case "BigInt":
case "Array": case "String":
var mapped = ArrayPrototypeMap.call( case "Boolean":
value, prettyPrintedArrayElement); case "Date":
var joined = ArrayPrototypeJoin.call(mapped, ","); return objectClass + "(" + prettyPrint(ValueOf(value)) + ")";
return "[" + joined + "]"; case "RegExp":
case "Uint8Array": return RegExpPrototypeToString.call(value);
case "Int8Array": case "Array":
case "Int16Array": var mapped = ArrayPrototypeMap.call(
case "Uint16Array": value, (v,i,array)=>{
case "Uint32Array": if (v === undefined && !(i in array)) return "";
case "Int32Array": return prettyPrint(v, visited);
case "Float32Array": });
case "Float64Array": var joined = ArrayPrototypeJoin.call(mapped, ",");
var joined = ArrayPrototypeJoin.call(value, ","); return "[" + joined + "]";
return objectClass + "([" + joined + "])"; case "Uint8Array":
case "Object": case "Int8Array":
break; case "Int16Array":
case "Uint16Array":
case "Uint32Array":
case "Int32Array":
case "Float32Array":
case "Float64Array":
var joined = ArrayPrototypeJoin.call(value, ",");
return objectClass + "([" + joined + "])";
case "Object":
break;
default:
return objectClass + "(" + String(value) + ")";
}
// classOf() returned "Object".
var name = value.constructor?.name ?? "Object";
var pretty_properties = [];
for (let [k,v] of Object.entries(value)) {
ArrayPrototypePush.call(
pretty_properties, `${k}:${prettyPrint(v, visited)}`);
}
var joined = ArrayPrototypeJoin.call(pretty_properties, ",");
return `${name}({${joined}})`;
default: default:
return objectClass + "(" + String(value) + ")"; return "-- unknown value --";
} }
// classOf() returned "Object". } catch (e) {
var name = value.constructor.name; // Guard against general exceptions (especially stack overflows).
if (name) return name + "()"; return "<error>"
return "Object()"; }
default:
return "-- unknown value --";
} }
return prettyPrint(value);
} }
function prettyPrintedArrayElement(value, index, array) {
if (value === undefined && !(index in array)) return "";
return prettyPrinted(value);
}
failWithMessage = function failWithMessage(message) { failWithMessage = function failWithMessage(message) {
throw new MjsUnitAssertionError(message); throw new MjsUnitAssertionError(()=>message);
} }
formatFailureText = function(expectedText, found, name_opt) { formatFailureText = function(expectedText, found, name_opt) {
...@@ -340,7 +364,8 @@ var prettyPrinted; ...@@ -340,7 +364,8 @@ var prettyPrinted;
} }
function fail(expectedText, found, name_opt) { function fail(expectedText, found, name_opt) {
return failWithMessage(formatFailureText(expectedText, found, name_opt)); throw new MjsUnitAssertionError(
()=>formatFailureText(expectedText, found, name_opt));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment