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 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 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 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> 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 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 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. 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. 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. 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. 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. 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. 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. 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. 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 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