1 // Copyright 2015 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 <string>
6 #include <utility>
7
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "mojo/public/cpp/bindings/binding_set.h"
14 #include "mojo/public/cpp/bindings/interface_request.h"
15 #include "mojo/public/cpp/bindings/tests/pickled_types_blink.h"
16 #include "mojo/public/cpp/bindings/tests/pickled_types_chromium.h"
17 #include "mojo/public/cpp/bindings/tests/variant_test_util.h"
18 #include "mojo/public/interfaces/bindings/tests/test_native_types.mojom-blink.h"
19 #include "mojo/public/interfaces/bindings/tests/test_native_types.mojom.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace mojo {
23 namespace test {
24 namespace {
25
26 template <typename T>
DoExpectResult(int foo,int bar,const base::Closure & callback,T actual)27 void DoExpectResult(int foo, int bar, const base::Closure& callback, T actual) {
28 EXPECT_EQ(foo, actual.foo());
29 EXPECT_EQ(bar, actual.bar());
30 callback.Run();
31 }
32
33 template <typename T>
ExpectResult(const T & t,const base::Closure & callback)34 base::Callback<void(T)> ExpectResult(const T& t,
35 const base::Closure& callback) {
36 return base::Bind(&DoExpectResult<T>, t.foo(), t.bar(), callback);
37 }
38
39 template <typename T>
DoFail(const std::string & reason,T)40 void DoFail(const std::string& reason, T) {
41 EXPECT_TRUE(false) << reason;
42 }
43
44 template <typename T>
Fail(const std::string & reason)45 base::Callback<void(T)> Fail(const std::string& reason) {
46 return base::Bind(&DoFail<T>, reason);
47 }
48
49 template <typename T>
DoExpectEnumResult(T expected,const base::Closure & callback,T actual)50 void DoExpectEnumResult(T expected, const base::Closure& callback, T actual) {
51 EXPECT_EQ(expected, actual);
52 callback.Run();
53 }
54
55 template <typename T>
ExpectEnumResult(T t,const base::Closure & callback)56 base::Callback<void(T)> ExpectEnumResult(T t, const base::Closure& callback) {
57 return base::Bind(&DoExpectEnumResult<T>, t, callback);
58 }
59
60 template <typename T>
DoEnumFail(const std::string & reason,T)61 void DoEnumFail(const std::string& reason, T) {
62 EXPECT_TRUE(false) << reason;
63 }
64
65 template <typename T>
EnumFail(const std::string & reason)66 base::Callback<void(T)> EnumFail(const std::string& reason) {
67 return base::Bind(&DoEnumFail<T>, reason);
68 }
69
70 template <typename T>
ExpectError(InterfacePtr<T> * proxy,const base::Closure & callback)71 void ExpectError(InterfacePtr<T>* proxy, const base::Closure& callback) {
72 proxy->set_connection_error_handler(callback);
73 }
74
75 template <typename Func, typename Arg>
RunSimpleLambda(Func func,Arg arg)76 void RunSimpleLambda(Func func, Arg arg) { func(std::move(arg)); }
77
78 template <typename Arg, typename Func>
BindSimpleLambda(Func func)79 base::Callback<void(Arg)> BindSimpleLambda(Func func) {
80 return base::Bind(&RunSimpleLambda<Func, Arg>, func);
81 }
82
83 // This implements the generated Chromium variant of PicklePasser.
84 class ChromiumPicklePasserImpl : public PicklePasser {
85 public:
ChromiumPicklePasserImpl()86 ChromiumPicklePasserImpl() {}
87
88 // mojo::test::PicklePasser:
PassPickledStruct(PickledStructChromium pickle,const PassPickledStructCallback & callback)89 void PassPickledStruct(PickledStructChromium pickle,
90 const PassPickledStructCallback& callback) override {
91 callback.Run(std::move(pickle));
92 }
93
PassPickledEnum(PickledEnumChromium pickle,const PassPickledEnumCallback & callback)94 void PassPickledEnum(PickledEnumChromium pickle,
95 const PassPickledEnumCallback& callback) override {
96 callback.Run(pickle);
97 }
98
PassPickleContainer(PickleContainerPtr container,const PassPickleContainerCallback & callback)99 void PassPickleContainer(
100 PickleContainerPtr container,
101 const PassPickleContainerCallback& callback) override {
102 callback.Run(std::move(container));
103 }
104
PassPickles(std::vector<PickledStructChromium> pickles,const PassPicklesCallback & callback)105 void PassPickles(std::vector<PickledStructChromium> pickles,
106 const PassPicklesCallback& callback) override {
107 callback.Run(std::move(pickles));
108 }
109
PassPickleArrays(std::vector<std::vector<PickledStructChromium>> pickle_arrays,const PassPickleArraysCallback & callback)110 void PassPickleArrays(
111 std::vector<std::vector<PickledStructChromium>> pickle_arrays,
112 const PassPickleArraysCallback& callback) override {
113 callback.Run(std::move(pickle_arrays));
114 }
115 };
116
117 // This implements the generated Blink variant of PicklePasser.
118 class BlinkPicklePasserImpl : public blink::PicklePasser {
119 public:
BlinkPicklePasserImpl()120 BlinkPicklePasserImpl() {}
121
122 // mojo::test::blink::PicklePasser:
PassPickledStruct(PickledStructBlink pickle,const PassPickledStructCallback & callback)123 void PassPickledStruct(PickledStructBlink pickle,
124 const PassPickledStructCallback& callback) override {
125 callback.Run(std::move(pickle));
126 }
127
PassPickledEnum(PickledEnumBlink pickle,const PassPickledEnumCallback & callback)128 void PassPickledEnum(PickledEnumBlink pickle,
129 const PassPickledEnumCallback& callback) override {
130 callback.Run(pickle);
131 }
132
PassPickleContainer(blink::PickleContainerPtr container,const PassPickleContainerCallback & callback)133 void PassPickleContainer(
134 blink::PickleContainerPtr container,
135 const PassPickleContainerCallback& callback) override {
136 callback.Run(std::move(container));
137 }
138
PassPickles(WTF::Vector<PickledStructBlink> pickles,const PassPicklesCallback & callback)139 void PassPickles(WTF::Vector<PickledStructBlink> pickles,
140 const PassPicklesCallback& callback) override {
141 callback.Run(std::move(pickles));
142 }
143
PassPickleArrays(WTF::Vector<WTF::Vector<PickledStructBlink>> pickle_arrays,const PassPickleArraysCallback & callback)144 void PassPickleArrays(
145 WTF::Vector<WTF::Vector<PickledStructBlink>> pickle_arrays,
146 const PassPickleArraysCallback& callback) override {
147 callback.Run(std::move(pickle_arrays));
148 }
149 };
150
151 // A test which runs both Chromium and Blink implementations of the
152 // PicklePasser service.
153 class PickleTest : public testing::Test {
154 public:
PickleTest()155 PickleTest() {}
156
157 template <typename ProxyType = PicklePasser>
ConnectToChromiumService()158 InterfacePtr<ProxyType> ConnectToChromiumService() {
159 InterfacePtr<ProxyType> proxy;
160 chromium_bindings_.AddBinding(
161 &chromium_service_,
162 ConvertInterfaceRequest<PicklePasser>(mojo::MakeRequest(&proxy)));
163 return proxy;
164 }
165
166 template <typename ProxyType = blink::PicklePasser>
ConnectToBlinkService()167 InterfacePtr<ProxyType> ConnectToBlinkService() {
168 InterfacePtr<ProxyType> proxy;
169 blink_bindings_.AddBinding(&blink_service_,
170 ConvertInterfaceRequest<blink::PicklePasser>(
171 mojo::MakeRequest(&proxy)));
172 return proxy;
173 }
174
175 protected:
ForceMessageSerialization(bool forced)176 static void ForceMessageSerialization(bool forced) {
177 // Force messages to be serialized in this test since it intentionally
178 // exercises StructTraits logic.
179 Connector::OverrideDefaultSerializationBehaviorForTesting(
180 forced ? Connector::OutgoingSerializationMode::kEager
181 : Connector::OutgoingSerializationMode::kLazy,
182 Connector::IncomingSerializationMode::kDispatchAsIs);
183 }
184
185 class ScopedForceMessageSerialization {
186 public:
ScopedForceMessageSerialization()187 ScopedForceMessageSerialization() { ForceMessageSerialization(true); }
~ScopedForceMessageSerialization()188 ~ScopedForceMessageSerialization() { ForceMessageSerialization(false); }
189
190 private:
191 DISALLOW_COPY_AND_ASSIGN(ScopedForceMessageSerialization);
192 };
193
194 private:
195 base::MessageLoop loop_;
196 ChromiumPicklePasserImpl chromium_service_;
197 BindingSet<PicklePasser> chromium_bindings_;
198 BlinkPicklePasserImpl blink_service_;
199 BindingSet<blink::PicklePasser> blink_bindings_;
200 };
201
202 } // namespace
203
TEST_F(PickleTest,ChromiumProxyToChromiumService)204 TEST_F(PickleTest, ChromiumProxyToChromiumService) {
205 auto chromium_proxy = ConnectToChromiumService();
206 {
207 base::RunLoop loop;
208 chromium_proxy->PassPickledStruct(
209 PickledStructChromium(1, 2),
210 ExpectResult(PickledStructChromium(1, 2), loop.QuitClosure()));
211 loop.Run();
212 }
213 {
214 base::RunLoop loop;
215 chromium_proxy->PassPickledStruct(
216 PickledStructChromium(4, 5),
217 ExpectResult(PickledStructChromium(4, 5), loop.QuitClosure()));
218 loop.Run();
219 }
220
221 {
222 base::RunLoop loop;
223 chromium_proxy->PassPickledEnum(
224 PickledEnumChromium::VALUE_1,
225 ExpectEnumResult(PickledEnumChromium::VALUE_1, loop.QuitClosure()));
226 loop.Run();
227 }
228 }
229
TEST_F(PickleTest,ChromiumProxyToBlinkService)230 TEST_F(PickleTest, ChromiumProxyToBlinkService) {
231 auto chromium_proxy = ConnectToBlinkService<PicklePasser>();
232 {
233 base::RunLoop loop;
234 chromium_proxy->PassPickledStruct(
235 PickledStructChromium(1, 2),
236 ExpectResult(PickledStructChromium(1, 2), loop.QuitClosure()));
237 loop.Run();
238 }
239 {
240 base::RunLoop loop;
241 chromium_proxy->PassPickledStruct(
242 PickledStructChromium(4, 5),
243 ExpectResult(PickledStructChromium(4, 5), loop.QuitClosure()));
244 loop.Run();
245 }
246 // The Blink service should drop our connection because the
247 // PickledStructBlink ParamTraits deserializer rejects negative values.
248 {
249 base::RunLoop loop;
250 chromium_proxy->PassPickledStruct(
251 PickledStructChromium(-1, -1),
252 Fail<PickledStructChromium>("Blink service should reject this."));
253 ExpectError(&chromium_proxy, loop.QuitClosure());
254 loop.Run();
255 }
256
257 chromium_proxy = ConnectToBlinkService<PicklePasser>();
258 {
259 base::RunLoop loop;
260 chromium_proxy->PassPickledEnum(
261 PickledEnumChromium::VALUE_0,
262 ExpectEnumResult(PickledEnumChromium::VALUE_0, loop.QuitClosure()));
263 loop.Run();
264 }
265
266 // The Blink service should drop our connection because the
267 // PickledEnumBlink ParamTraits deserializer rejects this value.
268 {
269 base::RunLoop loop;
270 chromium_proxy->PassPickledEnum(
271 PickledEnumChromium::VALUE_2,
272 EnumFail<PickledEnumChromium>("Blink service should reject this."));
273 ExpectError(&chromium_proxy, loop.QuitClosure());
274 loop.Run();
275 }
276 }
277
TEST_F(PickleTest,BlinkProxyToBlinkService)278 TEST_F(PickleTest, BlinkProxyToBlinkService) {
279 auto blink_proxy = ConnectToBlinkService();
280 {
281 base::RunLoop loop;
282 blink_proxy->PassPickledStruct(
283 PickledStructBlink(1, 1),
284 ExpectResult(PickledStructBlink(1, 1), loop.QuitClosure()));
285 loop.Run();
286 }
287
288 {
289 base::RunLoop loop;
290 blink_proxy->PassPickledEnum(
291 PickledEnumBlink::VALUE_0,
292 ExpectEnumResult(PickledEnumBlink::VALUE_0, loop.QuitClosure()));
293 loop.Run();
294 }
295 }
296
TEST_F(PickleTest,BlinkProxyToChromiumService)297 TEST_F(PickleTest, BlinkProxyToChromiumService) {
298 auto blink_proxy = ConnectToChromiumService<blink::PicklePasser>();
299 {
300 base::RunLoop loop;
301 blink_proxy->PassPickledStruct(
302 PickledStructBlink(1, 1),
303 ExpectResult(PickledStructBlink(1, 1), loop.QuitClosure()));
304 loop.Run();
305 }
306
307 {
308 base::RunLoop loop;
309 blink_proxy->PassPickledEnum(
310 PickledEnumBlink::VALUE_1,
311 ExpectEnumResult(PickledEnumBlink::VALUE_1, loop.QuitClosure()));
312 loop.Run();
313 }
314 }
315
TEST_F(PickleTest,PickleArray)316 TEST_F(PickleTest, PickleArray) {
317 ScopedForceMessageSerialization force_serialization;
318 auto proxy = ConnectToChromiumService();
319 auto pickles = std::vector<PickledStructChromium>(2);
320 pickles[0].set_foo(1);
321 pickles[0].set_bar(2);
322 pickles[0].set_baz(100);
323 pickles[1].set_foo(3);
324 pickles[1].set_bar(4);
325 pickles[1].set_baz(100);
326 {
327 base::RunLoop run_loop;
328 // Verify that the array of pickled structs can be serialized and
329 // deserialized intact. This ensures that the ParamTraits are actually used
330 // rather than doing a byte-for-byte copy of the element data, beacuse the
331 // |baz| field should never be serialized.
332 proxy->PassPickles(std::move(pickles),
333 BindSimpleLambda<std::vector<PickledStructChromium>>(
334 [&](std::vector<PickledStructChromium> passed) {
335 ASSERT_EQ(2u, passed.size());
336 EXPECT_EQ(1, passed[0].foo());
337 EXPECT_EQ(2, passed[0].bar());
338 EXPECT_EQ(0, passed[0].baz());
339 EXPECT_EQ(3, passed[1].foo());
340 EXPECT_EQ(4, passed[1].bar());
341 EXPECT_EQ(0, passed[1].baz());
342 run_loop.Quit();
343 }));
344 run_loop.Run();
345 }
346 }
347
TEST_F(PickleTest,PickleArrayArray)348 TEST_F(PickleTest, PickleArrayArray) {
349 ScopedForceMessageSerialization force_serialization;
350 auto proxy = ConnectToChromiumService();
351 auto pickle_arrays = std::vector<std::vector<PickledStructChromium>>(2);
352 for (size_t i = 0; i < 2; ++i)
353 pickle_arrays[i] = std::vector<PickledStructChromium>(2);
354
355 pickle_arrays[0][0].set_foo(1);
356 pickle_arrays[0][0].set_bar(2);
357 pickle_arrays[0][0].set_baz(100);
358 pickle_arrays[0][1].set_foo(3);
359 pickle_arrays[0][1].set_bar(4);
360 pickle_arrays[0][1].set_baz(100);
361 pickle_arrays[1][0].set_foo(5);
362 pickle_arrays[1][0].set_bar(6);
363 pickle_arrays[1][0].set_baz(100);
364 pickle_arrays[1][1].set_foo(7);
365 pickle_arrays[1][1].set_bar(8);
366 pickle_arrays[1][1].set_baz(100);
367 {
368 base::RunLoop run_loop;
369 // Verify that the array-of-arrays serializes and deserializes properly.
370 proxy->PassPickleArrays(
371 std::move(pickle_arrays),
372 BindSimpleLambda<std::vector<std::vector<PickledStructChromium>>>(
373 [&](std::vector<std::vector<PickledStructChromium>> passed) {
374 ASSERT_EQ(2u, passed.size());
375 ASSERT_EQ(2u, passed[0].size());
376 ASSERT_EQ(2u, passed[1].size());
377 EXPECT_EQ(1, passed[0][0].foo());
378 EXPECT_EQ(2, passed[0][0].bar());
379 EXPECT_EQ(0, passed[0][0].baz());
380 EXPECT_EQ(3, passed[0][1].foo());
381 EXPECT_EQ(4, passed[0][1].bar());
382 EXPECT_EQ(0, passed[0][1].baz());
383 EXPECT_EQ(5, passed[1][0].foo());
384 EXPECT_EQ(6, passed[1][0].bar());
385 EXPECT_EQ(0, passed[1][0].baz());
386 EXPECT_EQ(7, passed[1][1].foo());
387 EXPECT_EQ(8, passed[1][1].bar());
388 EXPECT_EQ(0, passed[1][1].baz());
389 run_loop.Quit();
390 }));
391 run_loop.Run();
392 }
393 }
394
TEST_F(PickleTest,PickleContainer)395 TEST_F(PickleTest, PickleContainer) {
396 ScopedForceMessageSerialization force_serialization;
397 auto proxy = ConnectToChromiumService();
398 PickleContainerPtr pickle_container = PickleContainer::New();
399 pickle_container->f_struct.set_foo(42);
400 pickle_container->f_struct.set_bar(43);
401 pickle_container->f_struct.set_baz(44);
402 pickle_container->f_enum = PickledEnumChromium::VALUE_1;
403 EXPECT_TRUE(pickle_container.Equals(pickle_container));
404 EXPECT_FALSE(pickle_container.Equals(PickleContainer::New()));
405 {
406 base::RunLoop run_loop;
407 proxy->PassPickleContainer(std::move(pickle_container),
408 BindSimpleLambda<PickleContainerPtr>(
409 [&](PickleContainerPtr passed) {
410 ASSERT_FALSE(passed.is_null());
411 EXPECT_EQ(42, passed->f_struct.foo());
412 EXPECT_EQ(43, passed->f_struct.bar());
413 EXPECT_EQ(0, passed->f_struct.baz());
414 EXPECT_EQ(PickledEnumChromium::VALUE_1,
415 passed->f_enum);
416 run_loop.Quit();
417 }));
418 run_loop.Run();
419 }
420 }
421
422 } // namespace test
423 } // namespace mojo
424