// 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);