// Copyright (c) 2009 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 "testing/gtest/include/gtest/gtest.h" #include "test_handler.h" namespace { bool g_V8TestV8HandlerExecuteCalled; bool g_V8TestV8HandlerExecute2Called; 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); ASSERT_EQ(date.day_of_week, 1); ASSERT_EQ(date.hour, 12); ASSERT_EQ(date.minute, 30); ASSERT_EQ(date.second, 10); ASSERT_EQ(date.millisecond, 100); 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; CefString exception; ASSERT_TRUE(arguments[argct]->ExecuteFunction( arguments[argct], args, rv, exception)); 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; CefString exception; ASSERT_TRUE(arguments[argct]->ExecuteFunction( arguments[argct], args, rv, exception)); ASSERT_EQ(exception, "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); ASSERT_EQ(date.day_of_week, 1); ASSERT_EQ(date.day_of_month, 3); ASSERT_EQ(date.hour, 12); ASSERT_EQ(date.minute, 30); ASSERT_EQ(date.second, 10); ASSERT_EQ(date.millisecond, 100); 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); }; 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"; } else { // extension uses a global object object = "test"; } 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 OnJSBinding(CefRefPtr browser, CefRefPtr frame, CefRefPtr object) OVERRIDE { if(binding_test_) TestHandleJSBinding(browser, frame, object); } void TestHandleJSBinding(CefRefPtr browser, CefRefPtr frame, CefRefPtr object) { // Create the new V8 object CefRefPtr testObj = CefV8Value::CreateObject(NULL); ASSERT_TRUE(testObj.get() != NULL); ASSERT_TRUE(object->SetValue("test", testObj)); // 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)); testFunc = CefV8Value::CreateFunction("execute2", testHandler); ASSERT_TRUE(testFunc.get() != NULL); ASSERT_TRUE(testObj->SetValue("execute2", testFunc)); // Add the values ASSERT_TRUE(testObj->SetValue("intVal", CefV8Value::CreateInt(12))); ASSERT_TRUE(testObj->SetValue("doubleVal", CefV8Value::CreateDouble(5.432))); ASSERT_TRUE(testObj->SetValue("boolVal", CefV8Value::CreateBool(true))); ASSERT_TRUE(testObj->SetValue("stringVal", CefV8Value::CreateString("the string"))); cef_time_t date = {2010, 5, 1, 3, 12, 30, 10, 100}; ASSERT_TRUE(testObj->SetValue("dateVal", CefV8Value::CreateDate(date))); CefRefPtr testArray(CefV8Value::CreateArray()); ASSERT_TRUE(testArray.get() != NULL); ASSERT_TRUE(testObj->SetValue("arrayVal", testArray)); 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 { // 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, CefRefPtr& retval, CefString& exception) = 0; virtual bool Get(const CefString& name, const CefRefPtr object, CefRefPtr& retval, CefString& exception) = 0; virtual bool Set(const CefString& name, const CefRefPtr object, const CefRefPtr value, CefString& exception) = 0; }; 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 OnJSBinding(CefRefPtr browser, CefRefPtr frame, CefRefPtr object) OVERRIDE { 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); CefRefPtr fromIFrameFunc = CefV8Value::CreateFunction("fromIFrame", funcHandler); object->SetValue("fromIFrame", fromIFrameFunc); CefRefPtr goFunc = CefV8Value::CreateFunction("begin", funcHandler); object->SetValue("begin", goFunc); CefRefPtr doneFunc = CefV8Value::CreateFunction("end", funcHandler); object->SetValue("end", doneFunc); CefRefPtr compFunc = CefV8Value::CreateFunction("comp", funcHandler); object->SetValue("comp", compFunc); // Used for testing exceptions returned from accessors. CefRefPtr gotGetExceptionFunc = CefV8Value::CreateFunction("gotGetException", funcHandler); object->SetValue("gotGetException", gotGetExceptionFunc); CefRefPtr gotSetExceptionFunc = CefV8Value::CreateFunction("gotSetException", funcHandler); object->SetValue("gotSetException", gotSetExceptionFunc); // 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); // 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); } void CallIFrame() { CefV8ValueList args; CefRefPtr rv; CefString exception; CefRefPtr empty; ASSERT_TRUE(funcIFrame_->ExecuteFunctionWithContext(contextIFrame_, empty, args, rv, exception)); } 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; CefString exception; CefRefPtr empty; ASSERT_TRUE(func->ExecuteFunctionWithContext(context, empty, args, rv, exception)); if(exception == "Uncaught My Exception") got_exception_.yes(); } void AsyncTestNavigation(CefRefPtr context, CefRefPtr func) { CefString 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); url = CefV8Value::CreateString("http://tests/end.html"); obj->SetValue("url", url); obj->SetValue("foobar", foobarFunc); obj->SetValue("anArray", anArray); args.push_back(obj); ASSERT_TRUE(func->ExecuteFunctionWithContext(context, global, args, rv, exception)); if(exception.empty()) 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)); 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); // IsSame should match the expected if ( bExpected != bOne2Two || bExpected != bTwo2One) got_bad_is_same_.yes(); } 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; } 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; } 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; } // 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_); }