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, ®ion2, &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, ®ion2, &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(®ion);
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