blob: eb937be7778735a82d5f8fe82a486688e1c78f52 [file] [log] [blame]
// Copyright 2014 The Chromium 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 "config.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/ExceptionState.h"
#include "core/testing/GarbageCollectedScriptWrappable.h"
#include "core/testing/RefCountedScriptWrappable.h"
#include "platform/heap/Heap.h"
#include "wtf/Vector.h"
#include <gtest/gtest.h>
#include <v8.h>
#define CHECK_TOV8VALUE(expected, value) check(expected, value, __FILE__, __LINE__)
namespace blink {
namespace {
class V8ValueTraitsTest : public ::testing::Test {
public:
V8ValueTraitsTest()
: m_scope(v8::Isolate::GetCurrent())
{
}
virtual ~V8ValueTraitsTest()
{
}
template <typename T> v8::Local<v8::Value> toV8Value(const T& value)
{
return V8ValueTraits<T>::toV8Value(value, m_scope.scriptState()->context()->Global(), m_scope.isolate());
}
template <typename T>
void check(const char* expected, const T& value, const char* path, int lineNumber)
{
v8::Local<v8::Value> actual = toV8Value(value);
if (actual.IsEmpty()) {
ADD_FAILURE_AT(path, lineNumber) << "toV8Value returns an empty value.";
return;
}
String actualString = toCoreString(actual->ToString());
if (String(expected) != actualString) {
ADD_FAILURE_AT(path, lineNumber) << "toV8Value returns an incorrect value.\n Actual: " << actualString.utf8().data() << "\nExpected: " << expected;
return;
}
}
V8TestingScope m_scope;
};
class GarbageCollectedHolder : public GarbageCollectedFinalized<GarbageCollectedHolder> {
public:
GarbageCollectedHolder(GarbageCollectedScriptWrappable* scriptWrappable)
: m_scriptWrappable(scriptWrappable) { }
void trace(Visitor* visitor) { visitor->trace(m_scriptWrappable); }
// This should be public in order to access a Member<X> object.
Member<GarbageCollectedScriptWrappable> m_scriptWrappable;
};
class OffHeapGarbageCollectedHolder {
public:
OffHeapGarbageCollectedHolder(GarbageCollectedScriptWrappable* scriptWrappable)
: m_scriptWrappable(scriptWrappable) { }
// This should be public in order to access a Persistent<X> object.
Persistent<GarbageCollectedScriptWrappable> m_scriptWrappable;
};
TEST_F(V8ValueTraitsTest, numeric)
{
CHECK_TOV8VALUE("0", static_cast<int>(0));
CHECK_TOV8VALUE("1", static_cast<int>(1));
CHECK_TOV8VALUE("-1", static_cast<int>(-1));
CHECK_TOV8VALUE("-2", static_cast<long>(-2));
CHECK_TOV8VALUE("2", static_cast<unsigned>(2));
CHECK_TOV8VALUE("2", static_cast<unsigned long>(2));
CHECK_TOV8VALUE("0.5", static_cast<double>(0.5));
CHECK_TOV8VALUE("-0.5", static_cast<float>(-0.5));
}
TEST_F(V8ValueTraitsTest, boolean)
{
CHECK_TOV8VALUE("true", true);
CHECK_TOV8VALUE("false", false);
}
TEST_F(V8ValueTraitsTest, string)
{
char arrayString[] = "arrayString";
const char constArrayString[] = "constArrayString";
CHECK_TOV8VALUE("arrayString", arrayString);
CHECK_TOV8VALUE("constArrayString", constArrayString);
CHECK_TOV8VALUE("pointer", const_cast<char*>(static_cast<const char*>("pointer")));
CHECK_TOV8VALUE("constpointer", static_cast<const char*>("constpointer"));
CHECK_TOV8VALUE("coreString", String("coreString"));
CHECK_TOV8VALUE("atomicString", AtomicString("atomicString"));
// Null strings are converted to empty strings.
CHECK_TOV8VALUE("", static_cast<char*>(nullptr));
CHECK_TOV8VALUE("", static_cast<const char*>(nullptr));
CHECK_TOV8VALUE("", String());
CHECK_TOV8VALUE("", AtomicString());
}
TEST_F(V8ValueTraitsTest, nullType)
{
CHECK_TOV8VALUE("null", V8NullType());
}
TEST_F(V8ValueTraitsTest, nullptrType)
{
CHECK_TOV8VALUE("null", nullptr);
}
TEST_F(V8ValueTraitsTest, undefinedType)
{
CHECK_TOV8VALUE("undefined", V8UndefinedType());
}
TEST_F(V8ValueTraitsTest, refCountedScriptWrappable)
{
RefPtr<RefCountedScriptWrappable> object = RefCountedScriptWrappable::create("hello");
CHECK_TOV8VALUE("hello", object);
CHECK_TOV8VALUE("hello", object.get());
CHECK_TOV8VALUE("hello", object.release());
ASSERT_FALSE(object);
CHECK_TOV8VALUE("null", object);
CHECK_TOV8VALUE("null", object.get());
CHECK_TOV8VALUE("null", object.release());
}
TEST_F(V8ValueTraitsTest, garbageCollectedScriptWrappable)
{
GarbageCollectedScriptWrappable* object = new GarbageCollectedScriptWrappable("world");
GarbageCollectedHolder holder(object);
OffHeapGarbageCollectedHolder offHeapHolder(object);
CHECK_TOV8VALUE("world", object);
CHECK_TOV8VALUE("world", RawPtr<GarbageCollectedScriptWrappable>(object));
CHECK_TOV8VALUE("world", holder.m_scriptWrappable);
CHECK_TOV8VALUE("world", offHeapHolder.m_scriptWrappable);
object = nullptr;
holder.m_scriptWrappable = nullptr;
offHeapHolder.m_scriptWrappable = nullptr;
CHECK_TOV8VALUE("null", object);
CHECK_TOV8VALUE("null", RawPtr<GarbageCollectedScriptWrappable>(object));
CHECK_TOV8VALUE("null", holder.m_scriptWrappable);
CHECK_TOV8VALUE("null", offHeapHolder.m_scriptWrappable);
}
TEST_F(V8ValueTraitsTest, vector)
{
Vector<RefPtr<RefCountedScriptWrappable> > v;
v.append(RefCountedScriptWrappable::create("foo"));
v.append(RefCountedScriptWrappable::create("bar"));
CHECK_TOV8VALUE("foo,bar", v);
}
TEST_F(V8ValueTraitsTest, stringVectors)
{
Vector<String> stringVector;
stringVector.append("foo");
stringVector.append("bar");
CHECK_TOV8VALUE("foo,bar", stringVector);
Vector<AtomicString> atomicStringVector;
atomicStringVector.append("quux");
atomicStringVector.append("bar");
CHECK_TOV8VALUE("quux,bar", atomicStringVector);
}
TEST_F(V8ValueTraitsTest, basicTypeVectors)
{
Vector<int> intVector;
intVector.append(42);
intVector.append(23);
CHECK_TOV8VALUE("42,23", intVector);
Vector<long> longVector;
longVector.append(31773);
longVector.append(404);
CHECK_TOV8VALUE("31773,404", longVector);
Vector<unsigned> unsignedVector;
unsignedVector.append(1);
unsignedVector.append(2);
CHECK_TOV8VALUE("1,2", unsignedVector);
Vector<unsigned long> unsignedLongVector;
unsignedLongVector.append(1001);
unsignedLongVector.append(2002);
CHECK_TOV8VALUE("1001,2002", unsignedLongVector);
Vector<float> floatVector;
floatVector.append(0.125);
floatVector.append(1.);
CHECK_TOV8VALUE("0.125,1", floatVector);
Vector<double> doubleVector;
doubleVector.append(2.3);
doubleVector.append(4.2);
CHECK_TOV8VALUE("2.3,4.2", doubleVector);
Vector<bool> boolVector;
boolVector.append(true);
boolVector.append(true);
boolVector.append(false);
CHECK_TOV8VALUE("true,true,false", boolVector);
}
TEST_F(V8ValueTraitsTest, heapVector)
{
HeapVector<Member<GarbageCollectedScriptWrappable> > v;
v.append(new GarbageCollectedScriptWrappable("hoge"));
v.append(new GarbageCollectedScriptWrappable("fuga"));
v.append(nullptr);
CHECK_TOV8VALUE("hoge,fuga,", v);
}
TEST_F(V8ValueTraitsTest, stringHeapVectors)
{
HeapVector<String> stringVector;
stringVector.append("foo");
stringVector.append("bar");
CHECK_TOV8VALUE("foo,bar", stringVector);
HeapVector<AtomicString> atomicStringVector;
atomicStringVector.append("quux");
atomicStringVector.append("bar");
CHECK_TOV8VALUE("quux,bar", atomicStringVector);
}
TEST_F(V8ValueTraitsTest, basicTypeHeapVectors)
{
HeapVector<int> intVector;
intVector.append(42);
intVector.append(23);
CHECK_TOV8VALUE("42,23", intVector);
HeapVector<long> longVector;
longVector.append(31773);
longVector.append(404);
CHECK_TOV8VALUE("31773,404", longVector);
HeapVector<unsigned> unsignedVector;
unsignedVector.append(1);
unsignedVector.append(2);
CHECK_TOV8VALUE("1,2", unsignedVector);
HeapVector<unsigned long> unsignedLongVector;
unsignedLongVector.append(1001);
unsignedLongVector.append(2002);
CHECK_TOV8VALUE("1001,2002", unsignedLongVector);
HeapVector<float> floatVector;
floatVector.append(0.125);
floatVector.append(1.);
CHECK_TOV8VALUE("0.125,1", floatVector);
HeapVector<double> doubleVector;
doubleVector.append(2.3);
doubleVector.append(4.2);
CHECK_TOV8VALUE("2.3,4.2", doubleVector);
HeapVector<bool> boolVector;
boolVector.append(true);
boolVector.append(true);
boolVector.append(false);
CHECK_TOV8VALUE("true,true,false", boolVector);
}
TEST_F(V8ValueTraitsTest, scriptValue)
{
ScriptValue value(m_scope.scriptState(), v8::Number::New(m_scope.isolate(), 1234));
CHECK_TOV8VALUE("1234", value);
}
TEST_F(V8ValueTraitsTest, v8Value)
{
v8::Local<v8::Value> localValue(v8::Number::New(m_scope.isolate(), 1234));
v8::Handle<v8::Value> handleValue(v8::Number::New(m_scope.isolate(), 5678));
CHECK_TOV8VALUE("1234", localValue);
CHECK_TOV8VALUE("5678", handleValue);
}
TEST_F(V8ValueTraitsTest, toImplArray)
{
{
v8::Handle<v8::Array> v8StringArray = v8::Array::New(m_scope.isolate(), 2);
v8StringArray->Set(toV8Value(0), toV8Value("Hello, World!"));
v8StringArray->Set(toV8Value(1), toV8Value("Hi, Mom!"));
NonThrowableExceptionState exceptionState;
Vector<String> stringVector = toImplArray<String>(v8StringArray, 0, m_scope.isolate(), exceptionState);
EXPECT_EQ(2U, stringVector.size());
EXPECT_EQ("Hello, World!", stringVector[0]);
EXPECT_EQ("Hi, Mom!", stringVector[1]);
}
{
v8::Handle<v8::Array> v8UnsignedArray = v8::Array::New(m_scope.isolate(), 3);
v8UnsignedArray->Set(toV8Value(0), toV8Value(42));
v8UnsignedArray->Set(toV8Value(1), toV8Value(1729));
v8UnsignedArray->Set(toV8Value(2), toV8Value(31773));
NonThrowableExceptionState exceptionState;
Vector<unsigned> unsignedVector = toImplArray<unsigned>(v8UnsignedArray, 0, m_scope.isolate(), exceptionState);
EXPECT_EQ(3U, unsignedVector.size());
EXPECT_EQ(42U, unsignedVector[0]);
EXPECT_EQ(1729U, unsignedVector[1]);
EXPECT_EQ(31773U, unsignedVector[2]);
}
{
const double doublePi = 3.141592653589793238;
const float floatPi = doublePi;
v8::Handle<v8::Array> v8RealArray = v8::Array::New(m_scope.isolate(), 1);
v8RealArray->Set(toV8Value(0), toV8Value(doublePi));
NonThrowableExceptionState exceptionState;
Vector<double> doubleVector = toImplArray<double>(v8RealArray, 0, m_scope.isolate(), exceptionState);
EXPECT_EQ(1U, doubleVector.size());
EXPECT_EQ(doublePi, doubleVector[0]);
Vector<float> floatVector = toImplArray<float>(v8RealArray, 0, m_scope.isolate(), exceptionState);
EXPECT_EQ(1U, floatVector.size());
EXPECT_EQ(floatPi, floatVector[0]);
}
{
v8::Handle<v8::Array> v8Array = v8::Array::New(m_scope.isolate(), 3);
v8Array->Set(toV8Value(0), toV8Value("Vini, vidi, vici."));
v8Array->Set(toV8Value(1), toV8Value(65535));
v8Array->Set(toV8Value(2), toV8Value(0.125));
NonThrowableExceptionState exceptionState;
Vector<v8::Handle<v8::Value> > v8HandleVector = toImplArray<v8::Handle<v8::Value> >(v8Array, 0, m_scope.isolate(), exceptionState);
EXPECT_EQ(3U, v8HandleVector.size());
EXPECT_EQ("Vini, vidi, vici.", toUSVString(v8HandleVector[0], exceptionState));
EXPECT_EQ(65535U, toUInt32(v8HandleVector[1]));
EXPECT_EQ(0.125, toFloat(v8HandleVector[2]));
Vector<ScriptValue> scriptValueVector = toImplArray<ScriptValue>(v8Array, 0, m_scope.isolate(), exceptionState);
EXPECT_EQ(3U, scriptValueVector.size());
String reportOnZela;
EXPECT_TRUE(scriptValueVector[0].toString(reportOnZela));
EXPECT_EQ("Vini, vidi, vici.", reportOnZela);
EXPECT_EQ(65535U, toUInt32(scriptValueVector[1].v8Value()));
EXPECT_EQ(0.125, toFloat(scriptValueVector[2].v8Value()));
}
{
v8::Handle<v8::Array> v8StringArray1 = v8::Array::New(m_scope.isolate(), 2);
v8StringArray1->Set(toV8Value(0), toV8Value("foo"));
v8StringArray1->Set(toV8Value(1), toV8Value("bar"));
v8::Handle<v8::Array> v8StringArray2 = v8::Array::New(m_scope.isolate(), 3);
v8StringArray2->Set(toV8Value(0), toV8Value("x"));
v8StringArray2->Set(toV8Value(1), toV8Value("y"));
v8StringArray2->Set(toV8Value(2), toV8Value("z"));
v8::Handle<v8::Array> v8StringArrayArray = v8::Array::New(m_scope.isolate(), 2);
v8StringArrayArray->Set(toV8Value(0), v8StringArray1);
v8StringArrayArray->Set(toV8Value(1), v8StringArray2);
NonThrowableExceptionState exceptionState;
Vector<Vector<String> > stringVectorVector = toImplArray<Vector<String> >(v8StringArrayArray, 0, m_scope.isolate(), exceptionState);
EXPECT_EQ(2U, stringVectorVector.size());
EXPECT_EQ(2U, stringVectorVector[0].size());
EXPECT_EQ("foo", stringVectorVector[0][0]);
EXPECT_EQ("bar", stringVectorVector[0][1]);
EXPECT_EQ(3U, stringVectorVector[1].size());
EXPECT_EQ("x", stringVectorVector[1][0]);
EXPECT_EQ("y", stringVectorVector[1][1]);
EXPECT_EQ("z", stringVectorVector[1][2]);
}
}
} // namespace
} // namespace blink