Commit 8c3c1b6c authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[mjsunit] Move the implementation of testAsync into a separate file

The original implementation of 'testAsync' in mjsunit.js required to
put the call to '%AbortJS' into an 'eval' statement. The reason is that
this call requires the flag --allow-natives-syntax to be set, but the
flag is not set in all mjsunit tests. With the use of 'eval'
compilation errors can be avoided.

The problem with this approach was that the fuzzer started to produce
test cases which include the line 'eval("%AbortJS(message)");', and
this line crashes intentionally. Different to the line
'%Abort(message)', however, the 'eval' statement cannot be filtered
so easily in the fuzzer. Therefore I pulled the implementation of
'testAsync' into a separate file to avoid the 'eval'.

Additional changes: I use '===' now instead of 'deepEquals' in
AsyncAssertion.equals because 'deepEquals' is not available outside
mjsunit.js. Using '===' seems more appropriate anyways because for
all tests but one it is sufficient, and it is more precise than
deepEquals.

R=gsathya@chromium.org

Bug: chromium:774841
Change-Id: I47270aa63ff5a1d6aa76a771f9276eaaf579c5ac
Reviewed-on: https://chromium-review.googlesource.com/1156598Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54833}
parent d9c3867a
......@@ -4,6 +4,8 @@
// Flags: --allow-natives-syntax
load('test/mjsunit/test-async.js');
// Make sure we properly throw a RangeError when overflowing the maximum
// number of elements for Promise.all, which is capped at 2^21 bits right
// now, since we store the indices as identity hash on the resolve element
......
......@@ -4,6 +4,8 @@
// Flags: --allow-natives-syntax
load('test/mjsunit/test-async.js');
// Test that pre-allocation of the result array works even if it needs to be
// allocated in large object space.
const a = new Array(64 * 1024);
......
......@@ -4,6 +4,8 @@
// Flags: --allow-natives-syntax
load('test/mjsunit/test-async.js');
// We store the index in the hash code field of the Promise.all resolve
// element closures, so make sure we properly handle the cases where this
// magical field turns into a PropertyArray later.
......
......@@ -4,6 +4,8 @@
// Flags: --allow-natives-syntax
load('test/mjsunit/test-async.js');
// .return() from state suspendedStart with undefined
testAsync(test => {
test.plan(3);
......
......@@ -4,6 +4,8 @@
// Flags: --allow-natives-syntax
load('test/mjsunit/test-async.js');
testAsync(test => {
test.plan(2);
......@@ -68,7 +70,7 @@ testAsync(test => {
// Return a thenable which is fulfilled later
testAsync(test => {
test.plan(2);
test.plan(3);
let resolve;
let awaitedThenable = { then(resolveFn) { resolve = resolveFn; } };
......@@ -84,7 +86,8 @@ testAsync(test => {
gen().next().then(
(iterResult) => {
test.equals({ value: "resolvedPromise", done: true }, iterResult);
test.equals("resolvedPromise", iterResult.value);
test.equals(true, iterResult.done);
test.equals(true, finallyEvaluated);
},
test.unexpectedRejection());
......
......@@ -4,6 +4,8 @@
// Flags: --allow-natives-syntax
load('test/mjsunit/test-async.js');
// Yield a thenable which is never settled
testAsync(test => {
test.plan(0);
......
......@@ -4,6 +4,8 @@
// Flags: --harmony-private-fields --allow-natives-syntax
load('test/mjsunit/test-async.js');
async function f(assert) {
try {
module_namespace_obj = await import('modules-skip-1.js');
......
......@@ -4,6 +4,8 @@
// Flags: --allow-natives-syntax
load('test/mjsunit/test-async.js');
assertThrows(() => Promise.prototype.finally.call(5), TypeError);
testAsync(assert => {
......
......@@ -180,9 +180,6 @@ var isOptimized;
// Returns true if given function is compiled by TurboFan.
var isTurboFanned;
// Used for async tests. See definition below for more documentation.
var testAsync;
// Monkey-patchable all-purpose failure handler.
var failWithMessage;
......@@ -757,111 +754,4 @@ var prettyPrinted;
} catch(e) {};
return error.stack;
}
/**
* This is to be used through the testAsync helper function defined
* below.
*
* This requires the --allow-natives-syntax flag to allow calling
* runtime functions.
*
* There must be at least one assertion in an async test. A test
* with no assertions will fail.
*
* @example
* testAsync(assert => {
* assert.plan(1) // There should be one assertion in this test.
* Promise.resolve(1)
* .then(val => assert.equals(1, val),
* assert.unreachable);
* })
*/
class AsyncAssertion {
constructor(test, name) {
this.expectedAsserts_ = -1;
this.actualAsserts_ = 0;
this.test_ = test;
this.name_ = name || '';
}
/**
* Sets the number of expected asserts in the test. The test fails
* if the number of asserts computed after running the test is not
* equal to this specified value.
* @param {number} expectedAsserts
*/
plan(expectedAsserts) {
this.expectedAsserts_ = expectedAsserts;
}
fail(expectedText, found) {
let message = formatFailureText(expectedText, found);
message += "\nin test:" + this.name_
message += "\n" + Function.prototype.toString.apply(this.test_);
eval("%AbortJS(message)");
}
equals(expected, found, name_opt) {
this.actualAsserts_++;
if (!deepEquals(expected, found)) {
this.fail(prettyPrinted(expected), found, name_opt);
}
}
unreachable() {
let message = "Failure: unreachable in test: " + this.name_;
message += "\n" + Function.prototype.toString.apply(this.test_);
eval("%AbortJS(message)");
}
unexpectedRejection(details) {
return (error) => {
let message =
"Failure: unexpected Promise rejection in test: " + this.name_;
if (details) message += "\n @" + details;
if (error instanceof Error) {
message += "\n" + String(error.stack);
} else {
message += "\n" + String(error);
}
message += "\n\n" + Function.prototype.toString.apply(this.test_);
eval("%AbortJS(message)");
};
}
drainMicrotasks() {
eval("%RunMicrotasks()");
}
done_() {
if (this.expectedAsserts_ === -1) {
let message = "Please call t.plan(count) to initialize test harness " +
"with correct assert count (Note: count > 0)";
eval("%AbortJS(message)");
}
if (this.expectedAsserts_ !== this.actualAsserts_) {
let message = "Expected asserts: " + this.expectedAsserts_;
message += ", Actual asserts: " + this.actualAsserts_;
message += "\nin test: " + this.name_;
message += "\n" + Function.prototype.toString.apply(this.test_);
eval("%AbortJS(message)");
}
}
}
/** This is used to test async functions and promises.
* @param {testCallback} test - test function
* @param {string} [name] - optional name of the test
*
*
* @callback testCallback
* @param {AsyncAssertion} assert
*/
testAsync = function(test, name) {
let assert = new AsyncAssertion(test, name);
test(assert);
eval("%RunMicrotasks()");
assert.done_();
}
})();
......@@ -4,6 +4,8 @@
//
// Flags: --allow-natives-syntax --no-lazy
load('test/mjsunit/test-async.js');
// For regression testing, it's important that these functions are:
// 1) toplevel
// 2) arrow functions with single-expression bodies
......
......@@ -4,6 +4,8 @@
// Flags: --allow-natives-syntax
load('test/mjsunit/test-async.js');
testAsync(assert => {
assert.plan(1);
const error = new TypeError('Throwing');
......
// 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: --allow-natives-syntax
// Used for async tests. See definition below for more documentation.
var testAsync;
(function () { // Scope for utility functions.
/**
* This is to be used through the testAsync helper function defined
* below.
*
* This requires the --allow-natives-syntax flag to allow calling
* runtime functions.
*
* There must be at least one assertion in an async test. A test
* with no assertions will fail.
*
* @example
* testAsync(assert => {
* assert.plan(1) // There should be one assertion in this test.
* Promise.resolve(1)
* .then(val => assert.equals(1, val),
* assert.unreachable);
* })
*/
class AsyncAssertion {
constructor(test, name) {
this.expectedAsserts_ = -1;
this.actualAsserts_ = 0;
this.test_ = test;
this.name_ = name || '';
}
/**
* Sets the number of expected asserts in the test. The test fails
* if the number of asserts computed after running the test is not
* equal to this specified value.
* @param {number} expectedAsserts
*/
plan(expectedAsserts) {
this.expectedAsserts_ = expectedAsserts;
}
fail(expectedText, found) {
let message = formatFailureText(expectedText, found);
message += "\nin test:" + this.name_
message += "\n" + Function.prototype.toString.apply(this.test_);
%AbortJS(message);
}
equals(expected, found, name_opt) {
this.actualAsserts_++;
if (expected !== found) {
this.fail(prettyPrinted(expected), found, name_opt);
}
}
unreachable() {
let message = "Failure: unreachable in test: " + this.name_;
message += "\n" + Function.prototype.toString.apply(this.test_);
%AbortJS(message);
}
unexpectedRejection(details) {
return (error) => {
let message =
"Failure: unexpected Promise rejection in test: " + this.name_;
if (details) message += "\n @" + details;
if (error instanceof Error) {
message += "\n" + String(error.stack);
} else {
message += "\n" + String(error);
}
message += "\n\n" + Function.prototype.toString.apply(this.test_);
%AbortJS(message);
};
}
drainMicrotasks() {
%RunMicrotasks();
}
done_() {
if (this.expectedAsserts_ === -1) {
let message = "Please call t.plan(count) to initialize test harness " +
"with correct assert count (Note: count > 0)";
%AbortJS(message);
}
if (this.expectedAsserts_ !== this.actualAsserts_) {
let message = "Expected asserts: " + this.expectedAsserts_;
message += ", Actual asserts: " + this.actualAsserts_;
message += "\nin test: " + this.name_;
message += "\n" + Function.prototype.toString.apply(this.test_);
%AbortJS(message);
}
}
}
/** This is used to test async functions and promises.
* @param {testCallback} test - test function
* @param {string} [name] - optional name of the test
*
*
* @callback testCallback
* @param {AsyncAssertion} assert
*/
testAsync = function(test, name) {
let assert = new AsyncAssertion(test, name);
test(assert);
%RunMicrotasks();
assert.done_();
}
})();
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