1 // Copyright 2016 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.
4
5 #include "base/bind.h"
6 #include "base/macros.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/run_loop.h"
9 #include "mojo/public/cpp/bindings/binding.h"
10 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
11 #include "mojo/public/cpp/bindings/lib/serialization.h"
12 #include "mojo/public/cpp/bindings/lib/wtf_serialization.h"
13 #include "mojo/public/cpp/bindings/tests/variant_test_util.h"
14 #include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom-blink.h"
15 #include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
18
19 namespace mojo {
20 namespace test {
21 namespace {
22
23 const char kHelloWorld[] = "hello world";
24
25 // Replace the "o"s in "hello world" with "o"s with acute.
26 const char kUTF8HelloWorld[] = "hell\xC3\xB3 w\xC3\xB3rld";
27
28 class TestWTFImpl : public TestWTF {
29 public:
TestWTFImpl(TestWTFRequest request)30 explicit TestWTFImpl(TestWTFRequest request)
31 : binding_(this, std::move(request)) {}
32
33 // mojo::test::TestWTF implementation:
EchoString(const base::Optional<std::string> & str,const EchoStringCallback & callback)34 void EchoString(const base::Optional<std::string>& str,
35 const EchoStringCallback& callback) override {
36 callback.Run(str);
37 }
38
EchoStringArray(const base::Optional<std::vector<base::Optional<std::string>>> & arr,const EchoStringArrayCallback & callback)39 void EchoStringArray(
40 const base::Optional<std::vector<base::Optional<std::string>>>& arr,
41 const EchoStringArrayCallback& callback) override {
42 callback.Run(std::move(arr));
43 }
44
EchoStringMap(const base::Optional<base::flat_map<std::string,base::Optional<std::string>>> & str_map,const EchoStringMapCallback & callback)45 void EchoStringMap(
46 const base::Optional<
47 base::flat_map<std::string, base::Optional<std::string>>>& str_map,
48 const EchoStringMapCallback& callback) override {
49 callback.Run(std::move(str_map));
50 }
51
52 private:
53 Binding<TestWTF> binding_;
54 };
55
56 class WTFTypesTest : public testing::Test {
57 public:
WTFTypesTest()58 WTFTypesTest() {}
59
60 private:
61 base::MessageLoop loop_;
62 };
63
ConstructStringArray()64 WTF::Vector<WTF::String> ConstructStringArray() {
65 WTF::Vector<WTF::String> strs(4);
66 // strs[0] is null.
67 // strs[1] is empty.
68 strs[1] = "";
69 strs[2] = kHelloWorld;
70 strs[3] = WTF::String::FromUTF8(kUTF8HelloWorld);
71
72 return strs;
73 }
74
ConstructStringMap()75 WTF::HashMap<WTF::String, WTF::String> ConstructStringMap() {
76 WTF::HashMap<WTF::String, WTF::String> str_map;
77 // A null string as value.
78 str_map.insert("0", WTF::String());
79 str_map.insert("1", kHelloWorld);
80 str_map.insert("2", WTF::String::FromUTF8(kUTF8HelloWorld));
81
82 return str_map;
83 }
84
ExpectString(const WTF::String & expected_string,const base::Closure & closure,const WTF::String & string)85 void ExpectString(const WTF::String& expected_string,
86 const base::Closure& closure,
87 const WTF::String& string) {
88 EXPECT_EQ(expected_string, string);
89 closure.Run();
90 }
91
ExpectStringArray(base::Optional<WTF::Vector<WTF::String>> * expected_arr,const base::Closure & closure,const base::Optional<WTF::Vector<WTF::String>> & arr)92 void ExpectStringArray(base::Optional<WTF::Vector<WTF::String>>* expected_arr,
93 const base::Closure& closure,
94 const base::Optional<WTF::Vector<WTF::String>>& arr) {
95 EXPECT_EQ(*expected_arr, arr);
96 closure.Run();
97 }
98
ExpectStringMap(base::Optional<WTF::HashMap<WTF::String,WTF::String>> * expected_map,const base::Closure & closure,const base::Optional<WTF::HashMap<WTF::String,WTF::String>> & map)99 void ExpectStringMap(
100 base::Optional<WTF::HashMap<WTF::String, WTF::String>>* expected_map,
101 const base::Closure& closure,
102 const base::Optional<WTF::HashMap<WTF::String, WTF::String>>& map) {
103 EXPECT_EQ(*expected_map, map);
104 closure.Run();
105 }
106
107 } // namespace
108
TEST_F(WTFTypesTest,Serialization_WTFVectorToWTFVector)109 TEST_F(WTFTypesTest, Serialization_WTFVectorToWTFVector) {
110 using MojomType = ArrayDataView<StringDataView>;
111
112 WTF::Vector<WTF::String> strs = ConstructStringArray();
113 auto cloned_strs = strs;
114
115 mojo::Message message(0, 0, 0, 0, nullptr);
116 mojo::internal::SerializationContext context;
117 typename mojo::internal::MojomTypeTraits<MojomType>::Data::BufferWriter
118 writer;
119 mojo::internal::ContainerValidateParams validate_params(
120 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr));
121 mojo::internal::Serialize<MojomType>(cloned_strs, message.payload_buffer(),
122 &writer, &validate_params, &context);
123
124 WTF::Vector<WTF::String> strs2;
125 mojo::internal::Deserialize<MojomType>(writer.data(), &strs2, &context);
126
127 EXPECT_EQ(strs, strs2);
128 }
129
TEST_F(WTFTypesTest,Serialization_WTFVectorInlineCapacity)130 TEST_F(WTFTypesTest, Serialization_WTFVectorInlineCapacity) {
131 using MojomType = ArrayDataView<StringDataView>;
132
133 WTF::Vector<WTF::String, 1> strs(4);
134 // strs[0] is null.
135 // strs[1] is empty.
136 strs[1] = "";
137 strs[2] = kHelloWorld;
138 strs[3] = WTF::String::FromUTF8(kUTF8HelloWorld);
139 auto cloned_strs = strs;
140
141 mojo::Message message(0, 0, 0, 0, nullptr);
142 mojo::internal::SerializationContext context;
143 typename mojo::internal::MojomTypeTraits<MojomType>::Data::BufferWriter
144 writer;
145 mojo::internal::ContainerValidateParams validate_params(
146 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr));
147 mojo::internal::Serialize<MojomType>(cloned_strs, message.payload_buffer(),
148 &writer, &validate_params, &context);
149
150 WTF::Vector<WTF::String, 1> strs2;
151 mojo::internal::Deserialize<MojomType>(writer.data(), &strs2, &context);
152
153 EXPECT_EQ(strs, strs2);
154 }
155
TEST_F(WTFTypesTest,Serialization_WTFVectorToStlVector)156 TEST_F(WTFTypesTest, Serialization_WTFVectorToStlVector) {
157 using MojomType = ArrayDataView<StringDataView>;
158
159 WTF::Vector<WTF::String> strs = ConstructStringArray();
160 auto cloned_strs = strs;
161
162 mojo::Message message(0, 0, 0, 0, nullptr);
163 mojo::internal::SerializationContext context;
164 typename mojo::internal::MojomTypeTraits<MojomType>::Data::BufferWriter
165 writer;
166 mojo::internal::ContainerValidateParams validate_params(
167 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr));
168 mojo::internal::Serialize<MojomType>(cloned_strs, message.payload_buffer(),
169 &writer, &validate_params, &context);
170
171 std::vector<base::Optional<std::string>> strs2;
172 mojo::internal::Deserialize<MojomType>(writer.data(), &strs2, &context);
173
174 ASSERT_EQ(4u, strs2.size());
175 EXPECT_FALSE(strs2[0]);
176 EXPECT_EQ("", *strs2[1]);
177 EXPECT_EQ(kHelloWorld, *strs2[2]);
178 EXPECT_EQ(kUTF8HelloWorld, *strs2[3]);
179 }
180
TEST_F(WTFTypesTest,Serialization_PublicAPI)181 TEST_F(WTFTypesTest, Serialization_PublicAPI) {
182 blink::TestWTFStructPtr input(blink::TestWTFStruct::New(kHelloWorld, 42));
183
184 blink::TestWTFStructPtr cloned_input = input.Clone();
185
186 auto data = blink::TestWTFStruct::Serialize(&input);
187
188 blink::TestWTFStructPtr output;
189 ASSERT_TRUE(blink::TestWTFStruct::Deserialize(std::move(data), &output));
190 EXPECT_TRUE(cloned_input.Equals(output));
191 }
192
TEST_F(WTFTypesTest,SendString)193 TEST_F(WTFTypesTest, SendString) {
194 blink::TestWTFPtr ptr;
195 TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(MakeRequest(&ptr)));
196
197 WTF::Vector<WTF::String> strs = ConstructStringArray();
198
199 for (size_t i = 0; i < strs.size(); ++i) {
200 base::RunLoop loop;
201 // Test that a WTF::String is unchanged after the following conversion:
202 // - serialized;
203 // - deserialized as base::Optional<std::string>;
204 // - serialized;
205 // - deserialized as WTF::String.
206 ptr->EchoString(strs[i],
207 base::Bind(&ExpectString, strs[i], loop.QuitClosure()));
208 loop.Run();
209 }
210 }
211
TEST_F(WTFTypesTest,SendStringArray)212 TEST_F(WTFTypesTest, SendStringArray) {
213 blink::TestWTFPtr ptr;
214 TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(MakeRequest(&ptr)));
215
216 base::Optional<WTF::Vector<WTF::String>> arrs[3];
217 // arrs[0] is empty.
218 arrs[0].emplace();
219 // arrs[1] is null.
220 arrs[2] = ConstructStringArray();
221
222 for (size_t i = 0; i < arraysize(arrs); ++i) {
223 base::RunLoop loop;
224 // Test that a base::Optional<WTF::Vector<WTF::String>> is unchanged after
225 // the following conversion:
226 // - serialized;
227 // - deserialized as
228 // base::Optional<std::vector<base::Optional<std::string>>>;
229 // - serialized;
230 // - deserialized as base::Optional<WTF::Vector<WTF::String>>.
231 ptr->EchoStringArray(
232 arrs[i], base::Bind(&ExpectStringArray, base::Unretained(&arrs[i]),
233 loop.QuitClosure()));
234 loop.Run();
235 }
236 }
237
TEST_F(WTFTypesTest,SendStringMap)238 TEST_F(WTFTypesTest, SendStringMap) {
239 blink::TestWTFPtr ptr;
240 TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(MakeRequest(&ptr)));
241
242 base::Optional<WTF::HashMap<WTF::String, WTF::String>> maps[3];
243 // maps[0] is empty.
244 maps[0].emplace();
245 // maps[1] is null.
246 maps[2] = ConstructStringMap();
247
248 for (size_t i = 0; i < arraysize(maps); ++i) {
249 base::RunLoop loop;
250 // Test that a base::Optional<WTF::HashMap<WTF::String, WTF::String>> is
251 // unchanged after the following conversion:
252 // - serialized;
253 // - deserialized as base::Optional<
254 // base::flat_map<std::string, base::Optional<std::string>>>;
255 // - serialized;
256 // - deserialized as base::Optional<WTF::HashMap<WTF::String,
257 // WTF::String>>.
258 ptr->EchoStringMap(maps[i],
259 base::Bind(&ExpectStringMap, base::Unretained(&maps[i]),
260 loop.QuitClosure()));
261 loop.Run();
262 }
263 }
264
TEST_F(WTFTypesTest,NestedStruct_CloneAndEquals)265 TEST_F(WTFTypesTest, NestedStruct_CloneAndEquals) {
266 auto a = blink::TestWTFStructWrapper::New();
267 a->nested_struct = blink::TestWTFStruct::New("foo", 1);
268 a->array_struct.push_back(blink::TestWTFStruct::New("bar", 2));
269 a->array_struct.push_back(blink::TestWTFStruct::New("bar", 3));
270 a->map_struct.insert(blink::TestWTFStruct::New("baz", 4),
271 blink::TestWTFStruct::New("baz", 5));
272 auto b = a.Clone();
273 EXPECT_EQ(a, b);
274 EXPECT_EQ(2u, b->array_struct.size());
275 EXPECT_EQ(1u, b->map_struct.size());
276 EXPECT_NE(blink::TestWTFStructWrapper::New(), a);
277 EXPECT_NE(blink::TestWTFStructWrapper::New(), b);
278 }
279
280 } // namespace test
281 } // namespace mojo
282