Add support for native creation and resolution of Promises (fixes issue #3305)

This commit is contained in:
VodBox 2022-10-11 14:54:32 -04:00 committed by Marshall Greenblatt
parent 60ee4a34aa
commit fa643b269e
10 changed files with 609 additions and 9 deletions

View File

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=98f6d1c93609958fa457c15d7f6fef56fac7e3f6$
// $hash=b8af0d090bcb54f99d98804f7e3aaa0eab24449a$
//
#ifndef CEF_INCLUDE_CAPI_CEF_V8_CAPI_H_
@ -454,6 +454,11 @@ typedef struct _cef_v8value_t {
///
int(CEF_CALLBACK* is_function)(struct _cef_v8value_t* self);
///
/// True if the value type is a Promise.
///
int(CEF_CALLBACK* is_promise)(struct _cef_v8value_t* self);
///
/// Returns true (1) if this object is pointing to the same handle as |that|
/// object.
@ -718,6 +723,27 @@ typedef struct _cef_v8value_t {
struct _cef_v8value_t* object,
size_t argumentsCount,
struct _cef_v8value_t* const* arguments);
///
/// Resolve the Promise using the current V8 context. This function should
/// only be called from within the scope of a cef_v8handler_t or
/// cef_v8accessor_t callback, or in combination with calling enter() and
/// exit() on a stored cef_v8context_t reference. |arg| is the argument passed
/// to the resolved promise. Returns true (1) on success. Returns false (0) if
/// this function is called incorrectly or an exception is thrown.
///
int(CEF_CALLBACK* resolve_promise)(struct _cef_v8value_t* self,
struct _cef_v8value_t* arg);
///
/// Reject the Promise using the current V8 context. This function should only
/// be called from within the scope of a cef_v8handler_t or cef_v8accessor_t
/// callback, or in combination with calling enter() and exit() on a stored
/// cef_v8context_t reference. Returns true (1) on success. Returns false (0)
/// if this function is called incorrectly or an exception is thrown.
///
int(CEF_CALLBACK* reject_promise)(struct _cef_v8value_t* self,
const cef_string_t* errorMsg);
} cef_v8value_t;
///
@ -808,6 +834,14 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_array_buffer(
CEF_EXPORT cef_v8value_t* cef_v8value_create_function(const cef_string_t* name,
cef_v8handler_t* handler);
///
/// Create a new cef_v8value_t object of type Promise. This function should only
/// be called from within the scope of a cef_render_process_handler_t,
/// cef_v8handler_t or cef_v8accessor_t callback, or in combination with calling
/// enter() and exit() on a stored cef_v8context_t reference.
///
CEF_EXPORT cef_v8value_t* cef_v8value_create_promise(void);
///
/// Structure representing a V8 stack trace handle. V8 handles can only be
/// accessed from the thread on which they are created. Valid threads for

View File

@ -42,13 +42,13 @@
// way that may cause binary incompatibility with other builds. The universal
// hash value will change if any platform is affected whereas the platform hash
// values will change only if that particular platform is affected.
#define CEF_API_HASH_UNIVERSAL "c06406b23dc4a845177dcd306541ce527d061364"
#define CEF_API_HASH_UNIVERSAL "dfec58669a2c79108d61246f4e523570c3a21f63"
#if defined(OS_WIN)
#define CEF_API_HASH_PLATFORM "edd206c50f636a935872c9cc251ccb9448b9050e"
#define CEF_API_HASH_PLATFORM "bd5a6f54227d8bd35d33580342cd78f81d0cee2e"
#elif defined(OS_MAC)
#define CEF_API_HASH_PLATFORM "a74e6429302d2d947cc614688e83cd3b29e74c17"
#define CEF_API_HASH_PLATFORM "11902ab39267c1048acfa5c41053c6cfe0bd6227"
#elif defined(OS_LINUX)
#define CEF_API_HASH_PLATFORM "e119b68ec7e406ca74ddea5e244af7150eef7118"
#define CEF_API_HASH_PLATFORM "213fb79db129c756661e7cfbe6749c15276bbebf"
#endif
#ifdef __cplusplus

View File

@ -536,6 +536,15 @@ class CefV8Value : public virtual CefBaseRefCounted {
static CefRefPtr<CefV8Value> CreateFunction(const CefString& name,
CefRefPtr<CefV8Handler> handler);
///
/// Create a new CefV8Value object of type Promise. This method should only be
/// called from within the scope of a CefRenderProcessHandler, CefV8Handler or
/// CefV8Accessor callback, or in combination with calling Enter() and Exit()
/// on a stored CefV8Context reference.
///
/*--cef()--*/
static CefRefPtr<CefV8Value> CreatePromise();
///
/// Returns true if the underlying handle is valid and it can be accessed on
/// the current thread. Do not call any other methods if this method returns
@ -616,6 +625,12 @@ class CefV8Value : public virtual CefBaseRefCounted {
/*--cef()--*/
virtual bool IsFunction() = 0;
///
/// True if the value type is a Promise.
///
/*--cef()--*/
virtual bool IsPromise() = 0;
///
/// Returns true if this object is pointing to the same handle as |that|
/// object.
@ -893,6 +908,29 @@ class CefV8Value : public virtual CefBaseRefCounted {
CefRefPtr<CefV8Context> context,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments) = 0;
// PROMISE METHODS - These methods are only available on Promises.
///
/// Resolve the Promise using the current V8 context. This method should only
/// be called from within the scope of a CefV8Handler or CefV8Accessor
/// callback, or in combination with calling Enter() and Exit() on a stored
/// CefV8Context reference. |arg| is the argument passed to the resolved
/// promise. Returns true on success. Returns false if this method is called
/// incorrectly or an exception is thrown.
///
/*--cef(optional_param=arg)--*/
virtual bool ResolvePromise(CefRefPtr<CefV8Value> arg) = 0;
///
/// Reject the Promise using the current V8 context. This method should only
/// be called from within the scope of a CefV8Handler or CefV8Accessor
/// callback, or in combination with calling Enter() and Exit() on a stored
/// CefV8Context reference. Returns true on success. Returns false if this
/// method is called incorrectly or an exception is thrown.
///
/*--cef()--*/
virtual bool RejectPromise(const CefString& errorMsg) = 0;
};
///

View File

@ -1480,6 +1480,33 @@ CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
return impl.get();
}
// static
CefRefPtr<CefV8Value> CefV8Value::CreatePromise() {
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
v8::Isolate* isolate = GetIsolateManager()->isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
if (context.IsEmpty()) {
NOTREACHED() << "not currently in a V8 context";
return nullptr;
}
v8::Local<v8::Promise::Resolver> promise_resolver =
v8::Promise::Resolver::New(context).ToLocalChecked();
// Create a tracker object that will cause the user data reference to be
// released when the V8 object is destroyed.
V8TrackObject* tracker = new V8TrackObject(isolate);
// Attach the tracker object.
tracker->AttachTo(context, promise_resolver);
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
impl->InitObject(promise_resolver, tracker);
return impl.get();
}
// CefV8ValueImpl
CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate)
@ -1713,6 +1740,16 @@ bool CefV8ValueImpl::IsFunction() {
}
}
bool CefV8ValueImpl::IsPromise() {
CEF_V8_REQUIRE_MLT_RETURN(false);
if (type_ == TYPE_OBJECT) {
v8::HandleScope handle_scope(handle_->isolate());
return handle_->GetNewV8Handle(false)->IsPromise();
} else {
return false;
}
}
bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
CEF_V8_REQUIRE_MLT_RETURN(false);
@ -2444,6 +2481,75 @@ CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunctionWithContext(
return retval;
}
bool CefV8ValueImpl::ResolvePromise(CefRefPtr<CefV8Value> arg) {
CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::Isolate* isolate = handle_->isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
if (!value->IsPromise()) {
NOTREACHED() << "V8 value is not a Promise";
return false;
}
if (arg.get() && !arg->IsValid()) {
NOTREACHED() << "invalid V8 arg parameter";
return false;
}
v8::Local<v8::Context> context_local = isolate->GetCurrentContext();
v8::Context::Scope context_scope(context_local);
v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
v8::Local<v8::Promise::Resolver> promise =
v8::Local<v8::Promise::Resolver>::Cast(obj);
v8::TryCatch try_catch(isolate);
try_catch.SetVerbose(true);
if (arg.get()) {
promise
->Resolve(context_local,
static_cast<CefV8ValueImpl*>(arg.get())->GetV8Value(true))
.ToChecked();
} else {
promise->Resolve(context_local, v8::Undefined(isolate)).ToChecked();
}
return !HasCaught(context_local, try_catch);
}
bool CefV8ValueImpl::RejectPromise(const CefString& errorMsg) {
CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::Isolate* isolate = handle_->isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
if (!value->IsPromise()) {
NOTREACHED() << "V8 value is not a Promise";
return false;
}
v8::Local<v8::Context> context_local = isolate->GetCurrentContext();
v8::Context::Scope context_scope(context_local);
v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
v8::Local<v8::Promise::Resolver> promise =
v8::Local<v8::Promise::Resolver>::Cast(obj);
v8::TryCatch try_catch(isolate);
try_catch.SetVerbose(true);
promise
->Reject(context_local,
v8::Exception::Error(GetV8String(isolate, errorMsg)))
.ToChecked();
return !HasCaught(context_local, try_catch);
}
bool CefV8ValueImpl::HasCaught(v8::Local<v8::Context> context,
v8::TryCatch& try_catch) {
if (try_catch.HasCaught()) {

View File

@ -237,6 +237,7 @@ class CefV8ValueImpl : public CefV8Value {
bool IsArray() override;
bool IsArrayBuffer() override;
bool IsFunction() override;
bool IsPromise() override;
bool IsSame(CefRefPtr<CefV8Value> value) override;
bool GetBoolValue() override;
int32 GetIntValue() override;
@ -282,6 +283,9 @@ class CefV8ValueImpl : public CefV8Value {
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments) override;
bool ResolvePromise(CefRefPtr<CefV8Value> arg) override;
bool RejectPromise(const CefString& errorMsg) override;
private:
// Test for and record any exception.
bool HasCaught(v8::Local<v8::Context> context, v8::TryCatch& try_catch);

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=46a80d60441e386e6a8999ecb5fd338f3f6b4319$
// $hash=5dd413b62070b7d80292faf8396d3b795dd4035e$
//
#include "libcef_dll/cpptoc/v8value_cpptoc.h"
@ -178,6 +178,16 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_function(
return CefV8ValueCppToC::Wrap(_retval);
}
CEF_EXPORT cef_v8value_t* cef_v8value_create_promise() {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
CefRefPtr<CefV8Value> _retval = CefV8Value::CreatePromise();
// Return type: refptr_same
return CefV8ValueCppToC::Wrap(_retval);
}
namespace {
// MEMBER FUNCTIONS - Body may be edited by hand.
@ -364,6 +374,20 @@ int CEF_CALLBACK v8value_is_function(struct _cef_v8value_t* self) {
return _retval;
}
int CEF_CALLBACK v8value_is_promise(struct _cef_v8value_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
bool _retval = CefV8ValueCppToC::Get(self)->IsPromise();
// Return type: bool
return _retval;
}
int CEF_CALLBACK v8value_is_same(struct _cef_v8value_t* self,
struct _cef_v8value_t* that) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -974,6 +998,43 @@ v8value_execute_function_with_context(struct _cef_v8value_t* self,
return CefV8ValueCppToC::Wrap(_retval);
}
int CEF_CALLBACK v8value_resolve_promise(struct _cef_v8value_t* self,
struct _cef_v8value_t* arg) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Unverified params: arg
// Execute
bool _retval = CefV8ValueCppToC::Get(self)->ResolvePromise(
CefV8ValueCppToC::Unwrap(arg));
// Return type: bool
return _retval;
}
int CEF_CALLBACK v8value_reject_promise(struct _cef_v8value_t* self,
const cef_string_t* errorMsg) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: errorMsg; type: string_byref_const
DCHECK(errorMsg);
if (!errorMsg)
return 0;
// Execute
bool _retval =
CefV8ValueCppToC::Get(self)->RejectPromise(CefString(errorMsg));
// Return type: bool
return _retval;
}
} // namespace
// CONSTRUCTOR - Do not edit by hand.
@ -992,6 +1053,7 @@ CefV8ValueCppToC::CefV8ValueCppToC() {
GetStruct()->is_array = v8value_is_array;
GetStruct()->is_array_buffer = v8value_is_array_buffer;
GetStruct()->is_function = v8value_is_function;
GetStruct()->is_promise = v8value_is_promise;
GetStruct()->is_same = v8value_is_same;
GetStruct()->get_bool_value = v8value_get_bool_value;
GetStruct()->get_int_value = v8value_get_int_value;
@ -1030,6 +1092,8 @@ CefV8ValueCppToC::CefV8ValueCppToC() {
GetStruct()->execute_function = v8value_execute_function;
GetStruct()->execute_function_with_context =
v8value_execute_function_with_context;
GetStruct()->resolve_promise = v8value_resolve_promise;
GetStruct()->reject_promise = v8value_reject_promise;
}
// DESTRUCTOR - Do not edit by hand.

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=1dd04012b442aa3ceae8d56653dc499aed1e181f$
// $hash=17fe0420a1c56309ff2156c9d7f7a4def484bd15$
//
#include "libcef_dll/ctocpp/v8value_ctocpp.h"
@ -188,6 +188,16 @@ CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
return CefV8ValueCToCpp::Wrap(_retval);
}
NO_SANITIZE("cfi-icall") CefRefPtr<CefV8Value> CefV8Value::CreatePromise() {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
cef_v8value_t* _retval = cef_v8value_create_promise();
// Return type: refptr_same
return CefV8ValueCToCpp::Wrap(_retval);
}
// VIRTUAL METHODS - Body may be edited by hand.
NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsValid() {
@ -372,6 +382,20 @@ NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsFunction() {
return _retval ? true : false;
}
NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsPromise() {
cef_v8value_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, is_promise))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = _struct->is_promise(_struct);
// Return type: bool
return _retval ? true : false;
}
NO_SANITIZE("cfi-icall")
bool CefV8ValueCToCpp::IsSame(CefRefPtr<CefV8Value> that) {
cef_v8value_t* _struct = GetStruct();
@ -988,6 +1012,44 @@ CefRefPtr<CefV8Value> CefV8ValueCToCpp::ExecuteFunctionWithContext(
return CefV8ValueCToCpp::Wrap(_retval);
}
NO_SANITIZE("cfi-icall")
bool CefV8ValueCToCpp::ResolvePromise(CefRefPtr<CefV8Value> arg) {
cef_v8value_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, resolve_promise))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Unverified params: arg
// Execute
int _retval =
_struct->resolve_promise(_struct, CefV8ValueCToCpp::Unwrap(arg));
// Return type: bool
return _retval ? true : false;
}
NO_SANITIZE("cfi-icall")
bool CefV8ValueCToCpp::RejectPromise(const CefString& errorMsg) {
cef_v8value_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, reject_promise))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: errorMsg; type: string_byref_const
DCHECK(!errorMsg.empty());
if (errorMsg.empty())
return false;
// Execute
int _retval = _struct->reject_promise(_struct, errorMsg.GetStruct());
// Return type: bool
return _retval ? true : false;
}
// CONSTRUCTOR - Do not edit by hand.
CefV8ValueCToCpp::CefV8ValueCToCpp() {}

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=012bb9108d28ddefb6ebc58963be24469b79146f$
// $hash=ee45dceec69f21be7a17e0c10ed15b29f28e63ec$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_V8VALUE_CTOCPP_H_
@ -47,6 +47,7 @@ class CefV8ValueCToCpp
bool IsArray() override;
bool IsArrayBuffer() override;
bool IsFunction() override;
bool IsPromise() override;
bool IsSame(CefRefPtr<CefV8Value> that) override;
bool GetBoolValue() override;
int32 GetIntValue() override;
@ -91,6 +92,8 @@ class CefV8ValueCToCpp
CefRefPtr<CefV8Context> context,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments) override;
bool ResolvePromise(CefRefPtr<CefV8Value> arg) override;
bool RejectPromise(const CefString& errorMsg) override;
};
#endif // CEF_LIBCEF_DLL_CTOCPP_V8VALUE_CTOCPP_H_

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=6c8f094d04b36c879f379e87ebf45dc4698eb41e$
// $hash=a753ff43760df4f3c1126d248b4128ca14a8cd68$
//
#include <dlfcn.h>
@ -204,6 +204,7 @@ struct libcef_pointers {
decltype(&cef_v8value_create_array) cef_v8value_create_array;
decltype(&cef_v8value_create_array_buffer) cef_v8value_create_array_buffer;
decltype(&cef_v8value_create_function) cef_v8value_create_function;
decltype(&cef_v8value_create_promise) cef_v8value_create_promise;
decltype(&cef_v8stack_trace_get_current) cef_v8stack_trace_get_current;
decltype(&cef_value_create) cef_value_create;
decltype(&cef_binary_value_create) cef_binary_value_create;
@ -420,6 +421,7 @@ int libcef_init_pointers(const char* path) {
INIT_ENTRY(cef_v8value_create_array);
INIT_ENTRY(cef_v8value_create_array_buffer);
INIT_ENTRY(cef_v8value_create_function);
INIT_ENTRY(cef_v8value_create_promise);
INIT_ENTRY(cef_v8stack_trace_get_current);
INIT_ENTRY(cef_value_create);
INIT_ENTRY(cef_binary_value_create);
@ -1114,6 +1116,10 @@ struct _cef_v8value_t* cef_v8value_create_function(
return g_libcef_pointers.cef_v8value_create_function(name, handler);
}
NO_SANITIZE("cfi-icall") struct _cef_v8value_t* cef_v8value_create_promise() {
return g_libcef_pointers.cef_v8value_create_promise();
}
NO_SANITIZE("cfi-icall")
struct _cef_v8stack_trace_t* cef_v8stack_trace_get_current(int frame_limit) {
return g_libcef_pointers.cef_v8stack_trace_get_current(frame_limit);

View File

@ -84,6 +84,12 @@ enum V8TestMode {
V8TEST_FUNCTION_HANDLER_NO_OBJECT,
V8TEST_FUNCTION_HANDLER_WITH_CONTEXT,
V8TEST_FUNCTION_HANDLER_EMPTY_STRING,
V8TEST_PROMISE_CREATE,
V8TEST_PROMISE_RESOLVE,
V8TEST_PROMISE_RESOLVE_NO_ARGUMENT,
V8TEST_PROMISE_RESOLVE_HANDLER,
V8TEST_PROMISE_REJECT,
V8TEST_PROMISE_REJECT_HANDLER,
V8TEST_CONTEXT_EVAL,
V8TEST_CONTEXT_EVAL_EXCEPTION,
V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL,
@ -214,6 +220,24 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
case V8TEST_FUNCTION_HANDLER_EMPTY_STRING:
RunFunctionHandlerEmptyStringTest();
break;
case V8TEST_PROMISE_CREATE:
RunPromiseCreateTest();
break;
case V8TEST_PROMISE_RESOLVE:
RunPromiseResolveTest();
break;
case V8TEST_PROMISE_RESOLVE_NO_ARGUMENT:
RunPromiseResolveNoArgumentTest();
break;
case V8TEST_PROMISE_RESOLVE_HANDLER:
RunPromiseResolveHandlerTest();
break;
case V8TEST_PROMISE_REJECT:
RunPromiseRejectTest();
break;
case V8TEST_PROMISE_REJECT_HANDLER:
RunPromiseRejectHandlerTest();
break;
case V8TEST_CONTEXT_EVAL:
RunContextEvalTest();
break;
@ -273,6 +297,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsInt());
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsObject());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsString());
DestroyTest();
@ -293,6 +318,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsObject());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsString());
DestroyTest();
@ -315,6 +341,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsFunction());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsObject());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsString());
DestroyTest();
@ -337,6 +364,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsFunction());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsObject());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsString());
DestroyTest();
@ -357,6 +385,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsObject());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsString());
DestroyTest();
@ -396,6 +425,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsObject());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsString());
DestroyTest();
@ -416,6 +446,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsInt());
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsObject());
DestroyTest();
@ -437,6 +468,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsObject());
EXPECT_FALSE(value->IsPromise());
DestroyTest();
}
@ -466,6 +498,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsInt());
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsString());
DestroyTest();
@ -645,6 +678,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsInt());
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsString());
// Exit the V8 context.
@ -1900,6 +1934,7 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_FALSE(value->IsInt());
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsPromise());
EXPECT_FALSE(value->IsString());
DestroyTest();
@ -2228,6 +2263,248 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
DestroyTest();
}
void RunPromiseCreateTest() {
CefRefPtr<CefV8Context> context = GetContext();
// Enter the V8 context.
EXPECT_TRUE(context->Enter());
CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
// Exit the V8 context.
EXPECT_TRUE(context->Exit());
EXPECT_TRUE(value.get());
EXPECT_TRUE(value->IsPromise());
EXPECT_TRUE(value->IsObject());
EXPECT_FALSE(value->IsUndefined());
EXPECT_FALSE(value->IsArray());
EXPECT_FALSE(value->IsBool());
EXPECT_FALSE(value->IsDate());
EXPECT_FALSE(value->IsDouble());
EXPECT_FALSE(value->IsFunction());
EXPECT_FALSE(value->IsInt());
EXPECT_FALSE(value->IsUInt());
EXPECT_FALSE(value->IsNull());
EXPECT_FALSE(value->IsString());
DestroyTest();
}
void RunPromiseResolveTest() {
CefRefPtr<CefV8Context> context = GetContext();
// Enter the V8 context.
EXPECT_TRUE(context->Enter());
CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(nullptr, nullptr);
EXPECT_TRUE(value.get());
EXPECT_TRUE(value->ResolvePromise(obj));
// Exit the V8 context.
EXPECT_TRUE(context->Exit());
DestroyTest();
}
void RunPromiseResolveNoArgumentTest() {
CefRefPtr<CefV8Context> context = GetContext();
// Enter the V8 context.
EXPECT_TRUE(context->Enter());
CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
EXPECT_TRUE(value.get());
EXPECT_TRUE(value->ResolvePromise(nullptr));
// Exit the V8 context.
EXPECT_TRUE(context->Exit());
DestroyTest();
}
void RunPromiseResolveHandlerTest() {
CefRefPtr<CefV8Context> context = GetContext();
static const char* kPromiseName = "myprom";
static const char* kResolveName = "myresolve";
static const char* kRejectName = "myreject";
static const int kVal1 = 32;
class Handler : public CefV8Handler {
public:
Handler() {}
bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) override {
EXPECT_STREQ(kResolveName, name.ToString().c_str());
EXPECT_EQ((size_t)1, arguments.size());
EXPECT_TRUE(arguments[0]->IsInt());
EXPECT_EQ(kVal1, arguments[0]->GetIntValue());
got_execute_.yes();
return false;
}
TrackCallback got_execute_;
IMPLEMENT_REFCOUNTING(Handler);
};
// Enter the V8 context.
EXPECT_TRUE(context->Enter());
Handler* resolveHandler = new Handler;
Handler* rejectHandler = new Handler;
CefRefPtr<CefV8Handler> resolveHandlerPtr(resolveHandler);
CefRefPtr<CefV8Handler> rejectHandlerPtr(rejectHandler);
CefRefPtr<CefV8Value> resolveFunc =
CefV8Value::CreateFunction(kResolveName, resolveHandler);
EXPECT_TRUE(resolveFunc.get());
EXPECT_TRUE(context->GetGlobal()->SetValue(kResolveName, resolveFunc,
V8_PROPERTY_ATTRIBUTE_NONE));
CefRefPtr<CefV8Value> rejectFunc =
CefV8Value::CreateFunction(kRejectName, rejectHandler);
EXPECT_TRUE(rejectFunc.get());
EXPECT_TRUE(context->GetGlobal()->SetValue(kRejectName, rejectFunc,
V8_PROPERTY_ATTRIBUTE_NONE));
CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
EXPECT_TRUE(value.get());
EXPECT_TRUE(context->GetGlobal()->SetValue(kPromiseName, value,
V8_PROPERTY_ATTRIBUTE_NONE));
CefRefPtr<CefV8Value> retval;
CefRefPtr<CefV8Exception> exception;
std::stringstream test;
test << "window." << kPromiseName << ".then(" << kResolveName << ").catch("
<< kRejectName << ")";
EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
EXPECT_TRUE(retval.get());
EXPECT_TRUE(retval->IsPromise());
EXPECT_FALSE(exception.get());
CefRefPtr<CefV8Value> arg = CefV8Value::CreateInt(kVal1);
EXPECT_TRUE(value->ResolvePromise(arg));
// Exit the V8 context.
EXPECT_TRUE(context->Exit());
EXPECT_TRUE(resolveHandler->got_execute_);
EXPECT_FALSE(rejectHandler->got_execute_);
DestroyTest();
}
void RunPromiseRejectTest() {
CefRefPtr<CefV8Context> context = GetContext();
// Enter the V8 context.
EXPECT_TRUE(context->Enter());
CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
EXPECT_TRUE(value.get());
EXPECT_TRUE(value->RejectPromise("Error: Unknown"));
// Exit the V8 context.
EXPECT_TRUE(context->Exit());
DestroyTest();
}
void RunPromiseRejectHandlerTest() {
CefRefPtr<CefV8Context> context = GetContext();
static const char* kPromiseName = "myprom";
static const char* kResolveName = "myresolve";
static const char* kRejectName = "myreject";
class Handler : public CefV8Handler {
public:
Handler() {}
bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) override {
EXPECT_STREQ(kRejectName, name.ToString().c_str());
EXPECT_EQ((size_t)1, arguments.size());
EXPECT_TRUE(arguments[0]->IsObject());
got_execute_.yes();
return false;
}
TrackCallback got_execute_;
IMPLEMENT_REFCOUNTING(Handler);
};
// Enter the V8 context.
EXPECT_TRUE(context->Enter());
Handler* resolveHandler = new Handler;
Handler* rejectHandler = new Handler;
CefRefPtr<CefV8Handler> resolveHandlerPtr(resolveHandler);
CefRefPtr<CefV8Handler> rejectHandlerPtr(rejectHandler);
CefRefPtr<CefV8Value> resolveFunc =
CefV8Value::CreateFunction(kResolveName, resolveHandler);
EXPECT_TRUE(resolveFunc.get());
EXPECT_TRUE(context->GetGlobal()->SetValue(kResolveName, resolveFunc,
V8_PROPERTY_ATTRIBUTE_NONE));
CefRefPtr<CefV8Value> rejectFunc =
CefV8Value::CreateFunction(kRejectName, rejectHandler);
EXPECT_TRUE(rejectFunc.get());
EXPECT_TRUE(context->GetGlobal()->SetValue(kRejectName, rejectFunc,
V8_PROPERTY_ATTRIBUTE_NONE));
CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
EXPECT_TRUE(value.get());
EXPECT_TRUE(context->GetGlobal()->SetValue(kPromiseName, value,
V8_PROPERTY_ATTRIBUTE_NONE));
CefRefPtr<CefV8Value> retval;
CefRefPtr<CefV8Exception> exception;
std::stringstream test;
test << "window." << kPromiseName << ".then(" << kResolveName << ").catch("
<< kRejectName << ")";
EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
EXPECT_TRUE(retval.get());
EXPECT_TRUE(retval->IsPromise());
EXPECT_FALSE(exception.get());
EXPECT_TRUE(value->RejectPromise("Error: Unknown"));
// Exit the V8 context.
EXPECT_TRUE(context->Exit());
EXPECT_FALSE(resolveHandler->got_execute_);
EXPECT_TRUE(rejectHandler->got_execute_);
DestroyTest();
}
void RunContextEvalTest() {
CefRefPtr<CefV8Context> context = GetContext();
@ -3055,6 +3332,12 @@ V8_TEST(FunctionHandlerFail, V8TEST_FUNCTION_HANDLER_FAIL)
V8_TEST(FunctionHandlerNoObject, V8TEST_FUNCTION_HANDLER_NO_OBJECT)
V8_TEST(FunctionHandlerWithContext, V8TEST_FUNCTION_HANDLER_WITH_CONTEXT)
V8_TEST(FunctionHandlerEmptyString, V8TEST_FUNCTION_HANDLER_EMPTY_STRING)
V8_TEST(PromiseCreate, V8TEST_PROMISE_CREATE)
V8_TEST(PromiseResolve, V8TEST_PROMISE_RESOLVE)
V8_TEST(PromiseResolveNoArgument, V8TEST_PROMISE_RESOLVE_NO_ARGUMENT)
V8_TEST(PromiseResolveHandler, V8TEST_PROMISE_RESOLVE_HANDLER)
V8_TEST(PromiseReject, V8TEST_PROMISE_REJECT)
V8_TEST(PromiseRejectHandler, V8TEST_PROMISE_REJECT_HANDLER)
V8_TEST(ContextEval, V8TEST_CONTEXT_EVAL)
V8_TEST(ContextEvalException, V8TEST_CONTEXT_EVAL_EXCEPTION)
V8_TEST_EX(ContextEvalCspBypassUnsafeEval,