| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index 1fb5e5620a684dba9a23af511eaffcf54e10a47b..d6d8e9b1f844bc8df7d959e162e071422b6d0071 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -18139,6 +18139,168 @@ TEST(InlineScriptWithSourceURLInStackTrace) {
|
| CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
|
| }
|
|
|
| +void SetPromise(const char* name, v8::Local<v8::Promise> promise) {
|
| + CcTest::global()
|
| + ->Set(CcTest::isolate()->GetCurrentContext(), v8_str(name), promise)
|
| + .FromJust();
|
| +}
|
| +
|
| +class PromiseHookData {
|
| + public:
|
| + int before_hook_count = 0;
|
| + int after_hook_count = 0;
|
| + int promise_hook_count = 0;
|
| + int parent_promise_count = 0;
|
| + std::string promise_hook_value;
|
| +
|
| + void Reset() {
|
| + before_hook_count = 0;
|
| + after_hook_count = 0;
|
| + promise_hook_count = 0;
|
| + parent_promise_count = 0;
|
| + promise_hook_value = "";
|
| + }
|
| +};
|
| +
|
| +PromiseHookData* promise_hook_data;
|
| +
|
| +void CustomPromiseHook(v8::PromiseHookType type, v8::Local<v8::Promise> promise,
|
| + v8::Local<v8::Value> parentPromise) {
|
| + promise_hook_data->promise_hook_count++;
|
| + switch (type) {
|
| + case v8::PromiseHookType::kInit:
|
| + SetPromise("init", promise);
|
| +
|
| + if (!parentPromise->IsUndefined()) {
|
| + promise_hook_data->parent_promise_count++;
|
| + SetPromise("parent", v8::Local<v8::Promise>::Cast(parentPromise));
|
| + }
|
| +
|
| + break;
|
| + case v8::PromiseHookType::kResolve:
|
| + SetPromise("resolve", promise);
|
| + break;
|
| + case v8::PromiseHookType::kBefore:
|
| + promise_hook_data->before_hook_count++;
|
| + CHECK(promise_hook_data->before_hook_count >
|
| + promise_hook_data->after_hook_count);
|
| + CHECK(CcTest::global()
|
| + ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
|
| + .ToLocalChecked()
|
| + ->Equals(CcTest::isolate()->GetCurrentContext(), v8_str(""))
|
| + .FromJust());
|
| + SetPromise("before", promise);
|
| + break;
|
| + case v8::PromiseHookType::kAfter:
|
| + promise_hook_data->after_hook_count++;
|
| + CHECK(promise_hook_data->after_hook_count <=
|
| + promise_hook_data->before_hook_count);
|
| + CHECK(CcTest::global()
|
| + ->Get(CcTest::isolate()->GetCurrentContext(), v8_str("value"))
|
| + .ToLocalChecked()
|
| + ->Equals(CcTest::isolate()->GetCurrentContext(),
|
| + v8_str(promise_hook_data->promise_hook_value.c_str()))
|
| + .FromJust());
|
| + SetPromise("after", promise);
|
| + break;
|
| + }
|
| +}
|
| +
|
| +TEST(PromiseHook) {
|
| + LocalContext env;
|
| + v8::Isolate* isolate = env->GetIsolate();
|
| + v8::HandleScope scope(isolate);
|
| +
|
| + v8::Local<v8::Object> global = CcTest::global();
|
| + v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
|
| +
|
| + promise_hook_data = new PromiseHookData();
|
| + promise_hook_data->promise_hook_value = "fulfilled";
|
| + const char* source =
|
| + "var resolve, value = ''; \n"
|
| + "var p = new Promise(r => resolve = r); \n";
|
| +
|
| + isolate->SetPromiseHook(CustomPromiseHook);
|
| +
|
| + CompileRun(source);
|
| + auto init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
|
| + CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
|
| + CHECK_EQ(1, promise_hook_data->promise_hook_count);
|
| + CHECK_EQ(0, promise_hook_data->parent_promise_count);
|
| +
|
| + CompileRun("var p1 = p.then(() => { value = 'fulfilled'; }); \n");
|
| + init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
|
| + auto parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
|
| + CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
|
| + CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
|
| + CHECK_EQ(2, promise_hook_data->promise_hook_count);
|
| + CHECK_EQ(1, promise_hook_data->parent_promise_count);
|
| +
|
| + CompileRun("resolve(); \n");
|
| + auto resolve_promise =
|
| + global->Get(context, v8_str("resolve")).ToLocalChecked();
|
| + auto before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
|
| + auto after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
|
| + CHECK(GetPromise("p")->Equals(env.local(), before_promise).FromJust());
|
| + CHECK(GetPromise("p")->Equals(env.local(), after_promise).FromJust());
|
| + CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
|
| + CHECK_EQ(5, promise_hook_data->promise_hook_count);
|
| +
|
| + promise_hook_data->Reset();
|
| + promise_hook_data->promise_hook_value = "rejected";
|
| + source =
|
| + "var reject, value = ''; \n"
|
| + "var p = new Promise((_, r) => reject = r); \n";
|
| +
|
| + CompileRun(source);
|
| + init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
|
| + CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
|
| + CHECK_EQ(1, promise_hook_data->promise_hook_count);
|
| + CHECK_EQ(0, promise_hook_data->parent_promise_count);
|
| +
|
| + CompileRun("var p1 = p.catch(() => { value = 'rejected'; }); \n");
|
| + init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
|
| + parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
|
| + CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
|
| + CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
|
| + CHECK_EQ(2, promise_hook_data->promise_hook_count);
|
| + CHECK_EQ(1, promise_hook_data->parent_promise_count);
|
| +
|
| + CompileRun("reject(); \n");
|
| + resolve_promise = global->Get(context, v8_str("resolve")).ToLocalChecked();
|
| + before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
|
| + after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
|
| + CHECK(GetPromise("p")->Equals(env.local(), before_promise).FromJust());
|
| + CHECK(GetPromise("p")->Equals(env.local(), after_promise).FromJust());
|
| + CHECK(GetPromise("p")->Equals(env.local(), resolve_promise).FromJust());
|
| + CHECK_EQ(5, promise_hook_data->promise_hook_count);
|
| +
|
| + promise_hook_data->Reset();
|
| + promise_hook_data->promise_hook_value = "Promise.resolve";
|
| + source =
|
| + "var value = ''; \n"
|
| + "var p = Promise.resolve('Promise.resolve'); \n";
|
| +
|
| + CompileRun(source);
|
| + init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
|
| + CHECK(GetPromise("p")->Equals(env.local(), init_promise).FromJust());
|
| + CHECK_EQ(1, promise_hook_data->promise_hook_count);
|
| + CHECK_EQ(0, promise_hook_data->parent_promise_count);
|
| +
|
| + CompileRun("var p1 = p.then((v) => { value = v; }); \n");
|
| + init_promise = global->Get(context, v8_str("init")).ToLocalChecked();
|
| + parent_promise = global->Get(context, v8_str("parent")).ToLocalChecked();
|
| + before_promise = global->Get(context, v8_str("before")).ToLocalChecked();
|
| + after_promise = global->Get(context, v8_str("after")).ToLocalChecked();
|
| + CHECK(GetPromise("p1")->Equals(env.local(), init_promise).FromJust());
|
| + CHECK(GetPromise("p")->Equals(env.local(), parent_promise).FromJust());
|
| + CHECK(GetPromise("p")->Equals(env.local(), before_promise).FromJust());
|
| + CHECK(GetPromise("p")->Equals(env.local(), after_promise).FromJust());
|
| + // There is no resolve hook called here.
|
| + CHECK_EQ(4, promise_hook_data->promise_hook_count);
|
| + CHECK_EQ(1, promise_hook_data->parent_promise_count);
|
| + delete promise_hook_data;
|
| +}
|
|
|
| void AnalyzeStackOfDynamicScriptWithSourceURL(
|
| const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
|