1 // Copyright 2014 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 <stddef.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <utility>
9 
10 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
11 #include "mojo/public/cpp/system/message_pipe.h"
12 #include "mojo/public/interfaces/bindings/tests/test_export2.mojom.h"
13 #include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 namespace mojo {
17 namespace test {
18 namespace {
19 
MakeRect(int32_t factor=1)20 RectPtr MakeRect(int32_t factor = 1) {
21   return Rect::New(1 * factor, 2 * factor, 10 * factor, 20 * factor);
22 }
23 
CheckRect(const Rect & rect,int32_t factor=1)24 void CheckRect(const Rect& rect, int32_t factor = 1) {
25   EXPECT_EQ(1 * factor, rect.x);
26   EXPECT_EQ(2 * factor, rect.y);
27   EXPECT_EQ(10 * factor, rect.width);
28   EXPECT_EQ(20 * factor, rect.height);
29 }
30 
31 template <typename StructType>
32 struct SerializeStructHelperTraits {
33   using DataView = typename StructType::DataView;
34 };
35 
36 template <>
37 struct SerializeStructHelperTraits<native::NativeStruct> {
38   using DataView = native::NativeStructDataView;
39 };
40 
41 template <typename InputType, typename DataType>
SerializeStruct(InputType & input,mojo::Message * message,mojo::internal::SerializationContext * context,DataType ** out_data)42 size_t SerializeStruct(InputType& input,
43                        mojo::Message* message,
44                        mojo::internal::SerializationContext* context,
45                        DataType** out_data) {
46   using StructType = typename InputType::Struct;
47   using DataViewType =
48       typename SerializeStructHelperTraits<StructType>::DataView;
49   *message = mojo::Message(0, 0, 0, 0, nullptr);
50   const size_t payload_start = message->payload_buffer()->cursor();
51   typename DataType::BufferWriter writer;
52   mojo::internal::Serialize<DataViewType>(input, message->payload_buffer(),
53                                           &writer, context);
54   *out_data = writer.is_null() ? nullptr : writer.data();
55   return message->payload_buffer()->cursor() - payload_start;
56 }
57 
MakeMultiVersionStruct()58 MultiVersionStructPtr MakeMultiVersionStruct() {
59   MessagePipe pipe;
60   return MultiVersionStruct::New(123, MakeRect(5), std::string("hello"),
61                                  std::vector<int8_t>{10, 9, 8},
62                                  std::move(pipe.handle0), false, 42);
63 }
64 
65 template <typename U, typename T>
SerializeAndDeserialize(T input)66 U SerializeAndDeserialize(T input) {
67   using InputMojomType = typename T::Struct::DataView;
68   using OutputMojomType = typename U::Struct::DataView;
69 
70   using InputDataType =
71       typename mojo::internal::MojomTypeTraits<InputMojomType>::Data*;
72   using OutputDataType =
73       typename mojo::internal::MojomTypeTraits<OutputMojomType>::Data*;
74 
75   mojo::Message message;
76   mojo::internal::SerializationContext context;
77   InputDataType data;
78   SerializeStruct(input, &message, &context, &data);
79 
80   // Set the subsequent area to a special value, so that we can find out if we
81   // mistakenly access the area.
82   void* subsequent_area = message.payload_buffer()->AllocateAndGet(32);
83   memset(subsequent_area, 0xAA, 32);
84 
85   OutputDataType output_data =
86       reinterpret_cast<OutputDataType>(message.mutable_payload());
87 
88   U output;
89   mojo::internal::Deserialize<OutputMojomType>(output_data, &output, &context);
90   return std::move(output);
91 }
92 
93 using StructTest = testing::Test;
94 
95 }  // namespace
96 
TEST_F(StructTest,Rect)97 TEST_F(StructTest, Rect) {
98   RectPtr rect;
99   EXPECT_TRUE(rect.is_null());
100   EXPECT_TRUE(!rect);
101   EXPECT_FALSE(rect);
102 
103   rect = nullptr;
104   EXPECT_TRUE(rect.is_null());
105   EXPECT_TRUE(!rect);
106   EXPECT_FALSE(rect);
107 
108   rect = MakeRect();
109   EXPECT_FALSE(rect.is_null());
110   EXPECT_FALSE(!rect);
111   EXPECT_TRUE(rect);
112 
113   RectPtr null_rect = nullptr;
114   EXPECT_TRUE(null_rect.is_null());
115   EXPECT_TRUE(!null_rect);
116   EXPECT_FALSE(null_rect);
117 
118   CheckRect(*rect);
119 }
120 
TEST_F(StructTest,Clone)121 TEST_F(StructTest, Clone) {
122   NamedRegionPtr region;
123 
124   NamedRegionPtr clone_region = region.Clone();
125   EXPECT_TRUE(clone_region.is_null());
126 
127   region = NamedRegion::New();
128   clone_region = region.Clone();
129   EXPECT_FALSE(clone_region->name);
130   EXPECT_FALSE(clone_region->rects);
131 
132   region->name.emplace("hello world");
133   clone_region = region.Clone();
134   EXPECT_EQ(region->name, clone_region->name);
135 
136   region->rects.emplace(2);
137   (*region->rects)[1] = MakeRect();
138   clone_region = region.Clone();
139   EXPECT_EQ(2u, clone_region->rects->size());
140   EXPECT_TRUE((*clone_region->rects)[0].is_null());
141   CheckRect(*(*clone_region->rects)[1]);
142 
143   // NoDefaultFieldValues contains handles, so Clone() is not available, but
144   // NoDefaultFieldValuesPtr should still compile.
145   NoDefaultFieldValuesPtr no_default_field_values(NoDefaultFieldValues::New());
146   EXPECT_FALSE(no_default_field_values->f13.is_valid());
147 }
148 
149 // Serialization test of a struct with no pointer or handle members.
TEST_F(StructTest,Serialization_Basic)150 TEST_F(StructTest, Serialization_Basic) {
151   RectPtr rect(MakeRect());
152 
153   mojo::Message message;
154   mojo::internal::SerializationContext context;
155   internal::Rect_Data* data;
156   EXPECT_EQ(8U + 16U, SerializeStruct(rect, &message, &context, &data));
157 
158   RectPtr rect2;
159   mojo::internal::Deserialize<RectDataView>(data, &rect2, &context);
160 
161   CheckRect(*rect2);
162 }
163 
164 // Construction of a struct with struct pointers from null.
TEST_F(StructTest,Construction_StructPointers)165 TEST_F(StructTest, Construction_StructPointers) {
166   RectPairPtr pair;
167   EXPECT_TRUE(pair.is_null());
168 
169   pair = RectPair::New();
170   EXPECT_FALSE(pair.is_null());
171   EXPECT_TRUE(pair->first.is_null());
172   EXPECT_TRUE(pair->first.is_null());
173 
174   pair = nullptr;
175   EXPECT_TRUE(pair.is_null());
176 }
177 
178 // Serialization test of a struct with struct pointers.
TEST_F(StructTest,Serialization_StructPointers)179 TEST_F(StructTest, Serialization_StructPointers) {
180   RectPairPtr pair(RectPair::New(MakeRect(), MakeRect()));
181 
182   mojo::Message message;
183   mojo::internal::SerializationContext context;
184   internal::RectPair_Data* data;
185   EXPECT_EQ(8U + 16U + 2 * (8U + 16U),
186             SerializeStruct(pair, &message, &context, &data));
187 
188   RectPairPtr pair2;
189   mojo::internal::Deserialize<RectPairDataView>(data, &pair2, &context);
190 
191   CheckRect(*pair2->first);
192   CheckRect(*pair2->second);
193 }
194 
195 // Serialization test of a struct with an array member.
TEST_F(StructTest,Serialization_ArrayPointers)196 TEST_F(StructTest, Serialization_ArrayPointers) {
197   std::vector<RectPtr> rects;
198   for (size_t i = 0; i < 4; ++i)
199     rects.push_back(MakeRect(static_cast<int32_t>(i) + 1));
200 
201   NamedRegionPtr region(
202       NamedRegion::New(std::string("region"), std::move(rects)));
203 
204   mojo::Message message;
205   mojo::internal::SerializationContext context;
206   internal::NamedRegion_Data* data;
207   EXPECT_EQ(8U +            // header
208                 8U +        // name pointer
209                 8U +        // rects pointer
210                 8U +        // name header
211                 8U +        // name payload (rounded up)
212                 8U +        // rects header
213                 4 * 8U +    // rects payload (four pointers)
214                 4 * (8U +   // rect header
215                      16U),  // rect payload (four ints)
216             SerializeStruct(region, &message, &context, &data));
217 
218   NamedRegionPtr region2;
219   mojo::internal::Deserialize<NamedRegionDataView>(data, &region2, &context);
220 
221   EXPECT_EQ("region", *region2->name);
222 
223   EXPECT_EQ(4U, region2->rects->size());
224   for (size_t i = 0; i < region2->rects->size(); ++i)
225     CheckRect(*(*region2->rects)[i], static_cast<int32_t>(i) + 1);
226 }
227 
228 // Serialization test of a struct with null array pointers.
TEST_F(StructTest,Serialization_NullArrayPointers)229 TEST_F(StructTest, Serialization_NullArrayPointers) {
230   NamedRegionPtr region(NamedRegion::New());
231   EXPECT_FALSE(region->name);
232   EXPECT_FALSE(region->rects);
233 
234   mojo::Message message;
235   mojo::internal::SerializationContext context;
236   internal::NamedRegion_Data* data;
237   EXPECT_EQ(8U +      // header
238                 8U +  // name pointer
239                 8U,   // rects pointer
240             SerializeStruct(region, &message, &context, &data));
241 
242   NamedRegionPtr region2;
243   mojo::internal::Deserialize<NamedRegionDataView>(data, &region2, &context);
244 
245   EXPECT_FALSE(region2->name);
246   EXPECT_FALSE(region2->rects);
247 }
248 
249 // Tests deserializing structs as a newer version.
TEST_F(StructTest,Versioning_OldToNew)250 TEST_F(StructTest, Versioning_OldToNew) {
251   {
252     MultiVersionStructV0Ptr input(MultiVersionStructV0::New(123));
253     MultiVersionStructPtr expected_output(MultiVersionStruct::New(123));
254 
255     MultiVersionStructPtr output =
256         SerializeAndDeserialize<MultiVersionStructPtr>(std::move(input));
257     EXPECT_TRUE(output);
258     EXPECT_TRUE(output->Equals(*expected_output));
259   }
260 
261   {
262     MultiVersionStructV1Ptr input(MultiVersionStructV1::New(123, MakeRect(5)));
263     MultiVersionStructPtr expected_output(
264         MultiVersionStruct::New(123, MakeRect(5)));
265 
266     MultiVersionStructPtr output =
267         SerializeAndDeserialize<MultiVersionStructPtr>(std::move(input));
268     EXPECT_TRUE(output);
269     EXPECT_TRUE(output->Equals(*expected_output));
270   }
271 
272   {
273     MultiVersionStructV3Ptr input(
274         MultiVersionStructV3::New(123, MakeRect(5), std::string("hello")));
275     MultiVersionStructPtr expected_output(
276         MultiVersionStruct::New(123, MakeRect(5), std::string("hello")));
277 
278     MultiVersionStructPtr output =
279         SerializeAndDeserialize<MultiVersionStructPtr>(std::move(input));
280     EXPECT_TRUE(output);
281     EXPECT_TRUE(output->Equals(*expected_output));
282   }
283 
284   {
285     MultiVersionStructV5Ptr input(MultiVersionStructV5::New(
286         123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8}));
287     MultiVersionStructPtr expected_output(MultiVersionStruct::New(
288         123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8}));
289 
290     MultiVersionStructPtr output =
291         SerializeAndDeserialize<MultiVersionStructPtr>(std::move(input));
292     EXPECT_TRUE(output);
293     EXPECT_TRUE(output->Equals(*expected_output));
294   }
295 
296   {
297     MessagePipe pipe;
298     MultiVersionStructV7Ptr input(MultiVersionStructV7::New(
299         123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8},
300         std::move(pipe.handle0), false));
301 
302     MultiVersionStructPtr expected_output(MultiVersionStruct::New(
303         123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8}));
304     // Save the raw handle value separately so that we can compare later.
305     MojoHandle expected_handle = input->f_message_pipe.get().value();
306 
307     MultiVersionStructPtr output =
308         SerializeAndDeserialize<MultiVersionStructPtr>(std::move(input));
309     EXPECT_TRUE(output);
310     EXPECT_EQ(expected_handle, output->f_message_pipe.get().value());
311     output->f_message_pipe.reset();
312     EXPECT_TRUE(output->Equals(*expected_output));
313   }
314 }
315 
316 // Tests deserializing structs as an older version.
TEST_F(StructTest,Versioning_NewToOld)317 TEST_F(StructTest, Versioning_NewToOld) {
318   {
319     MultiVersionStructPtr input = MakeMultiVersionStruct();
320     MultiVersionStructV7Ptr expected_output(MultiVersionStructV7::New(
321         123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8}));
322     // Save the raw handle value separately so that we can compare later.
323     MojoHandle expected_handle = input->f_message_pipe.get().value();
324 
325     MultiVersionStructV7Ptr output =
326         SerializeAndDeserialize<MultiVersionStructV7Ptr>(std::move(input));
327     EXPECT_TRUE(output);
328     EXPECT_EQ(expected_handle, output->f_message_pipe.get().value());
329     output->f_message_pipe.reset();
330     EXPECT_TRUE(output->Equals(*expected_output));
331   }
332 
333   {
334     MultiVersionStructPtr input = MakeMultiVersionStruct();
335     MultiVersionStructV5Ptr expected_output(MultiVersionStructV5::New(
336         123, MakeRect(5), std::string("hello"), std::vector<int8_t>{10, 9, 8}));
337 
338     MultiVersionStructV5Ptr output =
339         SerializeAndDeserialize<MultiVersionStructV5Ptr>(std::move(input));
340     EXPECT_TRUE(output);
341     EXPECT_TRUE(output->Equals(*expected_output));
342   }
343 
344   {
345     MultiVersionStructPtr input = MakeMultiVersionStruct();
346     MultiVersionStructV3Ptr expected_output(
347         MultiVersionStructV3::New(123, MakeRect(5), std::string("hello")));
348 
349     MultiVersionStructV3Ptr output =
350         SerializeAndDeserialize<MultiVersionStructV3Ptr>(std::move(input));
351     EXPECT_TRUE(output);
352     EXPECT_TRUE(output->Equals(*expected_output));
353   }
354 
355   {
356     MultiVersionStructPtr input = MakeMultiVersionStruct();
357     MultiVersionStructV1Ptr expected_output(
358         MultiVersionStructV1::New(123, MakeRect(5)));
359 
360     MultiVersionStructV1Ptr output =
361         SerializeAndDeserialize<MultiVersionStructV1Ptr>(std::move(input));
362     EXPECT_TRUE(output);
363     EXPECT_TRUE(output->Equals(*expected_output));
364   }
365 
366   {
367     MultiVersionStructPtr input = MakeMultiVersionStruct();
368     MultiVersionStructV0Ptr expected_output(MultiVersionStructV0::New(123));
369 
370     MultiVersionStructV0Ptr output =
371         SerializeAndDeserialize<MultiVersionStructV0Ptr>(std::move(input));
372     EXPECT_TRUE(output);
373     EXPECT_TRUE(output->Equals(*expected_output));
374   }
375 }
376 
377 // Serialization test for native struct.
TEST_F(StructTest,Serialization_NativeStruct)378 TEST_F(StructTest, Serialization_NativeStruct) {
379   using Data = native::internal::NativeStruct_Data;
380   {
381     // Serialization of a null native struct.
382     native::NativeStructPtr native;
383 
384     mojo::Message message;
385     mojo::internal::SerializationContext context;
386     Data* data = nullptr;
387     EXPECT_EQ(0u, SerializeStruct(native, &message, &context, &data));
388     EXPECT_EQ(nullptr, data);
389 
390     native::NativeStructPtr output_native;
391     mojo::internal::Deserialize<native::NativeStructDataView>(
392         data, &output_native, &context);
393     EXPECT_TRUE(output_native.is_null());
394   }
395 
396   {
397     // Serialization of a native struct with null data.
398     native::NativeStructPtr native(native::NativeStruct::New());
399 
400     mojo::Message message;
401     mojo::internal::SerializationContext context;
402     Data* data = nullptr;
403     EXPECT_EQ(32u, SerializeStruct(native, &message, &context, &data));
404     EXPECT_EQ(0u, data->data.Get()->size());
405 
406     native::NativeStructPtr output_native;
407     mojo::internal::Deserialize<native::NativeStructDataView>(
408         data, &output_native, &context);
409     EXPECT_TRUE(output_native->data.empty());
410   }
411 
412   {
413     native::NativeStructPtr native(native::NativeStruct::New());
414     native->data = std::vector<uint8_t>{'X', 'Y'};
415 
416     mojo::Message message;
417     mojo::internal::SerializationContext context;
418     Data* data = nullptr;
419     EXPECT_EQ(40u, SerializeStruct(native, &message, &context, &data));
420     EXPECT_EQ(2u, data->data.Get()->size());
421 
422     native::NativeStructPtr output_native;
423     mojo::internal::Deserialize<native::NativeStructDataView>(
424         data, &output_native, &context);
425     ASSERT_TRUE(output_native);
426     ASSERT_FALSE(output_native->data.empty());
427     EXPECT_EQ(2u, output_native->data.size());
428     EXPECT_EQ('X', output_native->data[0]);
429     EXPECT_EQ('Y', output_native->data[1]);
430   }
431 }
432 
TEST_F(StructTest,Serialization_PublicAPI)433 TEST_F(StructTest, Serialization_PublicAPI) {
434   {
435     // A null struct pointer.
436     RectPtr null_struct;
437     auto data = Rect::Serialize(&null_struct);
438     EXPECT_TRUE(data.empty());
439 
440     // Initialize it to non-null.
441     RectPtr output(Rect::New());
442     ASSERT_TRUE(Rect::Deserialize(data, &output));
443     EXPECT_TRUE(output.is_null());
444   }
445 
446   {
447     // A struct with no fields.
448     EmptyStructPtr empty_struct(EmptyStruct::New());
449     auto data = EmptyStruct::Serialize(&empty_struct);
450     EXPECT_FALSE(data.empty());
451 
452     EmptyStructPtr output;
453     ASSERT_TRUE(EmptyStruct::Deserialize(data, &output));
454     EXPECT_FALSE(output.is_null());
455   }
456 
457   {
458     // A simple struct.
459     RectPtr rect = MakeRect();
460     RectPtr cloned_rect = rect.Clone();
461     auto data = Rect::Serialize(&rect);
462 
463     RectPtr output;
464     ASSERT_TRUE(Rect::Deserialize(data, &output));
465     EXPECT_TRUE(output.Equals(cloned_rect));
466   }
467 
468   {
469     // A struct containing other objects.
470     std::vector<RectPtr> rects;
471     for (size_t i = 0; i < 3; ++i)
472       rects.push_back(MakeRect(static_cast<int32_t>(i) + 1));
473     NamedRegionPtr region(
474         NamedRegion::New(std::string("region"), std::move(rects)));
475 
476     NamedRegionPtr cloned_region = region.Clone();
477     auto data = NamedRegion::Serialize(&region);
478 
479     // Make sure that the serialized result gets pointers encoded properly.
480     auto cloned_data = data;
481     NamedRegionPtr output;
482     ASSERT_TRUE(NamedRegion::Deserialize(cloned_data, &output));
483     EXPECT_TRUE(output.Equals(cloned_region));
484   }
485 
486   {
487     // Deserialization failure.
488     RectPtr rect = MakeRect();
489     auto data = Rect::Serialize(&rect);
490 
491     NamedRegionPtr output;
492     EXPECT_FALSE(NamedRegion::Deserialize(data, &output));
493   }
494 
495   {
496     // A struct from another component.
497     auto pair = test_export2::StringPair::New("hello", "world");
498     auto data = test_export2::StringPair::Serialize(&pair);
499 
500     test_export2::StringPairPtr output;
501     ASSERT_TRUE(test_export2::StringPair::Deserialize(data, &output));
502     EXPECT_TRUE(output.Equals(pair));
503   }
504 }
505 
TEST_F(StructTest,VersionedStructConstructor)506 TEST_F(StructTest, VersionedStructConstructor) {
507   auto reordered = ReorderedStruct::New(123, 456, 789);
508   EXPECT_EQ(123, reordered->a);
509   EXPECT_EQ(456, reordered->b);
510   EXPECT_EQ(789, reordered->c);
511 
512   reordered = ReorderedStruct::New(123, 456);
513   EXPECT_EQ(123, reordered->a);
514   EXPECT_EQ(6, reordered->b);
515   EXPECT_EQ(456, reordered->c);
516 
517   reordered = ReorderedStruct::New(123);
518   EXPECT_EQ(3, reordered->a);
519   EXPECT_EQ(6, reordered->b);
520   EXPECT_EQ(123, reordered->c);
521 
522   reordered = ReorderedStruct::New();
523   EXPECT_EQ(3, reordered->a);
524   EXPECT_EQ(6, reordered->b);
525   EXPECT_EQ(1, reordered->c);
526 }
527 
528 }  // namespace test
529 }  // namespace mojo
530