blob: 4d9c86397f36545ce7a1068f1adfefa8f4560140 [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 "bindings/core/v8/ToV8.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8BindingForTesting.h"
#include "core/testing/GarbageCollectedScriptWrappable.h"
#include "platform/heap/Heap.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "wtf/Vector.h"
#include <limits>
#define TEST_TOV8(expected, value) \
testToV8(&scope, expected, value, __FILE__, __LINE__)
namespace blink {
namespace {
template <typename T>
void testToV8(V8TestingScope* scope,
const char* expected,
T value,
const char* path,
int lineNumber) {
v8::Local<v8::Value> actual =
toV8(value, scope->context()->Global(), scope->isolate());
if (actual.IsEmpty()) {
ADD_FAILURE_AT(path, lineNumber) << "toV8 returns an empty value.";
return;
}
String actualString =
toCoreString(actual->ToString(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;
}
}
class GarbageCollectedHolder : public GarbageCollected<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(ToV8Test, garbageCollectedScriptWrappable) {
V8TestingScope scope;
GarbageCollectedScriptWrappable* object =
new GarbageCollectedScriptWrappable("world");
GarbageCollectedHolder holder(object);
OffHeapGarbageCollectedHolder offHeapHolder(object);
TEST_TOV8("world", 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", holder.m_scriptWrappable);
TEST_TOV8("null", offHeapHolder.m_scriptWrappable);
}
TEST(ToV8Test, string) {
V8TestingScope scope;
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(ToV8Test, numeric) {
V8TestingScope scope;
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(ToV8Test, boolean) {
V8TestingScope scope;
TEST_TOV8("true", true);
TEST_TOV8("false", false);
}
TEST(ToV8Test, v8Value) {
V8TestingScope scope;
v8::Local<v8::Value> localValue(v8::Number::New(scope.isolate(), 1234));
v8::Local<v8::Value> handleValue(v8::Number::New(scope.isolate(), 5678));
TEST_TOV8("1234", localValue);
TEST_TOV8("5678", handleValue);
}
TEST(ToV8Test, undefinedType) {
V8TestingScope scope;
TEST_TOV8("undefined", ToV8UndefinedGenerator());
}
TEST(ToV8Test, scriptValue) {
V8TestingScope scope;
ScriptValue value(scope.getScriptState(),
v8::Number::New(scope.isolate(), 1234));
TEST_TOV8("1234", value);
}
TEST(ToV8Test, stringVectors) {
V8TestingScope scope;
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(ToV8Test, basicTypeVectors) {
V8TestingScope scope;
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(ToV8Test, dictionaryVector) {
V8TestingScope scope;
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 = scope.getScriptState()->context();
v8::Local<v8::Object> result =
toV8(dictionary, context->Global(), scope.isolate())
->ToObject(context)
.ToLocalChecked();
v8::Local<v8::Value> one =
result->Get(context, v8String(scope.isolate(), "one")).ToLocalChecked();
EXPECT_EQ(1, one->NumberValue(context).FromJust());
v8::Local<v8::Value> two =
result->Get(context, v8String(scope.isolate(), "two")).ToLocalChecked();
EXPECT_EQ(2, two->NumberValue(context).FromJust());
}
TEST(ToV8Test, heapVector) {
V8TestingScope scope;
HeapVector<Member<GarbageCollectedScriptWrappable>> v;
v.append(new GarbageCollectedScriptWrappable("hoge"));
v.append(new GarbageCollectedScriptWrappable("fuga"));
v.append(nullptr);
TEST_TOV8("hoge,fuga,", v);
}
TEST(ToV8Test, withScriptState) {
V8TestingScope scope;
ScriptValue value(scope.getScriptState(),
v8::Number::New(scope.isolate(), 1234.0));
v8::Local<v8::Value> actual = toV8(value, scope.getScriptState());
EXPECT_FALSE(actual.IsEmpty());
double actualAsNumber = actual.As<v8::Number>()->Value();
EXPECT_EQ(1234.0, actualAsNumber);
}
} // namespace
} // namespace blink