blob: f1fa351124fae2329fa7a6303131bb7bfee4db32 [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/ToV8.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8BindingForTesting.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 <limits>
#define TEST_TOV8(expected, value) testToV8(expected, value, __FILE__, __LINE__)
namespace blink {
namespace {
class ToV8Test : public ::testing::Test {
public:
ToV8Test() : m_scope(v8::Isolate::GetCurrent()) { }
template<typename T>
void testToV8(const char* expected, T value, const char* path, int lineNumber)
{
v8::Local<v8::Value> actual = toV8(value, m_scope.scriptState()->context()->Global(), m_scope.isolate());
if (actual.IsEmpty()) {
ADD_FAILURE_AT(path, lineNumber) << "toV8 returns an empty value.";
return;
}
String actualString = toCoreString(actual->ToString(m_scope.context()).ToLocalChecked());
if (String(expected) != actualString) {
ADD_FAILURE_AT(path, lineNumber) << "toV8 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) { }
DEFINE_INLINE_TRACE() { 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(ToV8Test, refCountedScriptWrappable)
{
RefPtr<RefCountedScriptWrappable> object = RefCountedScriptWrappable::create("hello");
TEST_TOV8("hello", object);
TEST_TOV8("hello", object.get());
TEST_TOV8("hello", object.release());
ASSERT_FALSE(object);
TEST_TOV8("null", object);
TEST_TOV8("null", object.get());
TEST_TOV8("null", object.release());
}
TEST_F(ToV8Test, garbageCollectedScriptWrappable)
{
GarbageCollectedScriptWrappable* object = new GarbageCollectedScriptWrappable("world");
GarbageCollectedHolder holder(object);
OffHeapGarbageCollectedHolder offHeapHolder(object);
TEST_TOV8("world", object);
TEST_TOV8("world", RawPtr<GarbageCollectedScriptWrappable>(object));
TEST_TOV8("world", holder.m_scriptWrappable);
TEST_TOV8("world", offHeapHolder.m_scriptWrappable);
object = nullptr;
holder.m_scriptWrappable = nullptr;
offHeapHolder.m_scriptWrappable = nullptr;
TEST_TOV8("null", object);
TEST_TOV8("null", RawPtr<GarbageCollectedScriptWrappable>(object));
TEST_TOV8("null", holder.m_scriptWrappable);
TEST_TOV8("null", offHeapHolder.m_scriptWrappable);
}
TEST_F(ToV8Test, string)
{
char arrayString[] = "arrayString";
const char constArrayString[] = "constArrayString";
TEST_TOV8("arrayString", arrayString);
TEST_TOV8("constArrayString", constArrayString);
TEST_TOV8("pointer", const_cast<char*>("pointer"));
TEST_TOV8("constPointer", static_cast<const char*>("constPointer"));
TEST_TOV8("coreString", String("coreString"));
TEST_TOV8("atomicString", AtomicString("atomicString"));
// Null strings are converted to empty strings.
TEST_TOV8("", static_cast<char*>(nullptr));
TEST_TOV8("", static_cast<const char*>(nullptr));
TEST_TOV8("", String());
TEST_TOV8("", AtomicString());
}
TEST_F(ToV8Test, numeric)
{
TEST_TOV8("0", static_cast<int>(0));
TEST_TOV8("1", static_cast<int>(1));
TEST_TOV8("-1", static_cast<int>(-1));
TEST_TOV8("-2", static_cast<long>(-2));
TEST_TOV8("2", static_cast<unsigned>(2));
TEST_TOV8("2", static_cast<unsigned long>(2));
TEST_TOV8("-2147483648", std::numeric_limits<int32_t>::min());
TEST_TOV8("2147483647", std::numeric_limits<int32_t>::max());
TEST_TOV8("4294967295", std::numeric_limits<uint32_t>::max());
// v8::Number can represent exact numbers in [-(2^53-1), 2^53-1].
TEST_TOV8("-9007199254740991", -9007199254740991); // -(2^53-1)
TEST_TOV8("9007199254740991", 9007199254740991); // 2^53-1
TEST_TOV8("0.5", static_cast<double>(0.5));
TEST_TOV8("-0.5", static_cast<float>(-0.5));
TEST_TOV8("NaN", std::numeric_limits<double>::quiet_NaN());
TEST_TOV8("Infinity", std::numeric_limits<double>::infinity());
TEST_TOV8("-Infinity", -std::numeric_limits<double>::infinity());
}
TEST_F(ToV8Test, boolean)
{
TEST_TOV8("true", true);
TEST_TOV8("false", false);
}
TEST_F(ToV8Test, v8Value)
{
v8::Local<v8::Value> localValue(v8::Number::New(m_scope.isolate(), 1234));
v8::Local<v8::Value> handleValue(v8::Number::New(m_scope.isolate(), 5678));
TEST_TOV8("1234", localValue);
TEST_TOV8("5678", handleValue);
}
TEST_F(ToV8Test, undefinedType)
{
TEST_TOV8("undefined", ToV8UndefinedGenerator());
}
TEST_F(ToV8Test, scriptValue)
{
ScriptValue value(m_scope.scriptState(), v8::Number::New(m_scope.isolate(), 1234));
TEST_TOV8("1234", value);
}
TEST_F(ToV8Test, vector)
{
Vector<RefPtr<RefCountedScriptWrappable>> v;
v.append(RefCountedScriptWrappable::create("foo"));
v.append(RefCountedScriptWrappable::create("bar"));
TEST_TOV8("foo,bar", v);
}
TEST_F(ToV8Test, stringVectors)
{
Vector<String> stringVector;
stringVector.append("foo");
stringVector.append("bar");
TEST_TOV8("foo,bar", stringVector);
Vector<AtomicString> atomicStringVector;
atomicStringVector.append("quux");
atomicStringVector.append("bar");
TEST_TOV8("quux,bar", atomicStringVector);
}
TEST_F(ToV8Test, basicTypeVectors)
{
Vector<int> intVector;
intVector.append(42);
intVector.append(23);
TEST_TOV8("42,23", intVector);
Vector<long> longVector;
longVector.append(31773);
longVector.append(404);
TEST_TOV8("31773,404", longVector);
Vector<unsigned> unsignedVector;
unsignedVector.append(1);
unsignedVector.append(2);
TEST_TOV8("1,2", unsignedVector);
Vector<unsigned long> unsignedLongVector;
unsignedLongVector.append(1001);
unsignedLongVector.append(2002);
TEST_TOV8("1001,2002", unsignedLongVector);
Vector<float> floatVector;
floatVector.append(0.125);
floatVector.append(1.);
TEST_TOV8("0.125,1", floatVector);
Vector<double> doubleVector;
doubleVector.append(2.3);
doubleVector.append(4.2);
TEST_TOV8("2.3,4.2", doubleVector);
Vector<bool> boolVector;
boolVector.append(true);
boolVector.append(true);
boolVector.append(false);
TEST_TOV8("true,true,false", boolVector);
}
TEST_F(ToV8Test, dictionaryVector)
{
Vector<std::pair<String, int>> dictionary;
dictionary.append(std::make_pair("one", 1));
dictionary.append(std::make_pair("two", 2));
TEST_TOV8("[object Object]", dictionary);
v8::Local<v8::Context> context = m_scope.scriptState()->context();
v8::Local<v8::Object> result = toV8(dictionary, context->Global(), m_scope.isolate())->ToObject(context).ToLocalChecked();
v8::Local<v8::Value> one = result->Get(context, v8String(m_scope.isolate(), "one")).ToLocalChecked();
EXPECT_EQ(1, one->NumberValue(context).FromJust());
v8::Local<v8::Value> two = result->Get(context, v8String(m_scope.isolate(), "two")).ToLocalChecked();
EXPECT_EQ(2, two->NumberValue(context).FromJust());
}
TEST_F(ToV8Test, heapVector)
{
HeapVector<Member<GarbageCollectedScriptWrappable>> v;
v.append(new GarbageCollectedScriptWrappable("hoge"));
v.append(new GarbageCollectedScriptWrappable("fuga"));
v.append(nullptr);
TEST_TOV8("hoge,fuga,", v);
}
TEST_F(ToV8Test, stringHeapVectors)
{
HeapVector<String> stringVector;
stringVector.append("foo");
stringVector.append("bar");
TEST_TOV8("foo,bar", stringVector);
HeapVector<AtomicString> atomicStringVector;
atomicStringVector.append("quux");
atomicStringVector.append("bar");
TEST_TOV8("quux,bar", atomicStringVector);
}
TEST_F(ToV8Test, basicTypeHeapVectors)
{
HeapVector<int> intVector;
intVector.append(42);
intVector.append(23);
TEST_TOV8("42,23", intVector);
HeapVector<long> longVector;
longVector.append(31773);
longVector.append(404);
TEST_TOV8("31773,404", longVector);
HeapVector<unsigned> unsignedVector;
unsignedVector.append(1);
unsignedVector.append(2);
TEST_TOV8("1,2", unsignedVector);
HeapVector<unsigned long> unsignedLongVector;
unsignedLongVector.append(1001);
unsignedLongVector.append(2002);
TEST_TOV8("1001,2002", unsignedLongVector);
HeapVector<float> floatVector;
floatVector.append(0.125);
floatVector.append(1.);
TEST_TOV8("0.125,1", floatVector);
HeapVector<double> doubleVector;
doubleVector.append(2.3);
doubleVector.append(4.2);
TEST_TOV8("2.3,4.2", doubleVector);
HeapVector<bool> boolVector;
boolVector.append(true);
boolVector.append(true);
boolVector.append(false);
TEST_TOV8("true,true,false", boolVector);
}
} // namespace
} // namespace blink