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