1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gin/converter.h"
11 #include "base/compiler_specific.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "gin/function_template.h"
16 #include "gin/handle.h"
17 #include "gin/public/isolate_holder.h"
18 #include "gin/test/v8_test.h"
19 #include "gin/wrappable.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "v8/include/v8.h"
28 using v8::HandleScope;
38 typedef V8Test ConverterTest;
40 TEST_F(ConverterTest, Bool) {
41 HandleScope handle_scope(instance_->isolate());
43 EXPECT_TRUE(Converter<bool>::ToV8(instance_->isolate(), true)->StrictEquals(
44 Boolean::New(instance_->isolate(), true)));
45 EXPECT_TRUE(Converter<bool>::ToV8(instance_->isolate(), false)->StrictEquals(
46 Boolean::New(instance_->isolate(), false)));
52 {Boolean::New(instance_->isolate(), false).As<Value>(), false},
53 {Boolean::New(instance_->isolate(), true).As<Value>(), true},
54 {Number::New(instance_->isolate(), 0).As<Value>(), false},
55 {Number::New(instance_->isolate(), 1).As<Value>(), true},
56 {Number::New(instance_->isolate(), -1).As<Value>(), true},
57 {Number::New(instance_->isolate(), 0.1).As<Value>(), true},
58 {String::NewFromUtf8(instance_->isolate(), "", v8::NewStringType::kNormal)
62 {String::NewFromUtf8(instance_->isolate(), "foo",
63 v8::NewStringType::kNormal)
67 {Object::New(instance_->isolate()).As<Value>(), true},
68 {Null(instance_->isolate()).As<Value>(), false},
69 {Undefined(instance_->isolate()).As<Value>(), false},
72 for (size_t i = 0; i < base::size(test_data); ++i) {
74 EXPECT_TRUE(Converter<bool>::FromV8(instance_->isolate(),
75 test_data[i].input, &result));
76 EXPECT_EQ(test_data[i].expected, result);
79 EXPECT_TRUE(Converter<bool>::FromV8(instance_->isolate(),
80 test_data[i].input, &result));
81 EXPECT_EQ(test_data[i].expected, result);
85 TEST_F(ConverterTest, String16) {
86 v8::Isolate* isolate = instance_->isolate();
88 HandleScope handle_scope(isolate);
90 EXPECT_TRUE(Converter<base::string16>::ToV8(isolate, base::ASCIIToUTF16(""))
91 ->StrictEquals(StringToV8(isolate, "")));
93 Converter<base::string16>::ToV8(isolate, base::ASCIIToUTF16("hello"))
94 ->StrictEquals(StringToV8(isolate, "hello")));
96 base::string16 result;
99 Converter<base::string16>::FromV8(isolate, v8::False(isolate), &result));
101 Converter<base::string16>::FromV8(isolate, v8::True(isolate), &result));
102 ASSERT_TRUE(Converter<base::string16>::FromV8(
103 isolate, v8::String::Empty(isolate), &result));
104 EXPECT_EQ(result, base::string16());
105 ASSERT_TRUE(Converter<base::string16>::FromV8(
106 isolate, StringToV8(isolate, "hello"), &result));
107 EXPECT_EQ(result, base::ASCIIToUTF16("hello"));
110 TEST_F(ConverterTest, Int32) {
111 HandleScope handle_scope(instance_->isolate());
113 int test_data_to[] = {-1, 0, 1};
114 for (size_t i = 0; i < base::size(test_data_to); ++i) {
115 EXPECT_TRUE(Converter<int32_t>::ToV8(instance_->isolate(), test_data_to[i])
117 Integer::New(instance_->isolate(), test_data_to[i])));
121 v8::Local<v8::Value> input;
124 } test_data_from[] = {
125 {Boolean::New(instance_->isolate(), false).As<Value>(), false, 0},
126 {Boolean::New(instance_->isolate(), true).As<Value>(), false, 0},
127 {Integer::New(instance_->isolate(), -1).As<Value>(), true, -1},
128 {Integer::New(instance_->isolate(), 0).As<Value>(), true, 0},
129 {Integer::New(instance_->isolate(), 1).As<Value>(), true, 1},
130 {Number::New(instance_->isolate(), -1).As<Value>(), true, -1},
131 {Number::New(instance_->isolate(), 1.1).As<Value>(), false, 0},
132 {String::NewFromUtf8(instance_->isolate(), "42",
133 v8::NewStringType::kNormal)
137 {String::NewFromUtf8(instance_->isolate(), "foo",
138 v8::NewStringType::kNormal)
142 {Object::New(instance_->isolate()).As<Value>(), false, 0},
143 {Array::New(instance_->isolate()).As<Value>(), false, 0},
144 {v8::Null(instance_->isolate()).As<Value>(), false, 0},
145 {v8::Undefined(instance_->isolate()).As<Value>(), false, 0},
148 for (size_t i = 0; i < base::size(test_data_from); ++i) {
149 int32_t result = std::numeric_limits<int32_t>::min();
150 bool success = Converter<int32_t>::FromV8(instance_->isolate(),
151 test_data_from[i].input, &result);
152 EXPECT_EQ(test_data_from[i].expect_success, success) << i;
154 EXPECT_EQ(test_data_from[i].expected_result, result) << i;
158 TEST_F(ConverterTest, Vector) {
159 HandleScope handle_scope(instance_->isolate());
161 std::vector<int> expected;
162 expected.push_back(-1);
163 expected.push_back(0);
164 expected.push_back(1);
167 Converter<std::vector<int>>::ToV8(instance_->isolate(), expected)
169 EXPECT_EQ(3u, js_array->Length());
170 v8::Local<v8::Context> context = instance_->isolate()->GetCurrentContext();
171 for (size_t i = 0; i < expected.size(); ++i) {
173 Integer::New(instance_->isolate(), expected[i])
175 js_array->Get(context, static_cast<int>(i)).ToLocalChecked()));
179 TEST_F(ConverterTest, VectorOfVectors) {
180 HandleScope handle_scope(instance_->isolate());
182 std::vector<std::vector<int>> vector_of_vectors = {
183 {1, 2, 3}, {4, 5, 6},
186 v8::Local<v8::Value> v8_value =
187 ConvertToV8(instance_->isolate(), vector_of_vectors);
188 std::vector<std::vector<int>> out_value;
189 ASSERT_TRUE(ConvertFromV8(instance_->isolate(), v8_value, &out_value));
190 EXPECT_THAT(out_value, testing::ContainerEq(vector_of_vectors));
195 class MyObject : public Wrappable<MyObject> {
197 static WrapperInfo kWrapperInfo;
199 static gin::Handle<MyObject> Create(v8::Isolate* isolate) {
200 return CreateHandle(isolate, new MyObject());
204 WrapperInfo MyObject::kWrapperInfo = {kEmbedderNativeGin};
208 TEST_F(ConverterTest, VectorOfWrappables) {
209 v8::Isolate* isolate = instance_->isolate();
210 v8::HandleScope handle_scope(isolate);
212 Handle<MyObject> obj = MyObject::Create(isolate);
213 std::vector<MyObject*> vector = {obj.get()};
214 v8::MaybeLocal<v8::Value> maybe = ConvertToV8(isolate, vector);
215 v8::Local<v8::Value> array;
216 ASSERT_TRUE(maybe.ToLocal(&array));
217 v8::Local<v8::Value> array2;
218 ASSERT_TRUE(TryConvertToV8(isolate, vector, &array2));
220 std::vector<MyObject*> out_value;
221 ASSERT_TRUE(ConvertFromV8(isolate, array, &out_value));
222 EXPECT_THAT(out_value, testing::ContainerEq(vector));
223 std::vector<MyObject*> out_value2;
224 ASSERT_TRUE(ConvertFromV8(isolate, array2, &out_value2));
225 EXPECT_THAT(out_value2, testing::ContainerEq(vector));
230 class MoveOnlyObject {
232 MoveOnlyObject() = default;
233 MoveOnlyObject(const MoveOnlyObject&) = delete;
234 MoveOnlyObject& operator=(const MoveOnlyObject&) = delete;
236 MoveOnlyObject(MoveOnlyObject&&) noexcept = default;
237 MoveOnlyObject& operator=(MoveOnlyObject&&) noexcept = default;
243 struct Converter<MoveOnlyObject> {
244 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, MoveOnlyObject in) {
245 return v8::Undefined(isolate);
247 static bool FromV8(v8::Isolate* isolate,
248 v8::Local<v8::Value> val,
249 MoveOnlyObject* out) {
250 *out = MoveOnlyObject();
255 TEST_F(ConverterTest, MoveOnlyParameters) {
256 v8::Isolate* isolate = instance_->isolate();
257 v8::HandleScope handle_scope(isolate);
259 auto receives_move_only_obj = [](MoveOnlyObject obj) {};
260 auto func_templ = gin::CreateFunctionTemplate(
261 isolate, base::BindRepeating(receives_move_only_obj));
263 v8::Local<v8::Context> context = instance_->isolate()->GetCurrentContext();
264 auto func = func_templ->GetFunction(context).ToLocalChecked();
265 v8::Local<v8::Value> argv[] = {v8::Undefined(isolate)};
266 func->Call(context, v8::Undefined(isolate), 1, argv).ToLocalChecked();