// 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" // 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 { // 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"; 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: 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 { EXPECT_TRUE(test_url_ != NULL); AddResource(test_url_, "TEST", "text/html"); CreateBrowser(test_url_); } } // 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; } } void RunNullCreateTest() { CefRefPtr value = CefV8Value::CreateNull(); EXPECT_TRUE(value.get()); EXPECT_TRUE(value->IsNull()); 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()); DestroyTest(); } void RunBoolCreateTest() { CefRefPtr value = CefV8Value::CreateBool(true); EXPECT_TRUE(value.get()); EXPECT_TRUE(value->IsBool()); EXPECT_EQ(true, value->GetBoolValue()); 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(); } 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()); 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()); DestroyTest(); } void RunDoubleCreateTest() { CefRefPtr value = CefV8Value::CreateDouble(12.1223); EXPECT_TRUE(value.get()); EXPECT_TRUE(value->IsDouble()); EXPECT_EQ(12.1223, value->GetDoubleValue()); 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()); DestroyTest(); } 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) OVERRIDE { EXPECT_STREQ(kName, name.ToString().c_str()); EXPECT_TRUE(object.get()); EXPECT_TRUE(object->IsSame(object_)); EXPECT_FALSE(retval.get()); EXPECT_TRUE(exception.empty()); got_get_.yes(); retval = CefV8Value::CreateInt(value_); EXPECT_EQ(kValue, retval->GetIntValue()); return true; } virtual bool Set(const CefString& name, const CefRefPtr object, const CefRefPtr value, CefString& exception) OVERRIDE { EXPECT_STREQ(kName, name.ToString().c_str()); 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; } 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(); } void RunObjectAccessorFailTest() { CefRefPtr context = GetContext(); static const char* kName = "val"; 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; } virtual bool Set(const CefString& name, const CefRefPtr object, const CefRefPtr value, CefString& exception) OVERRIDE { got_set_.yes(); return false; } 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_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(); } void RunObjectAccessorReadOnlyTest() { CefRefPtr context = GetContext(); static const char* kName = "val"; 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; } 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(); } void RunObjectValueTest() { 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 << ";"; 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 RunObjectValueReadOnlyTest() { 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_READONLY); std::stringstream test; test << "if (window." << kName << " != " << kVal1 << ") throw 'Fail';\n" << "window." << kName << " = " << kVal2 << ";"; 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(kVal1, newval->GetIntValue()); // Exit the V8 context. EXPECT_TRUE(context->Exit()); DestroyTest(); } void RunObjectValueEnumTest() { 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_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 { return false; } IMPLEMENT_REFCOUNTING(Handler); }; // 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; } CefRefPtr object_; 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(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(); } void RunFunctionHandlerExceptionTest() { CefRefPtr context = GetContext(); static const char* kException = "My error"; static const char* kExceptionMsg = "Uncaught Error: My error"; 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; } 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_FALSE(retval.get()); EXPECT_TRUE(exception.get()); EXPECT_STREQ(kExceptionMsg, exception->GetMessage().ToString().c_str()); // Exit the V8 context. EXPECT_TRUE(context->Exit()); DestroyTest(); } void RunFunctionHandlerFailTest() { 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 { got_execute_.yes(); return false; } 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 { if (frame->IsMain()) RunTest(test_mode_); } virtual void OnContextCreated(CefRefPtr browser, CefRefPtr frame, 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()); // 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)); } } // Return the V8 context. CefRefPtr GetContext() { CefRefPtr context = GetBrowser()->GetMainFrame()->GetV8Context(); EXPECT_TRUE(context.get()); return context; } V8TestMode test_mode_; const char* test_url_; }; } // namespace // 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(); \ } #define V8_TEST(name, test_mode) \ V8_TEST_EX(name, test_mode, kV8TestUrl) // 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);