[mjsunit] Cleanup assertPromiseResult and add tests

assertPromiseResult caused tests to timeout when the result of the
promise was unexpected, e.g. rejected instead of the expected
fulfillment. This CL cleans up the implementation of
assertPromiseResult, adds better stack traces, and adds tests for all
the important cases I can think of.

R=mathias@chromium.org
CC=clemensh@chromium.org

Bug: v8:7570
Change-Id: I6ecb94fd3e5151502edf73c3bcdeb518b80fc81c
Reviewed-on: https://chromium-review.googlesource.com/1032786
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Mathias Bynens <mathias@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52882}
This commit is contained in:
Andreas Haas 2018-04-30 13:15:55 +02:00 committed by Commit Bot
parent 9011927acd
commit 938761ab60
15 changed files with 181 additions and 26 deletions

View File

@ -0,0 +1,11 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
load("test/mjsunit/mjsunit.js");
let promise = new Promise(function(resolve, reject) {
throw new Error("Error in creation");
});
assertPromiseResult(promise);

View File

@ -0,0 +1,12 @@
test/mjsunit/mjsunit.js:{NUMBER}: Error: Error in creation
throw concatenateErrors(stack, e);
^
Error
at assertPromiseResult (test/mjsunit/mjsunit.js:{NUMBER}:{NUMBER})
at *%(basename)s:11:1
Error: Error in creation
at *%(basename)s:8:9
at new Promise (<anonymous>)
at *%(basename)s:7:15

View File

@ -0,0 +1,14 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
load("test/mjsunit/mjsunit.js");
let reject_handler;
let promise = new Promise(function(resolve, reject) {
reject_handler = reject;
});
assertPromiseResult(promise);
reject_handler("Reject with callback");

View File

@ -0,0 +1,10 @@
test/mjsunit/mjsunit.js:{NUMBER}: Error: Reject with callback
throw concatenateErrors(stack, e);
^
Error
at assertPromiseResult (test/mjsunit/mjsunit.js:{NUMBER}:{NUMBER})
at *%(basename)s:12:1
Error: Reject with callback
at concatenateErrors (test/mjsunit/mjsunit.js:{NUMBER}:{NUMBER})
at _ (test/mjsunit/mjsunit.js:{NUMBER}:{NUMBER})

View File

@ -0,0 +1,11 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
load("test/mjsunit/mjsunit.js");
let obj = {f: 1254};
assertPromiseResult(
Promise.reject(obj), (o) => {print(o.f)},
_ => {throw new Error('Error in reject handler')});

View File

@ -0,0 +1,12 @@
test/mjsunit/mjsunit.js:{NUMBER}: Error: Error in reject handler
throw concatenateErrors(stack, e);
^
Error
at assertPromiseResult (test/mjsunit/mjsunit.js:{NUMBER}:{NUMBER})
at *%(basename)s:9:1
Error: Error in reject handler
at _ *%(basename)s:11:17)
at promise.then.result (test/mjsunit/mjsunit.js:{NUMBER}:{NUMBER})

View File

@ -0,0 +1,11 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
load("test/mjsunit/mjsunit.js");
let obj = {f: 1254};
assertPromiseResult(
Promise.resolve(obj), _ => {throw new Error('Error in resolve handler')},
(o) => {print(o.f)});

View File

@ -0,0 +1,13 @@
test/mjsunit/mjsunit.js:{NUMBER}: Error: Error in resolve handler
throw concatenateErrors(stack, e);
^
Error
at assertPromiseResult (test/mjsunit/mjsunit.js:{NUMBER}:{NUMBER})
at *%(basename)s:9:1
Error: Error in resolve handler
at _ *%(basename)s:10:39)
at promise.then.result (test/mjsunit/mjsunit.js:{NUMBER}:{NUMBER})

View File

@ -0,0 +1,12 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --no-stress-opt
load("test/mjsunit/mjsunit.js");
let obj = {f: 6254};
assertPromiseResult(
Promise.reject(obj), assertUnreachable, (o) => {print(o.f)});

View File

@ -0,0 +1 @@
6254

View File

@ -0,0 +1,16 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --no-stress-opt
load("test/mjsunit/mjsunit.js");
let resolve_handler;
let promise = new Promise(function(resolve, reject) {
resolve_handler = resolve;
});
assertPromiseResult(promise);
resolve_handler({f: 3463});

View File

@ -0,0 +1,11 @@
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --no-stress-opt
load("test/mjsunit/mjsunit.js");
let obj = {f: 1254};
assertPromiseResult(Promise.resolve(obj), (o) => {print(o.f)});

View File

@ -0,0 +1 @@
1254

View File

@ -135,7 +135,15 @@ var assertContains;
// Assert that a string matches a given regex.
var assertMatches;
// Assert the result of a promise.
// Assert that a promise resolves or rejects.
// Parameters:
// {promise} - the promise
// {success} - optional - a callback which is called with the result of the
// resolving promise.
// {fail} - optional - a callback which is called with the result of the
// rejecting promise. If the promise is rejected but no {fail}
// callback is set, the error is propagated out of the promise
// chain.
var assertPromiseResult;
var promiseTestChain;
@ -555,35 +563,47 @@ var prettyPrinted;
}
};
assertPromiseResult = function(promise, success, fail) {
// Use --allow-natives-syntax to use this function. Note that this function
// overwrites {failWithMessage} permanently with %AbortJS.
function concatenateErrors(stack, exception) {
// If the exception does not contain a stack trace, wrap it in a new Error.
if (!exception.stack) exception = new Error(exception);
// We have to patch mjsunit because normal assertion failures just throw
// exceptions which are swallowed in a then clause.
// We use eval here to avoid parsing issues with the natives syntax.
if (!success) success = () => {};
failWithMessage = (msg) => eval("%AbortJS(msg)");
if (!fail) {
fail = result => failWithMessage("assertPromiseResult failed: " + result);
// If the exception already provides a special stack trace, we do not modify
// it.
if (typeof exception.stack !== 'string') {
return exception;
}
exception.stack = stack + '\n\n' + exception.stack;
return exception;
}
var test_promise =
promise.then(
result => {
try {
success(result);
} catch (e) {
failWithMessage(String(e));
}
},
result => {
fail(result);
assertPromiseResult = function(promise, success, fail) {
const stack = (new Error()).stack;
var test_promise = promise.then(
result => {
try {
if (--promiseTestCount == 0) testRunner.notifyDone();
if (success) success(result);
} catch (e) {
// Use setTimeout to throw the error again to get out of the promise
// chain.
setTimeout(_ => {
throw concatenateErrors(stack, e);
}, 0);
}
},
result => {
try {
if (--promiseTestCount == 0) testRunner.notifyDone();
if (!fail) throw result;
fail(result);
} catch (e) {
// Use setTimeout to throw the error again to get out of the promise
// chain.
setTimeout(_ => {
throw concatenateErrors(stack, e);
}, 0);
}
)
.then((x)=> {
if (--promiseTestCount == 0) testRunner.notifyDone();
});
if (!promiseTestChain) promiseTestChain = Promise.resolve();