1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 #include <google/protobuf/util/internal/protostream_objectsource.h> 32 33 #include <memory> 34 #ifndef _SHARED_PTR_H 35 #include <google/protobuf/stubs/shared_ptr.h> 36 #endif 37 #include <sstream> 38 39 #include <google/protobuf/stubs/casts.h> 40 #include <google/protobuf/any.pb.h> 41 #include <google/protobuf/io/coded_stream.h> 42 #include <google/protobuf/io/zero_copy_stream_impl_lite.h> 43 #include <google/protobuf/descriptor.h> 44 #include <google/protobuf/util/internal/expecting_objectwriter.h> 45 #include <google/protobuf/util/internal/testdata/books.pb.h> 46 #include <google/protobuf/util/internal/testdata/field_mask.pb.h> 47 #include <google/protobuf/util/internal/type_info_test_helper.h> 48 #include <google/protobuf/util/internal/constants.h> 49 #include <google/protobuf/stubs/strutil.h> 50 #include <google/protobuf/util/internal/testdata/anys.pb.h> 51 #include <google/protobuf/util/internal/testdata/maps.pb.h> 52 #include <google/protobuf/util/internal/testdata/struct.pb.h> 53 #include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h> 54 #include <gtest/gtest.h> 55 56 57 namespace google { 58 namespace protobuf { 59 namespace util { 60 namespace converter { 61 62 using google::protobuf::Descriptor; 63 using google::protobuf::DescriptorPool; 64 using google::protobuf::FileDescriptorProto; 65 using google::protobuf::Message; 66 using google::protobuf::io::ArrayInputStream; 67 using google::protobuf::io::CodedInputStream; 68 using util::Status; 69 using google::protobuf::testing::Author; 70 using google::protobuf::testing::BadAuthor; 71 using google::protobuf::testing::BadNestedBook; 72 using google::protobuf::testing::Book; 73 using google::protobuf::testing::Cyclic; 74 using google::protobuf::testing::Book_Label; 75 using google::protobuf::testing::NestedBook; 76 using google::protobuf::testing::PackedPrimitive; 77 using google::protobuf::testing::Primitive; 78 using google::protobuf::testing::more_author; 79 using google::protobuf::testing::maps::MapOut; 80 using google::protobuf::testing::maps::MapOutWireFormat; 81 using google::protobuf::testing::timestampduration::TimestampDuration; 82 using google::protobuf::testing::anys::AnyOut; 83 using google::protobuf::testing::anys::AnyM; 84 using google::protobuf::testing::FieldMaskTest; 85 using google::protobuf::testing::NestedFieldMask; 86 using google::protobuf::testing::structs::StructType; 87 using ::testing::_; 88 89 90 namespace { 91 string GetTypeUrl(const Descriptor* descriptor) { 92 return string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(); 93 } 94 } // namespace 95 96 class ProtostreamObjectSourceTest 97 : public ::testing::TestWithParam<testing::TypeInfoSource> { 98 protected: 99 ProtostreamObjectSourceTest() 100 : helper_(GetParam()), 101 mock_(), 102 ow_(&mock_), 103 use_lower_camel_for_enums_(false) { 104 helper_.ResetTypeInfo(Book::descriptor()); 105 } 106 107 virtual ~ProtostreamObjectSourceTest() {} 108 109 void DoTest(const Message& msg, const Descriptor* descriptor) { 110 Status status = ExecuteTest(msg, descriptor); 111 EXPECT_EQ(Status::OK, status); 112 } 113 114 Status ExecuteTest(const Message& msg, const Descriptor* descriptor) { 115 ostringstream oss; 116 msg.SerializePartialToOstream(&oss); 117 string proto = oss.str(); 118 ArrayInputStream arr_stream(proto.data(), proto.size()); 119 CodedInputStream in_stream(&arr_stream); 120 121 google::protobuf::scoped_ptr<ProtoStreamObjectSource> os( 122 helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor))); 123 if (use_lower_camel_for_enums_) os->set_use_lower_camel_for_enums(true); 124 os->set_max_recursion_depth(64); 125 return os->WriteTo(&mock_); 126 } 127 128 void PrepareExpectingObjectWriterForRepeatedPrimitive() { 129 ow_.StartObject("") 130 ->StartList("repFix32") 131 ->RenderUint32("", bit_cast<uint32>(3201)) 132 ->RenderUint32("", bit_cast<uint32>(0)) 133 ->RenderUint32("", bit_cast<uint32>(3202)) 134 ->EndList() 135 ->StartList("repU32") 136 ->RenderUint32("", bit_cast<uint32>(3203)) 137 ->RenderUint32("", bit_cast<uint32>(0)) 138 ->EndList() 139 ->StartList("repI32") 140 ->RenderInt32("", 0) 141 ->RenderInt32("", 3204) 142 ->RenderInt32("", 3205) 143 ->EndList() 144 ->StartList("repSf32") 145 ->RenderInt32("", 3206) 146 ->RenderInt32("", 0) 147 ->EndList() 148 ->StartList("repS32") 149 ->RenderInt32("", 0) 150 ->RenderInt32("", 3207) 151 ->RenderInt32("", 3208) 152 ->EndList() 153 ->StartList("repFix64") 154 ->RenderUint64("", bit_cast<uint64>(6401LL)) 155 ->RenderUint64("", bit_cast<uint64>(0LL)) 156 ->EndList() 157 ->StartList("repU64") 158 ->RenderUint64("", bit_cast<uint64>(0LL)) 159 ->RenderUint64("", bit_cast<uint64>(6402LL)) 160 ->RenderUint64("", bit_cast<uint64>(6403LL)) 161 ->EndList() 162 ->StartList("repI64") 163 ->RenderInt64("", 6404L) 164 ->RenderInt64("", 0L) 165 ->EndList() 166 ->StartList("repSf64") 167 ->RenderInt64("", 0L) 168 ->RenderInt64("", 6405L) 169 ->RenderInt64("", 6406L) 170 ->EndList() 171 ->StartList("repS64") 172 ->RenderInt64("", 6407L) 173 ->RenderInt64("", 0L) 174 ->EndList() 175 ->StartList("repFloat") 176 ->RenderFloat("", 0.0f) 177 ->RenderFloat("", 32.1f) 178 ->RenderFloat("", 32.2f) 179 ->EndList() 180 ->StartList("repDouble") 181 ->RenderDouble("", 64.1L) 182 ->RenderDouble("", 0.0L) 183 ->EndList() 184 ->StartList("repBool") 185 ->RenderBool("", true) 186 ->RenderBool("", false) 187 ->EndList() 188 ->EndObject(); 189 } 190 191 Primitive PrepareRepeatedPrimitive() { 192 Primitive primitive; 193 primitive.add_rep_fix32(3201); 194 primitive.add_rep_fix32(0); 195 primitive.add_rep_fix32(3202); 196 primitive.add_rep_u32(3203); 197 primitive.add_rep_u32(0); 198 primitive.add_rep_i32(0); 199 primitive.add_rep_i32(3204); 200 primitive.add_rep_i32(3205); 201 primitive.add_rep_sf32(3206); 202 primitive.add_rep_sf32(0); 203 primitive.add_rep_s32(0); 204 primitive.add_rep_s32(3207); 205 primitive.add_rep_s32(3208); 206 primitive.add_rep_fix64(6401L); 207 primitive.add_rep_fix64(0L); 208 primitive.add_rep_u64(0L); 209 primitive.add_rep_u64(6402L); 210 primitive.add_rep_u64(6403L); 211 primitive.add_rep_i64(6404L); 212 primitive.add_rep_i64(0L); 213 primitive.add_rep_sf64(0L); 214 primitive.add_rep_sf64(6405L); 215 primitive.add_rep_sf64(6406L); 216 primitive.add_rep_s64(6407L); 217 primitive.add_rep_s64(0L); 218 primitive.add_rep_float(0.0f); 219 primitive.add_rep_float(32.1f); 220 primitive.add_rep_float(32.2f); 221 primitive.add_rep_double(64.1L); 222 primitive.add_rep_double(0.0); 223 primitive.add_rep_bool(true); 224 primitive.add_rep_bool(false); 225 226 PrepareExpectingObjectWriterForRepeatedPrimitive(); 227 return primitive; 228 } 229 230 PackedPrimitive PreparePackedPrimitive() { 231 PackedPrimitive primitive; 232 primitive.add_rep_fix32(3201); 233 primitive.add_rep_fix32(0); 234 primitive.add_rep_fix32(3202); 235 primitive.add_rep_u32(3203); 236 primitive.add_rep_u32(0); 237 primitive.add_rep_i32(0); 238 primitive.add_rep_i32(3204); 239 primitive.add_rep_i32(3205); 240 primitive.add_rep_sf32(3206); 241 primitive.add_rep_sf32(0); 242 primitive.add_rep_s32(0); 243 primitive.add_rep_s32(3207); 244 primitive.add_rep_s32(3208); 245 primitive.add_rep_fix64(6401L); 246 primitive.add_rep_fix64(0L); 247 primitive.add_rep_u64(0L); 248 primitive.add_rep_u64(6402L); 249 primitive.add_rep_u64(6403L); 250 primitive.add_rep_i64(6404L); 251 primitive.add_rep_i64(0L); 252 primitive.add_rep_sf64(0L); 253 primitive.add_rep_sf64(6405L); 254 primitive.add_rep_sf64(6406L); 255 primitive.add_rep_s64(6407L); 256 primitive.add_rep_s64(0L); 257 primitive.add_rep_float(0.0f); 258 primitive.add_rep_float(32.1f); 259 primitive.add_rep_float(32.2f); 260 primitive.add_rep_double(64.1L); 261 primitive.add_rep_double(0.0); 262 primitive.add_rep_bool(true); 263 primitive.add_rep_bool(false); 264 265 PrepareExpectingObjectWriterForRepeatedPrimitive(); 266 return primitive; 267 } 268 269 void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; } 270 271 testing::TypeInfoTestHelper helper_; 272 273 ::testing::NiceMock<MockObjectWriter> mock_; 274 ExpectingObjectWriter ow_; 275 bool use_lower_camel_for_enums_; 276 }; 277 278 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 279 ProtostreamObjectSourceTest, 280 ::testing::Values( 281 testing::USE_TYPE_RESOLVER)); 282 283 TEST_P(ProtostreamObjectSourceTest, EmptyMessage) { 284 Book empty; 285 ow_.StartObject("")->EndObject(); 286 DoTest(empty, Book::descriptor()); 287 } 288 289 TEST_P(ProtostreamObjectSourceTest, Primitives) { 290 Primitive primitive; 291 primitive.set_fix32(3201); 292 primitive.set_u32(3202); 293 primitive.set_i32(3203); 294 primitive.set_sf32(3204); 295 primitive.set_s32(3205); 296 primitive.set_fix64(6401L); 297 primitive.set_u64(6402L); 298 primitive.set_i64(6403L); 299 primitive.set_sf64(6404L); 300 primitive.set_s64(6405L); 301 primitive.set_str("String Value"); 302 primitive.set_bytes("Some Bytes"); 303 primitive.set_float_(32.1f); 304 primitive.set_double_(64.1L); 305 primitive.set_bool_(true); 306 307 ow_.StartObject("") 308 ->RenderUint32("fix32", bit_cast<uint32>(3201)) 309 ->RenderUint32("u32", bit_cast<uint32>(3202)) 310 ->RenderInt32("i32", 3203) 311 ->RenderInt32("sf32", 3204) 312 ->RenderInt32("s32", 3205) 313 ->RenderUint64("fix64", bit_cast<uint64>(6401LL)) 314 ->RenderUint64("u64", bit_cast<uint64>(6402LL)) 315 ->RenderInt64("i64", 6403L) 316 ->RenderInt64("sf64", 6404L) 317 ->RenderInt64("s64", 6405L) 318 ->RenderString("str", "String Value") 319 ->RenderBytes("bytes", "Some Bytes") 320 ->RenderFloat("float", 32.1f) 321 ->RenderDouble("double", 64.1L) 322 ->RenderBool("bool", true) 323 ->EndObject(); 324 DoTest(primitive, Primitive::descriptor()); 325 } 326 327 TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) { 328 Primitive primitive = PrepareRepeatedPrimitive(); 329 primitive.add_rep_str("String One"); 330 primitive.add_rep_str("String Two"); 331 primitive.add_rep_bytes("Some Bytes"); 332 333 ow_.StartList("repStr") 334 ->RenderString("", "String One") 335 ->RenderString("", "String Two") 336 ->EndList() 337 ->StartList("repBytes") 338 ->RenderBytes("", "Some Bytes") 339 ->EndList(); 340 DoTest(primitive, Primitive::descriptor()); 341 } 342 343 TEST_P(ProtostreamObjectSourceTest, CustomJsonName) { 344 Author author; 345 author.set_id(12345); 346 347 ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject(); 348 DoTest(author, Author::descriptor()); 349 } 350 351 TEST_P(ProtostreamObjectSourceTest, NestedMessage) { 352 Author* author = new Author(); 353 author->set_name("Tolstoy"); 354 Book book; 355 book.set_title("My Book"); 356 book.set_allocated_author(author); 357 358 ow_.StartObject("") 359 ->RenderString("title", "My Book") 360 ->StartObject("author") 361 ->RenderString("name", "Tolstoy") 362 ->EndObject() 363 ->EndObject(); 364 DoTest(book, Book::descriptor()); 365 } 366 367 TEST_P(ProtostreamObjectSourceTest, RepeatingField) { 368 Author author; 369 author.set_alive(false); 370 author.set_name("john"); 371 author.add_pseudonym("phil"); 372 author.add_pseudonym("bob"); 373 374 ow_.StartObject("") 375 ->RenderBool("alive", false) 376 ->RenderString("name", "john") 377 ->StartList("pseudonym") 378 ->RenderString("", "phil") 379 ->RenderString("", "bob") 380 ->EndList() 381 ->EndObject(); 382 DoTest(author, Author::descriptor()); 383 } 384 385 TEST_P(ProtostreamObjectSourceTest, PackedRepeatingFields) { 386 DoTest(PreparePackedPrimitive(), PackedPrimitive::descriptor()); 387 } 388 389 TEST_P(ProtostreamObjectSourceTest, NonPackedPackableFieldsActuallyPacked) { 390 // Protostream is packed, but parse with non-packed Primitive. 391 DoTest(PreparePackedPrimitive(), Primitive::descriptor()); 392 } 393 394 TEST_P(ProtostreamObjectSourceTest, PackedPackableFieldNotActuallyPacked) { 395 // Protostream is not packed, but parse with PackedPrimitive. 396 DoTest(PrepareRepeatedPrimitive(), PackedPrimitive::descriptor()); 397 } 398 399 TEST_P(ProtostreamObjectSourceTest, BadAuthor) { 400 Author author; 401 author.set_alive(false); 402 author.set_name("john"); 403 author.set_id(1234L); 404 author.add_pseudonym("phil"); 405 author.add_pseudonym("bob"); 406 407 ow_.StartObject("") 408 ->StartList("alive") 409 ->RenderBool("", false) 410 ->EndList() 411 ->StartList("name") 412 ->RenderUint64("", static_cast<uint64>('j')) 413 ->RenderUint64("", static_cast<uint64>('o')) 414 ->RenderUint64("", static_cast<uint64>('h')) 415 ->RenderUint64("", static_cast<uint64>('n')) 416 ->EndList() 417 ->RenderString("pseudonym", "phil") 418 ->RenderString("pseudonym", "bob") 419 ->EndObject(); 420 // Protostream created with Author, but parsed with BadAuthor. 421 DoTest(author, BadAuthor::descriptor()); 422 } 423 424 TEST_P(ProtostreamObjectSourceTest, NestedBookToBadNestedBook) { 425 Book* book = new Book(); 426 book->set_length(250); 427 book->set_published(2014L); 428 NestedBook nested; 429 nested.set_allocated_book(book); 430 431 ow_.StartObject("") 432 ->StartList("book") 433 ->RenderUint32("", 24) // tag for field length (3 << 3) 434 ->RenderUint32("", 250) 435 ->RenderUint32("", 32) // tag for field published (4 << 3) 436 ->RenderUint32("", 2014) 437 ->EndList() 438 ->EndObject(); 439 // Protostream created with NestedBook, but parsed with BadNestedBook. 440 DoTest(nested, BadNestedBook::descriptor()); 441 } 442 443 TEST_P(ProtostreamObjectSourceTest, BadNestedBookToNestedBook) { 444 BadNestedBook nested; 445 nested.add_book(1); 446 nested.add_book(2); 447 nested.add_book(3); 448 nested.add_book(4); 449 nested.add_book(5); 450 nested.add_book(6); 451 nested.add_book(7); 452 453 ow_.StartObject("")->StartObject("book")->EndObject()->EndObject(); 454 // Protostream created with BadNestedBook, but parsed with NestedBook. 455 DoTest(nested, NestedBook::descriptor()); 456 } 457 458 TEST_P(ProtostreamObjectSourceTest, 459 LongRepeatedListDoesNotBreakIntoMultipleJsonLists) { 460 Book book; 461 462 int repeat = 10000; 463 for (int i = 0; i < repeat; ++i) { 464 Book_Label* label = book.add_labels(); 465 label->set_key(StrCat("i", i)); 466 label->set_value(StrCat("v", i)); 467 } 468 469 // Make sure StartList and EndList are called exactly once (see b/18227499 for 470 // problems when this doesn't happen) 471 EXPECT_CALL(mock_, StartList(_)).Times(1); 472 EXPECT_CALL(mock_, EndList()).Times(1); 473 474 DoTest(book, Book::descriptor()); 475 } 476 477 TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputTest) { 478 Book book; 479 book.set_type(Book::ACTION_AND_ADVENTURE); 480 481 UseLowerCamelForEnums(); 482 483 ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject(); 484 DoTest(book, Book::descriptor()); 485 } 486 487 TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) { 488 Book book; 489 book.set_type(Book::ACTION_AND_ADVENTURE); 490 ow_.StartObject("") 491 ->RenderString("type", "ACTION_AND_ADVENTURE") 492 ->EndObject(); 493 DoTest(book, Book::descriptor()); 494 } 495 496 TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) { 497 Cyclic cyclic; 498 cyclic.set_m_int(123); 499 500 Book* book = cyclic.mutable_m_book(); 501 book->set_title("book title"); 502 Cyclic* current = cyclic.mutable_m_cyclic(); 503 Author* current_author = cyclic.add_m_author(); 504 for (int i = 0; i < 63; ++i) { 505 Author* next = current_author->add_friend_(); 506 next->set_id(i); 507 next->set_name(StrCat("author_name_", i)); 508 next->set_alive(true); 509 current_author = next; 510 } 511 512 // Recursive message with depth (65) > max (max is 64). 513 for (int i = 0; i < 64; ++i) { 514 Cyclic* next = current->mutable_m_cyclic(); 515 next->set_m_str(StrCat("count_", i)); 516 current = next; 517 } 518 519 Status status = ExecuteTest(cyclic, Cyclic::descriptor()); 520 EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code()); 521 } 522 523 class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest { 524 protected: 525 ProtostreamObjectSourceMapsTest() { 526 helper_.ResetTypeInfo(MapOut::descriptor()); 527 } 528 }; 529 530 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 531 ProtostreamObjectSourceMapsTest, 532 ::testing::Values( 533 testing::USE_TYPE_RESOLVER)); 534 535 // Tests JSON map. 536 // 537 // This is the example expected output. 538 // { 539 // "map1": { 540 // "key1": { 541 // "foo": "foovalue" 542 // }, 543 // "key2": { 544 // "foo": "barvalue" 545 // } 546 // }, 547 // "map2": { 548 // "nestedself": { 549 // "map1": { 550 // "nested_key1": { 551 // "foo": "nested_foo" 552 // } 553 // }, 554 // "bar": "nested_bar_string" 555 // } 556 // }, 557 // "map3": { 558 // "111": "one one one" 559 // }, 560 // "bar": "top bar" 561 // } 562 TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) { 563 MapOut out; 564 (*out.mutable_map1())["key1"].set_foo("foovalue"); 565 (*out.mutable_map1())["key2"].set_foo("barvalue"); 566 567 MapOut* nested_value = &(*out.mutable_map2())["nestedself"]; 568 (*nested_value->mutable_map1())["nested_key1"].set_foo("nested_foo"); 569 nested_value->set_bar("nested_bar_string"); 570 571 (*out.mutable_map3())[111] = "one one one"; 572 573 out.set_bar("top bar"); 574 575 ow_.StartObject("") 576 ->StartObject("map1") 577 ->StartObject("key1") 578 ->RenderString("foo", "foovalue") 579 ->EndObject() 580 ->StartObject("key2") 581 ->RenderString("foo", "barvalue") 582 ->EndObject() 583 ->StartObject("map2") 584 ->StartObject("nestedself") 585 ->StartObject("map1") 586 ->StartObject("nested_key1") 587 ->RenderString("foo", "nested_foo") 588 ->EndObject() 589 ->EndObject() 590 ->RenderString("bar", "nested_bar_string") 591 ->EndObject() 592 ->EndObject() 593 ->StartObject("map3") 594 ->RenderString("111", "one one one") 595 ->EndObject() 596 ->EndObject() 597 ->RenderString("bar", "top bar") 598 ->EndObject(); 599 600 DoTest(out, MapOut::descriptor()); 601 } 602 603 TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) { 604 // MapOutWireFormat has the same wire representation with MapOut but uses 605 // repeated message fields to represent map fields so we can intentionally 606 // leave out the key field or the value field of a map entry. 607 MapOutWireFormat out; 608 // Create some map entries without keys. They will be rendered with the 609 // default values ("" for strings, "0" for integers, etc.). 610 // { 611 // "map1": { 612 // "": { 613 // "foo": "foovalue" 614 // } 615 // }, 616 // "map2": { 617 // "": { 618 // "map1": { 619 // "nested_key1": { 620 // "foo": "nested_foo" 621 // } 622 // } 623 // } 624 // }, 625 // "map3": { 626 // "0": "one one one" 627 // }, 628 // "map4": { 629 // "false": "bool" 630 // } 631 // } 632 out.add_map1()->mutable_value()->set_foo("foovalue"); 633 MapOut* nested = out.add_map2()->mutable_value(); 634 (*nested->mutable_map1())["nested_key1"].set_foo("nested_foo"); 635 out.add_map3()->set_value("one one one"); 636 out.add_map4()->set_value("bool"); 637 638 ow_.StartObject("") 639 ->StartObject("map1") 640 ->StartObject("") 641 ->RenderString("foo", "foovalue") 642 ->EndObject() 643 ->EndObject() 644 ->StartObject("map2") 645 ->StartObject("") 646 ->StartObject("map1") 647 ->StartObject("nested_key1") 648 ->RenderString("foo", "nested_foo") 649 ->EndObject() 650 ->EndObject() 651 ->EndObject() 652 ->EndObject() 653 ->StartObject("map3") 654 ->RenderString("0", "one one one") 655 ->EndObject() 656 ->StartObject("map4") 657 ->RenderString("false", "bool") 658 ->EndObject() 659 ->EndObject(); 660 661 DoTest(out, MapOut::descriptor()); 662 } 663 664 class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest { 665 protected: 666 ProtostreamObjectSourceAnysTest() { 667 helper_.ResetTypeInfo(AnyOut::descriptor(), 668 google::protobuf::Any::descriptor()); 669 } 670 }; 671 672 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 673 ProtostreamObjectSourceAnysTest, 674 ::testing::Values( 675 testing::USE_TYPE_RESOLVER)); 676 677 // Tests JSON any support. 678 // 679 // This is the example expected output. 680 // { 681 // "any": { 682 // "@type": "type.googleapis.com/google.protobuf.testing.anys.AnyM" 683 // "foo": "foovalue" 684 // } 685 // } 686 TEST_P(ProtostreamObjectSourceAnysTest, BasicAny) { 687 AnyOut out; 688 ::google::protobuf::Any* any = out.mutable_any(); 689 690 AnyM m; 691 m.set_foo("foovalue"); 692 any->PackFrom(m); 693 694 ow_.StartObject("") 695 ->StartObject("any") 696 ->RenderString("@type", 697 "type.googleapis.com/google.protobuf.testing.anys.AnyM") 698 ->RenderString("foo", "foovalue") 699 ->EndObject() 700 ->EndObject(); 701 702 DoTest(out, AnyOut::descriptor()); 703 } 704 705 TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) { 706 AnyOut out; 707 ::google::protobuf::Any* any = out.mutable_any(); 708 any->set_type_url("type.googleapis.com/google.protobuf.Any"); 709 710 ::google::protobuf::Any nested_any; 711 nested_any.set_type_url( 712 "type.googleapis.com/google.protobuf.testing.anys.AnyM"); 713 714 AnyM m; 715 m.set_foo("foovalue"); 716 nested_any.set_value(m.SerializeAsString()); 717 718 any->set_value(nested_any.SerializeAsString()); 719 720 ow_.StartObject("") 721 ->StartObject("any") 722 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") 723 ->StartObject("value") 724 ->RenderString("@type", 725 "type.googleapis.com/google.protobuf.testing.anys.AnyM") 726 ->RenderString("foo", "foovalue") 727 ->EndObject() 728 ->EndObject() 729 ->EndObject(); 730 731 DoTest(out, AnyOut::descriptor()); 732 } 733 734 TEST_P(ProtostreamObjectSourceAnysTest, DoubleRecursiveAny) { 735 AnyOut out; 736 ::google::protobuf::Any* any = out.mutable_any(); 737 any->set_type_url("type.googleapis.com/google.protobuf.Any"); 738 739 ::google::protobuf::Any nested_any; 740 nested_any.set_type_url("type.googleapis.com/google.protobuf.Any"); 741 742 ::google::protobuf::Any second_nested_any; 743 second_nested_any.set_type_url( 744 "type.googleapis.com/google.protobuf.testing.anys.AnyM"); 745 746 AnyM m; 747 m.set_foo("foovalue"); 748 second_nested_any.set_value(m.SerializeAsString()); 749 nested_any.set_value(second_nested_any.SerializeAsString()); 750 any->set_value(nested_any.SerializeAsString()); 751 752 ow_.StartObject("") 753 ->StartObject("any") 754 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") 755 ->StartObject("value") 756 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") 757 ->StartObject("value") 758 ->RenderString("@type", 759 "type.googleapis.com/google.protobuf.testing.anys.AnyM") 760 ->RenderString("foo", "foovalue") 761 ->EndObject() 762 ->EndObject() 763 ->EndObject() 764 ->EndObject(); 765 766 DoTest(out, AnyOut::descriptor()); 767 } 768 769 TEST_P(ProtostreamObjectSourceAnysTest, EmptyAnyOutputsEmptyObject) { 770 AnyOut out; 771 out.mutable_any(); 772 773 ow_.StartObject("")->StartObject("any")->EndObject()->EndObject(); 774 775 DoTest(out, AnyOut::descriptor()); 776 } 777 778 TEST_P(ProtostreamObjectSourceAnysTest, EmptyWithTypeAndNoValueOutputsType) { 779 AnyOut out; 780 out.mutable_any()->set_type_url("foo.googleapis.com/my.Type"); 781 782 ow_.StartObject("") 783 ->StartObject("any") 784 ->RenderString("@type", "foo.googleapis.com/my.Type") 785 ->EndObject() 786 ->EndObject(); 787 788 DoTest(out, AnyOut::descriptor()); 789 } 790 791 TEST_P(ProtostreamObjectSourceAnysTest, MissingTypeUrlError) { 792 AnyOut out; 793 ::google::protobuf::Any* any = out.mutable_any(); 794 795 AnyM m; 796 m.set_foo("foovalue"); 797 any->set_value(m.SerializeAsString()); 798 799 // We start the "AnyOut" part and then fail when we hit the Any object. 800 ow_.StartObject(""); 801 802 Status status = ExecuteTest(out, AnyOut::descriptor()); 803 EXPECT_EQ(util::error::INTERNAL, status.error_code()); 804 } 805 806 TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeServiceError) { 807 AnyOut out; 808 ::google::protobuf::Any* any = out.mutable_any(); 809 any->set_type_url("foo.googleapis.com/my.own.Type"); 810 811 AnyM m; 812 m.set_foo("foovalue"); 813 any->set_value(m.SerializeAsString()); 814 815 // We start the "AnyOut" part and then fail when we hit the Any object. 816 ow_.StartObject(""); 817 818 Status status = ExecuteTest(out, AnyOut::descriptor()); 819 EXPECT_EQ(util::error::INTERNAL, status.error_code()); 820 } 821 822 TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeError) { 823 AnyOut out; 824 ::google::protobuf::Any* any = out.mutable_any(); 825 any->set_type_url("type.googleapis.com/unknown.Type"); 826 827 AnyM m; 828 m.set_foo("foovalue"); 829 any->set_value(m.SerializeAsString()); 830 831 // We start the "AnyOut" part and then fail when we hit the Any object. 832 ow_.StartObject(""); 833 834 Status status = ExecuteTest(out, AnyOut::descriptor()); 835 EXPECT_EQ(util::error::INTERNAL, status.error_code()); 836 } 837 838 class ProtostreamObjectSourceStructTest : public ProtostreamObjectSourceTest { 839 protected: 840 ProtostreamObjectSourceStructTest() { 841 helper_.ResetTypeInfo(StructType::descriptor(), 842 google::protobuf::Struct::descriptor()); 843 } 844 }; 845 846 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 847 ProtostreamObjectSourceStructTest, 848 ::testing::Values( 849 testing::USE_TYPE_RESOLVER)); 850 851 // Tests struct 852 // 853 // "object": { 854 // "k1": 123, 855 // "k2": true 856 // } 857 TEST_P(ProtostreamObjectSourceStructTest, StructRenderSuccess) { 858 StructType out; 859 google::protobuf::Struct* s = out.mutable_object(); 860 s->mutable_fields()->operator[]("k1").set_number_value(123); 861 s->mutable_fields()->operator[]("k2").set_bool_value(true); 862 863 ow_.StartObject("") 864 ->StartObject("object") 865 ->RenderDouble("k1", 123) 866 ->RenderBool("k2", true) 867 ->EndObject() 868 ->EndObject(); 869 870 DoTest(out, StructType::descriptor()); 871 } 872 873 TEST_P(ProtostreamObjectSourceStructTest, MissingValueSkipsField) { 874 StructType out; 875 google::protobuf::Struct* s = out.mutable_object(); 876 s->mutable_fields()->operator[]("k1"); 877 878 ow_.StartObject("")->StartObject("object")->EndObject()->EndObject(); 879 880 DoTest(out, StructType::descriptor()); 881 } 882 883 class ProtostreamObjectSourceFieldMaskTest 884 : public ProtostreamObjectSourceTest { 885 protected: 886 ProtostreamObjectSourceFieldMaskTest() { 887 helper_.ResetTypeInfo(FieldMaskTest::descriptor(), 888 google::protobuf::FieldMask::descriptor()); 889 } 890 }; 891 892 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 893 ProtostreamObjectSourceFieldMaskTest, 894 ::testing::Values( 895 testing::USE_TYPE_RESOLVER)); 896 897 TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) { 898 FieldMaskTest out; 899 out.set_id("1"); 900 out.mutable_single_mask()->add_paths("path1"); 901 out.mutable_single_mask()->add_paths("snake_case_path2"); 902 ::google::protobuf::FieldMask* mask = out.add_repeated_mask(); 903 mask->add_paths("path3"); 904 mask = out.add_repeated_mask(); 905 mask->add_paths("snake_case_path4"); 906 mask->add_paths("path5"); 907 NestedFieldMask* nested = out.add_nested_mask(); 908 nested->set_data("data"); 909 nested->mutable_single_mask()->add_paths("nested.path1"); 910 nested->mutable_single_mask()->add_paths("nested_field.snake_case_path2"); 911 mask = nested->add_repeated_mask(); 912 mask->add_paths("nested_field.path3"); 913 mask->add_paths("nested.snake_case_path4"); 914 mask = nested->add_repeated_mask(); 915 mask->add_paths("nested.path5"); 916 mask = nested->add_repeated_mask(); 917 mask->add_paths( 918 "snake_case.map_field[\"map_key_should_be_ignored\"].nested_snake_case." 919 "map_field[\"map_key_sho\\\"uld_be_ignored\"]"); 920 921 ow_.StartObject("") 922 ->RenderString("id", "1") 923 ->RenderString("singleMask", "path1,snakeCasePath2") 924 ->StartList("repeatedMask") 925 ->RenderString("", "path3") 926 ->RenderString("", "snakeCasePath4,path5") 927 ->EndList() 928 ->StartList("nestedMask") 929 ->StartObject("") 930 ->RenderString("data", "data") 931 ->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2") 932 ->StartList("repeatedMask") 933 ->RenderString("", "nestedField.path3,nested.snakeCasePath4") 934 ->RenderString("", "nested.path5") 935 ->RenderString("", 936 "snakeCase.mapField[\"map_key_should_be_ignored\"]." 937 "nestedSnakeCase.mapField[\"map_key_sho\\\"uld_be_" 938 "ignored\"]") 939 ->EndList() 940 ->EndObject() 941 ->EndList() 942 ->EndObject(); 943 944 DoTest(out, FieldMaskTest::descriptor()); 945 } 946 947 class ProtostreamObjectSourceTimestampTest 948 : public ProtostreamObjectSourceTest { 949 protected: 950 ProtostreamObjectSourceTimestampTest() { 951 helper_.ResetTypeInfo(TimestampDuration::descriptor()); 952 } 953 }; 954 955 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 956 ProtostreamObjectSourceTimestampTest, 957 ::testing::Values( 958 testing::USE_TYPE_RESOLVER)); 959 960 TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) { 961 TimestampDuration out; 962 google::protobuf::Timestamp* ts = out.mutable_ts(); 963 // Min allowed seconds - 1 964 ts->set_seconds(kTimestampMinSeconds - 1); 965 ow_.StartObject(""); 966 967 Status status = ExecuteTest(out, TimestampDuration::descriptor()); 968 EXPECT_EQ(util::error::INTERNAL, status.error_code()); 969 } 970 971 TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) { 972 TimestampDuration out; 973 google::protobuf::Timestamp* ts = out.mutable_ts(); 974 // Max allowed seconds + 1 975 ts->set_seconds(kTimestampMaxSeconds + 1); 976 ow_.StartObject(""); 977 978 Status status = ExecuteTest(out, TimestampDuration::descriptor()); 979 EXPECT_EQ(util::error::INTERNAL, status.error_code()); 980 } 981 982 TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) { 983 TimestampDuration out; 984 google::protobuf::Duration* dur = out.mutable_dur(); 985 // Min allowed seconds - 1 986 dur->set_seconds(kDurationMinSeconds - 1); 987 ow_.StartObject(""); 988 989 Status status = ExecuteTest(out, TimestampDuration::descriptor()); 990 EXPECT_EQ(util::error::INTERNAL, status.error_code()); 991 } 992 993 TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) { 994 TimestampDuration out; 995 google::protobuf::Duration* dur = out.mutable_dur(); 996 // Min allowed seconds + 1 997 dur->set_seconds(kDurationMaxSeconds + 1); 998 ow_.StartObject(""); 999 1000 Status status = ExecuteTest(out, TimestampDuration::descriptor()); 1001 EXPECT_EQ(util::error::INTERNAL, status.error_code()); 1002 } 1003 1004 } // namespace converter 1005 } // namespace util 1006 } // namespace protobuf 1007 } // namespace google 1008