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
18 namespace mojo {
19 namespace test {
20 namespace {
21
22 const char kHelloWorld[] = "hello world";
23
24 // Replace the "o"s in "hello world" with "o"s with acute.
25 const char kUTF8HelloWorld[] = "hell\xC3\xB3 w\xC3\xB3rld";
26
27 class TestWTFImpl : public TestWTF {
28 public:
TestWTFImpl(TestWTFRequest request)29 explicit TestWTFImpl(TestWTFRequest request)
30 : binding_(this, std::move(request)) {}
31
32 // mojo::test::TestWTF implementation:
EchoString(const base::Optional<std::string> & str,const EchoStringCallback & callback)33 void EchoString(const base::Optional<std::string>& str,
34 const EchoStringCallback& callback) override {
35 callback.Run(str);
36 }
37
EchoStringArray(const base::Optional<std::vector<base::Optional<std::string>>> & arr,const EchoStringArrayCallback & callback)38 void EchoStringArray(
39 const base::Optional<std::vector<base::Optional<std::string>>>& arr,
40 const EchoStringArrayCallback& callback) override {
41 callback.Run(std::move(arr));
42 }
43
EchoStringMap(const base::Optional<std::unordered_map<std::string,base::Optional<std::string>>> & str_map,const EchoStringMapCallback & callback)44 void EchoStringMap(
45 const base::Optional<
46 std::unordered_map<std::string, base::Optional<std::string>>>&
47 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.add("0", WTF::String());
79 str_map.add("1", kHelloWorld);
80 str_map.add("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(WTF::Optional<WTF::Vector<WTF::String>> * expected_arr,const base::Closure & closure,const WTF::Optional<WTF::Vector<WTF::String>> & arr)92 void ExpectStringArray(WTF::Optional<WTF::Vector<WTF::String>>* expected_arr,
93 const base::Closure& closure,
94 const WTF::Optional<WTF::Vector<WTF::String>>& arr) {
95 EXPECT_EQ(*expected_arr, arr);
96 closure.Run();
97 }
98
ExpectStringMap(WTF::Optional<WTF::HashMap<WTF::String,WTF::String>> * expected_map,const base::Closure & closure,const WTF::Optional<WTF::HashMap<WTF::String,WTF::String>> & map)99 void ExpectStringMap(
100 WTF::Optional<WTF::HashMap<WTF::String, WTF::String>>* expected_map,
101 const base::Closure& closure,
102 const WTF::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_WTFArrayToWTFArray)109 TEST_F(WTFTypesTest, Serialization_WTFArrayToWTFArray) {
110 WTFArray<WTF::String> strs = ConstructStringArray();
111 auto cloned_strs = strs.Clone();
112
113 mojo::internal::SerializationContext context;
114 size_t size = mojo::internal::PrepareToSerialize<Array<mojo::String>>(
115 cloned_strs, &context);
116
117 mojo::internal::FixedBufferForTesting buf(size);
118 typename mojo::internal::MojomTypeTraits<Array<mojo::String>>::Data* data;
119 mojo::internal::ContainerValidateParams validate_params(
120 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr));
121 mojo::internal::Serialize<Array<mojo::String>>(cloned_strs, &buf, &data,
122 &validate_params, &context);
123
124 WTFArray<WTF::String> strs2;
125 mojo::internal::Deserialize<Array<mojo::String>>(data, &strs2, &context);
126
127 EXPECT_TRUE(strs.Equals(strs2));
128 }
129
TEST_F(WTFTypesTest,Serialization_WTFVectorToWTFVector)130 TEST_F(WTFTypesTest, Serialization_WTFVectorToWTFVector) {
131 WTF::Vector<WTF::String> strs = ConstructStringArray();
132 auto cloned_strs = strs;
133
134 mojo::internal::SerializationContext context;
135 size_t size = mojo::internal::PrepareToSerialize<Array<mojo::String>>(
136 cloned_strs, &context);
137
138 mojo::internal::FixedBufferForTesting buf(size);
139 typename mojo::internal::MojomTypeTraits<Array<mojo::String>>::Data* data;
140 mojo::internal::ContainerValidateParams validate_params(
141 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr));
142 mojo::internal::Serialize<Array<mojo::String>>(cloned_strs, &buf, &data,
143 &validate_params, &context);
144
145 WTF::Vector<WTF::String> strs2;
146 mojo::internal::Deserialize<Array<mojo::String>>(data, &strs2, &context);
147
148 EXPECT_EQ(strs, strs2);
149 }
150
TEST_F(WTFTypesTest,Serialization_WTFArrayToMojoArray)151 TEST_F(WTFTypesTest, Serialization_WTFArrayToMojoArray) {
152 WTFArray<WTF::String> strs = ConstructStringArray();
153
154 mojo::internal::SerializationContext context;
155 size_t size =
156 mojo::internal::PrepareToSerialize<Array<mojo::String>>(strs, &context);
157
158 mojo::internal::FixedBufferForTesting buf(size);
159 typename mojo::internal::MojomTypeTraits<Array<mojo::String>>::Data* data;
160 mojo::internal::ContainerValidateParams validate_params(
161 0, true, new mojo::internal::ContainerValidateParams(0, false, nullptr));
162 mojo::internal::Serialize<Array<mojo::String>>(strs, &buf, &data,
163 &validate_params, &context);
164
165 Array<mojo::String> strs2;
166 mojo::internal::Deserialize<Array<mojo::String>>(data, &strs2, &context);
167
168 ASSERT_EQ(4u, strs2.size());
169 EXPECT_TRUE(strs2[0].is_null());
170 EXPECT_TRUE("" == strs2[1]);
171 EXPECT_TRUE(kHelloWorld == strs2[2]);
172 EXPECT_TRUE(kUTF8HelloWorld == strs2[3]);
173 }
174
TEST_F(WTFTypesTest,Serialization_WTFMapToWTFMap)175 TEST_F(WTFTypesTest, Serialization_WTFMapToWTFMap) {
176 using WTFType = WTFMap<WTF::String, WTF::String>;
177 using MojomType = Map<mojo::String, mojo::String>;
178
179 WTFType str_map = ConstructStringMap();
180 WTFType cloned_str_map = str_map.Clone();
181
182 mojo::internal::SerializationContext context;
183 size_t size =
184 mojo::internal::PrepareToSerialize<MojomType>(cloned_str_map, &context);
185
186 mojo::internal::FixedBufferForTesting buf(size);
187 typename mojo::internal::MojomTypeTraits<MojomType>::Data* data;
188 mojo::internal::ContainerValidateParams validate_params(
189 new mojo::internal::ContainerValidateParams(
190 0, false,
191 new mojo::internal::ContainerValidateParams(0, false, nullptr)),
192 new mojo::internal::ContainerValidateParams(
193 0, true,
194 new mojo::internal::ContainerValidateParams(0, false, nullptr)));
195 mojo::internal::Serialize<MojomType>(cloned_str_map, &buf, &data,
196 &validate_params, &context);
197
198 WTFType str_map2;
199 mojo::internal::Deserialize<MojomType>(data, &str_map2, &context);
200
201 EXPECT_TRUE(str_map.Equals(str_map2));
202 }
203
TEST_F(WTFTypesTest,Serialization_WTFMapToMojoMap)204 TEST_F(WTFTypesTest, Serialization_WTFMapToMojoMap) {
205 using WTFType = WTFMap<WTF::String, WTF::String>;
206 using MojomType = Map<mojo::String, mojo::String>;
207
208 WTFType str_map = ConstructStringMap();
209
210 mojo::internal::SerializationContext context;
211 size_t size =
212 mojo::internal::PrepareToSerialize<MojomType>(str_map, &context);
213
214 mojo::internal::FixedBufferForTesting buf(size);
215 typename mojo::internal::MojomTypeTraits<MojomType>::Data* data;
216 mojo::internal::ContainerValidateParams validate_params(
217 new mojo::internal::ContainerValidateParams(
218 0, false,
219 new mojo::internal::ContainerValidateParams(0, false, nullptr)),
220 new mojo::internal::ContainerValidateParams(
221 0, true,
222 new mojo::internal::ContainerValidateParams(0, false, nullptr)));
223 mojo::internal::Serialize<MojomType>(str_map, &buf, &data, &validate_params,
224 &context);
225
226 MojomType str_map2;
227 mojo::internal::Deserialize<MojomType>(data, &str_map2, &context);
228
229 ASSERT_EQ(3u, str_map2.size());
230 EXPECT_TRUE(str_map2["0"].is_null());
231 EXPECT_TRUE(kHelloWorld == str_map2["1"]);
232 EXPECT_TRUE(kUTF8HelloWorld == str_map2["2"]);
233 }
234
TEST_F(WTFTypesTest,Serialization_PublicAPI)235 TEST_F(WTFTypesTest, Serialization_PublicAPI) {
236 blink::TestWTFStructPtr input(blink::TestWTFStruct::New());
237 input->str = kHelloWorld;
238 input->integer = 42;
239
240 blink::TestWTFStructPtr cloned_input = input.Clone();
241
242 WTFArray<uint8_t> data = blink::TestWTFStruct::Serialize(&input);
243
244 blink::TestWTFStructPtr output;
245 ASSERT_TRUE(blink::TestWTFStruct::Deserialize(std::move(data), &output));
246 EXPECT_TRUE(cloned_input.Equals(output));
247 }
248
TEST_F(WTFTypesTest,SendString)249 TEST_F(WTFTypesTest, SendString) {
250 blink::TestWTFPtr ptr;
251 TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr)));
252
253 WTF::Vector<WTF::String> strs = ConstructStringArray();
254
255 for (size_t i = 0; i < strs.size(); ++i) {
256 base::RunLoop loop;
257 // Test that a WTF::String is unchanged after the following conversion:
258 // - serialized;
259 // - deserialized as base::Optional<std::string>;
260 // - serialized;
261 // - deserialized as WTF::String.
262 ptr->EchoString(strs[i],
263 base::Bind(&ExpectString, strs[i], loop.QuitClosure()));
264 loop.Run();
265 }
266 }
267
TEST_F(WTFTypesTest,SendStringArray)268 TEST_F(WTFTypesTest, SendStringArray) {
269 blink::TestWTFPtr ptr;
270 TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr)));
271
272 WTF::Optional<WTF::Vector<WTF::String>> arrs[3];
273 // arrs[0] is empty.
274 arrs[0].emplace();
275 // arrs[1] is null.
276 arrs[2] = ConstructStringArray();
277
278 for (size_t i = 0; i < arraysize(arrs); ++i) {
279 base::RunLoop loop;
280 // Test that a WTF::Optional<WTF::Vector<WTF::String>> is unchanged after
281 // the following conversion:
282 // - serialized;
283 // - deserialized as
284 // base::Optional<std::vector<base::Optional<std::string>>>;
285 // - serialized;
286 // - deserialized as WTF::Optional<WTF::Vector<WTF::String>>.
287 ptr->EchoStringArray(
288 arrs[i], base::Bind(&ExpectStringArray, base::Unretained(&arrs[i]),
289 loop.QuitClosure()));
290 loop.Run();
291 }
292 }
293
TEST_F(WTFTypesTest,SendStringMap)294 TEST_F(WTFTypesTest, SendStringMap) {
295 blink::TestWTFPtr ptr;
296 TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr)));
297
298 WTF::Optional<WTF::HashMap<WTF::String, WTF::String>> maps[3];
299 // maps[0] is empty.
300 maps[0].emplace();
301 // maps[1] is null.
302 maps[2] = ConstructStringMap();
303
304 for (size_t i = 0; i < arraysize(maps); ++i) {
305 base::RunLoop loop;
306 // Test that a WTF::Optional<WTF::HashMap<WTF::String, WTF::String>> is
307 // unchanged after the following conversion:
308 // - serialized;
309 // - deserialized as base::Optional<
310 // std::unordered_map<std::string, base::Optional<std::string>>>;
311 // - serialized;
312 // - deserialized as WTF::Optional<WTF::HashMap<WTF::String,
313 // WTF::String>>.
314 ptr->EchoStringMap(maps[i],
315 base::Bind(&ExpectStringMap, base::Unretained(&maps[i]),
316 loop.QuitClosure()));
317 loop.Run();
318 }
319 }
320
321 } // namespace test
322 } // namespace mojo
323