From 939b5a200812fd12e2adb80bf5227b83b92673ce Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Wed, 25 Jul 2012 09:54:04 +0000 Subject: [PATCH] Merge revision 644 and 725 changes: - Add new CefV8StackTrace and CefV8StackFrame interfaces to support retrieval of the JavaScript stack trace for the currently active V8 context (issue #682). - Add CefV8Context::Eval method for synchronous JavaScript execution that returns a value or exception (issue #444). - Refactor V8 unit tests (issue #480). git-svn-id: https://chromiumembedded.googlecode.com/svn/branches/963@726 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- cef.gyp | 4 + cef_paths.gypi | 4 + include/cef.h | 96 + include/cef_capi.h | 96 + libcef/v8_impl.cc | 200 +- libcef/v8_impl.h | 168 +- libcef_dll/cpptoc/v8context_cpptoc.cc | 67 + libcef_dll/cpptoc/v8stack_frame_cpptoc.cc | 156 ++ libcef_dll/cpptoc/v8stack_frame_cpptoc.h | 37 + libcef_dll/cpptoc/v8stack_trace_cpptoc.cc | 86 + libcef_dll/cpptoc/v8stack_trace_cpptoc.h | 37 + libcef_dll/ctocpp/v8context_ctocpp.cc | 53 + libcef_dll/ctocpp/v8context_ctocpp.h | 2 + libcef_dll/ctocpp/v8stack_frame_ctocpp.cc | 135 + libcef_dll/ctocpp/v8stack_frame_ctocpp.h | 48 + libcef_dll/ctocpp/v8stack_trace_ctocpp.cc | 71 + libcef_dll/ctocpp/v8stack_trace_ctocpp.h | 43 + libcef_dll/libcef_dll.cc | 4 + libcef_dll/wrapper/libcef_dll_wrapper.cc | 4 + tests/unittests/v8_unittest.cc | 3033 +++++++++------------ 20 files changed, 2587 insertions(+), 1757 deletions(-) create mode 100644 libcef_dll/cpptoc/v8stack_frame_cpptoc.cc create mode 100644 libcef_dll/cpptoc/v8stack_frame_cpptoc.h create mode 100644 libcef_dll/cpptoc/v8stack_trace_cpptoc.cc create mode 100644 libcef_dll/cpptoc/v8stack_trace_cpptoc.h create mode 100644 libcef_dll/ctocpp/v8stack_frame_ctocpp.cc create mode 100644 libcef_dll/ctocpp/v8stack_frame_ctocpp.h create mode 100644 libcef_dll/ctocpp/v8stack_trace_ctocpp.cc create mode 100644 libcef_dll/ctocpp/v8stack_trace_ctocpp.h diff --git a/cef.gyp b/cef.gyp index 56c0f76c0..e3a9488ca 100644 --- a/cef.gyp +++ b/cef.gyp @@ -521,6 +521,10 @@ 'libcef_dll/cpptoc/v8context_cpptoc.h', 'libcef_dll/cpptoc/v8exception_cpptoc.cc', 'libcef_dll/cpptoc/v8exception_cpptoc.h', + 'libcef_dll/cpptoc/v8stack_frame_cpptoc.cc', + 'libcef_dll/cpptoc/v8stack_frame_cpptoc.h', + 'libcef_dll/cpptoc/v8stack_trace_cpptoc.cc', + 'libcef_dll/cpptoc/v8stack_trace_cpptoc.h', 'libcef_dll/cpptoc/v8value_cpptoc.cc', 'libcef_dll/cpptoc/v8value_cpptoc.h', 'libcef_dll/cpptoc/web_plugin_info_cpptoc.cc', diff --git a/cef_paths.gypi b/cef_paths.gypi index 0444ab89e..20a292a36 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -238,6 +238,10 @@ 'libcef_dll/ctocpp/v8context_ctocpp.h', 'libcef_dll/ctocpp/v8exception_ctocpp.cc', 'libcef_dll/ctocpp/v8exception_ctocpp.h', + 'libcef_dll/ctocpp/v8stack_frame_ctocpp.cc', + 'libcef_dll/ctocpp/v8stack_frame_ctocpp.h', + 'libcef_dll/ctocpp/v8stack_trace_ctocpp.cc', + 'libcef_dll/ctocpp/v8stack_trace_ctocpp.h', 'libcef_dll/ctocpp/v8value_ctocpp.cc', 'libcef_dll/ctocpp/v8value_ctocpp.h', 'libcef_dll/ctocpp/web_plugin_info_ctocpp.cc', diff --git a/include/cef.h b/include/cef.h index 4021a8f33..53dbcedf5 100644 --- a/include/cef.h +++ b/include/cef.h @@ -79,7 +79,9 @@ class CefStreamReader; class CefStreamWriter; class CefTask; class CefV8Context; +class CefV8Exception; class CefV8Handler; +class CefV8StackFrame; class CefV8Value; class CefWebPluginInfo; class CefWebURLRequest; @@ -2545,6 +2547,17 @@ public: /// /*--cef()--*/ virtual bool IsSame(CefRefPtr that) =0; + + /// + // Evaluates the specified JavaScript code using this context's global object. + // On success |retval| will be set to the return value, if any, and the + // function will return true. On failure |exception| will be set to the + // exception, if any, and the function will return false. + /// + /*--cef()--*/ + virtual bool Eval(const CefString& code, + CefRefPtr& retval, + CefRefPtr& exception) =0; }; @@ -2973,6 +2986,89 @@ public: bool rethrow_exception) =0; }; +/// +// Class representing a V8 stack trace. The methods of this class may only be +// called on the UI thread. +/// +/*--cef(source=library)--*/ +class CefV8StackTrace : public virtual CefBase +{ +public: + /// + // Returns the stack trace for the currently active context. |frame_limit| is + // the maximum number of frames that will be captured. + /// + /*--cef()--*/ + static CefRefPtr GetCurrent(int frame_limit); + + /// + // Returns the number of stack frames. + /// + /*--cef()--*/ + virtual int GetFrameCount() =0; + + /// + // Returns the stack frame at the specified 0-based index. + /// + /*--cef()--*/ + virtual CefRefPtr GetFrame(int index) =0; +}; + + +/// +// Class representing a V8 stack frame. The methods of this class may only be +// called on the UI thread. +/// +/*--cef(source=library)--*/ +class CefV8StackFrame : public virtual CefBase +{ +public: + /// + // Returns the name of the resource script that contains the function. + /// + /*--cef()--*/ + virtual CefString GetScriptName() =0; + + /// + // Returns the name of the resource script that contains the function or the + // sourceURL value if the script name is undefined and its source ends with + // a "//@ sourceURL=..." string. + /// + /*--cef()--*/ + virtual CefString GetScriptNameOrSourceURL() =0; + + /// + // Returns the name of the function. + /// + /*--cef()--*/ + virtual CefString GetFunctionName() =0; + + /// + // Returns the 1-based line number for the function call or 0 if unknown. + /// + /*--cef()--*/ + virtual int GetLineNumber() =0; + + /// + // Returns the 1-based column offset on the line for the function call or 0 if + // unknown. + /// + /*--cef()--*/ + virtual int GetColumn() =0; + + /// + // Returns true if the function was compiled using eval(). + /// + /*--cef()--*/ + virtual bool IsEval() =0; + + /// + // Returns true if the function was called as a constructor via "new". + /// + /*--cef()--*/ + virtual bool IsConstructor() =0; +}; + /// // Class that creates CefSchemeHandler instances. The methods of this class will diff --git a/include/cef_capi.h b/include/cef_capi.h index e9c910e83..7911f127d 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -2303,6 +2303,16 @@ typedef struct _cef_v8context_t int (CEF_CALLBACK *is_same)(struct _cef_v8context_t* self, struct _cef_v8context_t* that); + /// + // Evaluates the specified JavaScript code using this context's global object. + // On success |retval| will be set to the return value, if any, and the + // function will return true (1). On failure |exception| will be set to the + // exception, if any, and the function will return false (0). + /// + int (CEF_CALLBACK *eval)(struct _cef_v8context_t* self, + const cef_string_t* code, struct _cef_v8value_t** retval, + struct _cef_v8exception_t** exception); + } cef_v8context_t; @@ -2747,6 +2757,92 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_function(const cef_string_t* name, cef_v8handler_t* handler); +/// +// Structure representing a V8 stack trace. The functions of this structure may +// only be called on the UI thread. +/// +typedef struct _cef_v8stack_trace_t +{ + // Base structure. + cef_base_t base; + + /// + // Returns the number of stack frames. + /// + int (CEF_CALLBACK *get_frame_count)(struct _cef_v8stack_trace_t* self); + + /// + // Returns the stack frame at the specified 0-based index. + /// + struct _cef_v8stack_frame_t* (CEF_CALLBACK *get_frame)( + struct _cef_v8stack_trace_t* self, int index); + +} cef_v8stack_trace_t; + + +/// +// Returns the stack trace for the currently active context. |frame_limit| is +// the maximum number of frames that will be captured. +/// +CEF_EXPORT cef_v8stack_trace_t* cef_v8stack_trace_get_current(int frame_limit); + + +/// +// Structure representing a V8 stack frame. The functions of this structure may +// only be called on the UI thread. +/// +typedef struct _cef_v8stack_frame_t +{ + // Base structure. + cef_base_t base; + + /// + // Returns the name of the resource script that contains the function. + /// + // The resulting string must be freed by calling cef_string_userfree_free(). + cef_string_userfree_t (CEF_CALLBACK *get_script_name)( + struct _cef_v8stack_frame_t* self); + + /// + // Returns the name of the resource script that contains the function or the + // sourceURL value if the script name is undefined and its source ends with a + // "//@ sourceURL=..." string. + /// + // The resulting string must be freed by calling cef_string_userfree_free(). + cef_string_userfree_t (CEF_CALLBACK *get_script_name_or_source_url)( + struct _cef_v8stack_frame_t* self); + + /// + // Returns the name of the function. + /// + // The resulting string must be freed by calling cef_string_userfree_free(). + cef_string_userfree_t (CEF_CALLBACK *get_function_name)( + struct _cef_v8stack_frame_t* self); + + /// + // Returns the 1-based line number for the function call or 0 if unknown. + /// + int (CEF_CALLBACK *get_line_number)(struct _cef_v8stack_frame_t* self); + + /// + // Returns the 1-based column offset on the line for the function call or 0 if + // unknown. + /// + int (CEF_CALLBACK *get_column)(struct _cef_v8stack_frame_t* self); + + /// + // Returns true (1) if the function was compiled using eval(). + /// + int (CEF_CALLBACK *is_eval)(struct _cef_v8stack_frame_t* self); + + /// + // Returns true (1) if the function was called as a constructor via "new". + /// + int (CEF_CALLBACK *is_constructor)(struct _cef_v8stack_frame_t* self); + +} cef_v8stack_frame_t; + + /// // Structure that creates cef_scheme_handler_t instances. The functions of this // structure will always be called on the IO thread. diff --git a/libcef/v8_impl.cc b/libcef/v8_impl.cc index d265b850e..db17f870a 100644 --- a/libcef/v8_impl.cc +++ b/libcef/v8_impl.cc @@ -2,10 +2,23 @@ // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. -#include "browser_impl.h" -#include "v8_impl.h" -#include "cef_context.h" -#include "tracker.h" +#include + +#include "base/compiler_specific.h" + +#include "third_party/WebKit/Source/WebCore/config.h" +MSVC_PUSH_WARNING_LEVEL(0); +#include "V8Proxy.h" // NOLINT(build/include) +MSVC_POP_WARNING(); +#undef LOG + +#include "libcef/v8_impl.h" + +#include "libcef/browser_impl.h" +#include "libcef/cef_context.h" +#include "libcef/tracker.h" + +#include "base/bind.h" #include "base/lazy_instance.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" @@ -135,6 +148,9 @@ void v8impl_string_dtor(char* str) // Convert a v8::String to CefString. void GetCefString(v8::Handle str, CefString& out) { + if (str.IsEmpty()) + return; + #if defined(CEF_STRING_TYPE_WIDE) // Allocate enough space for a worst-case conversion. int len = str->Utf8Length(); @@ -406,11 +422,11 @@ bool CefV8Context::InContext() // CefV8ContextImpl CefV8ContextImpl::CefV8ContextImpl(v8::Handle context) + : handle_(new Handle(context)) #ifndef NDEBUG - : enter_count_(0) + , enter_count_(0) #endif { - v8_context_ = new CefV8ContextHandle(context); } CefV8ContextImpl::~CefV8ContextImpl() @@ -451,14 +467,14 @@ CefRefPtr CefV8ContextImpl::GetGlobal() CEF_REQUIRE_UI_THREAD(NULL); v8::HandleScope handle_scope; - v8::Context::Scope context_scope(v8_context_->GetHandle()); - return new CefV8ValueImpl(v8_context_->GetHandle()->Global()); + v8::Context::Scope context_scope(GetHandle()); + return new CefV8ValueImpl(GetHandle()->Global()); } bool CefV8ContextImpl::Enter() { CEF_REQUIRE_UI_THREAD(false); - v8_context_->GetHandle()->Enter(); + GetHandle()->Enter(); #ifndef NDEBUG ++enter_count_; #endif @@ -469,7 +485,7 @@ bool CefV8ContextImpl::Exit() { CEF_REQUIRE_UI_THREAD(false); DLOG_ASSERT(enter_count_ > 0); - v8_context_->GetHandle()->Exit(); + GetHandle()->Exit(); #ifndef NDEBUG --enter_count_; #endif @@ -492,32 +508,77 @@ bool CefV8ContextImpl::IsSame(CefRefPtr that) return (thisHandle == thatHandle); } +bool CefV8ContextImpl::Eval(const CefString& code, + CefRefPtr& retval, + CefRefPtr& exception) { + CEF_REQUIRE_UI_THREAD(NULL); + + if (code.empty()) { + NOTREACHED() << "invalid input parameter"; + return false; + } + + v8::HandleScope handle_scope; + v8::Context::Scope context_scope(GetHandle()); + v8::Local obj = GetHandle()->Global(); + + // Retrieve the eval function. + v8::Local val = obj->Get(v8::String::New("eval")); + if (val.IsEmpty() || !val->IsFunction()) + return false; + + v8::Local func = v8::Local::Cast(val); + v8::Handle code_val = GetV8String(code); + + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + v8::Local func_rv; + + retval = NULL; + exception = NULL; + + // Execute the function call using the V8Proxy so that inspector + // instrumentation works. + WebCore::V8Proxy* proxy = WebCore::V8Proxy::retrieve(); + DCHECK(proxy); + if (proxy) + func_rv = proxy->callFunction(func, obj, 1, &code_val); + + if (try_catch.HasCaught()) { + exception = new CefV8ExceptionImpl(try_catch.Message()); + return false; + } else if (!func_rv.IsEmpty()) { + retval = new CefV8ValueImpl(func_rv); + } + return true; +} + v8::Local CefV8ContextImpl::GetContext() { - return v8::Local::New(v8_context_->GetHandle()); + return v8::Local::New(GetHandle()); } WebKit::WebFrame* CefV8ContextImpl::GetWebFrame() { v8::HandleScope handle_scope; - v8::Context::Scope context_scope(v8_context_->GetHandle()); + v8::Context::Scope context_scope(GetHandle()); WebKit::WebFrame* frame = WebKit::WebFrame::frameForCurrentContext(); return frame; } -// CefV8ValueHandle +// CefV8ValueImpl::Handle // Custom destructor for a v8 value handle which gets called only on the UI // thread. -CefV8ValueHandle::~CefV8ValueHandle() +CefV8ValueImpl::Handle::~Handle() { if(tracker_) { TrackAdd(tracker_); - v8_handle_.MakeWeak(tracker_, TrackDestructor); + handle_.MakeWeak(tracker_, TrackDestructor); } else { - v8_handle_.Dispose(); - v8_handle_.Clear(); + handle_.Dispose(); + handle_.Clear(); } tracker_ = NULL; } @@ -706,8 +767,7 @@ CefRefPtr CefV8Value::CreateFunction(const CefString& name, CefV8ValueImpl::CefV8ValueImpl(v8::Handle value, CefTrackObject* tracker) -{ - v8_value_ = new CefV8ValueHandle(value, tracker); + : handle_(new Handle(value, tracker)) { } CefV8ValueImpl::~CefV8ValueImpl() @@ -1195,3 +1255,105 @@ CefV8Accessor* CefV8ValueImpl::GetAccessor(v8::Handle object) return NULL; } + + +// CefV8StackTrace + +// static +CefRefPtr CefV8StackTrace::GetCurrent(int frame_limit) { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); + + v8::Handle stackTrace = + v8::StackTrace::CurrentStackTrace( + frame_limit, v8::StackTrace::kDetailed); + if (stackTrace.IsEmpty()) + return NULL; + return new CefV8StackTraceImpl(stackTrace); +} + + +// CefV8StackTraceImpl + +CefV8StackTraceImpl::CefV8StackTraceImpl(v8::Handle handle) + : handle_(new Handle(handle)) { +} + +CefV8StackTraceImpl::~CefV8StackTraceImpl() { +} + +int CefV8StackTraceImpl::GetFrameCount() { + CEF_REQUIRE_UI_THREAD(0); + v8::HandleScope handle_scope; + return GetHandle()->GetFrameCount(); +} + +CefRefPtr CefV8StackTraceImpl::GetFrame(int index) { + CEF_REQUIRE_UI_THREAD(NULL); + v8::HandleScope handle_scope; + v8::Handle stackFrame = GetHandle()->GetFrame(index); + if (stackFrame.IsEmpty()) + return NULL; + return new CefV8StackFrameImpl(stackFrame); +} + + +// CefV8StackFrameImpl + +CefV8StackFrameImpl::CefV8StackFrameImpl(v8::Handle handle) + : handle_(new Handle(handle)) { +} + +CefV8StackFrameImpl::~CefV8StackFrameImpl() { +} + +CefString CefV8StackFrameImpl::GetScriptName() { + CefString rv; + CEF_REQUIRE_UI_THREAD(rv); + v8::HandleScope handle_scope; + GetCefString(v8::Handle::Cast(GetHandle()->GetScriptName()), rv); + return rv; +} + +CefString CefV8StackFrameImpl::GetScriptNameOrSourceURL() { + CefString rv; + CEF_REQUIRE_UI_THREAD(rv); + v8::HandleScope handle_scope; + GetCefString( + v8::Handle::Cast(GetHandle()->GetScriptNameOrSourceURL()), + rv); + return rv; +} + +CefString CefV8StackFrameImpl::GetFunctionName() { + CefString rv; + CEF_REQUIRE_UI_THREAD(rv); + v8::HandleScope handle_scope; + GetCefString( + v8::Handle::Cast(GetHandle()->GetFunctionName()), rv); + return rv; +} + +int CefV8StackFrameImpl::GetLineNumber() { + CEF_REQUIRE_UI_THREAD(0); + v8::HandleScope handle_scope; + return GetHandle()->GetLineNumber(); +} + +int CefV8StackFrameImpl::GetColumn() { + CEF_REQUIRE_UI_THREAD(0); + v8::HandleScope handle_scope; + return GetHandle()->GetColumn(); +} + +bool CefV8StackFrameImpl::IsEval() { + CEF_REQUIRE_UI_THREAD(false); + v8::HandleScope handle_scope; + return GetHandle()->IsEval(); +} + +bool CefV8StackFrameImpl::IsConstructor() { + CEF_REQUIRE_UI_THREAD(false); + v8::HandleScope handle_scope; + return GetHandle()->IsConstructor(); +} diff --git a/libcef/v8_impl.h b/libcef/v8_impl.h index 4eec22753..e8401c8b5 100644 --- a/libcef/v8_impl.h +++ b/libcef/v8_impl.h @@ -5,8 +5,12 @@ #ifndef _V8_IMPL_H #define _V8_IMPL_H +#include + #include "include/cef.h" #include "v8/include/v8.h" +#include "libcef/cef_thread.h" +#include "base/memory/ref_counted.h" class CefTrackObject; @@ -16,53 +20,40 @@ class WebFrame; // Template for V8 Handle types. This class is used to ensure that V8 objects // are only released on the UI thread. -template -class CefReleaseV8HandleOnUIThread: - public base::RefCountedThreadSafe, - CefThread::DeleteOnUIThread> -{ -public: +template +class CefV8Handle : + public base::RefCountedThreadSafe, + CefThread::DeleteOnUIThread> { + public: typedef v8::Handle handleType; typedef v8::Persistent persistentType; - typedef CefReleaseV8HandleOnUIThread superType; - CefReleaseV8HandleOnUIThread(handleType v) - { - v8_handle_ = persistentType::New(v); + CefV8Handle(handleType v) + : handle_(persistentType::New(v)) { } - virtual ~CefReleaseV8HandleOnUIThread() - { + ~CefV8Handle() { + handle_.Dispose(); + handle_.Clear(); } - handleType GetHandle() - { - return v8_handle_; - } + handleType GetHandle() { return handle_; } - persistentType v8_handle_; + protected: + persistentType handle_; + + DISALLOW_COPY_AND_ASSIGN(CefV8Handle); }; -// Special class for a v8::Context to ensure that it is deleted from the UI -// thread. -class CefV8ContextHandle : public CefReleaseV8HandleOnUIThread -{ -public: - CefV8ContextHandle(handleType context): superType(context) - { - } - - // Context handles are disposed rather than makeweak. - ~CefV8ContextHandle() - { - v8_handle_.Dispose(); - v8_handle_.Clear(); - } +// Specialization for v8::Value with empty implementation to avoid incorrect +// usage. +template <> +class CefV8Handle { }; -class CefV8ContextImpl : public CefV8Context -{ -public: - CefV8ContextImpl(v8::Handle context); + +class CefV8ContextImpl : public CefV8Context { + public: + explicit CefV8ContextImpl(v8::Handle context); virtual ~CefV8ContextImpl(); virtual CefRefPtr GetBrowser() OVERRIDE; @@ -71,12 +62,18 @@ public: virtual bool Enter() OVERRIDE; virtual bool Exit() OVERRIDE; virtual bool IsSame(CefRefPtr that) OVERRIDE; + virtual bool Eval(const CefString& code, + CefRefPtr& retval, + CefRefPtr& exception) OVERRIDE; v8::Local GetContext(); WebKit::WebFrame* GetWebFrame(); + v8::Handle GetHandle() { return handle_->GetHandle(); } + protected: - scoped_refptr v8_context_; + typedef CefV8Handle Handle; + scoped_refptr handle_; #ifndef NDEBUG // Used in debug builds to catch missing Exits in destructor. @@ -86,27 +83,8 @@ protected: IMPLEMENT_REFCOUNTING(CefV8ContextImpl); }; -// Special class for a v8::Value to ensure that it is deleted from the UI -// thread. -class CefV8ValueHandle: public CefReleaseV8HandleOnUIThread -{ -public: - CefV8ValueHandle(handleType value, CefTrackObject* tracker) - : superType(value), tracker_(tracker) - { - } - // Destructor implementation is provided in v8_impl.cc. - ~CefV8ValueHandle(); - -private: - // For Object and Function types, we need to hold on to a reference to their - // internal data or function handler objects that are reference counted. - CefTrackObject *tracker_; -}; - -class CefV8ValueImpl : public CefV8Value -{ -public: +class CefV8ValueImpl : public CefV8Value { + public: CefV8ValueImpl(v8::Handle value, CefTrackObject* tracker = NULL); virtual ~CefV8ValueImpl(); @@ -155,19 +133,79 @@ public: CefRefPtr& exception, bool rethrow_exception) OVERRIDE; - inline v8::Handle GetHandle() - { - DCHECK(v8_value_.get()); - return v8_value_->GetHandle(); - } + v8::Handle GetHandle() { return handle_->GetHandle(); } // Returns the accessor assigned for the specified object, if any. static CefV8Accessor* GetAccessor(v8::Handle object); -protected: - scoped_refptr v8_value_; + protected: + class Handle : + public base::RefCountedThreadSafe { + public: + typedef v8::Handle handleType; + typedef v8::Persistent persistentType; + + Handle(handleType v, CefTrackObject* tracker) + : handle_(persistentType::New(v)), + tracker_(tracker) { + } + ~Handle(); + + handleType GetHandle() { return handle_; } + + private: + persistentType handle_; + + // For Object and Function types, we need to hold on to a reference to their + // internal data or function handler objects that are reference counted. + CefTrackObject* tracker_; + + DISALLOW_COPY_AND_ASSIGN(Handle); + }; + scoped_refptr handle_; IMPLEMENT_REFCOUNTING(CefV8ValueImpl); }; +class CefV8StackTraceImpl : public CefV8StackTrace { + public: + explicit CefV8StackTraceImpl(v8::Handle handle); + virtual ~CefV8StackTraceImpl(); + + virtual int GetFrameCount() OVERRIDE; + virtual CefRefPtr GetFrame(int index) OVERRIDE; + + v8::Handle GetHandle() { return handle_->GetHandle(); } + + protected: + typedef CefV8Handle Handle; + scoped_refptr handle_; + + IMPLEMENT_REFCOUNTING(CefV8StackTraceImpl); + DISALLOW_COPY_AND_ASSIGN(CefV8StackTraceImpl); +}; + +class CefV8StackFrameImpl : public CefV8StackFrame { + public: + explicit CefV8StackFrameImpl(v8::Handle handle); + virtual ~CefV8StackFrameImpl(); + + virtual CefString GetScriptName() OVERRIDE; + virtual CefString GetScriptNameOrSourceURL() OVERRIDE; + virtual CefString GetFunctionName() OVERRIDE; + virtual int GetLineNumber() OVERRIDE; + virtual int GetColumn() OVERRIDE; + virtual bool IsEval() OVERRIDE; + virtual bool IsConstructor() OVERRIDE; + + v8::Handle GetHandle() { return handle_->GetHandle(); } + + protected: + typedef CefV8Handle Handle; + scoped_refptr handle_; + + IMPLEMENT_REFCOUNTING(CefV8StackFrameImpl); + DISALLOW_COPY_AND_ASSIGN(CefV8StackFrameImpl); +}; + #endif //_V8_IMPL_H diff --git a/libcef_dll/cpptoc/v8context_cpptoc.cc b/libcef_dll/cpptoc/v8context_cpptoc.cc index f2667c138..c40b33ea3 100644 --- a/libcef_dll/cpptoc/v8context_cpptoc.cc +++ b/libcef_dll/cpptoc/v8context_cpptoc.cc @@ -13,6 +13,7 @@ #include "libcef_dll/cpptoc/browser_cpptoc.h" #include "libcef_dll/cpptoc/frame_cpptoc.h" #include "libcef_dll/cpptoc/v8context_cpptoc.h" +#include "libcef_dll/cpptoc/v8exception_cpptoc.h" #include "libcef_dll/cpptoc/v8value_cpptoc.h" @@ -160,6 +161,71 @@ int CEF_CALLBACK v8context_is_same(struct _cef_v8context_t* self, } +int CEF_CALLBACK v8context_eval(struct _cef_v8context_t* self, + const cef_string_t* code, struct _cef_v8value_t** retval, + struct _cef_v8exception_t** exception) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: code; type: string_byref_const + DCHECK(code); + if (!code) + return 0; + // Verify param: retval; type: refptr_same_byref + DCHECK(retval); + if (!retval) + return 0; + // Verify param: exception; type: refptr_same_byref + DCHECK(exception); + if (!exception) + return 0; + + // Translate param: retval; type: refptr_same_byref + CefRefPtr retvalPtr; + if (retval && *retval) + retvalPtr = CefV8ValueCppToC::Unwrap(*retval); + CefV8Value* retvalOrig = retvalPtr.get(); + // Translate param: exception; type: refptr_same_byref + CefRefPtr exceptionPtr; + if (exception && *exception) + exceptionPtr = CefV8ExceptionCppToC::Unwrap(*exception); + CefV8Exception* exceptionOrig = exceptionPtr.get(); + + // Execute + bool _retval = CefV8ContextCppToC::Get(self)->Eval( + CefString(code), + retvalPtr, + exceptionPtr); + + // Restore param: retval; type: refptr_same_byref + if (retval) { + if (retvalPtr.get()) { + if (retvalPtr.get() != retvalOrig) { + *retval = CefV8ValueCppToC::Wrap(retvalPtr); + } + } else { + *retval = NULL; + } + } + // Restore param: exception; type: refptr_same_byref + if (exception) { + if (exceptionPtr.get()) { + if (exceptionPtr.get() != exceptionOrig) { + *exception = CefV8ExceptionCppToC::Wrap(exceptionPtr); + } + } else { + *exception = NULL; + } + } + + // Return type: bool + return _retval; +} + + // CONSTRUCTOR - Do not edit by hand. @@ -172,6 +238,7 @@ CefV8ContextCppToC::CefV8ContextCppToC(CefV8Context* cls) struct_.struct_.enter = v8context_enter; struct_.struct_.exit = v8context_exit; struct_.struct_.is_same = v8context_is_same; + struct_.struct_.eval = v8context_eval; } #ifndef NDEBUG diff --git a/libcef_dll/cpptoc/v8stack_frame_cpptoc.cc b/libcef_dll/cpptoc/v8stack_frame_cpptoc.cc new file mode 100644 index 000000000..17e21d778 --- /dev/null +++ b/libcef_dll/cpptoc/v8stack_frame_cpptoc.cc @@ -0,0 +1,156 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/v8stack_frame_cpptoc.h" + + +// MEMBER FUNCTIONS - Body may be edited by hand. + +cef_string_userfree_t CEF_CALLBACK v8stack_frame_get_script_name( + struct _cef_v8stack_frame_t* self) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + CefString _retval = CefV8StackFrameCppToC::Get(self)->GetScriptName(); + + // Return type: string + return _retval.DetachToUserFree(); +} + + +cef_string_userfree_t CEF_CALLBACK v8stack_frame_get_script_name_or_source_url( + struct _cef_v8stack_frame_t* self) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + CefString _retval = CefV8StackFrameCppToC::Get( + self)->GetScriptNameOrSourceURL(); + + // Return type: string + return _retval.DetachToUserFree(); +} + + +cef_string_userfree_t CEF_CALLBACK v8stack_frame_get_function_name( + struct _cef_v8stack_frame_t* self) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + CefString _retval = CefV8StackFrameCppToC::Get(self)->GetFunctionName(); + + // Return type: string + return _retval.DetachToUserFree(); +} + + +int CEF_CALLBACK v8stack_frame_get_line_number( + struct _cef_v8stack_frame_t* self) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + int _retval = CefV8StackFrameCppToC::Get(self)->GetLineNumber(); + + // Return type: simple + return _retval; +} + + +int CEF_CALLBACK v8stack_frame_get_column(struct _cef_v8stack_frame_t* self) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + int _retval = CefV8StackFrameCppToC::Get(self)->GetColumn(); + + // Return type: simple + return _retval; +} + + +int CEF_CALLBACK v8stack_frame_is_eval(struct _cef_v8stack_frame_t* self) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + bool _retval = CefV8StackFrameCppToC::Get(self)->IsEval(); + + // Return type: bool + return _retval; +} + + +int CEF_CALLBACK v8stack_frame_is_constructor(struct _cef_v8stack_frame_t* self) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + bool _retval = CefV8StackFrameCppToC::Get(self)->IsConstructor(); + + // Return type: bool + return _retval; +} + + + +// CONSTRUCTOR - Do not edit by hand. + +CefV8StackFrameCppToC::CefV8StackFrameCppToC(CefV8StackFrame* cls) + : CefCppToC( + cls) +{ + struct_.struct_.get_script_name = v8stack_frame_get_script_name; + struct_.struct_.get_script_name_or_source_url = + v8stack_frame_get_script_name_or_source_url; + struct_.struct_.get_function_name = v8stack_frame_get_function_name; + struct_.struct_.get_line_number = v8stack_frame_get_line_number; + struct_.struct_.get_column = v8stack_frame_get_column; + struct_.struct_.is_eval = v8stack_frame_is_eval; + struct_.struct_.is_constructor = v8stack_frame_is_constructor; +} + +#ifndef NDEBUG +template<> long CefCppToC::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/cpptoc/v8stack_frame_cpptoc.h b/libcef_dll/cpptoc/v8stack_frame_cpptoc.h new file mode 100644 index 000000000..e6f336df3 --- /dev/null +++ b/libcef_dll/cpptoc/v8stack_frame_cpptoc.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef _V8STACKFRAME_CPPTOC_H +#define _V8STACKFRAME_CPPTOC_H + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef.h" +#include "include/cef_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed DLL-side only. +class CefV8StackFrameCppToC + : public CefCppToC +{ +public: + CefV8StackFrameCppToC(CefV8StackFrame* cls); + virtual ~CefV8StackFrameCppToC() {} +}; + +#endif // BUILDING_CEF_SHARED +#endif // _V8STACKFRAME_CPPTOC_H + diff --git a/libcef_dll/cpptoc/v8stack_trace_cpptoc.cc b/libcef_dll/cpptoc/v8stack_trace_cpptoc.cc new file mode 100644 index 000000000..fc2b7d869 --- /dev/null +++ b/libcef_dll/cpptoc/v8stack_trace_cpptoc.cc @@ -0,0 +1,86 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/v8stack_frame_cpptoc.h" +#include "libcef_dll/cpptoc/v8stack_trace_cpptoc.h" + + +// GLOBAL FUNCTIONS - Body may be edited by hand. + +CEF_EXPORT cef_v8stack_trace_t* cef_v8stack_trace_get_current(int frame_limit) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + CefRefPtr _retval = CefV8StackTrace::GetCurrent( + frame_limit); + + // Return type: refptr_same + return CefV8StackTraceCppToC::Wrap(_retval); +} + + + +// MEMBER FUNCTIONS - Body may be edited by hand. + +int CEF_CALLBACK v8stack_trace_get_frame_count( + struct _cef_v8stack_trace_t* self) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + + // Execute + int _retval = CefV8StackTraceCppToC::Get(self)->GetFrameCount(); + + // Return type: simple + return _retval; +} + + +struct _cef_v8stack_frame_t* CEF_CALLBACK v8stack_trace_get_frame( + struct _cef_v8stack_trace_t* self, int index) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + CefRefPtr _retval = CefV8StackTraceCppToC::Get( + self)->GetFrame( + index); + + // Return type: refptr_same + return CefV8StackFrameCppToC::Wrap(_retval); +} + + + +// CONSTRUCTOR - Do not edit by hand. + +CefV8StackTraceCppToC::CefV8StackTraceCppToC(CefV8StackTrace* cls) + : CefCppToC( + cls) +{ + struct_.struct_.get_frame_count = v8stack_trace_get_frame_count; + struct_.struct_.get_frame = v8stack_trace_get_frame; +} + +#ifndef NDEBUG +template<> long CefCppToC::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/cpptoc/v8stack_trace_cpptoc.h b/libcef_dll/cpptoc/v8stack_trace_cpptoc.h new file mode 100644 index 000000000..1dcd7d081 --- /dev/null +++ b/libcef_dll/cpptoc/v8stack_trace_cpptoc.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef _V8STACKTRACE_CPPTOC_H +#define _V8STACKTRACE_CPPTOC_H + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef.h" +#include "include/cef_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed DLL-side only. +class CefV8StackTraceCppToC + : public CefCppToC +{ +public: + CefV8StackTraceCppToC(CefV8StackTrace* cls); + virtual ~CefV8StackTraceCppToC() {} +}; + +#endif // BUILDING_CEF_SHARED +#endif // _V8STACKTRACE_CPPTOC_H + diff --git a/libcef_dll/ctocpp/v8context_ctocpp.cc b/libcef_dll/ctocpp/v8context_ctocpp.cc index 117c265b1..d4a2912be 100644 --- a/libcef_dll/ctocpp/v8context_ctocpp.cc +++ b/libcef_dll/ctocpp/v8context_ctocpp.cc @@ -13,6 +13,7 @@ #include "libcef_dll/ctocpp/browser_ctocpp.h" #include "libcef_dll/ctocpp/frame_ctocpp.h" #include "libcef_dll/ctocpp/v8context_ctocpp.h" +#include "libcef_dll/ctocpp/v8exception_ctocpp.h" #include "libcef_dll/ctocpp/v8value_ctocpp.h" @@ -153,6 +154,58 @@ bool CefV8ContextCToCpp::IsSame(CefRefPtr that) } +bool CefV8ContextCToCpp::Eval(const CefString& code, + CefRefPtr& retval, CefRefPtr& exception) +{ + if (CEF_MEMBER_MISSING(struct_, eval)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: code; type: string_byref_const + DCHECK(!code.empty()); + if (code.empty()) + return false; + + // Translate param: retval; type: refptr_same_byref + cef_v8value_t* retvalStruct = NULL; + if(retval.get()) + retvalStruct = CefV8ValueCToCpp::Unwrap(retval); + cef_v8value_t* retvalOrig = retvalStruct; + // Translate param: exception; type: refptr_same_byref + cef_v8exception_t* exceptionStruct = NULL; + if(exception.get()) + exceptionStruct = CefV8ExceptionCToCpp::Unwrap(exception); + cef_v8exception_t* exceptionOrig = exceptionStruct; + + // Execute + int _retval = struct_->eval(struct_, + code.GetStruct(), + &retvalStruct, + &exceptionStruct); + + // Restore param:retval; type: refptr_same_byref + if (retvalStruct) { + if (retvalStruct != retvalOrig) { + retval = CefV8ValueCToCpp::Wrap(retvalStruct); + } + } else { + retval = NULL; + } + // Restore param:exception; type: refptr_same_byref + if (exceptionStruct) { + if (exceptionStruct != exceptionOrig) { + exception = CefV8ExceptionCToCpp::Wrap(exceptionStruct); + } + } else { + exception = NULL; + } + + // Return type: bool + return _retval?true:false; +} + + #ifndef NDEBUG template<> long CefCToCpp that) OVERRIDE; + virtual bool Eval(const CefString& code, CefRefPtr& retval, + CefRefPtr& exception) OVERRIDE; }; #endif // USING_CEF_SHARED diff --git a/libcef_dll/ctocpp/v8stack_frame_ctocpp.cc b/libcef_dll/ctocpp/v8stack_frame_ctocpp.cc new file mode 100644 index 000000000..df9030011 --- /dev/null +++ b/libcef_dll/ctocpp/v8stack_frame_ctocpp.cc @@ -0,0 +1,135 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/ctocpp/v8stack_frame_ctocpp.h" + + +// VIRTUAL METHODS - Body may be edited by hand. + +CefString CefV8StackFrameCToCpp::GetScriptName() +{ + if (CEF_MEMBER_MISSING(struct_, get_script_name)) + return CefString(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_string_userfree_t _retval = struct_->get_script_name(struct_); + + // Return type: string + CefString _retvalStr; + _retvalStr.AttachToUserFree(_retval); + return _retvalStr; +} + + +CefString CefV8StackFrameCToCpp::GetScriptNameOrSourceURL() +{ + if (CEF_MEMBER_MISSING(struct_, get_script_name_or_source_url)) + return CefString(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_string_userfree_t _retval = struct_->get_script_name_or_source_url( + struct_); + + // Return type: string + CefString _retvalStr; + _retvalStr.AttachToUserFree(_retval); + return _retvalStr; +} + + +CefString CefV8StackFrameCToCpp::GetFunctionName() +{ + if (CEF_MEMBER_MISSING(struct_, get_function_name)) + return CefString(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_string_userfree_t _retval = struct_->get_function_name(struct_); + + // Return type: string + CefString _retvalStr; + _retvalStr.AttachToUserFree(_retval); + return _retvalStr; +} + + +int CefV8StackFrameCToCpp::GetLineNumber() +{ + if (CEF_MEMBER_MISSING(struct_, get_line_number)) + return 0; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = struct_->get_line_number(struct_); + + // Return type: simple + return _retval; +} + + +int CefV8StackFrameCToCpp::GetColumn() +{ + if (CEF_MEMBER_MISSING(struct_, get_column)) + return 0; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = struct_->get_column(struct_); + + // Return type: simple + return _retval; +} + + +bool CefV8StackFrameCToCpp::IsEval() +{ + if (CEF_MEMBER_MISSING(struct_, is_eval)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = struct_->is_eval(struct_); + + // Return type: bool + return _retval?true:false; +} + + +bool CefV8StackFrameCToCpp::IsConstructor() +{ + if (CEF_MEMBER_MISSING(struct_, is_constructor)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = struct_->is_constructor(struct_); + + // Return type: bool + return _retval?true:false; +} + + + +#ifndef NDEBUG +template<> long CefCToCpp::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/ctocpp/v8stack_frame_ctocpp.h b/libcef_dll/ctocpp/v8stack_frame_ctocpp.h new file mode 100644 index 000000000..12bc5d1c0 --- /dev/null +++ b/libcef_dll/ctocpp/v8stack_frame_ctocpp.h @@ -0,0 +1,48 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef _V8STACKFRAME_CTOCPP_H +#define _V8STACKFRAME_CTOCPP_H + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef.h" +#include "include/cef_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed wrapper-side only. +class CefV8StackFrameCToCpp + : public CefCToCpp +{ +public: + CefV8StackFrameCToCpp(cef_v8stack_frame_t* str) + : CefCToCpp( + str) {} + virtual ~CefV8StackFrameCToCpp() {} + + // CefV8StackFrame methods + virtual CefString GetScriptName() OVERRIDE; + virtual CefString GetScriptNameOrSourceURL() OVERRIDE; + virtual CefString GetFunctionName() OVERRIDE; + virtual int GetLineNumber() OVERRIDE; + virtual int GetColumn() OVERRIDE; + virtual bool IsEval() OVERRIDE; + virtual bool IsConstructor() OVERRIDE; +}; + +#endif // USING_CEF_SHARED +#endif // _V8STACKFRAME_CTOCPP_H + diff --git a/libcef_dll/ctocpp/v8stack_trace_ctocpp.cc b/libcef_dll/ctocpp/v8stack_trace_ctocpp.cc new file mode 100644 index 000000000..15cc00ba8 --- /dev/null +++ b/libcef_dll/ctocpp/v8stack_trace_ctocpp.cc @@ -0,0 +1,71 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/ctocpp/v8stack_frame_ctocpp.h" +#include "libcef_dll/ctocpp/v8stack_trace_ctocpp.h" + + +// STATIC METHODS - Body may be edited by hand. + +CefRefPtr CefV8StackTrace::GetCurrent(int frame_limit) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_v8stack_trace_t* _retval = cef_v8stack_trace_get_current( + frame_limit); + + // Return type: refptr_same + return CefV8StackTraceCToCpp::Wrap(_retval); +} + + + +// VIRTUAL METHODS - Body may be edited by hand. + +int CefV8StackTraceCToCpp::GetFrameCount() +{ + if (CEF_MEMBER_MISSING(struct_, get_frame_count)) + return 0; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + int _retval = struct_->get_frame_count(struct_); + + // Return type: simple + return _retval; +} + + +CefRefPtr CefV8StackTraceCToCpp::GetFrame(int index) +{ + if (CEF_MEMBER_MISSING(struct_, get_frame)) + return NULL; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_v8stack_frame_t* _retval = struct_->get_frame(struct_, + index); + + // Return type: refptr_same + return CefV8StackFrameCToCpp::Wrap(_retval); +} + + + +#ifndef NDEBUG +template<> long CefCToCpp::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/ctocpp/v8stack_trace_ctocpp.h b/libcef_dll/ctocpp/v8stack_trace_ctocpp.h new file mode 100644 index 000000000..e3046412e --- /dev/null +++ b/libcef_dll/ctocpp/v8stack_trace_ctocpp.h @@ -0,0 +1,43 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef _V8STACKTRACE_CTOCPP_H +#define _V8STACKTRACE_CTOCPP_H + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef.h" +#include "include/cef_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed wrapper-side only. +class CefV8StackTraceCToCpp + : public CefCToCpp +{ +public: + CefV8StackTraceCToCpp(cef_v8stack_trace_t* str) + : CefCToCpp( + str) {} + virtual ~CefV8StackTraceCToCpp() {} + + // CefV8StackTrace methods + virtual int GetFrameCount() OVERRIDE; + virtual CefRefPtr GetFrame(int index) OVERRIDE; +}; + +#endif // USING_CEF_SHARED +#endif // _V8STACKTRACE_CTOCPP_H + diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index 9509c96de..b1e2c56aa 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -27,6 +27,8 @@ #include "libcef_dll/cpptoc/stream_writer_cpptoc.h" #include "libcef_dll/cpptoc/v8context_cpptoc.h" #include "libcef_dll/cpptoc/v8exception_cpptoc.h" +#include "libcef_dll/cpptoc/v8stack_frame_cpptoc.h" +#include "libcef_dll/cpptoc/v8stack_trace_cpptoc.h" #include "libcef_dll/cpptoc/v8value_cpptoc.h" #include "libcef_dll/cpptoc/web_plugin_info_cpptoc.h" #include "libcef_dll/cpptoc/web_urlrequest_cpptoc.h" @@ -147,6 +149,8 @@ CEF_EXPORT void cef_shutdown() DCHECK(CefV8ContextHandlerCToCpp::DebugObjCt == 0); DCHECK(CefV8ExceptionCppToC::DebugObjCt == 0); DCHECK(CefV8HandlerCToCpp::DebugObjCt == 0); + DCHECK(CefV8StackFrameCppToC::DebugObjCt == 0); + DCHECK(CefV8StackTraceCppToC::DebugObjCt == 0); DCHECK(CefV8ValueCppToC::DebugObjCt == 0); DCHECK(CefWebPluginInfoCppToC::DebugObjCt == 0); DCHECK(CefWebURLRequestClientCToCpp::DebugObjCt == 0); diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index 2560ed785..cc7aea093 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -59,6 +59,8 @@ #include "libcef_dll/ctocpp/stream_writer_ctocpp.h" #include "libcef_dll/ctocpp/v8context_ctocpp.h" #include "libcef_dll/ctocpp/v8exception_ctocpp.h" +#include "libcef_dll/ctocpp/v8stack_frame_ctocpp.h" +#include "libcef_dll/ctocpp/v8stack_trace_ctocpp.h" #include "libcef_dll/ctocpp/v8value_ctocpp.h" #include "libcef_dll/ctocpp/web_plugin_info_ctocpp.h" #include "libcef_dll/ctocpp/web_urlrequest_ctocpp.h" @@ -149,6 +151,8 @@ CEF_GLOBAL void CefShutdown() DCHECK(CefV8ContextHandlerCppToC::DebugObjCt == 0); DCHECK(CefV8ExceptionCToCpp::DebugObjCt == 0); DCHECK(CefV8HandlerCppToC::DebugObjCt == 0); + DCHECK(CefV8StackFrameCToCpp::DebugObjCt == 0); + DCHECK(CefV8StackTraceCToCpp::DebugObjCt == 0); DCHECK(CefV8ValueCToCpp::DebugObjCt == 0); DCHECK(CefWebPluginInfoCToCpp::DebugObjCt == 0); DCHECK(CefWebURLRequestCToCpp::DebugObjCt == 0); diff --git a/tests/unittests/v8_unittest.cc b/tests/unittests/v8_unittest.cc index 3f18f161d..c674d0a34 100644 --- a/tests/unittests/v8_unittest.cc +++ b/tests/unittests/v8_unittest.cc @@ -1,1800 +1,1487 @@ -// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "include/cef.h" #include "include/cef_runnable.h" +#include "tests/unittests/test_handler.h" #include "testing/gtest/include/gtest/gtest.h" -#include "test_handler.h" + +// How to add a new test: +// 1. Add a new value to the V8TestMode enumeration. +// 2. Add a method that implements the test in V8TestHandler. +// 3. Add a case for the new enumeration value in V8TestHandler::RunTest. +// 4. Add a line for the test in the "Define the tests" section at the bottom of +// the file. namespace { -bool g_V8TestV8HandlerExecuteCalled; -bool g_V8TestV8HandlerExecute2Called; +// Unique values for V8 tests. +const char* kV8TestUrl = "http://tests/V8Test.Test"; +const char* kV8BindingTestUrl = "http://tests/V8Test.BindingTest"; +const char* kV8ContextParentTestUrl = "http://tests/V8Test.ContextParentTest"; +const char* kV8ContextChildTestUrl = "http://tests/V8Test.ContextChildTest"; -class V8TestV8Handler : public CefV8Handler -{ -public: - V8TestV8Handler(bool bindingTest) { binding_test_ = bindingTest; } - - virtual bool Execute(const CefString& name, - CefRefPtr object, - const CefV8ValueList& arguments, - CefRefPtr& retval, - CefString& exception) - { - TestExecute(name, object, arguments, retval, exception); - return true; - } - - void TestExecute(const CefString& name, - CefRefPtr object, - const CefV8ValueList& arguments, - CefRefPtr& retval, - CefString& exception) - { - if(name == "execute") { - g_V8TestV8HandlerExecuteCalled = true; - - ASSERT_EQ((size_t)9, arguments.size()); - int argct = 0; - - // basic types - ASSERT_TRUE(arguments[argct]->IsInt()); - ASSERT_EQ(5, arguments[argct]->GetIntValue()); - argct++; - - ASSERT_TRUE(arguments[argct]->IsDouble()); - ASSERT_EQ(6.543, arguments[argct]->GetDoubleValue()); - argct++; - - ASSERT_TRUE(arguments[argct]->IsBool()); - ASSERT_EQ(true, arguments[argct]->GetBoolValue()); - argct++; - - ASSERT_TRUE(arguments[argct]->IsDate()); - CefTime date = arguments[argct]->GetDateValue(); - ASSERT_EQ(date.year, 2010); - ASSERT_EQ(date.month, 5); - ASSERT_EQ(date.day_of_month, 3); -#if !defined(OS_MACOSX) - ASSERT_EQ(date.day_of_week, 1); -#endif - ASSERT_EQ(date.hour, 12); - ASSERT_EQ(date.minute, 30); - ASSERT_EQ(date.second, 10); - ASSERT_NEAR(date.millisecond, 100, 1); - argct++; - - ASSERT_TRUE(arguments[argct]->IsString()); - ASSERT_EQ(arguments[argct]->GetStringValue(), "test string"); - argct++; - - CefRefPtr value; - - // array - ASSERT_TRUE(arguments[argct]->IsArray()); - ASSERT_EQ(4, arguments[argct]->GetArrayLength()); - { - int subargct = 0; - value = arguments[argct]->GetValue(subargct); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsInt()); - ASSERT_EQ(7, value->GetIntValue()); - subargct++; - - value = arguments[argct]->GetValue(subargct); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsDouble()); - ASSERT_EQ(5.432, value->GetDoubleValue()); - subargct++; - - value = arguments[argct]->GetValue(subargct); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsBool()); - ASSERT_FALSE(value->GetBoolValue()); - subargct++; - - value = arguments[argct]->GetValue(subargct); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsString()); - ASSERT_EQ(value->GetStringValue(), "another string"); - subargct++; - } - argct++; - - // object - ASSERT_TRUE(arguments[argct]->IsObject()); - { - value = arguments[argct]->GetValue("arg0"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsInt()); - ASSERT_EQ(2, value->GetIntValue()); - - value = arguments[argct]->GetValue("arg1"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsDouble()); - ASSERT_EQ(3.433, value->GetDoubleValue()); - - value = arguments[argct]->GetValue("arg2"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsBool()); - ASSERT_EQ(true, value->GetBoolValue()); - - value = arguments[argct]->GetValue("arg3"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsString()); - ASSERT_EQ(value->GetStringValue(), "some string"); - } - argct++; - - // function that returns a value - ASSERT_TRUE(arguments[argct]->IsFunction()); - { - CefV8ValueList args; - args.push_back(CefV8Value::CreateInt(5)); - args.push_back(CefV8Value::CreateDouble(3.5)); - args.push_back(CefV8Value::CreateBool(true)); - args.push_back(CefV8Value::CreateString("10")); - CefRefPtr rv; - CefRefPtr exception; - ASSERT_TRUE(arguments[argct]->ExecuteFunction( - arguments[argct], args, rv, exception, false)); - ASSERT_TRUE(rv.get() != NULL); - ASSERT_TRUE(rv->IsDouble()); - ASSERT_EQ(19.5, rv->GetDoubleValue()); - } - argct++; - - // function that throws an exception - ASSERT_TRUE(arguments[argct]->IsFunction()); - { - CefV8ValueList args; - args.push_back(CefV8Value::CreateDouble(5)); - args.push_back(CefV8Value::CreateDouble(0)); - CefRefPtr rv; - CefRefPtr exception; - ASSERT_TRUE(arguments[argct]->ExecuteFunction( - arguments[argct], args, rv, exception, false)); - ASSERT_TRUE(exception.get()); - ASSERT_EQ(exception->GetMessage(), "Uncaught My Exception"); - } - argct++; - - if(binding_test_) - { - // values - value = object->GetValue("intVal"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsInt()); - ASSERT_EQ(12, value->GetIntValue()); - - value = object->GetValue("doubleVal"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsDouble()); - ASSERT_EQ(5.432, value->GetDoubleValue()); - - value = object->GetValue("boolVal"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsBool()); - ASSERT_EQ(true, value->GetBoolValue()); - - value = object->GetValue("stringVal"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsString()); - ASSERT_EQ(value->GetStringValue(), "the string"); - - value = object->GetValue("dateVal"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsDate()); - CefTime date = value->GetDateValue(); - ASSERT_EQ(date.year, 2010); - ASSERT_EQ(date.month, 5); -#if !defined(OS_MACOSX) - ASSERT_EQ(date.day_of_week, 1); -#endif - ASSERT_EQ(date.day_of_month, 3); - ASSERT_EQ(date.hour, 12); - ASSERT_EQ(date.minute, 30); - ASSERT_EQ(date.second, 10); - ASSERT_NEAR(date.millisecond, 100, 1); - - value = object->GetValue("arrayVal"); - ASSERT_TRUE(value.get() != NULL); - ASSERT_TRUE(value->IsArray()); - { - CefRefPtr value2; - int subargct = 0; - value2 = value->GetValue(subargct); - ASSERT_TRUE(value2.get() != NULL); - ASSERT_TRUE(value2->IsInt()); - ASSERT_EQ(4, value2->GetIntValue()); - subargct++; - - value2 = value->GetValue(subargct); - ASSERT_TRUE(value2.get() != NULL); - ASSERT_TRUE(value2->IsDouble()); - ASSERT_EQ(120.43, value2->GetDoubleValue()); - subargct++; - - value2 = value->GetValue(subargct); - ASSERT_TRUE(value2.get() != NULL); - ASSERT_TRUE(value2->IsBool()); - ASSERT_EQ(true, value2->GetBoolValue()); - subargct++; - - value2 = value->GetValue(subargct); - ASSERT_TRUE(value2.get() != NULL); - ASSERT_TRUE(value2->IsString()); - ASSERT_EQ(value2->GetStringValue(), "a string"); - subargct++; - } - } - - retval = CefV8Value::CreateInt(5); - } else if(name == "execute2") { - g_V8TestV8HandlerExecute2Called = true; - - // check the result of calling the "execute" function - ASSERT_EQ((size_t)1, arguments.size()); - ASSERT_TRUE(arguments[0]->IsInt()); - ASSERT_EQ(5, arguments[0]->GetIntValue()); - } - } - - bool binding_test_; - - IMPLEMENT_REFCOUNTING(V8TestV8Handler); +enum V8TestMode { + V8TEST_NULL_CREATE = 0, + V8TEST_BOOL_CREATE, + V8TEST_INT_CREATE, + V8TEST_DOUBLE_CREATE, + V8TEST_DATE_CREATE, + V8TEST_STRING_CREATE, + V8TEST_ARRAY_CREATE, + V8TEST_ARRAY_VALUE, + V8TEST_OBJECT_CREATE, + V8TEST_OBJECT_USERDATA, + V8TEST_OBJECT_ACCESSOR, + V8TEST_OBJECT_ACCESSOR_FAIL, + V8TEST_OBJECT_ACCESSOR_READONLY, + V8TEST_OBJECT_VALUE, + V8TEST_OBJECT_VALUE_READONLY, + V8TEST_OBJECT_VALUE_ENUM, + V8TEST_OBJECT_VALUE_DONTENUM, + V8TEST_OBJECT_VALUE_DELETE, + V8TEST_OBJECT_VALUE_DONTDELETE, + V8TEST_FUNCTION_CREATE, + V8TEST_FUNCTION_HANDLER, + V8TEST_FUNCTION_HANDLER_EXCEPTION, + V8TEST_FUNCTION_HANDLER_FAIL, + V8TEST_FUNCTION_HANDLER_NO_OBJECT, + V8TEST_FUNCTION_HANDLER_WITH_CONTEXT, + V8TEST_CONTEXT_EVAL, + V8TEST_CONTEXT_EVAL_EXCEPTION, + V8TEST_CONTEXT_ENTERED, + V8TEST_BINDING, + V8TEST_STACK_TRACE, }; -class V8TestHandler : public TestHandler -{ -public: - V8TestHandler(bool bindingTest) { binding_test_ = bindingTest; } - virtual void RunTest() OVERRIDE - { - std::string object; - if(binding_test_) { - // binding uses the window object - object = "window.test"; +class V8TestHandler : public TestHandler { + public: + explicit V8TestHandler(V8TestMode test_mode, + const char* test_url) + : test_mode_(test_mode), + test_url_(test_url) { + } + + virtual void RunTest() OVERRIDE { + if (test_mode_ == V8TEST_CONTEXT_ENTERED) { + AddResource(kV8ContextParentTestUrl, "" + "", "text/html"); + AddResource(kV8ContextChildTestUrl, "CHILD", + "text/html"); + CreateBrowser(kV8ContextParentTestUrl); } else { - // extension uses a global object - object = "test"; + EXPECT_TRUE(test_url_ != NULL); + AddResource(test_url_, "TEST", "text/html"); + CreateBrowser(test_url_); } - - std::stringstream testHtml; - testHtml << - "" - "" - ""; - - AddResource("http://tests/run.html", testHtml.str(), "text/html"); - CreateBrowser("http://tests/run.html"); } - virtual void OnLoadEnd(CefRefPtr browser, - CefRefPtr frame, - int httpStatusCode) OVERRIDE - { - if(!browser->IsPopup() && frame->IsMain()) - DestroyTest(); - } - - virtual void OnContextCreated(CefRefPtr browser, - CefRefPtr frame, - CefRefPtr context) OVERRIDE - { - if(binding_test_) - TestHandleJSBinding(browser, frame, context->GetGlobal()); - } - - void TestHandleJSBinding(CefRefPtr browser, - CefRefPtr frame, - CefRefPtr object) - { - // Create the new V8 object - CefRefPtr testObj = CefV8Value::CreateObject(NULL, NULL); - ASSERT_TRUE(testObj.get() != NULL); - ASSERT_TRUE(object->SetValue("test", testObj, V8_PROPERTY_ATTRIBUTE_NONE)); - - // Create an instance of V8ExecuteV8Handler - CefRefPtr testHandler(new V8TestV8Handler(true)); - ASSERT_TRUE(testHandler.get() != NULL); - - // Add the functions - CefRefPtr testFunc; - testFunc = CefV8Value::CreateFunction("execute", testHandler); - ASSERT_TRUE(testFunc.get() != NULL); - ASSERT_TRUE(testObj->SetValue("execute", testFunc, - V8_PROPERTY_ATTRIBUTE_NONE)); - testFunc = CefV8Value::CreateFunction("execute2", testHandler); - ASSERT_TRUE(testFunc.get() != NULL); - ASSERT_TRUE(testObj->SetValue("execute2", testFunc, - V8_PROPERTY_ATTRIBUTE_NONE)); - - // Add the values - ASSERT_TRUE(testObj->SetValue("intVal", - CefV8Value::CreateInt(12), V8_PROPERTY_ATTRIBUTE_NONE)); - ASSERT_TRUE(testObj->SetValue("doubleVal", - CefV8Value::CreateDouble(5.432), V8_PROPERTY_ATTRIBUTE_NONE)); - ASSERT_TRUE(testObj->SetValue("boolVal", - CefV8Value::CreateBool(true), V8_PROPERTY_ATTRIBUTE_NONE)); - ASSERT_TRUE(testObj->SetValue("stringVal", - CefV8Value::CreateString("the string"), V8_PROPERTY_ATTRIBUTE_NONE)); - - cef_time_t date = { - 2010, - 5, -#if !defined(OS_MACOSX) - 1, -#endif - 3, - 12, - 30, - 10, - 100 - }; - ASSERT_TRUE(testObj->SetValue("dateVal", CefV8Value::CreateDate(date), - V8_PROPERTY_ATTRIBUTE_NONE)); - - CefRefPtr testArray(CefV8Value::CreateArray()); - ASSERT_TRUE(testArray.get() != NULL); - ASSERT_TRUE(testObj->SetValue("arrayVal", testArray, - V8_PROPERTY_ATTRIBUTE_NONE)); - ASSERT_TRUE(testArray->SetValue(0, CefV8Value::CreateInt(4))); - ASSERT_TRUE(testArray->SetValue(1, CefV8Value::CreateDouble(120.43))); - ASSERT_TRUE(testArray->SetValue(2, CefV8Value::CreateBool(true))); - ASSERT_TRUE(testArray->SetValue(3, CefV8Value::CreateString("a string"))); - } - - bool binding_test_; -}; - -} // namespace - -// Verify window binding -TEST(V8Test, Binding) -{ - g_V8TestV8HandlerExecuteCalled = false; - g_V8TestV8HandlerExecute2Called = false; - - CefRefPtr handler = new V8TestHandler(true); - handler->ExecuteTest(); - - ASSERT_TRUE(g_V8TestV8HandlerExecuteCalled); - ASSERT_TRUE(g_V8TestV8HandlerExecute2Called); -} - -// Verify extensions -TEST(V8Test, Extension) -{ - g_V8TestV8HandlerExecuteCalled = false; - g_V8TestV8HandlerExecute2Called = false; - - std::string extensionCode = - "var test;" - "if (!test)" - " test = {};" - "(function() {" - " test.execute = function(a,b,c,d,e,f,g,h,i) {" - " native function execute();" - " return execute(a,b,c,d,e,f,g,h,i);" - " };" - " test.execute2 = function(a) {" - " native function execute2();" - " return execute2(a);" - " };" - "})();"; - CefRegisterExtension("v8/test", extensionCode, new V8TestV8Handler(false)); - - CefRefPtr handler = new V8TestHandler(false); - handler->ExecuteTest(); - - ASSERT_TRUE(g_V8TestV8HandlerExecuteCalled); - ASSERT_TRUE(g_V8TestV8HandlerExecute2Called); -} - -namespace { - -class TestNoNativeHandler : public TestHandler -{ -public: - class TestHandler : public CefV8Handler - { - public: - TestHandler(CefRefPtr test) - : test_(test) - { + // Run the specified test. + void RunTest(V8TestMode test_mode) { + switch (test_mode) { + case V8TEST_NULL_CREATE: + RunNullCreateTest(); + break; + case V8TEST_BOOL_CREATE: + RunBoolCreateTest(); + break; + case V8TEST_INT_CREATE: + RunIntCreateTest(); + break; + case V8TEST_DOUBLE_CREATE: + RunDoubleCreateTest(); + break; + case V8TEST_DATE_CREATE: + RunDateCreateTest(); + break; + case V8TEST_STRING_CREATE: + RunStringCreateTest(); + break; + case V8TEST_ARRAY_CREATE: + RunArrayCreateTest(); + break; + case V8TEST_ARRAY_VALUE: + RunArrayValueTest(); + break; + case V8TEST_OBJECT_CREATE: + RunObjectCreateTest(); + break; + case V8TEST_OBJECT_USERDATA: + RunObjectUserDataTest(); + break; + case V8TEST_OBJECT_ACCESSOR: + RunObjectAccessorTest(); + break; + case V8TEST_OBJECT_ACCESSOR_FAIL: + RunObjectAccessorFailTest(); + break; + case V8TEST_OBJECT_ACCESSOR_READONLY: + RunObjectAccessorReadOnlyTest(); + break; + case V8TEST_OBJECT_VALUE: + RunObjectValueTest(); + break; + case V8TEST_OBJECT_VALUE_READONLY: + RunObjectValueReadOnlyTest(); + break; + case V8TEST_OBJECT_VALUE_ENUM: + RunObjectValueEnumTest(); + break; + case V8TEST_OBJECT_VALUE_DONTENUM: + RunObjectValueDontEnumTest(); + break; + case V8TEST_OBJECT_VALUE_DELETE: + RunObjectValueDeleteTest(); + break; + case V8TEST_OBJECT_VALUE_DONTDELETE: + RunObjectValueDontDeleteTest(); + break; + case V8TEST_FUNCTION_CREATE: + RunFunctionCreateTest(); + break; + case V8TEST_FUNCTION_HANDLER: + RunFunctionHandlerTest(); + break; + case V8TEST_FUNCTION_HANDLER_EXCEPTION: + RunFunctionHandlerExceptionTest(); + break; + case V8TEST_FUNCTION_HANDLER_FAIL: + RunFunctionHandlerFailTest(); + break; + case V8TEST_FUNCTION_HANDLER_NO_OBJECT: + RunFunctionHandlerNoObjectTest(); + break; + case V8TEST_FUNCTION_HANDLER_WITH_CONTEXT: + RunFunctionHandlerWithContextTest(); + break; + case V8TEST_CONTEXT_EVAL: + RunContextEvalTest(); + break; + case V8TEST_CONTEXT_EVAL_EXCEPTION: + RunContextEvalExceptionTest(); + break; + case V8TEST_CONTEXT_ENTERED: + RunContextEnteredTest(); + break; + case V8TEST_BINDING: + RunBindingTest(); + break; + case V8TEST_STACK_TRACE: + RunStackTraceTest(); + break; + default: + ADD_FAILURE(); + DestroyTest(); + break; } - - virtual bool Execute(const CefString& name, - CefRefPtr object, - const CefV8ValueList& arguments, - CefRefPtr& retval, - CefString& exception) OVERRIDE - { - if (name == "result") { - if (arguments.size() == 1 && arguments[0]->IsString()) { - std::string value = arguments[0]->GetStringValue(); - if (value == "correct") - test_->got_correct_.yes(); - else - return false; - return true; - } - } - - return false; - } - - CefRefPtr test_; - - IMPLEMENT_REFCOUNTING(TestHandler); - }; - - TestNoNativeHandler() - { } - virtual void RunTest() OVERRIDE - { - std::string testHtml = - "\n" - "\n" - ""; - AddResource("http://tests/run.html", testHtml, "text/html"); + void RunNullCreateTest() { + CefRefPtr value = CefV8Value::CreateNull(); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsNull()); - CreateBrowser("http://tests/run.html"); - } + 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->IsObject()); + EXPECT_FALSE(value->IsString()); - virtual void OnLoadEnd(CefRefPtr browser, - CefRefPtr frame, - int httpStatusCode) OVERRIDE - { DestroyTest(); } - virtual void OnContextCreated(CefRefPtr browser, - CefRefPtr frame, - CefRefPtr context) OVERRIDE - { - // Retrieve the 'window' object. - CefRefPtr object = context->GetGlobal(); + void RunBoolCreateTest() { + CefRefPtr value = CefV8Value::CreateBool(true); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsBool()); + EXPECT_EQ(true, value->GetBoolValue()); - // Create the functions that will be used during the test. - CefRefPtr obj = CefV8Value::CreateObject(NULL, NULL); - CefRefPtr handler = new TestHandler(this); - obj->SetValue("result", - CefV8Value::CreateFunction("result", handler), - V8_PROPERTY_ATTRIBUTE_NONE); - object->SetValue("test", obj, V8_PROPERTY_ATTRIBUTE_NONE); + EXPECT_FALSE(value->IsUndefined()); + EXPECT_FALSE(value->IsArray()); + EXPECT_FALSE(value->IsDate()); + EXPECT_FALSE(value->IsDouble()); + EXPECT_FALSE(value->IsFunction()); + EXPECT_FALSE(value->IsInt()); + EXPECT_FALSE(value->IsNull()); + EXPECT_FALSE(value->IsObject()); + EXPECT_FALSE(value->IsString()); + + DestroyTest(); } - TrackCallback got_correct_; -}; + void RunIntCreateTest() { + CefRefPtr value = CefV8Value::CreateInt(12); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsInt()); + EXPECT_TRUE(value->IsDouble()); + EXPECT_EQ(12, value->GetIntValue()); + EXPECT_EQ(12, value->GetDoubleValue()); -} // namespace + EXPECT_FALSE(value->IsUndefined()); + EXPECT_FALSE(value->IsArray()); + EXPECT_FALSE(value->IsBool()); + EXPECT_FALSE(value->IsDate()); + EXPECT_FALSE(value->IsFunction()); + EXPECT_FALSE(value->IsNull()); + EXPECT_FALSE(value->IsObject()); + EXPECT_FALSE(value->IsString()); -// Verify extensions with no native functions -TEST(V8Test, ExtensionNoNative) -{ - std::string extensionCode = - "var test_nonative;" - "if (!test_nonative)" - " test_nonative = {};" - "(function() {" - " test_nonative.add = function(a, b) {" - " return a + b;" - " };" - "})();"; - CefRegisterExtension("v8/test_nonative", extensionCode, NULL); + DestroyTest(); + } - CefRefPtr handler = new TestNoNativeHandler(); - handler->ExecuteTest(); + void RunDoubleCreateTest() { + CefRefPtr value = CefV8Value::CreateDouble(12.1223); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsDouble()); + EXPECT_EQ(12.1223, value->GetDoubleValue()); - EXPECT_TRUE(handler->got_correct_); -} + EXPECT_FALSE(value->IsUndefined()); + EXPECT_FALSE(value->IsArray()); + EXPECT_FALSE(value->IsBool()); + EXPECT_FALSE(value->IsDate()); + EXPECT_FALSE(value->IsFunction()); + EXPECT_FALSE(value->IsInt()); + EXPECT_FALSE(value->IsNull()); + EXPECT_FALSE(value->IsObject()); + EXPECT_FALSE(value->IsString()); -namespace { + DestroyTest(); + } -// Using a delegate so that the code below can remain inline. -class CefV8HandlerDelegate -{ -public: - virtual bool Execute(const CefString& name, - CefRefPtr object, - const CefV8ValueList& arguments, + void RunDateCreateTest() { + CefRefPtr context = GetContext(); + + CefTime date; + date.year = 2200; + date.month = 4; +#if !defined(OS_MACOSX) + date.day_of_week = 5; +#endif + date.day_of_month = 11; + date.hour = 20; + date.minute = 15; + date.second = 42; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr value = CefV8Value::CreateDate(date); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsDate()); + EXPECT_TRUE(value->IsObject()); + EXPECT_EQ(date.GetTimeT(), value->GetDateValue().GetTimeT()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + EXPECT_FALSE(value->IsUndefined()); + EXPECT_FALSE(value->IsArray()); + EXPECT_FALSE(value->IsBool()); + EXPECT_FALSE(value->IsDouble()); + EXPECT_FALSE(value->IsFunction()); + EXPECT_FALSE(value->IsInt()); + EXPECT_FALSE(value->IsNull()); + EXPECT_FALSE(value->IsString()); + + DestroyTest(); + } + + void RunStringCreateTest() { + CefRefPtr value = CefV8Value::CreateString("My string"); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsString()); + EXPECT_STREQ("My string", value->GetStringValue().ToString().c_str()); + + 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->IsNull()); + EXPECT_FALSE(value->IsObject()); + + DestroyTest(); + } + + void RunArrayCreateTest() { + CefRefPtr context = GetContext(); + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr value = CefV8Value::CreateArray(); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsArray()); + EXPECT_TRUE(value->IsObject()); + EXPECT_EQ(0, value->GetArrayLength()); + EXPECT_FALSE(value->HasValue(0)); + EXPECT_FALSE(value->HasValue(1)); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + EXPECT_FALSE(value->IsUndefined()); + EXPECT_FALSE(value->IsBool()); + EXPECT_FALSE(value->IsDate()); + EXPECT_FALSE(value->IsDouble()); + EXPECT_FALSE(value->IsFunction()); + EXPECT_FALSE(value->IsInt()); + EXPECT_FALSE(value->IsNull()); + EXPECT_FALSE(value->IsString()); + + DestroyTest(); + } + + void RunArrayValueTest() { + CefRefPtr context = GetContext(); + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr value = CefV8Value::CreateArray(); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsArray()); + EXPECT_EQ(0, value->GetArrayLength()); + + // Test addng values. + EXPECT_FALSE(value->HasValue(0)); + EXPECT_FALSE(value->HasValue(1)); + + EXPECT_TRUE(value->SetValue(0, CefV8Value::CreateInt(10))); + EXPECT_TRUE(value->HasValue(0)); + EXPECT_FALSE(value->HasValue(1)); + + EXPECT_TRUE(value->GetValue(0)->IsInt()); + EXPECT_EQ(10, value->GetValue(0)->GetIntValue()); + EXPECT_EQ(1, value->GetArrayLength()); + + EXPECT_TRUE(value->SetValue(1, CefV8Value::CreateInt(43))); + EXPECT_TRUE(value->HasValue(0)); + EXPECT_TRUE(value->HasValue(1)); + + EXPECT_TRUE(value->GetValue(1)->IsInt()); + EXPECT_EQ(43, value->GetValue(1)->GetIntValue()); + EXPECT_EQ(2, value->GetArrayLength()); + + EXPECT_TRUE(value->DeleteValue(0)); + EXPECT_FALSE(value->HasValue(0)); + EXPECT_TRUE(value->HasValue(1)); + EXPECT_EQ(2, value->GetArrayLength()); + + EXPECT_TRUE(value->DeleteValue(1)); + EXPECT_FALSE(value->HasValue(0)); + EXPECT_FALSE(value->HasValue(1)); + EXPECT_EQ(2, value->GetArrayLength()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunObjectCreateTest() { + CefRefPtr context = GetContext(); + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr value = CefV8Value::CreateObject(NULL); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsObject()); + EXPECT_FALSE(value->GetUserData().get()); + + 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->IsNull()); + EXPECT_FALSE(value->IsString()); + + DestroyTest(); + } + + void RunObjectUserDataTest() { + CefRefPtr context = GetContext(); + + class UserData : public CefBase { + public: + explicit UserData(int value) : value_(value) {} + int value_; + IMPLEMENT_REFCOUNTING(UserData); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr value = CefV8Value::CreateObject(new UserData(10)); + EXPECT_TRUE(value.get()); + + CefRefPtr user_data = value->GetUserData(); + EXPECT_TRUE(user_data.get()); + UserData* user_data_impl = static_cast(user_data.get()); + EXPECT_EQ(10, user_data_impl->value_); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunObjectAccessorTest() { + CefRefPtr context = GetContext(); + + static const char* kName = "val"; + static const int kValue = 20; + + class Accessor : public CefV8Accessor { + public: + Accessor() : value_(0) {} + virtual bool Get(const CefString& name, + const CefRefPtr object, CefRefPtr& retval, - CefString& exception) = 0; + CefString& exception) OVERRIDE { + EXPECT_STREQ(kName, name.ToString().c_str()); - virtual bool Get(const CefString& name, - const CefRefPtr object, - CefRefPtr& retval, - CefString& exception) = 0; + EXPECT_TRUE(object.get()); + EXPECT_TRUE(object->IsSame(object_)); - virtual bool Set(const CefString& name, - const CefRefPtr object, - const CefRefPtr value, - CefString& exception) = 0; -}; + EXPECT_FALSE(retval.get()); + EXPECT_TRUE(exception.empty()); -class DelegatingV8Handler : public CefV8Handler -{ -public: - DelegatingV8Handler(CefV8HandlerDelegate *delegate): - delegate_(delegate) { } - - ~DelegatingV8Handler() - { - } - - bool Execute(const CefString& name, - CefRefPtr object, - const CefV8ValueList& arguments, - CefRefPtr& retval, - CefString& exception) OVERRIDE - { - return delegate_->Execute(name, object, arguments, retval, exception); - } - -private: - CefV8HandlerDelegate *delegate_; - - IMPLEMENT_REFCOUNTING(DelegatingV8Handler); -}; - -class DelegatingV8Accessor: public CefV8Accessor -{ -public: - DelegatingV8Accessor(CefV8HandlerDelegate *delegate) - : delegate_(delegate) { } - - bool Get(const CefString& name, - const CefRefPtr object, - CefRefPtr& retval, - CefString& exception) OVERRIDE - { - return delegate_->Get(name, object, retval, exception); - } - - bool Set(const CefString& name, - const CefRefPtr object, - const CefRefPtr value, - CefString& exception) OVERRIDE - { - return delegate_->Set(name, object, value, exception); - } - -private: - CefV8HandlerDelegate *delegate_; - - IMPLEMENT_REFCOUNTING(DelegatingV8Accessor); -}; - -class TestContextHandler: public TestHandler, public CefV8HandlerDelegate -{ -public: - TestContextHandler() {} - - virtual void RunTest() OVERRIDE - { - // Test Flow: - // load main.html. - // 1. main.html calls hello("main", callIFrame) in the execute handler. - // The excute handler checks that "main" was called and saves - // the callIFrame function, context, and receiver object. - // 2. iframe.html calls hello("iframe") in the execute handler. - // The execute handler checks that "iframe" was called. if both main - // and iframe were called, it calls CallIFrame() - // 3. CallIFrame calls "callIFrame" in main.html - // 4. which calls iframe.html "calledFromMain()". - // 5. which calls "fromIFrame()" in execute handler. - // The execute handler checks that the entered and current urls are - // what we expect: "main.html" and "iframe.html", respectively - // 6. It then posts a task to call AsyncTestContext - // you can validate the entered and current context are still the - // same here, but it is not checked by this test case. - // 7. AsyncTestContext tests to make sure that no context is set at - // this point and loads "begin.html" - // 8. begin.html calls "begin(func1, func2)" in the execute handler - // The execute handler posts a tasks to call both of those functions - // when no context is defined. Both should work with the specified - // context. AsyncTestException should run first, followed by - // AsyncTestNavigate() which calls the func2 to do a document.location - // based loading of "end.html". - // 9. end.html calls "end()" in the execute handler. - // which concludes the test. - - y_ = 0; - - std::stringstream mainHtml; - mainHtml << - "" - "

Hello From Main Frame

" - "" - "" - ""; - - AddResource("http://tests/main.html", mainHtml.str(), "text/html"); - - std::stringstream iframeHtml; - iframeHtml << - "" - "

Hello From IFRAME

" - "" - ""; - - AddResource("http://tests/iframe.html", iframeHtml.str(), "text/html"); - - std::stringstream beginHtml; - beginHtml << - "" - "

V8 Context Test

" - "" - ""; - - AddResource("http://tests/begin.html", beginHtml.str(), "text/html"); - - std::stringstream endHtml; - endHtml << - "" - "

Navigation Succeeded!

" - "" - ""; - - AddResource("http://tests/end.html", endHtml.str(), "text/html"); - - CreateBrowser("http://tests/main.html"); - } - - virtual void OnLoadEnd(CefRefPtr browser, - CefRefPtr frame, - int httpStatusCode) OVERRIDE - { - } - - virtual void OnContextCreated(CefRefPtr browser, - CefRefPtr frame, - CefRefPtr context) OVERRIDE - { - // Retrieve the 'window' object. - CefRefPtr object = context->GetGlobal(); - - CefRefPtr cc = CefV8Context::GetCurrentContext(); - CefRefPtr currentBrowser = cc->GetBrowser(); - CefRefPtr currentFrame = cc->GetFrame(); - CefString currentURL = currentFrame->GetURL(); - - CefRefPtr ec = CefV8Context::GetEnteredContext(); - CefRefPtr enteredBrowser = ec->GetBrowser(); - CefRefPtr enteredFrame = ec->GetFrame(); - CefString enteredURL = enteredFrame->GetURL(); - - CefRefPtr funcHandler(new DelegatingV8Handler(this)); - CefRefPtr helloFunc = - CefV8Value::CreateFunction("hello", funcHandler); - object->SetValue("hello", helloFunc, V8_PROPERTY_ATTRIBUTE_NONE); - - CefRefPtr fromIFrameFunc = - CefV8Value::CreateFunction("fromIFrame", funcHandler); - object->SetValue("fromIFrame", fromIFrameFunc, V8_PROPERTY_ATTRIBUTE_NONE); - - CefRefPtr goFunc = - CefV8Value::CreateFunction("begin", funcHandler); - object->SetValue("begin", goFunc, V8_PROPERTY_ATTRIBUTE_NONE); - - CefRefPtr doneFunc = - CefV8Value::CreateFunction("end", funcHandler); - object->SetValue("end", doneFunc, V8_PROPERTY_ATTRIBUTE_NONE); - - CefRefPtr compFunc = - CefV8Value::CreateFunction("comp", funcHandler); - object->SetValue("comp", compFunc, V8_PROPERTY_ATTRIBUTE_NONE); - - // Used for testing exceptions returned from accessors. - CefRefPtr gotGetExceptionFunc = - CefV8Value::CreateFunction("gotGetException", funcHandler); - object->SetValue("gotGetException", gotGetExceptionFunc, - V8_PROPERTY_ATTRIBUTE_NONE); - CefRefPtr gotSetExceptionFunc = - CefV8Value::CreateFunction("gotSetException", funcHandler); - object->SetValue("gotSetException", gotSetExceptionFunc, - V8_PROPERTY_ATTRIBUTE_NONE); - - // Create an object with accessor based properties: - CefRefPtr blankBase; - CefRefPtr accessor(new DelegatingV8Accessor(this)); - CefRefPtr point = CefV8Value::CreateObject(blankBase, accessor); - - point->SetValue("x", V8_ACCESS_CONTROL_DEFAULT, - V8_PROPERTY_ATTRIBUTE_READONLY); - point->SetValue("y", V8_ACCESS_CONTROL_DEFAULT, - V8_PROPERTY_ATTRIBUTE_NONE); - - object->SetValue("point", point, V8_PROPERTY_ATTRIBUTE_NONE); - - // Create another object with accessor based properties: - CefRefPtr exceptObj = - CefV8Value::CreateObject(NULL, new DelegatingV8Accessor(this)); - - exceptObj->SetValue("makeException", V8_ACCESS_CONTROL_DEFAULT, - V8_PROPERTY_ATTRIBUTE_NONE); - - object->SetValue("exceptObj", exceptObj, V8_PROPERTY_ATTRIBUTE_NONE); - } - - void CallIFrame() - { - CefV8ValueList args; - CefRefPtr rv; - CefRefPtr exception; - CefRefPtr empty; - ASSERT_TRUE(funcIFrame_->ExecuteFunctionWithContext(contextIFrame_, empty, - args, rv, exception, - false)); - } - - void AsyncTestContext(CefRefPtr ec, - CefRefPtr cc) - { - // we should not be in a context in this call. - CefRefPtr noContext = CefV8Context::GetCurrentContext(); - if (!noContext.get()) - got_no_context_.yes(); - - CefRefPtr enteredBrowser = ec->GetBrowser(); - CefRefPtr enteredFrame = ec->GetFrame(); - CefString enteredURL = enteredFrame->GetURL(); - CefString enteredName = enteredFrame->GetName(); - CefRefPtr enteredMainFrame = enteredBrowser->GetMainFrame(); - CefString enteredMainURL = enteredMainFrame->GetURL(); - CefString enteredMainName = enteredMainFrame->GetName(); - - CefRefPtr currentBrowser = cc->GetBrowser(); - CefRefPtr currentFrame = cc->GetFrame(); - CefString currentURL = currentFrame->GetURL(); - CefString currentName = currentFrame->GetName(); - CefRefPtr currentMainFrame = currentBrowser->GetMainFrame(); - CefString currentMainURL = currentMainFrame->GetURL(); - CefString currentMainName = currentMainFrame->GetName(); - - CefRefPtr copyFromMainFrame = - currentMainFrame->GetBrowser(); - - currentMainFrame->LoadURL("http://tests/begin.html"); - } - - void AsyncTestException(CefRefPtr context, - CefRefPtr func) - { - CefV8ValueList args; - CefRefPtr rv; - CefRefPtr exception; - CefRefPtr empty; - ASSERT_TRUE(func->ExecuteFunctionWithContext(context, empty, args, rv, - exception, false)); - if(exception.get() && exception->GetMessage() == "Uncaught My Exception") - got_exception_.yes(); - } - - void AsyncTestNavigation(CefRefPtr context, - CefRefPtr func) - { - CefRefPtr exception; - CefV8ValueList args; - CefRefPtr rv, obj, url; - - // Need to enter the context in order to create an Object, - // Array, or Function. Simple types like String, Int, - // Boolean, and Double don't require you to be in the - // context before creating them. - if ( context->Enter() ) { - CefRefPtr global = context->GetGlobal(); - CefRefPtr anArray = CefV8Value::CreateArray(); - CefRefPtr funcHandler(new DelegatingV8Handler(this)); - CefRefPtr foobarFunc = - CefV8Value::CreateFunction("foobar", funcHandler); - - obj = CefV8Value::CreateObject(NULL, NULL); - url = CefV8Value::CreateString("http://tests/end.html"); - - obj->SetValue("url", url, V8_PROPERTY_ATTRIBUTE_NONE); - obj->SetValue("foobar", foobarFunc, V8_PROPERTY_ATTRIBUTE_NONE); - obj->SetValue("anArray", anArray, V8_PROPERTY_ATTRIBUTE_NONE); - - args.push_back(obj); - - ASSERT_TRUE(func->ExecuteFunctionWithContext(context, global, args, rv, - exception, false)); - if(!exception.get()) - got_navigation_.yes(); - - context->Exit(); - } - } - - bool Execute(const CefString& name, - CefRefPtr object, - const CefV8ValueList& arguments, - CefRefPtr& retval, - CefString& exception) OVERRIDE - { - CefRefPtr cc = CefV8Context::GetCurrentContext(); - CefRefPtr ec = CefV8Context::GetEnteredContext(); - - CefRefPtr enteredBrowser = ec->GetBrowser(); - CefRefPtr enteredFrame = ec->GetFrame(); - CefString enteredURL = enteredFrame->GetURL(); - CefString enteredName = enteredFrame->GetName(); - CefRefPtr enteredMainFrame = enteredBrowser->GetMainFrame(); - CefString enteredMainURL = enteredMainFrame->GetURL(); - CefString enteredMainName = enteredMainFrame->GetName(); - - CefRefPtr currentBrowser = cc->GetBrowser(); - CefRefPtr currentFrame = cc->GetFrame(); - CefString currentURL = currentFrame->GetURL(); - CefString currentName = currentFrame->GetName(); - CefRefPtr currentMainFrame = currentBrowser->GetMainFrame(); - CefString currentMainURL = currentMainFrame->GetURL(); - CefString currentMainName = currentMainFrame->GetName(); - - if (name == "hello") { - if(arguments.size() == 2 && arguments[0]->IsString() && - arguments[1]->IsFunction()) { - CefString msg = arguments[0]->GetStringValue(); - if(msg == "main") { - got_hello_main_.yes(); - contextIFrame_ = cc; - funcIFrame_ = arguments[1]; - } - } else if(arguments.size() == 1 && arguments[0]->IsString()) { - CefString msg = arguments[0]->GetStringValue(); - if(msg == "iframe") - got_hello_iframe_.yes(); - } - else - return false; - - if(got_hello_main_ && got_hello_iframe_ && funcIFrame_->IsFunction()) { - // NB: At this point, enteredURL == http://tests/iframe.html which is - // expected since the iframe made the call on its own. The unexpected - // behavior is that in the call to fromIFrame (below) the enteredURL - // == http://tests/main.html even though the iframe.html context was - // entered first. - // -- Perhaps WebKit does something other than look at the bottom - // of stack for the entered context. - if(enteredURL == "http://tests/iframe.html") - got_iframe_as_entered_url_.yes(); - CallIFrame(); - } - return true; - } else if(name == "fromIFrame") { - if(enteredURL == "http://tests/main.html") - got_correct_entered_url_.yes(); - if(currentURL == "http://tests/iframe.html") - got_correct_current_url_.yes(); - CefPostTask(TID_UI, NewCefRunnableMethod(this, - &TestContextHandler::AsyncTestContext, ec, cc)); - return true; - } else if(name == "begin") { - if(arguments.size() == 2 && arguments[0]->IsFunction() && - arguments[1]->IsFunction()) { - CefRefPtr funcException = arguments[0]; - CefRefPtr funcNavigate = arguments[1]; - CefPostTask(TID_UI, NewCefRunnableMethod(this, - &TestContextHandler::AsyncTestException, cc, funcException)); - CefPostTask(TID_UI, NewCefRunnableMethod(this, - &TestContextHandler::AsyncTestNavigation, cc, funcNavigate)); + got_get_.yes(); + retval = CefV8Value::CreateInt(value_); + EXPECT_EQ(kValue, retval->GetIntValue()); return true; } - } else if (name == "comp") { - if(arguments.size() == 3) - { - CefRefPtr expected = arguments[0]; - CefRefPtr one = arguments[1]; - CefRefPtr two = arguments[2]; - bool bExpected = expected->GetBoolValue(); - bool bOne2Two = one->IsSame(two); - bool bTwo2One = two->IsSame(one); + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + EXPECT_STREQ(kName, name.ToString().c_str()); - // IsSame should match the expected - if ( bExpected != bOne2Two || bExpected != bTwo2One) - got_bad_is_same_.yes(); + EXPECT_TRUE(object.get()); + EXPECT_TRUE(object->IsSame(object_)); + + EXPECT_TRUE(value.get()); + EXPECT_TRUE(exception.empty()); + + got_set_.yes(); + value_ = value->GetIntValue(); + EXPECT_EQ(kValue, value_); + return true; } - else - { - got_bad_is_same_.yes(); - } - } else if (name == "end") { - got_testcomplete_.yes(); - DestroyTest(); - return true; - } else if (name == "gotGetException") { - if (arguments.size() == 1 && - arguments[0]->GetStringValue() == "Error: My Get Exception") { - got_getexception_.yes(); - } - return true; - } else if (name == "gotSetException") { - if (arguments.size() == 1 && - arguments[0]->GetStringValue() == "Error: My Set Exception") { - got_setexception_.yes(); - } - return true; - } - return false; + + CefRefPtr object_; + int value_; + TrackCallback got_get_; + TrackCallback got_set_; + + IMPLEMENT_REFCOUNTING(Accessor); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Accessor* accessor = new Accessor; + CefRefPtr accessorPtr(accessor); + + CefRefPtr object = CefV8Value::CreateObject(NULL, accessor); + EXPECT_TRUE(object.get()); + accessor->object_ = object; + + EXPECT_FALSE(object->HasValue(kName)); + + EXPECT_TRUE(object->SetValue(kName, V8_ACCESS_CONTROL_DEFAULT, + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_TRUE(object->HasValue(kName)); + + EXPECT_TRUE(object->SetValue(kName, CefV8Value::CreateInt(kValue), + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_TRUE(accessor->got_set_); + EXPECT_EQ(kValue, accessor->value_); + + CefRefPtr val = object->GetValue(kName); + EXPECT_TRUE(val.get()); + EXPECT_TRUE(accessor->got_get_); + EXPECT_TRUE(val->IsInt()); + EXPECT_EQ(kValue, val->GetIntValue()); + + accessor->object_ = NULL; + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); } - bool Get(const CefString& name, - const CefRefPtr object, - CefRefPtr& retval, - CefString& exception) OVERRIDE - { - if(name == "x") { - got_point_x_read_.yes(); - retval = CefV8Value::CreateInt(1234); - return true; - } else if(name == "y") { - got_point_y_read_.yes(); - retval = CefV8Value::CreateInt(y_); - return true; - } else if(name == "makeException") { - exception = "My Get Exception"; - return true; - } - return false; - } + void RunObjectAccessorFailTest() { + CefRefPtr context = GetContext(); - bool Set(const CefString& name, - const CefRefPtr object, - const CefRefPtr value, - CefString& exception) OVERRIDE - { - if(name == "y") { - y_ = value->GetIntValue(); - if( y_ == 1234) - got_point_y_write_.yes(); - return true; - } else if(name == "makeException") { - exception = "My Set Exception"; - return true; - } - return false; - } + static const char* kName = "val"; - // This function we will be called later to make it call into the - // IFRAME, which then calls "fromIFrame" so that we can check the - // entered vs current contexts are working as expected. - CefRefPtr contextIFrame_; - CefRefPtr funcIFrame_; - - TrackCallback got_point_x_read_; - TrackCallback got_point_y_read_; - TrackCallback got_point_y_write_; - TrackCallback got_bad_is_same_; - TrackCallback got_hello_main_; - TrackCallback got_hello_iframe_; - TrackCallback got_correct_entered_url_; - TrackCallback got_correct_current_url_; - TrackCallback got_iframe_as_entered_url_; - TrackCallback got_no_context_; - TrackCallback got_exception_; - TrackCallback got_getexception_; - TrackCallback got_setexception_; - TrackCallback got_navigation_; - TrackCallback got_testcomplete_; - - int y_; -}; - -} // namespace - -// Verify context works to allow async v8 callbacks -TEST(V8Test, Context) -{ - CefRefPtr handler = new TestContextHandler(); - handler->ExecuteTest(); - - EXPECT_TRUE(handler->got_point_x_read_); - EXPECT_TRUE(handler->got_point_y_read_); - EXPECT_TRUE(handler->got_point_y_write_); - EXPECT_FALSE(handler->got_bad_is_same_); - EXPECT_TRUE(handler->got_hello_main_); - EXPECT_TRUE(handler->got_hello_iframe_); - EXPECT_TRUE(handler->got_no_context_); - EXPECT_TRUE(handler->got_iframe_as_entered_url_); - EXPECT_TRUE(handler->got_correct_entered_url_); - EXPECT_TRUE(handler->got_correct_current_url_); - EXPECT_TRUE(handler->got_exception_); - EXPECT_TRUE(handler->got_getexception_); - EXPECT_TRUE(handler->got_setexception_); - EXPECT_TRUE(handler->got_navigation_); - EXPECT_TRUE(handler->got_testcomplete_); -} - -namespace { - -class TestInternalHandler : public TestHandler -{ -public: - class UserData : public CefBase - { - public: - UserData(CefRefPtr test) - : test_(test) - { - } - - void Test(const std::string& name) - { - if (name == "obj1-before") { - if (test_->nav_ == 0) - test_->got_userdata_obj1_before_test1_fail_.yes(); - else - test_->got_userdata_obj1_before_test2_fail_.yes(); - } else if (name == "obj2-before") { - if (test_->nav_ == 0) - test_->got_userdata_obj2_before_test1_.yes(); - else - test_->got_userdata_obj2_before_test2_fail_.yes(); - }else if (name == "obj1-after") { - if (test_->nav_ == 0) - test_->got_userdata_obj1_after_test1_fail_.yes(); - else - test_->got_userdata_obj1_after_test2_fail_.yes(); - } else if (name == "obj2-after") { - if (test_->nav_ == 0) - test_->got_userdata_obj2_after_test1_.yes(); - else - test_->got_userdata_obj2_after_test2_fail_.yes(); - } - } - - CefRefPtr test_; - - IMPLEMENT_REFCOUNTING(UserData); - }; - - class Accessor : public CefV8Accessor - { - public: - Accessor(CefRefPtr test) - : test_(test) - { - } - - virtual bool Get(const CefString& name, - const CefRefPtr object, - CefRefPtr& retval, - CefString& exception) OVERRIDE - { - if (test_->nav_ == 0) - test_->got_accessor_get1_.yes(); - else - test_->got_accessor_get2_fail_.yes(); - - retval = CefV8Value::CreateString("default2"); - return true; - } - - virtual bool Set(const CefString& name, - const CefRefPtr object, - const CefRefPtr value, - CefString& exception) OVERRIDE - { - if (test_->nav_ == 0) - test_->got_accessor_set1_.yes(); - else - test_->got_accessor_set2_fail_.yes(); - - return true; - } - - CefRefPtr test_; - - IMPLEMENT_REFCOUNTING(Accessor); - }; - - class Handler : public CefV8Handler - { - public: - Handler(CefRefPtr test) - : test_(test), - execute_ct_(0) - { - } - - virtual bool Execute(const CefString& name, - CefRefPtr object, - const CefV8ValueList& arguments, - CefRefPtr& retval, - CefString& exception) OVERRIDE - { - CefRefPtr handler = - object->GetValue("func")->GetFunctionHandler(); - - if (execute_ct_ == 0) { - if (handler.get() == this) - test_->got_execute1_.yes(); - else - test_->got_execute1_fail_.yes(); - } else { - if (handler.get() == this) - test_->got_execute2_.yes(); - else - test_->got_execute2_fail_.yes(); + class Accessor : public CefV8Accessor { + public: + Accessor() {} + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + got_get_.yes(); + return false; } - execute_ct_++; - - return true; - } - - CefRefPtr test_; - int execute_ct_; - - IMPLEMENT_REFCOUNTING(Accessor); - }; - - class TestHandler : public CefV8Handler - { - public: - TestHandler(CefRefPtr test) - : test_(test) - { - } - - virtual bool Execute(const CefString& name, - CefRefPtr object, - const CefV8ValueList& arguments, - CefRefPtr& retval, - CefString& exception) OVERRIDE - { - if (name == "store") { - // Store a JSON value. - if (arguments.size() == 2 && arguments[0]->IsString() && - arguments[1]->IsString()) { - std::string name = arguments[0]->GetStringValue(); - std::string val = arguments[1]->GetStringValue(); - if (name == "obj1") { - test_->obj1_json_ = val; - if (val == "{\"value\":\"testval1\",\"value2\":\"default1\"}") - test_->got_obj1_json_.yes(); - } else if (name == "obj2") { - test_->obj2_json_ = val; - if (val == "{\"value\":\"testval2\",\"value2\":\"default2\"}") - test_->got_obj2_json_.yes(); - } else { - return false; - } - retval = CefV8Value::CreateBool(true); - return true; - } - } else if (name == "retrieve") { - // Retrieve a JSON value. - if (arguments.size() == 1 && arguments[0]->IsString()) { - std::string name = arguments[0]->GetStringValue(); - std::string val; - if (name == "obj1") - val = test_->obj1_json_; - else if (name == "obj2") - val = test_->obj2_json_; - if (!val.empty()) { - retval = CefV8Value::CreateString(val); - return true; - } - } - } else if (name == "userdata") { - if (arguments.size() == 2 && arguments[0]->IsString() && - arguments[1]->IsObject()) { - std::string name = arguments[0]->GetStringValue(); - CefRefPtr userData = - reinterpret_cast(arguments[1]->GetUserData().get()); - if (!userData.get()) { - // No UserData object. - if (name == "obj1-before") { - if (test_->nav_ == 0) - test_->got_userdata_obj1_before_null1_.yes(); - else - test_->got_userdata_obj1_before_null2_.yes(); - } else if (name == "obj2-before") { - if (test_->nav_ == 0) - test_->got_userdata_obj2_before_null1_fail_.yes(); - else - test_->got_userdata_obj2_before_null2_.yes(); - } else if (name == "obj1-after") { - if (test_->nav_ == 0) - test_->got_userdata_obj1_after_null1_.yes(); - else - test_->got_userdata_obj1_after_null2_.yes(); - } else if (name == "obj2-after") { - if (test_->nav_ == 0) - test_->got_userdata_obj2_after_null1_fail_.yes(); - else - test_->got_userdata_obj2_after_null2_.yes(); - } - } else { - // Call the test function. - userData->Test(name); - } - return true; - } - } else if (name == "record") { - if (arguments.size() == 1 && arguments[0]->IsString()) { - std::string name = arguments[0]->GetStringValue(); - if (name == "userdata-obj1-set-succeed") { - if (test_->nav_ == 0) - test_->got_userdata_obj1_set_succeed1_.yes(); - else - test_->got_userdata_obj1_set_succeed2_.yes(); - } else if (name == "userdata-obj1-set-except") { - if (test_->nav_ == 0) - test_->got_userdata_obj1_set_except1_fail_.yes(); - else - test_->got_userdata_obj1_set_except2_fail_.yes(); - } else if (name == "userdata-obj2-set-succeed") { - if (test_->nav_ == 0) - test_->got_userdata_obj2_set_succeed1_.yes(); - else - test_->got_userdata_obj2_set_succeed2_.yes(); - } else if (name == "userdata-obj2-set-except") { - if (test_->nav_ == 0) - test_->got_userdata_obj2_set_except1_fail_.yes(); - else - test_->got_userdata_obj2_set_except2_fail_.yes(); - } else if (name == "func-set-succeed") { - test_->got_func_set_succeed_.yes(); - } else if (name == "func-set-except") { - test_->got_func_set_except_fail_.yes(); - } - return true; - } + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + got_set_.yes(); + return false; } - return false; - } + TrackCallback got_get_; + TrackCallback got_set_; - CefRefPtr test_; + IMPLEMENT_REFCOUNTING(Accessor); + }; - IMPLEMENT_REFCOUNTING(TestHandler); - }; - - TestInternalHandler() - : nav_(0) - { + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr exception; + Accessor* accessor = new Accessor; + CefRefPtr accessorPtr(accessor); + + CefRefPtr object = CefV8Value::CreateObject(NULL, accessor); + EXPECT_TRUE(object.get()); + + EXPECT_FALSE(object->HasValue(kName)); + + EXPECT_TRUE(object->SetValue(kName, V8_ACCESS_CONTROL_DEFAULT, + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_TRUE(object->HasValue(kName)); + + EXPECT_TRUE(object->SetValue(kName, CefV8Value::CreateInt(1), + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_TRUE(accessor->got_set_); + + CefRefPtr val = object->GetValue(kName); + EXPECT_TRUE(val.get()); + EXPECT_TRUE(accessor->got_get_); + EXPECT_TRUE(val->IsUndefined()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); } - virtual void RunTest() OVERRIDE - { - std::string tests = - // Test userdata retrieval. - "window.test.userdata('obj1-before', window.obj1);\n" - "window.test.userdata('obj2-before', window.obj2);\n" - // Test accessors. - "window.obj1.value2 = 'newval1';\n" - "window.obj2.value2 = 'newval2';\n" - "val1 = window.obj1.value2;\n" - "val2 = window.obj2.value2;\n" - // Test setting the hidden internal values. - "try { window.obj1['Cef::UserData'] = 1;\n" - "window.obj1['Cef::Accessor'] = 1;\n" - "window.test.record('userdata-obj1-set-succeed'); }\n" - "catch(e) { window.test.record('userdata-obj1-set-except'); }\n" - "try { window.obj2['Cef::UserData'] = 1;\n" - "window.obj2['Cef::Accessor'] = 1;\n" - "window.test.record('userdata-obj2-set-succeed'); }\n" - "catch(e) { window.test.record('userdata-obj2-set-except'); }\n" - // Test userdata retrieval after messing with the internal values. - "window.test.userdata('obj1-after', window.obj1);\n" - "window.test.userdata('obj2-after', window.obj2);\n" - // Test accessors after messing with the internal values. - "window.obj1.value2 = 'newval1';\n" - "window.obj2.value2 = 'newval2';\n" - "val1 = window.obj1.value2;\n" - "val2 = window.obj2.value2;\n"; + void RunObjectAccessorReadOnlyTest() { + CefRefPtr context = GetContext(); - std::stringstream testHtml; + static const char* kName = "val"; - testHtml << - "\n" - "\n" - ""; - AddResource("http://tests/run1.html", testHtml.str(), "text/html"); - testHtml.str(""); - - testHtml << - "\n" - "\n" - ""; - AddResource("http://tests/run2.html", testHtml.str(), "text/html"); - testHtml.str(""); + class Accessor : public CefV8Accessor { + public: + Accessor() {} + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + got_get_.yes(); + return true; + } - CreateBrowser("http://tests/run1.html"); + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + got_set_.yes(); + return true; + } + + TrackCallback got_get_; + TrackCallback got_set_; + + IMPLEMENT_REFCOUNTING(Accessor); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr exception; + Accessor* accessor = new Accessor; + CefRefPtr accessorPtr(accessor); + + CefRefPtr object = CefV8Value::CreateObject(NULL, accessor); + EXPECT_TRUE(object.get()); + + EXPECT_FALSE(object->HasValue(kName)); + + EXPECT_TRUE(object->SetValue(kName, V8_ACCESS_CONTROL_DEFAULT, + V8_PROPERTY_ATTRIBUTE_READONLY)); + EXPECT_TRUE(object->HasValue(kName)); + + EXPECT_TRUE(object->SetValue(kName, CefV8Value::CreateInt(1), + V8_PROPERTY_ATTRIBUTE_NONE)); + EXPECT_FALSE(accessor->got_set_); + + CefRefPtr val = object->GetValue(kName); + EXPECT_TRUE(val.get()); + EXPECT_TRUE(accessor->got_get_); + EXPECT_TRUE(val->IsUndefined()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); } - virtual void OnLoadEnd(CefRefPtr browser, - CefRefPtr frame, - int httpStatusCode) OVERRIDE - { - if (nav_ == 0) { - // Navigate to the next page. - frame->LoadURL("http://tests/run2.html"); - } else { - DestroyTest(); - } + void RunObjectValueTest() { + CefRefPtr context = GetContext(); - nav_++; - } + static const char* kName = "test_arg"; + static const int kVal1 = 13; + static const int kVal2 = 65; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); - virtual void OnContextCreated(CefRefPtr browser, - CefRefPtr frame, - CefRefPtr context) OVERRIDE - { - // Retrieve the 'window' object. CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); - if (nav_ == 0) { - // Create an object without any internal values. - CefRefPtr obj1 = CefV8Value::CreateObject(NULL, NULL); - obj1->SetValue("value", CefV8Value::CreateString("testval1"), - V8_PROPERTY_ATTRIBUTE_NONE); - obj1->SetValue("value2", CefV8Value::CreateString("default1"), - V8_PROPERTY_ATTRIBUTE_NONE); - object->SetValue("obj1", obj1, V8_PROPERTY_ATTRIBUTE_NONE); - - // Create an object with Cef::Accessor and Cef::UserData internal values. - CefRefPtr obj2 = - CefV8Value::CreateObject(new UserData(this), new Accessor(this)); - obj2->SetValue("value", CefV8Value::CreateString("testval2"), - V8_PROPERTY_ATTRIBUTE_NONE); - obj2->SetValue("value2", V8_ACCESS_CONTROL_DEFAULT, - V8_PROPERTY_ATTRIBUTE_NONE); - object->SetValue("obj2", obj2, V8_PROPERTY_ATTRIBUTE_NONE); + object->SetValue(kName, CefV8Value::CreateInt(kVal1), + V8_PROPERTY_ATTRIBUTE_NONE); - // Create a function with Cef::Handler internal value. - CefRefPtr func = - CefV8Value::CreateFunction("func", new Handler(this)); - object->SetValue("func", func, V8_PROPERTY_ATTRIBUTE_NONE); - } + std::stringstream test; + test << + "if (window." << kName << " != " << kVal1 << ") throw 'Fail';\n" << + "window." << kName << " = " << kVal2 << ";"; - // Used for executing the test. - CefRefPtr handler = new TestHandler(this); - CefRefPtr obj = CefV8Value::CreateObject(NULL, NULL); - obj->SetValue("store", CefV8Value::CreateFunction("store", handler), - V8_PROPERTY_ATTRIBUTE_NONE); - obj->SetValue("retrieve", CefV8Value::CreateFunction("retrieve", handler), - V8_PROPERTY_ATTRIBUTE_NONE); - obj->SetValue("userdata", CefV8Value::CreateFunction("userdata", handler), - V8_PROPERTY_ATTRIBUTE_NONE); - obj->SetValue("record", CefV8Value::CreateFunction("record", handler), - V8_PROPERTY_ATTRIBUTE_NONE); - object->SetValue("test", obj, V8_PROPERTY_ATTRIBUTE_NONE); + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(context->Eval(test.str(), retval, exception)); + if (exception.get()) + ADD_FAILURE() << exception->GetMessage().c_str(); + + CefRefPtr newval = object->GetValue(kName); + EXPECT_TRUE(newval.get()); + EXPECT_TRUE(newval->IsInt()); + EXPECT_EQ(kVal2, newval->GetIntValue()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); } - int nav_; - std::string obj1_json_, obj2_json_; + void RunObjectValueReadOnlyTest() { + CefRefPtr context = GetContext(); - TrackCallback got_obj1_json_; - TrackCallback got_obj2_json_; + static const char* kName = "test_arg"; + static const int kVal1 = 13; + static const int kVal2 = 65; - TrackCallback got_userdata_obj1_before_null1_; - TrackCallback got_userdata_obj2_before_null1_fail_; - TrackCallback got_userdata_obj1_before_test1_fail_; - TrackCallback got_userdata_obj2_before_test1_; - TrackCallback got_userdata_obj1_set_succeed1_; - TrackCallback got_userdata_obj1_set_except1_fail_; - TrackCallback got_userdata_obj2_set_succeed1_; - TrackCallback got_userdata_obj2_set_except1_fail_; - TrackCallback got_userdata_obj1_after_null1_; - TrackCallback got_userdata_obj2_after_null1_fail_; - TrackCallback got_userdata_obj1_after_test1_fail_; - TrackCallback got_userdata_obj2_after_test1_; + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); - TrackCallback got_userdata_obj1_before_null2_; - TrackCallback got_userdata_obj2_before_null2_; - TrackCallback got_userdata_obj1_before_test2_fail_; - TrackCallback got_userdata_obj2_before_test2_fail_; - TrackCallback got_userdata_obj1_set_succeed2_; - TrackCallback got_userdata_obj1_set_except2_fail_; - TrackCallback got_userdata_obj2_set_succeed2_; - TrackCallback got_userdata_obj2_set_except2_fail_; - TrackCallback got_userdata_obj1_after_null2_; - TrackCallback got_userdata_obj2_after_null2_; - TrackCallback got_userdata_obj1_after_test2_fail_; - TrackCallback got_userdata_obj2_after_test2_fail_; - - TrackCallback got_accessor_get1_; - TrackCallback got_accessor_get2_fail_; - TrackCallback got_accessor_set1_; - TrackCallback got_accessor_set2_fail_; + CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); - TrackCallback got_execute1_; - TrackCallback got_execute1_fail_; - TrackCallback got_func_set_succeed_; - TrackCallback got_func_set_except_fail_; - TrackCallback got_execute2_; - TrackCallback got_execute2_fail_; -}; + object->SetValue(kName, CefV8Value::CreateInt(kVal1), + V8_PROPERTY_ATTRIBUTE_READONLY); -} // namespace + std::stringstream test; + test << + "if (window." << kName << " != " << kVal1 << ") throw 'Fail';\n" << + "window." << kName << " = " << kVal2 << ";"; -// Test that messing around with CEF internal values doesn't cause crashes. -TEST(V8Test, Internal) -{ - CefRefPtr handler = new TestInternalHandler(); - handler->ExecuteTest(); + CefRefPtr retval; + CefRefPtr exception; - EXPECT_TRUE(handler->got_obj1_json_.isSet()); - EXPECT_TRUE(handler->got_obj2_json_.isSet()); + EXPECT_TRUE(context->Eval(test.str(), retval, exception)); + if (exception.get()) + ADD_FAILURE() << exception->GetMessage().c_str(); - EXPECT_TRUE(handler->got_userdata_obj1_before_null1_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj2_before_null1_fail_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj1_before_test1_fail_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj2_before_test1_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj1_set_succeed1_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj1_set_except1_fail_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj2_set_succeed1_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj2_set_except1_fail_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj1_after_null1_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj2_after_null1_fail_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj1_after_test1_fail_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj2_after_test1_.isSet()); + CefRefPtr newval = object->GetValue(kName); + EXPECT_TRUE(newval.get()); + EXPECT_TRUE(newval->IsInt()); + EXPECT_EQ(kVal1, newval->GetIntValue()); - EXPECT_TRUE(handler->got_userdata_obj1_before_null2_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj2_before_null2_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj1_before_test2_fail_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj2_before_test2_fail_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj1_set_succeed2_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj1_set_except2_fail_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj2_set_succeed2_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj2_set_except2_fail_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj1_after_null2_.isSet()); - EXPECT_TRUE(handler->got_userdata_obj2_after_null2_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj1_after_test2_fail_.isSet()); - EXPECT_FALSE(handler->got_userdata_obj2_after_test2_fail_.isSet()); + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); - EXPECT_TRUE(handler->got_accessor_get1_.isSet()); - EXPECT_FALSE(handler->got_accessor_get2_fail_.isSet()); - EXPECT_TRUE(handler->got_accessor_set1_.isSet()); - EXPECT_FALSE(handler->got_accessor_set2_fail_.isSet()); + DestroyTest(); + } - EXPECT_TRUE(handler->got_execute1_.isSet()); - EXPECT_FALSE(handler->got_execute1_fail_.isSet()); - EXPECT_TRUE(handler->got_execute2_.isSet()); - EXPECT_FALSE(handler->got_execute2_fail_.isSet()); -} + void RunObjectValueEnumTest() { + CefRefPtr context = GetContext(); -namespace { + static const char* kObjName = "test_obj"; + static const char* kArgName = "test_arg"; -static const int kNumExceptionTests = 3; + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); -class TestExceptionHandler : public TestHandler -{ -public: - class TestHandler : public CefV8Handler - { - public: - TestHandler(CefRefPtr test) - : test_(test) - { - } + CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); - virtual bool Execute(const CefString& name, + CefRefPtr obj1 = CefV8Value::CreateObject(NULL); + object->SetValue(kObjName, obj1, V8_PROPERTY_ATTRIBUTE_NONE); + + obj1->SetValue(kArgName, CefV8Value::CreateInt(0), + V8_PROPERTY_ATTRIBUTE_NONE); + + std::stringstream test; + test << + "for (var i in window." << kObjName << ") {\n" + "window." << kObjName << "[i]++;\n" + "}"; + + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(context->Eval(test.str(), retval, exception)); + if (exception.get()) + ADD_FAILURE() << exception->GetMessage().c_str(); + + CefRefPtr newval = obj1->GetValue(kArgName); + EXPECT_TRUE(newval.get()); + EXPECT_TRUE(newval->IsInt()); + EXPECT_EQ(1, newval->GetIntValue()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunObjectValueDontEnumTest() { + CefRefPtr context = GetContext(); + + static const char* kObjName = "test_obj"; + static const char* kArgName = "test_arg"; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); + + CefRefPtr obj1 = CefV8Value::CreateObject(NULL); + object->SetValue(kObjName, obj1, V8_PROPERTY_ATTRIBUTE_NONE); + + obj1->SetValue(kArgName, CefV8Value::CreateInt(0), + V8_PROPERTY_ATTRIBUTE_DONTENUM); + + std::stringstream test; + test << + "for (var i in window." << kObjName << ") {\n" + "window." << kObjName << "[i]++;\n" + "}"; + + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(context->Eval(test.str(), retval, exception)); + if (exception.get()) + ADD_FAILURE() << exception->GetMessage().c_str(); + + CefRefPtr newval = obj1->GetValue(kArgName); + EXPECT_TRUE(newval.get()); + EXPECT_TRUE(newval->IsInt()); + EXPECT_EQ(0, newval->GetIntValue()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunObjectValueDeleteTest() { + CefRefPtr context = GetContext(); + + static const char* kName = "test_arg"; + static const int kVal1 = 13; + static const int kVal2 = 65; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); + + object->SetValue(kName, CefV8Value::CreateInt(kVal1), + V8_PROPERTY_ATTRIBUTE_NONE); + + std::stringstream test; + test << + "if (window." << kName << " != " << kVal1 << ") throw 'Fail';\n" << + "window." << kName << " = " << kVal2 << ";\n" + "delete window." << kName << ";"; + + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(context->Eval(test.str(), retval, exception)); + if (exception.get()) + ADD_FAILURE() << exception->GetMessage().c_str(); + + CefRefPtr newval = object->GetValue(kName); + EXPECT_TRUE(newval.get()); + EXPECT_TRUE(newval->IsUndefined()); + EXPECT_FALSE(newval->IsInt()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunObjectValueDontDeleteTest() { + CefRefPtr context = GetContext(); + + static const char* kName = "test_arg"; + static const int kVal1 = 13; + static const int kVal2 = 65; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); + + object->SetValue(kName, CefV8Value::CreateInt(kVal1), + V8_PROPERTY_ATTRIBUTE_DONTDELETE); + + std::stringstream test; + test << + "if (window." << kName << " != " << kVal1 << ") throw 'Fail';\n" << + "window." << kName << " = " << kVal2 << ";\n" + "delete window." << kName << ";"; + + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(context->Eval(test.str(), retval, exception)); + if (exception.get()) + ADD_FAILURE() << exception->GetMessage().c_str(); + + CefRefPtr newval = object->GetValue(kName); + EXPECT_TRUE(newval.get()); + EXPECT_TRUE(newval->IsInt()); + EXPECT_EQ(kVal2, newval->GetIntValue()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunFunctionCreateTest() { + CefRefPtr context = GetContext(); + + class Handler : public CefV8Handler { + public: + Handler() {} + virtual bool Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, - CefString& exception) OVERRIDE - { - if (name == "register") { - if (arguments.size() == 1 && arguments[0]->IsFunction()) { - test_->got_register_.yes(); + CefString& exception) OVERRIDE { return false; } + IMPLEMENT_REFCOUNTING(Handler); + }; - // Keep pointers to the callback function and context. - test_->test_func_ = arguments[0]; - test_->test_context_ = CefV8Context::GetCurrentContext(); - return true; - } - } else if (name == "execute") { - if (arguments.size() == 2 && arguments[0]->IsInt() && - arguments[1]->IsBool()) { - // Execute the test callback function. - test_->ExecuteTestCallback(arguments[0]->GetIntValue(), - arguments[1]->GetBoolValue()); - return true; - } - } else if (name == "result") { - if (arguments.size() == 1 && arguments[0]->IsString()) { - std::string value = arguments[0]->GetStringValue(); - if (value == "no_exception") - test_->got_no_exception_result_.yes(); - else if (value == "exception") - test_->got_exception_result_.yes(); - else if (value == "done") - test_->got_done_result_.yes(); - else - return false; - return true; - } + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr value = CefV8Value::CreateFunction("f", new Handler); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsFunction()); + 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->IsInt()); + EXPECT_FALSE(value->IsNull()); + EXPECT_FALSE(value->IsString()); + + DestroyTest(); + } + + void RunFunctionHandlerTest() { + CefRefPtr context = GetContext(); + + static const char* kFuncName = "myfunc"; + static const int kVal1 = 32; + static const int kVal2 = 41; + static const int kRetVal = 8; + + class Handler : public CefV8Handler { + public: + Handler() {} + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + EXPECT_STREQ(kFuncName, name.ToString().c_str()); + EXPECT_TRUE(object->IsSame(object_)); + + EXPECT_EQ((size_t)2, arguments.size()); + EXPECT_TRUE(arguments[0]->IsInt()); + EXPECT_EQ(kVal1, arguments[0]->GetIntValue()); + EXPECT_TRUE(arguments[1]->IsInt()); + EXPECT_EQ(kVal2, arguments[1]->GetIntValue()); + + EXPECT_TRUE(exception.empty()); + + retval = CefV8Value::CreateInt(kRetVal); + EXPECT_TRUE(retval.get()); + EXPECT_EQ(kRetVal, retval->GetIntValue()); + + got_execute_.yes(); + return true; } - return false; - } + CefRefPtr object_; + TrackCallback got_execute_; - CefRefPtr test_; + IMPLEMENT_REFCOUNTING(Handler); + }; - IMPLEMENT_REFCOUNTING(TestHandler); - }; - - TestExceptionHandler() - { + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Handler* handler = new Handler; + CefRefPtr handlerPtr(handler); + + CefRefPtr func = + CefV8Value::CreateFunction(kFuncName, handler); + EXPECT_TRUE(func.get()); + + CefRefPtr obj = CefV8Value::CreateObject(NULL); + EXPECT_TRUE(obj.get()); + handler->object_ = obj; + + CefV8ValueList args; + args.push_back(CefV8Value::CreateInt(kVal1)); + args.push_back(CefV8Value::CreateInt(kVal2)); + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(func->ExecuteFunction(obj, args, retval, exception, false)); + EXPECT_TRUE(handler->got_execute_); + EXPECT_TRUE(retval.get()); + EXPECT_TRUE(retval->IsInt()); + EXPECT_FALSE(exception.get()); + EXPECT_EQ(kRetVal, retval->GetIntValue()); + + handler->object_ = NULL; + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); } - virtual void RunTest() OVERRIDE - { - std::string testHtml = - "\n" - "\n" - ""; - AddResource("http://tests/run.html", testHtml, "text/html"); + void RunFunctionHandlerExceptionTest() { + CefRefPtr context = GetContext(); - CreateBrowser("http://tests/run.html"); - } + static const char* kException = "My error"; + static const char* kExceptionMsg = "Uncaught Error: My error"; - // Execute the callback function. - void ExecuteTestCallback(int test, bool rethrow_exception) - { - if(test <= 0 || test > kNumExceptionTests) - return; + class Handler : public CefV8Handler { + public: + Handler() {} + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + exception = kException; + got_execute_.yes(); + return true; + } - got_execute_test_[test-1].yes(); + TrackCallback got_execute_; - if (!test_func_.get()) - return; + IMPLEMENT_REFCOUNTING(Handler); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Handler* handler = new Handler; + CefRefPtr handlerPtr(handler); + + CefRefPtr func = + CefV8Value::CreateFunction("myfunc", handler); + EXPECT_TRUE(func.get()); CefV8ValueList args; CefRefPtr retval; CefRefPtr exception; - if (test_func_->ExecuteFunctionWithContext(test_context_, NULL, args, - retval, exception, rethrow_exception)) { - got_execute_function_[test-1].yes(); - if (exception.get()) { - got_exception_[test-1].yes(); + EXPECT_TRUE(func->ExecuteFunction(NULL, args, retval, exception, false)); + EXPECT_TRUE(handler->got_execute_); + EXPECT_FALSE(retval.get()); + EXPECT_TRUE(exception.get()); + EXPECT_STREQ(kExceptionMsg, exception->GetMessage().ToString().c_str()); - std::string message = exception->GetMessage(); - EXPECT_EQ("Uncaught Some test exception", message) << "test = " << test; + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); - std::string source_line = exception->GetSourceLine(); - EXPECT_EQ(" throw 'Some test exception';", source_line) << "test = " << - test; + DestroyTest(); + } - std::string script = exception->GetScriptResourceName(); - EXPECT_EQ("http://tests/run.html", script) << "test = " << test; + void RunFunctionHandlerFailTest() { + CefRefPtr context = GetContext(); - int line_number = exception->GetLineNumber(); - EXPECT_EQ(4, line_number) << "test = " << test; - - int start_pos = exception->GetStartPosition(); - EXPECT_EQ(25, start_pos) << "test = " << test; - - int end_pos = exception->GetEndPosition(); - EXPECT_EQ(26, end_pos) << "test = " << test; - - int start_col = exception->GetStartColumn(); - EXPECT_EQ(2, start_col) << "test = " << test; - - int end_col = exception->GetEndColumn(); - EXPECT_EQ(3, end_col) << "test = " << test; + class Handler : public CefV8Handler { + public: + Handler() {} + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + got_execute_.yes(); + return false; } - } - - if (test == kNumExceptionTests) - DestroyTest(); + + TrackCallback got_execute_; + + IMPLEMENT_REFCOUNTING(Handler); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Handler* handler = new Handler; + CefRefPtr handlerPtr(handler); + + CefRefPtr func = + CefV8Value::CreateFunction("myfunc", handler); + EXPECT_TRUE(func.get()); + + CefV8ValueList args; + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(func->ExecuteFunction(NULL, args, retval, exception, false)); + EXPECT_TRUE(handler->got_execute_); + EXPECT_TRUE(retval.get()); + EXPECT_FALSE(exception.get()); + EXPECT_TRUE(retval->IsUndefined()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunFunctionHandlerNoObjectTest() { + CefRefPtr context = GetContext(); + + class Handler : public CefV8Handler { + public: + Handler() {} + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + EXPECT_TRUE(object.get()); + CefRefPtr context = CefV8Context::GetCurrentContext(); + EXPECT_TRUE(context.get()); + CefRefPtr global = context->GetGlobal(); + EXPECT_TRUE(global.get()); + EXPECT_TRUE(global->IsSame(object)); + + got_execute_.yes(); + return true; + } + + TrackCallback got_execute_; + + IMPLEMENT_REFCOUNTING(Handler); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Handler* handler = new Handler; + CefRefPtr handlerPtr(handler); + + CefRefPtr func = + CefV8Value::CreateFunction("myfunc", handler); + EXPECT_TRUE(func.get()); + + CefV8ValueList args; + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(func->ExecuteFunction(NULL, args, retval, exception, false)); + EXPECT_TRUE(handler->got_execute_); + EXPECT_TRUE(retval.get()); + EXPECT_FALSE(exception.get()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunFunctionHandlerWithContextTest() { + CefRefPtr context = GetContext(); + + class Handler : public CefV8Handler { + public: + Handler() {} + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + CefRefPtr context = CefV8Context::GetCurrentContext(); + EXPECT_TRUE(context.get()); + EXPECT_TRUE(context->IsSame(context_)); + got_execute_.yes(); + return true; + } + + CefRefPtr context_; + TrackCallback got_execute_; + + IMPLEMENT_REFCOUNTING(Handler); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Handler* handler = new Handler; + CefRefPtr handlerPtr(handler); + handler->context_ = context; + + CefRefPtr func = + CefV8Value::CreateFunction("myfunc", handler); + EXPECT_TRUE(func.get()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + CefV8ValueList args; + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(func->ExecuteFunctionWithContext( + context, NULL, args, retval, exception, false)); + EXPECT_TRUE(handler->got_execute_); + EXPECT_TRUE(retval.get()); + EXPECT_FALSE(exception.get()); + + handler->context_ = NULL; + + DestroyTest(); + } + + void RunContextEvalTest() { + CefRefPtr context = GetContext(); + + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(context->Eval("1+2", retval, exception)); + EXPECT_TRUE(retval.get()); + EXPECT_TRUE(retval->IsInt()); + EXPECT_EQ(3, retval->GetIntValue()); + EXPECT_FALSE(exception.get()); + + DestroyTest(); + } + + void RunContextEvalExceptionTest() { + CefRefPtr context = GetContext(); + + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_FALSE(context->Eval("1+foo", retval, exception)); + EXPECT_FALSE(retval.get()); + EXPECT_TRUE(exception.get()); + + DestroyTest(); + } + + void RunContextEnteredTest() { + CefRefPtr context = GetContext(); + + CefRefPtr retval; + CefRefPtr exception; + + // Test value defined in OnContextCreated + EXPECT_TRUE(context->Eval( + "document.getElementById('f').contentWindow.v8_context_entered_test()", + retval, exception)); + if (exception.get()) + ADD_FAILURE() << exception->GetMessage().c_str(); + + EXPECT_TRUE(retval.get()); + EXPECT_TRUE(retval->IsInt()); + EXPECT_EQ(21, retval->GetIntValue()); + + DestroyTest(); + } + + void RunBindingTest() { + CefRefPtr context = GetContext(); + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); + + // Test value defined in OnContextCreated + CefRefPtr value = object->GetValue("v8_binding_test"); + EXPECT_TRUE(value.get()); + EXPECT_TRUE(value->IsInt()); + EXPECT_EQ(12, value->GetIntValue()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); + } + + void RunStackTraceTest() { + CefRefPtr context = GetContext(); + + static const char* kFuncName = "myfunc"; + + class Handler : public CefV8Handler { + public: + Handler() {} + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + EXPECT_STREQ(kFuncName, name.ToString().c_str()); + + stack_trace_ = CefV8StackTrace::GetCurrent(10); + + retval = CefV8Value::CreateInt(3); + got_execute_.yes(); + return true; + } + + TrackCallback got_execute_; + CefRefPtr stack_trace_; + + IMPLEMENT_REFCOUNTING(Handler); + }; + + // Enter the V8 context. + EXPECT_TRUE(context->Enter()); + + Handler* handler = new Handler; + CefRefPtr handlerPtr(handler); + + CefRefPtr func = + CefV8Value::CreateFunction(kFuncName, handler); + EXPECT_TRUE(func.get()); + CefRefPtr obj = context->GetGlobal(); + EXPECT_TRUE(obj.get()); + obj->SetValue(kFuncName, func, V8_PROPERTY_ATTRIBUTE_NONE); + + CefRefPtr retval; + CefRefPtr exception; + + EXPECT_TRUE(context->Eval( + "function jsfunc() { return window.myfunc(); }\n" + "jsfunc();", + retval, exception)); + EXPECT_TRUE(retval.get()); + EXPECT_TRUE(retval->IsInt()); + EXPECT_EQ(3, retval->GetIntValue()); + EXPECT_FALSE(exception.get()); + + EXPECT_TRUE(handler->stack_trace_.get()); + EXPECT_EQ(2, handler->stack_trace_->GetFrameCount()); + + CefRefPtr frame; + + frame = handler->stack_trace_->GetFrame(0); + EXPECT_TRUE(frame->GetScriptName().empty()); + EXPECT_TRUE(frame->GetScriptNameOrSourceURL().empty()); + EXPECT_STREQ("jsfunc", frame->GetFunctionName().ToString().c_str()); + EXPECT_EQ(1, frame->GetLineNumber()); + EXPECT_EQ(35, frame->GetColumn()); + EXPECT_TRUE(frame.get()); + EXPECT_TRUE(frame->IsEval()); + EXPECT_FALSE(frame->IsConstructor()); + + frame = handler->stack_trace_->GetFrame(1); + EXPECT_TRUE(frame->GetScriptName().empty()); + EXPECT_TRUE(frame->GetScriptNameOrSourceURL().empty()); + EXPECT_TRUE(frame->GetFunctionName().empty()); + EXPECT_EQ(2, frame->GetLineNumber()); + EXPECT_EQ(1, frame->GetColumn()); + EXPECT_TRUE(frame.get()); + EXPECT_TRUE(frame->IsEval()); + EXPECT_FALSE(frame->IsConstructor()); + + // Exit the V8 context. + EXPECT_TRUE(context->Exit()); + + DestroyTest(); } virtual void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, - int httpStatusCode) OVERRIDE - { - got_load_end_.yes(); - - // Test 3: Execute the callback asynchronously without re-throwing the - // exception. - CefPostTask(TID_UI, - NewCefRunnableMethod(this, &TestExceptionHandler::ExecuteTestCallback, - 3, false)); + int httpStatusCode) OVERRIDE { + if (frame->IsMain()) + RunTest(test_mode_); } virtual void OnContextCreated(CefRefPtr browser, CefRefPtr frame, - CefRefPtr context) OVERRIDE - { - // Retrieve the 'window' object. - CefRefPtr object = context->GetGlobal(); + CefRefPtr context) OVERRIDE { + std::string url = frame->GetURL(); + if (url == kV8ContextChildTestUrl) { + // For V8TEST_CONTEXT_ENTERED + class Handler : public CefV8Handler { + public: + Handler() {} + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + // context for the sub-frame + CefRefPtr context = CefV8Context::GetCurrentContext(); + EXPECT_TRUE(context.get()); - // Create the functions that will be used during the test. - CefRefPtr obj = CefV8Value::CreateObject(NULL, NULL); - CefRefPtr handler = new TestHandler(this); - obj->SetValue("register", - CefV8Value::CreateFunction("register", handler), - V8_PROPERTY_ATTRIBUTE_NONE); - obj->SetValue("execute", - CefV8Value::CreateFunction("execute", handler), - V8_PROPERTY_ATTRIBUTE_NONE); - obj->SetValue("result", - CefV8Value::CreateFunction("result", handler), - V8_PROPERTY_ATTRIBUTE_NONE); - object->SetValue("test", obj, V8_PROPERTY_ATTRIBUTE_NONE); + // entered context should be the same as the main frame context + CefRefPtr entered = CefV8Context::GetEnteredContext(); + EXPECT_TRUE(entered.get()); + EXPECT_TRUE(entered->IsSame(context_)); + + context_ = NULL; + retval = CefV8Value::CreateInt(21); + return true; + } + + CefRefPtr context_; + IMPLEMENT_REFCOUNTING(Handler); + }; + + Handler* handler = new Handler; + CefRefPtr handlerPtr(handler); + + // main frame context + handler->context_ = GetContext(); + + // Function that will be called from the parent frame context. + CefRefPtr func = + CefV8Value::CreateFunction("v8_context_entered_test", handler); + EXPECT_TRUE(func.get()); + + CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); + EXPECT_TRUE(object->SetValue("v8_context_entered_test", func, + V8_PROPERTY_ATTRIBUTE_NONE)); + } else if (url == kV8BindingTestUrl) { + // For V8TEST_BINDING + CefRefPtr object = context->GetGlobal(); + EXPECT_TRUE(object.get()); + EXPECT_TRUE(object->SetValue("v8_binding_test", + CefV8Value::CreateInt(12), + V8_PROPERTY_ATTRIBUTE_NONE)); + } } - CefRefPtr test_func_; - CefRefPtr test_context_; + // Return the V8 context. + CefRefPtr GetContext() { + CefRefPtr context = + GetBrowser()->GetMainFrame()->GetV8Context(); + EXPECT_TRUE(context.get()); + return context; + } - TrackCallback got_register_; - TrackCallback got_load_end_; - TrackCallback got_execute_test_[kNumExceptionTests]; - TrackCallback got_execute_function_[kNumExceptionTests]; - TrackCallback got_exception_[kNumExceptionTests]; - TrackCallback got_exception_result_; - TrackCallback got_no_exception_result_; - TrackCallback got_done_result_; + V8TestMode test_mode_; + const char* test_url_; }; -} // namespace +} // namespace -// Test V8 exception results. -TEST(V8Test, Exception) -{ - CefRefPtr handler = new TestExceptionHandler(); - handler->ExecuteTest(); - EXPECT_TRUE(handler->got_register_); - EXPECT_TRUE(handler->got_load_end_); - EXPECT_TRUE(handler->got_exception_result_); - EXPECT_FALSE(handler->got_no_exception_result_); - EXPECT_TRUE(handler->got_done_result_); - - for (int i = 0; i < kNumExceptionTests; ++i) { - EXPECT_TRUE(handler->got_execute_test_[i]) << "test = " << i+1; - EXPECT_TRUE(handler->got_execute_function_[i]) << "test = " << i+1; - EXPECT_TRUE(handler->got_exception_[i]) << "test = " << i+1; - } -} - -namespace { - -class TestPermissionsHandler : public V8TestHandler -{ -public: - TestPermissionsHandler(bool denyExtensions) : V8TestHandler(false) { - deny_extensions_ = denyExtensions; +// Helpers for defining V8 tests. +#define V8_TEST_EX(name, test_mode, test_url) \ + TEST(V8Test, name) { \ + CefRefPtr handler = \ + new V8TestHandler(test_mode, test_url); \ + handler->ExecuteTest(); \ } - virtual bool OnBeforeScriptExtensionLoad(CefRefPtr browser, - CefRefPtr frame, - const CefString& extensionName) - { - return deny_extensions_; - } +#define V8_TEST(name, test_mode) \ + V8_TEST_EX(name, test_mode, kV8TestUrl) - bool deny_extensions_; -}; - -}; // namespace - -// Verify extension permissions -TEST(V8Test, Permissions) -{ - g_V8TestV8HandlerExecuteCalled = false; - - std::string extensionCode = - "var test;" - "if (!test)" - " test = {};" - "(function() {" - " test.execute = function(a,b,c,d,e,f,g,h,i) {" - " native function execute();" - " return execute(a,b,c,d,e,f,g,h,i);" - " };" - "})();"; - CefRegisterExtension("v8/test", extensionCode, new V8TestV8Handler(false)); - - CefRefPtr deny_handler = new TestPermissionsHandler(true); - deny_handler->ExecuteTest(); - - ASSERT_FALSE(g_V8TestV8HandlerExecuteCalled); - - CefRefPtr allow_handler = new TestPermissionsHandler(false); - allow_handler->ExecuteTest(); - - ASSERT_TRUE(g_V8TestV8HandlerExecuteCalled); -} +// Define the tests. +V8_TEST(NullCreate, V8TEST_NULL_CREATE); +V8_TEST(BoolCreate, V8TEST_BOOL_CREATE); +V8_TEST(IntCreate, V8TEST_INT_CREATE); +V8_TEST(DoubleCreate, V8TEST_DOUBLE_CREATE); +V8_TEST(DateCreate, V8TEST_DATE_CREATE); +V8_TEST(StringCreate, V8TEST_STRING_CREATE); +V8_TEST(ArrayCreate, V8TEST_ARRAY_CREATE); +V8_TEST(ArrayValue, V8TEST_ARRAY_VALUE); +V8_TEST(ObjectCreate, V8TEST_OBJECT_CREATE); +V8_TEST(ObjectUserData, V8TEST_OBJECT_USERDATA); +V8_TEST(ObjectAccessor, V8TEST_OBJECT_ACCESSOR); +V8_TEST(ObjectAccessorFail, V8TEST_OBJECT_ACCESSOR_FAIL); +V8_TEST(ObjectAccessorReadOnly, V8TEST_OBJECT_ACCESSOR_READONLY); +V8_TEST(ObjectValue, V8TEST_OBJECT_VALUE); +V8_TEST(ObjectValueReadOnly, V8TEST_OBJECT_VALUE_READONLY); +V8_TEST(ObjectValueEnum, V8TEST_OBJECT_VALUE_ENUM); +V8_TEST(ObjectValueDontEnum, V8TEST_OBJECT_VALUE_DONTENUM); +V8_TEST(ObjectValueDelete, V8TEST_OBJECT_VALUE_DELETE); +V8_TEST(ObjectValueDontDelete, V8TEST_OBJECT_VALUE_DONTDELETE); +V8_TEST(FunctionCreate, V8TEST_FUNCTION_CREATE); +V8_TEST(FunctionHandler, V8TEST_FUNCTION_HANDLER); +V8_TEST(FunctionHandlerException, V8TEST_FUNCTION_HANDLER_EXCEPTION); +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(ContextEval, V8TEST_CONTEXT_EVAL); +V8_TEST(ContextEvalException, V8TEST_CONTEXT_EVAL_EXCEPTION); +V8_TEST_EX(ContextEntered, V8TEST_CONTEXT_ENTERED, NULL); +V8_TEST_EX(Binding, V8TEST_BINDING, kV8BindingTestUrl); +V8_TEST(StackTrace, V8TEST_STACK_TRACE);