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