1 // Copyright 2013 The Chromium Authors
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"
13 #include "base/compiler_specific.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-container.h"
23 #include "v8/include/v8-forward.h"
24 #include "v8/include/v8-function.h"
25 #include "v8/include/v8-isolate.h"
26 #include "v8/include/v8-primitive.h"
27 #include "v8/include/v8-template.h"
33 using v8::HandleScope;
43 typedef V8Test ConverterTest;
45 TEST_F(ConverterTest, Bool) {
46 HandleScope handle_scope(instance_->isolate());
48 EXPECT_TRUE(Converter<bool>::ToV8(instance_->isolate(), true)->StrictEquals(
49 Boolean::New(instance_->isolate(), true)));
50 EXPECT_TRUE(Converter<bool>::ToV8(instance_->isolate(), false)->StrictEquals(
51 Boolean::New(instance_->isolate(), false)));
57 {Boolean::New(instance_->isolate(), false).As<Value>(), false},
58 {Boolean::New(instance_->isolate(), true).As<Value>(), true},
59 {Number::New(instance_->isolate(), 0).As<Value>(), false},
60 {Number::New(instance_->isolate(), 1).As<Value>(), true},
61 {Number::New(instance_->isolate(), -1).As<Value>(), true},
62 {Number::New(instance_->isolate(), 0.1).As<Value>(), true},
63 {String::NewFromUtf8(instance_->isolate(), "", v8::NewStringType::kNormal)
67 {String::NewFromUtf8(instance_->isolate(), "foo",
68 v8::NewStringType::kNormal)
72 {Object::New(instance_->isolate()).As<Value>(), true},
73 {Null(instance_->isolate()).As<Value>(), false},
74 {Undefined(instance_->isolate()).As<Value>(), false},
77 for (size_t i = 0; i < std::size(test_data); ++i) {
79 EXPECT_TRUE(Converter<bool>::FromV8(instance_->isolate(),
80 test_data[i].input, &result));
81 EXPECT_EQ(test_data[i].expected, result);
84 EXPECT_TRUE(Converter<bool>::FromV8(instance_->isolate(),
85 test_data[i].input, &result));
86 EXPECT_EQ(test_data[i].expected, result);
90 TEST_F(ConverterTest, String16) {
91 v8::Isolate* isolate = instance_->isolate();
93 HandleScope handle_scope(isolate);
95 EXPECT_TRUE(Converter<std::u16string>::ToV8(isolate, u"")
96 ->StrictEquals(StringToV8(isolate, "")));
97 EXPECT_TRUE(Converter<std::u16string>::ToV8(isolate, u"hello")
98 ->StrictEquals(StringToV8(isolate, "hello")));
100 std::u16string result;
103 Converter<std::u16string>::FromV8(isolate, v8::False(isolate), &result));
105 Converter<std::u16string>::FromV8(isolate, v8::True(isolate), &result));
106 ASSERT_TRUE(Converter<std::u16string>::FromV8(
107 isolate, v8::String::Empty(isolate), &result));
108 EXPECT_EQ(result, std::u16string());
109 ASSERT_TRUE(Converter<std::u16string>::FromV8(
110 isolate, StringToV8(isolate, "hello"), &result));
111 EXPECT_EQ(result, u"hello");
114 TEST_F(ConverterTest, Int32) {
115 HandleScope handle_scope(instance_->isolate());
117 int test_data_to[] = {-1, 0, 1};
118 for (size_t i = 0; i < std::size(test_data_to); ++i) {
119 EXPECT_TRUE(Converter<int32_t>::ToV8(instance_->isolate(), test_data_to[i])
121 Integer::New(instance_->isolate(), test_data_to[i])));
125 v8::Local<v8::Value> input;
128 } test_data_from[] = {
129 {Boolean::New(instance_->isolate(), false).As<Value>(), false, 0},
130 {Boolean::New(instance_->isolate(), true).As<Value>(), false, 0},
131 {Integer::New(instance_->isolate(), -1).As<Value>(), true, -1},
132 {Integer::New(instance_->isolate(), 0).As<Value>(), true, 0},
133 {Integer::New(instance_->isolate(), 1).As<Value>(), true, 1},
134 {Number::New(instance_->isolate(), -1).As<Value>(), true, -1},
135 {Number::New(instance_->isolate(), 1.1).As<Value>(), false, 0},
136 {String::NewFromUtf8(instance_->isolate(), "42",
137 v8::NewStringType::kNormal)
141 {String::NewFromUtf8(instance_->isolate(), "foo",
142 v8::NewStringType::kNormal)
146 {Object::New(instance_->isolate()).As<Value>(), false, 0},
147 {Array::New(instance_->isolate()).As<Value>(), false, 0},
148 {v8::Null(instance_->isolate()).As<Value>(), false, 0},
149 {v8::Undefined(instance_->isolate()).As<Value>(), false, 0},
152 for (size_t i = 0; i < std::size(test_data_from); ++i) {
153 int32_t result = std::numeric_limits<int32_t>::min();
154 bool success = Converter<int32_t>::FromV8(instance_->isolate(),
155 test_data_from[i].input, &result);
156 EXPECT_EQ(test_data_from[i].expect_success, success) << i;
158 EXPECT_EQ(test_data_from[i].expected_result, result) << i;
162 TEST_F(ConverterTest, Vector) {
163 HandleScope handle_scope(instance_->isolate());
165 std::vector<int> expected;
166 expected.push_back(-1);
167 expected.push_back(0);
168 expected.push_back(1);
171 Converter<std::vector<int>>::ToV8(instance_->isolate(), expected)
173 EXPECT_EQ(3u, js_array->Length());
174 v8::Local<v8::Context> context = instance_->isolate()->GetCurrentContext();
175 for (size_t i = 0; i < expected.size(); ++i) {
177 Integer::New(instance_->isolate(), expected[i])
179 js_array->Get(context, static_cast<int>(i)).ToLocalChecked()));
183 TEST_F(ConverterTest, VectorOfVectors) {
184 HandleScope handle_scope(instance_->isolate());
186 std::vector<std::vector<int>> vector_of_vectors = {
187 {1, 2, 3}, {4, 5, 6},
190 v8::Local<v8::Value> v8_value =
191 ConvertToV8(instance_->isolate(), vector_of_vectors);
192 std::vector<std::vector<int>> out_value;
193 ASSERT_TRUE(ConvertFromV8(instance_->isolate(), v8_value, &out_value));
194 EXPECT_THAT(out_value, testing::ContainerEq(vector_of_vectors));
199 class MyObject : public Wrappable<MyObject> {
201 static WrapperInfo kWrapperInfo;
203 static gin::Handle<MyObject> Create(v8::Isolate* isolate) {
204 return CreateHandle(isolate, new MyObject());
208 WrapperInfo MyObject::kWrapperInfo = {kEmbedderNativeGin};
212 TEST_F(ConverterTest, VectorOfWrappables) {
213 v8::Isolate* isolate = instance_->isolate();
214 v8::HandleScope handle_scope(isolate);
216 Handle<MyObject> obj = MyObject::Create(isolate);
217 std::vector<MyObject*> vector = {obj.get()};
218 v8::MaybeLocal<v8::Value> maybe = ConvertToV8(isolate, vector);
219 v8::Local<v8::Value> array;
220 ASSERT_TRUE(maybe.ToLocal(&array));
221 v8::Local<v8::Value> array2;
222 ASSERT_TRUE(TryConvertToV8(isolate, vector, &array2));
224 std::vector<MyObject*> out_value;
225 ASSERT_TRUE(ConvertFromV8(isolate, array, &out_value));
226 EXPECT_THAT(out_value, testing::ContainerEq(vector));
227 std::vector<MyObject*> out_value2;
228 ASSERT_TRUE(ConvertFromV8(isolate, array2, &out_value2));
229 EXPECT_THAT(out_value2, testing::ContainerEq(vector));
234 class MoveOnlyObject {
236 MoveOnlyObject() = default;
237 MoveOnlyObject(const MoveOnlyObject&) = delete;
238 MoveOnlyObject& operator=(const MoveOnlyObject&) = delete;
240 MoveOnlyObject(MoveOnlyObject&&) noexcept = default;
241 MoveOnlyObject& operator=(MoveOnlyObject&&) noexcept = default;
247 struct Converter<MoveOnlyObject> {
248 static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, MoveOnlyObject in) {
249 return v8::Undefined(isolate);
251 static bool FromV8(v8::Isolate* isolate,
252 v8::Local<v8::Value> val,
253 MoveOnlyObject* out) {
254 *out = MoveOnlyObject();
259 TEST_F(ConverterTest, MoveOnlyParameters) {
260 v8::Isolate* isolate = instance_->isolate();
261 v8::HandleScope handle_scope(isolate);
263 auto receives_move_only_obj = [](MoveOnlyObject obj) {};
264 auto func_templ = gin::CreateFunctionTemplate(
265 isolate, base::BindRepeating(receives_move_only_obj));
267 v8::Local<v8::Context> context = instance_->isolate()->GetCurrentContext();
268 auto func = func_templ->GetFunction(context).ToLocalChecked();
269 v8::Local<v8::Value> argv[] = {v8::Undefined(isolate)};
270 func->Call(context, v8::Undefined(isolate), 1, argv).ToLocalChecked();