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_objectwriter.h> 32 33 #include <stddef.h> // For size_t 34 35 #include <google/protobuf/field_mask.pb.h> 36 #include <google/protobuf/timestamp.pb.h> 37 #include <google/protobuf/wrappers.pb.h> 38 #include <google/protobuf/io/zero_copy_stream_impl_lite.h> 39 #include <google/protobuf/descriptor.pb.h> 40 #include <google/protobuf/descriptor.h> 41 #include <google/protobuf/dynamic_message.h> 42 #include <google/protobuf/message.h> 43 #include <google/protobuf/util/internal/mock_error_listener.h> 44 #include <google/protobuf/util/internal/testdata/books.pb.h> 45 #include <google/protobuf/util/internal/testdata/field_mask.pb.h> 46 #include <google/protobuf/util/internal/type_info_test_helper.h> 47 #include <google/protobuf/util/internal/constants.h> 48 #include <google/protobuf/util/message_differencer.h> 49 #include <google/protobuf/stubs/bytestream.h> 50 #include <google/protobuf/stubs/strutil.h> 51 #include <google/protobuf/util/internal/testdata/anys.pb.h> 52 #include <google/protobuf/util/internal/testdata/maps.pb.h> 53 #include <google/protobuf/util/internal/testdata/oneofs.pb.h> 54 #include <google/protobuf/util/internal/testdata/struct.pb.h> 55 #include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h> 56 #include <gtest/gtest.h> 57 58 59 namespace google { 60 namespace protobuf { 61 namespace util { 62 namespace converter { 63 64 using google::protobuf::testing::Author; 65 using google::protobuf::testing::Book; 66 using google::protobuf::testing::Book_Data; 67 using google::protobuf::testing::Primitive; 68 using google::protobuf::testing::Publisher; 69 using google::protobuf::Descriptor; 70 using google::protobuf::DescriptorPool; 71 using google::protobuf::DynamicMessageFactory; 72 using google::protobuf::FileDescriptorProto; 73 using google::protobuf::Message; 74 using google::protobuf::io::ArrayInputStream; 75 using strings::GrowingArrayByteSink; 76 using ::testing::_; 77 using ::testing::Args; 78 using google::protobuf::testing::anys::AnyM; 79 using google::protobuf::testing::anys::AnyOut; 80 using google::protobuf::testing::oneofs::OneOfsRequest; 81 using google::protobuf::testing::FieldMaskTest; 82 using google::protobuf::testing::maps::MapIn; 83 using google::protobuf::testing::structs::StructType; 84 using google::protobuf::testing::timestampduration::TimestampDuration; 85 86 87 namespace { 88 string GetTypeUrl(const Descriptor* descriptor) { 89 return string(kTypeServiceBaseUrl) + "/" + descriptor->full_name(); 90 } 91 } // namespace 92 93 #if __cplusplus >= 201103L 94 using std::get; 95 #else 96 using std::tr1::get; 97 #endif 98 99 class BaseProtoStreamObjectWriterTest 100 : public ::testing::TestWithParam<testing::TypeInfoSource> { 101 protected: 102 BaseProtoStreamObjectWriterTest() 103 : helper_(GetParam()), 104 listener_(), 105 output_(new GrowingArrayByteSink(1000)), 106 ow_() {} 107 108 explicit BaseProtoStreamObjectWriterTest(const Descriptor* descriptor) 109 : helper_(GetParam()), 110 listener_(), 111 output_(new GrowingArrayByteSink(1000)), 112 ow_() { 113 vector<const Descriptor*> descriptors; 114 descriptors.push_back(descriptor); 115 ResetTypeInfo(descriptors); 116 } 117 118 explicit BaseProtoStreamObjectWriterTest( 119 vector<const Descriptor*> descriptors) 120 : helper_(GetParam()), 121 listener_(), 122 output_(new GrowingArrayByteSink(1000)), 123 ow_() { 124 ResetTypeInfo(descriptors); 125 } 126 127 void ResetTypeInfo(vector<const Descriptor*> descriptors) { 128 GOOGLE_CHECK(!descriptors.empty()) << "Must have at least one descriptor!"; 129 helper_.ResetTypeInfo(descriptors); 130 ow_.reset(helper_.NewProtoWriter(GetTypeUrl(descriptors[0]), output_.get(), 131 &listener_, options_)); 132 } 133 134 void ResetTypeInfo(const Descriptor* descriptor) { 135 vector<const Descriptor*> descriptors; 136 descriptors.push_back(descriptor); 137 ResetTypeInfo(descriptors); 138 } 139 140 virtual ~BaseProtoStreamObjectWriterTest() {} 141 142 void CheckOutput(const Message& expected, int expected_length) { 143 size_t nbytes; 144 google::protobuf::scoped_array<char> buffer(output_->GetBuffer(&nbytes)); 145 if (expected_length >= 0) { 146 EXPECT_EQ(expected_length, nbytes); 147 } 148 string str(buffer.get(), nbytes); 149 150 std::stringbuf str_buf(str, std::ios_base::in); 151 std::istream istream(&str_buf); 152 google::protobuf::scoped_ptr<Message> message(expected.New()); 153 message->ParsePartialFromIstream(&istream); 154 155 if (!MessageDifferencer::Equivalent(expected, *message)) { 156 EXPECT_EQ(expected.DebugString(), message->DebugString()); 157 } 158 } 159 160 void CheckOutput(const Message& expected) { CheckOutput(expected, -1); } 161 162 const google::protobuf::Type* GetType(const Descriptor* descriptor) { 163 return helper_.GetTypeInfo()->GetTypeByTypeUrl(GetTypeUrl(descriptor)); 164 } 165 166 testing::TypeInfoTestHelper helper_; 167 MockErrorListener listener_; 168 google::protobuf::scoped_ptr<GrowingArrayByteSink> output_; 169 google::protobuf::scoped_ptr<ProtoStreamObjectWriter> ow_; 170 ProtoStreamObjectWriter::Options options_; 171 }; 172 173 MATCHER_P(HasObjectLocation, expected, 174 "Verifies the expected object location") { 175 string actual = get<0>(arg).ToString(); 176 if (actual.compare(expected) == 0) return true; 177 *result_listener << "actual location is: " << actual; 178 return false; 179 } 180 181 class ProtoStreamObjectWriterTest : public BaseProtoStreamObjectWriterTest { 182 protected: 183 ProtoStreamObjectWriterTest() 184 : BaseProtoStreamObjectWriterTest(Book::descriptor()) {} 185 186 virtual ~ProtoStreamObjectWriterTest() {} 187 }; 188 189 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 190 ProtoStreamObjectWriterTest, 191 ::testing::Values( 192 testing::USE_TYPE_RESOLVER)); 193 194 TEST_P(ProtoStreamObjectWriterTest, EmptyObject) { 195 Book empty; 196 ow_->StartObject("")->EndObject(); 197 CheckOutput(empty, 0); 198 } 199 200 TEST_P(ProtoStreamObjectWriterTest, SimpleObject) { 201 string content("My content"); 202 203 Book book; 204 book.set_title("My Title"); 205 book.set_length(222); 206 book.set_content(content); 207 208 ow_->StartObject("") 209 ->RenderString("title", "My Title") 210 ->RenderInt32("length", 222) 211 ->RenderBytes("content", content) 212 ->EndObject(); 213 CheckOutput(book); 214 } 215 216 TEST_P(ProtoStreamObjectWriterTest, SimpleMessage) { 217 Book book; 218 book.set_title("Some Book"); 219 book.set_length(102); 220 Publisher* publisher = book.mutable_publisher(); 221 publisher->set_name("My Publisher"); 222 Author* robert = book.mutable_author(); 223 robert->set_alive(true); 224 robert->set_name("robert"); 225 robert->add_pseudonym("bob"); 226 robert->add_pseudonym("bobby"); 227 robert->add_friend_()->set_name("john"); 228 229 ow_->StartObject("") 230 ->RenderString("title", "Some Book") 231 ->RenderInt32("length", 102) 232 ->StartObject("publisher") 233 ->RenderString("name", "My Publisher") 234 ->EndObject() 235 ->StartObject("author") 236 ->RenderBool("alive", true) 237 ->RenderString("name", "robert") 238 ->StartList("pseudonym") 239 ->RenderString("", "bob") 240 ->RenderString("", "bobby") 241 ->EndList() 242 ->StartList("friend") 243 ->StartObject("") 244 ->RenderString("name", "john") 245 ->EndObject() 246 ->EndList() 247 ->EndObject() 248 ->EndObject(); 249 CheckOutput(book); 250 } 251 252 TEST_P(ProtoStreamObjectWriterTest, CustomJsonName) { 253 Book book; 254 Author* robert = book.mutable_author(); 255 robert->set_id(12345); 256 robert->set_name("robert"); 257 258 ow_->StartObject("") 259 ->StartObject("author") 260 ->RenderUint64("@id", 12345) 261 ->RenderString("name", "robert") 262 ->EndObject() 263 ->EndObject(); 264 CheckOutput(book); 265 } 266 267 TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) { 268 Primitive full; 269 full.set_fix32(101); 270 full.set_u32(102); 271 full.set_i32(-103); 272 full.set_sf32(-104); 273 full.set_s32(-105); 274 full.set_fix64(40000000001L); 275 full.set_u64(40000000002L); 276 full.set_i64(-40000000003L); 277 full.set_sf64(-40000000004L); 278 full.set_s64(-40000000005L); 279 full.set_str("string1"); 280 full.set_bytes("Some Bytes"); 281 full.set_float_(3.14f); 282 full.set_double_(-4.05L); 283 full.set_bool_(true); 284 full.add_rep_fix32(201); 285 full.add_rep_u32(202); 286 full.add_rep_i32(-203); 287 full.add_rep_sf32(-204); 288 full.add_rep_s32(-205); 289 full.add_rep_fix64(80000000001L); 290 full.add_rep_u64(80000000002L); 291 full.add_rep_i64(-80000000003L); 292 full.add_rep_sf64(-80000000004L); 293 full.add_rep_s64(-80000000005L); 294 full.add_rep_str("string2"); 295 full.add_rep_bytes("More Bytes"); 296 full.add_rep_float(6.14f); 297 full.add_rep_double(-8.05L); 298 full.add_rep_bool(false); 299 300 ResetTypeInfo(Primitive::descriptor()); 301 302 ow_->StartObject("") 303 ->RenderString("fix32", "101") 304 ->RenderString("u32", "102") 305 ->RenderString("i32", "-103") 306 ->RenderString("sf32", "-104") 307 ->RenderString("s32", "-105") 308 ->RenderString("fix64", "40000000001") 309 ->RenderString("u64", "40000000002") 310 ->RenderString("i64", "-40000000003") 311 ->RenderString("sf64", "-40000000004") 312 ->RenderString("s64", "-40000000005") 313 ->RenderString("str", "string1") 314 ->RenderString("bytes", "U29tZSBCeXRlcw==") // "Some Bytes" 315 ->RenderString("float", "3.14") 316 ->RenderString("double", "-4.05") 317 ->RenderString("bool", "true") 318 ->StartList("rep_fix32") 319 ->RenderString("", "201") 320 ->EndList() 321 ->StartList("rep_u32") 322 ->RenderString("", "202") 323 ->EndList() 324 ->StartList("rep_i32") 325 ->RenderString("", "-203") 326 ->EndList() 327 ->StartList("rep_sf32") 328 ->RenderString("", "-204") 329 ->EndList() 330 ->StartList("rep_s32") 331 ->RenderString("", "-205") 332 ->EndList() 333 ->StartList("rep_fix64") 334 ->RenderString("", "80000000001") 335 ->EndList() 336 ->StartList("rep_u64") 337 ->RenderString("", "80000000002") 338 ->EndList() 339 ->StartList("rep_i64") 340 ->RenderString("", "-80000000003") 341 ->EndList() 342 ->StartList("rep_sf64") 343 ->RenderString("", "-80000000004") 344 ->EndList() 345 ->StartList("rep_s64") 346 ->RenderString("", "-80000000005") 347 ->EndList() 348 ->StartList("rep_str") 349 ->RenderString("", "string2") 350 ->EndList() 351 ->StartList("rep_bytes") 352 ->RenderString("", "TW9yZSBCeXRlcw==") // "More Bytes" 353 ->EndList() 354 ->StartList("rep_float") 355 ->RenderString("", "6.14") 356 ->EndList() 357 ->StartList("rep_double") 358 ->RenderString("", "-8.05") 359 ->EndList() 360 ->StartList("rep_bool") 361 ->RenderString("", "false") 362 ->EndList() 363 ->EndObject(); 364 CheckOutput(full); 365 } 366 367 TEST_P(ProtoStreamObjectWriterTest, InfinityInputTest) { 368 Primitive full; 369 full.set_double_(std::numeric_limits<double>::infinity()); 370 full.set_float_(std::numeric_limits<float>::infinity()); 371 full.set_str("-Infinity"); 372 373 ResetTypeInfo(Primitive::descriptor()); 374 375 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"), 376 StringPiece("\"Infinity\""))) 377 .With(Args<0>(HasObjectLocation("i32"))); 378 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"), 379 StringPiece("\"Infinity\""))) 380 .With(Args<0>(HasObjectLocation("u32"))); 381 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_SFIXED64"), 382 StringPiece("\"-Infinity\""))) 383 .With(Args<0>(HasObjectLocation("sf64"))); 384 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_BOOL"), 385 StringPiece("\"Infinity\""))) 386 .With(Args<0>(HasObjectLocation("bool"))); 387 388 ow_->StartObject("") 389 ->RenderString("double", "Infinity") 390 ->RenderString("float", "Infinity") 391 ->RenderString("i32", "Infinity") 392 ->RenderString("u32", "Infinity") 393 ->RenderString("sf64", "-Infinity") 394 ->RenderString("str", "-Infinity") 395 ->RenderString("bool", "Infinity") 396 ->EndObject(); 397 CheckOutput(full); 398 } 399 400 TEST_P(ProtoStreamObjectWriterTest, NaNInputTest) { 401 Primitive full; 402 full.set_double_(std::numeric_limits<double>::quiet_NaN()); 403 full.set_float_(std::numeric_limits<float>::quiet_NaN()); 404 full.set_str("NaN"); 405 406 ResetTypeInfo(Primitive::descriptor()); 407 408 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"), 409 StringPiece("\"NaN\""))) 410 .With(Args<0>(HasObjectLocation("i32"))); 411 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"), 412 StringPiece("\"NaN\""))) 413 .With(Args<0>(HasObjectLocation("u32"))); 414 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_SFIXED64"), 415 StringPiece("\"NaN\""))) 416 .With(Args<0>(HasObjectLocation("sf64"))); 417 EXPECT_CALL(listener_, 418 InvalidValue(_, StringPiece("TYPE_BOOL"), StringPiece("\"NaN\""))) 419 .With(Args<0>(HasObjectLocation("bool"))); 420 421 ow_->StartObject("") 422 ->RenderString("double", "NaN") 423 ->RenderString("float", "NaN") 424 ->RenderString("i32", "NaN") 425 ->RenderString("u32", "NaN") 426 ->RenderString("sf64", "NaN") 427 ->RenderString("str", "NaN") 428 ->RenderString("bool", "NaN") 429 ->EndObject(); 430 431 CheckOutput(full); 432 } 433 434 TEST_P(ProtoStreamObjectWriterTest, ImplicitPrimitiveList) { 435 Book expected; 436 Author* author = expected.mutable_author(); 437 author->set_name("The Author"); 438 author->add_pseudonym("first"); 439 author->add_pseudonym("second"); 440 441 ow_->StartObject("") 442 ->StartObject("author") 443 ->RenderString("name", "The Author") 444 ->RenderString("pseudonym", "first") 445 ->RenderString("pseudonym", "second") 446 ->EndObject() 447 ->EndObject(); 448 CheckOutput(expected); 449 } 450 451 TEST_P(ProtoStreamObjectWriterTest, 452 LastWriteWinsOnNonRepeatedPrimitiveFieldWithDuplicates) { 453 Book expected; 454 Author* author = expected.mutable_author(); 455 author->set_name("second"); 456 457 ow_->StartObject("") 458 ->StartObject("author") 459 ->RenderString("name", "first") 460 ->RenderString("name", "second") 461 ->EndObject() 462 ->EndObject(); 463 CheckOutput(expected); 464 } 465 466 TEST_P(ProtoStreamObjectWriterTest, ExplicitPrimitiveList) { 467 Book expected; 468 Author* author = expected.mutable_author(); 469 author->set_name("The Author"); 470 author->add_pseudonym("first"); 471 author->add_pseudonym("second"); 472 473 ow_->StartObject("") 474 ->StartObject("author") 475 ->RenderString("name", "The Author") 476 ->StartList("pseudonym") 477 ->RenderString("", "first") 478 ->RenderString("", "second") 479 ->EndList() 480 ->EndObject() 481 ->EndObject(); 482 CheckOutput(expected); 483 } 484 485 TEST_P(ProtoStreamObjectWriterTest, NonRepeatedExplicitPrimitiveList) { 486 Book expected; 487 expected.set_allocated_author(new Author()); 488 489 EXPECT_CALL( 490 listener_, 491 InvalidName( 492 _, StringPiece("name"), 493 StringPiece("Proto field is not repeating, cannot start list."))) 494 .With(Args<0>(HasObjectLocation("author"))); 495 ow_->StartObject("") 496 ->StartObject("author") 497 ->StartList("name") 498 ->RenderString("", "first") 499 ->RenderString("", "second") 500 ->EndList() 501 ->EndObject() 502 ->EndObject(); 503 CheckOutput(expected); 504 } 505 506 TEST_P(ProtoStreamObjectWriterTest, ImplicitMessageList) { 507 Book expected; 508 Author* outer = expected.mutable_author(); 509 outer->set_name("outer"); 510 outer->set_alive(true); 511 Author* first = outer->add_friend_(); 512 first->set_name("first"); 513 Author* second = outer->add_friend_(); 514 second->set_name("second"); 515 516 ow_->StartObject("") 517 ->StartObject("author") 518 ->RenderString("name", "outer") 519 ->RenderBool("alive", true) 520 ->StartObject("friend") 521 ->RenderString("name", "first") 522 ->EndObject() 523 ->StartObject("friend") 524 ->RenderString("name", "second") 525 ->EndObject() 526 ->EndObject() 527 ->EndObject(); 528 CheckOutput(expected); 529 } 530 531 TEST_P(ProtoStreamObjectWriterTest, 532 LastWriteWinsOnNonRepeatedMessageFieldWithDuplicates) { 533 Book expected; 534 Author* author = expected.mutable_author(); 535 author->set_name("The Author"); 536 Publisher* publisher = expected.mutable_publisher(); 537 publisher->set_name("second"); 538 539 ow_->StartObject("") 540 ->StartObject("author") 541 ->RenderString("name", "The Author") 542 ->EndObject() 543 ->StartObject("publisher") 544 ->RenderString("name", "first") 545 ->EndObject() 546 ->StartObject("publisher") 547 ->RenderString("name", "second") 548 ->EndObject() 549 ->EndObject(); 550 CheckOutput(expected); 551 } 552 553 TEST_P(ProtoStreamObjectWriterTest, ExplicitMessageList) { 554 Book expected; 555 Author* outer = expected.mutable_author(); 556 outer->set_name("outer"); 557 outer->set_alive(true); 558 Author* first = outer->add_friend_(); 559 first->set_name("first"); 560 Author* second = outer->add_friend_(); 561 second->set_name("second"); 562 563 ow_->StartObject("") 564 ->StartObject("author") 565 ->RenderString("name", "outer") 566 ->RenderBool("alive", true) 567 ->StartList("friend") 568 ->StartObject("") 569 ->RenderString("name", "first") 570 ->EndObject() 571 ->StartObject("") 572 ->RenderString("name", "second") 573 ->EndObject() 574 ->EndList() 575 ->EndObject() 576 ->EndObject(); 577 CheckOutput(expected); 578 } 579 580 TEST_P(ProtoStreamObjectWriterTest, NonRepeatedExplicitMessageList) { 581 Book expected; 582 Author* author = expected.mutable_author(); 583 author->set_name("The Author"); 584 585 EXPECT_CALL( 586 listener_, 587 InvalidName( 588 _, StringPiece("publisher"), 589 StringPiece("Proto field is not repeating, cannot start list."))) 590 .With(Args<0>(HasObjectLocation(""))); 591 ow_->StartObject("") 592 ->StartObject("author") 593 ->RenderString("name", "The Author") 594 ->EndObject() 595 ->StartList("publisher") 596 ->StartObject("") 597 ->RenderString("name", "first") 598 ->EndObject() 599 ->StartObject("") 600 ->RenderString("name", "second") 601 ->EndObject() 602 ->EndList() 603 ->EndObject(); 604 CheckOutput(expected); 605 } 606 607 TEST_P(ProtoStreamObjectWriterTest, UnknownFieldAtRoot) { 608 Book empty; 609 610 EXPECT_CALL(listener_, InvalidName(_, StringPiece("unknown"), 611 StringPiece("Cannot find field."))) 612 .With(Args<0>(HasObjectLocation(""))); 613 ow_->StartObject("")->RenderString("unknown", "Nope!")->EndObject(); 614 CheckOutput(empty, 0); 615 } 616 617 TEST_P(ProtoStreamObjectWriterTest, UnknownFieldAtAuthorFriend) { 618 Book expected; 619 Author* paul = expected.mutable_author(); 620 paul->set_name("Paul"); 621 Author* mark = paul->add_friend_(); 622 mark->set_name("Mark"); 623 Author* john = paul->add_friend_(); 624 john->set_name("John"); 625 Author* luke = paul->add_friend_(); 626 luke->set_name("Luke"); 627 628 EXPECT_CALL(listener_, InvalidName(_, StringPiece("address"), 629 StringPiece("Cannot find field."))) 630 .With(Args<0>(HasObjectLocation("author.friend[1]"))); 631 ow_->StartObject("") 632 ->StartObject("author") 633 ->RenderString("name", "Paul") 634 ->StartList("friend") 635 ->StartObject("") 636 ->RenderString("name", "Mark") 637 ->EndObject() 638 ->StartObject("") 639 ->RenderString("name", "John") 640 ->RenderString("address", "Patmos") 641 ->EndObject() 642 ->StartObject("") 643 ->RenderString("name", "Luke") 644 ->EndObject() 645 ->EndList() 646 ->EndObject() 647 ->EndObject(); 648 CheckOutput(expected); 649 } 650 651 TEST_P(ProtoStreamObjectWriterTest, UnknownObjectAtRoot) { 652 Book empty; 653 654 EXPECT_CALL(listener_, InvalidName(_, StringPiece("unknown"), 655 StringPiece("Cannot find field."))) 656 .With(Args<0>(HasObjectLocation(""))); 657 ow_->StartObject("")->StartObject("unknown")->EndObject()->EndObject(); 658 CheckOutput(empty, 0); 659 } 660 661 TEST_P(ProtoStreamObjectWriterTest, UnknownObjectAtAuthor) { 662 Book expected; 663 Author* author = expected.mutable_author(); 664 author->set_name("William"); 665 author->add_pseudonym("Bill"); 666 667 EXPECT_CALL(listener_, InvalidName(_, StringPiece("wife"), 668 StringPiece("Cannot find field."))) 669 .With(Args<0>(HasObjectLocation("author"))); 670 ow_->StartObject("") 671 ->StartObject("author") 672 ->RenderString("name", "William") 673 ->StartObject("wife") 674 ->RenderString("name", "Hilary") 675 ->EndObject() 676 ->RenderString("pseudonym", "Bill") 677 ->EndObject() 678 ->EndObject(); 679 CheckOutput(expected); 680 } 681 682 TEST_P(ProtoStreamObjectWriterTest, UnknownListAtRoot) { 683 Book empty; 684 685 EXPECT_CALL(listener_, InvalidName(_, StringPiece("unknown"), 686 StringPiece("Cannot find field."))) 687 .With(Args<0>(HasObjectLocation(""))); 688 ow_->StartObject("")->StartList("unknown")->EndList()->EndObject(); 689 CheckOutput(empty, 0); 690 } 691 692 TEST_P(ProtoStreamObjectWriterTest, UnknownListAtPublisher) { 693 Book expected; 694 expected.set_title("Brainwashing"); 695 Publisher* publisher = expected.mutable_publisher(); 696 publisher->set_name("propaganda"); 697 698 EXPECT_CALL(listener_, InvalidName(_, StringPiece("alliance"), 699 StringPiece("Cannot find field."))) 700 .With(Args<0>(HasObjectLocation("publisher"))); 701 ow_->StartObject("") 702 ->StartObject("publisher") 703 ->RenderString("name", "propaganda") 704 ->StartList("alliance") 705 ->EndList() 706 ->EndObject() 707 ->RenderString("title", "Brainwashing") 708 ->EndObject(); 709 CheckOutput(expected); 710 } 711 712 TEST_P(ProtoStreamObjectWriterTest, MissingRequiredField) { 713 Book expected; 714 expected.set_title("My Title"); 715 expected.set_allocated_publisher(new Publisher()); 716 717 EXPECT_CALL(listener_, MissingField(_, StringPiece("name"))) 718 .With(Args<0>(HasObjectLocation("publisher"))); 719 ow_->StartObject("") 720 ->StartObject("publisher") 721 ->EndObject() 722 ->RenderString("title", "My Title") 723 ->EndObject(); 724 CheckOutput(expected); 725 } 726 727 TEST_P(ProtoStreamObjectWriterTest, InvalidFieldValueAtRoot) { 728 Book empty; 729 730 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"), 731 StringPiece("\"garbage\""))) 732 .With(Args<0>(HasObjectLocation("length"))); 733 ow_->StartObject("")->RenderString("length", "garbage")->EndObject(); 734 CheckOutput(empty, 0); 735 } 736 737 TEST_P(ProtoStreamObjectWriterTest, MultipleInvalidFieldValues) { 738 Book expected; 739 expected.set_title("My Title"); 740 741 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_UINT32"), 742 StringPiece("\"-400\""))) 743 .With(Args<0>(HasObjectLocation("length"))); 744 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT64"), 745 StringPiece("\"3.14\""))) 746 .With(Args<0>(HasObjectLocation("published"))); 747 ow_->StartObject("") 748 ->RenderString("length", "-400") 749 ->RenderString("published", "3.14") 750 ->RenderString("title", "My Title") 751 ->EndObject(); 752 CheckOutput(expected); 753 } 754 755 TEST_P(ProtoStreamObjectWriterTest, UnnamedFieldAtRoot) { 756 Book empty; 757 758 EXPECT_CALL(listener_, 759 InvalidName(_, StringPiece(""), 760 StringPiece("Proto fields must have a name."))) 761 .With(Args<0>(HasObjectLocation(""))); 762 ow_->StartObject("")->RenderFloat("", 3.14)->EndObject(); 763 CheckOutput(empty, 0); 764 } 765 766 TEST_P(ProtoStreamObjectWriterTest, UnnamedFieldAtAuthor) { 767 Book expected; 768 expected.set_title("noname"); 769 expected.set_allocated_author(new Author()); 770 771 EXPECT_CALL(listener_, 772 InvalidName(_, StringPiece(""), 773 StringPiece("Proto fields must have a name."))) 774 .With(Args<0>(HasObjectLocation("author"))); 775 ow_->StartObject("") 776 ->StartObject("author") 777 ->RenderInt32("", 123) 778 ->EndObject() 779 ->RenderString("title", "noname") 780 ->EndObject(); 781 CheckOutput(expected); 782 } 783 784 TEST_P(ProtoStreamObjectWriterTest, UnnamedListAtRoot) { 785 Book expected; 786 expected.set_title("noname"); 787 788 EXPECT_CALL(listener_, 789 InvalidName(_, StringPiece(""), 790 StringPiece("Proto fields must have a name."))) 791 .With(Args<0>(HasObjectLocation(""))); 792 ow_->StartObject("") 793 ->StartList("") 794 ->EndList() 795 ->RenderString("title", "noname") 796 ->EndObject(); 797 CheckOutput(expected); 798 } 799 800 TEST_P(ProtoStreamObjectWriterTest, RootNamedObject) { 801 Book expected; 802 expected.set_title("Annie"); 803 804 EXPECT_CALL(listener_, 805 InvalidName(_, StringPiece("oops"), 806 StringPiece("Root element should not be named."))) 807 .With(Args<0>(HasObjectLocation(""))); 808 ow_->StartObject("oops")->RenderString("title", "Annie")->EndObject(); 809 CheckOutput(expected, 7); 810 } 811 812 TEST_P(ProtoStreamObjectWriterTest, RootNamedList) { 813 Book empty; 814 815 EXPECT_CALL(listener_, 816 InvalidName(_, StringPiece("oops"), 817 StringPiece("Root element should not be named."))) 818 .With(Args<0>(HasObjectLocation(""))); 819 ow_->StartList("oops")->RenderString("", "item")->EndList(); 820 CheckOutput(empty, 0); 821 } 822 823 TEST_P(ProtoStreamObjectWriterTest, RootUnnamedField) { 824 Book empty; 825 826 EXPECT_CALL(listener_, 827 InvalidName(_, StringPiece(""), 828 StringPiece("Root element must be a message."))) 829 .With(Args<0>(HasObjectLocation(""))); 830 ow_->RenderBool("", true); 831 CheckOutput(empty, 0); 832 } 833 834 TEST_P(ProtoStreamObjectWriterTest, RootNamedField) { 835 Book empty; 836 837 EXPECT_CALL(listener_, 838 InvalidName(_, StringPiece("oops"), 839 StringPiece("Root element must be a message."))) 840 .With(Args<0>(HasObjectLocation(""))); 841 ow_->RenderBool("oops", true); 842 CheckOutput(empty, 0); 843 } 844 845 TEST_P(ProtoStreamObjectWriterTest, NullValue) { 846 Book empty; 847 848 ow_->RenderNull(""); 849 CheckOutput(empty, 0); 850 } 851 852 TEST_P(ProtoStreamObjectWriterTest, NullValueForMessageField) { 853 Book empty; 854 855 ow_->RenderNull("author"); 856 CheckOutput(empty, 0); 857 } 858 859 TEST_P(ProtoStreamObjectWriterTest, NullValueForPrimitiveField) { 860 Book empty; 861 862 ow_->RenderNull("length"); 863 CheckOutput(empty, 0); 864 } 865 866 class ProtoStreamObjectWriterTimestampDurationTest 867 : public BaseProtoStreamObjectWriterTest { 868 protected: 869 ProtoStreamObjectWriterTimestampDurationTest() { 870 vector<const Descriptor*> descriptors; 871 descriptors.push_back(TimestampDuration::descriptor()); 872 descriptors.push_back(google::protobuf::Timestamp::descriptor()); 873 descriptors.push_back(google::protobuf::Duration::descriptor()); 874 ResetTypeInfo(descriptors); 875 } 876 }; 877 878 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 879 ProtoStreamObjectWriterTimestampDurationTest, 880 ::testing::Values( 881 testing::USE_TYPE_RESOLVER)); 882 883 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) { 884 TimestampDuration timestamp; 885 google::protobuf::Timestamp* ts = timestamp.mutable_ts(); 886 ts->set_seconds(1448249855); 887 ts->set_nanos(33155000); 888 889 ow_->StartObject("") 890 ->RenderString("ts", "2015-11-23T03:37:35.033155Z") 891 ->EndObject(); 892 CheckOutput(timestamp); 893 } 894 895 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 896 ParseTimestampYearNotZeroPadded) { 897 TimestampDuration timestamp; 898 google::protobuf::Timestamp* ts = timestamp.mutable_ts(); 899 ts->set_seconds(-61665654145); 900 ts->set_nanos(33155000); 901 902 ow_->StartObject("") 903 ->RenderString("ts", "15-11-23T03:37:35.033155Z") 904 ->EndObject(); 905 CheckOutput(timestamp); 906 } 907 908 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 909 ParseTimestampYearZeroPadded) { 910 TimestampDuration timestamp; 911 google::protobuf::Timestamp* ts = timestamp.mutable_ts(); 912 ts->set_seconds(-61665654145); 913 ts->set_nanos(33155000); 914 915 ow_->StartObject("") 916 ->RenderString("ts", "0015-11-23T03:37:35.033155Z") 917 ->EndObject(); 918 CheckOutput(timestamp); 919 } 920 921 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 922 ParseTimestampWithPositiveOffset) { 923 TimestampDuration timestamp; 924 google::protobuf::Timestamp* ts = timestamp.mutable_ts(); 925 ts->set_seconds(1448249855); 926 ts->set_nanos(33155000); 927 928 ow_->StartObject("") 929 ->RenderString("ts", "2015-11-23T11:47:35.033155+08:10") 930 ->EndObject(); 931 CheckOutput(timestamp); 932 } 933 934 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 935 ParseTimestampWithNegativeOffset) { 936 TimestampDuration timestamp; 937 google::protobuf::Timestamp* ts = timestamp.mutable_ts(); 938 ts->set_seconds(1448249855); 939 ts->set_nanos(33155000); 940 941 ow_->StartObject("") 942 ->RenderString("ts", "2015-11-22T19:47:35.033155-07:50") 943 ->EndObject(); 944 CheckOutput(timestamp); 945 } 946 947 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 948 TimestampWithInvalidOffset1) { 949 TimestampDuration timestamp; 950 951 EXPECT_CALL( 952 listener_, 953 InvalidValue(_, 954 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 955 StringPiece("Field 'ts', Invalid time format: " 956 "2016-03-07T15:14:23+"))); 957 958 ow_->StartObject("")->RenderString("ts", "2016-03-07T15:14:23+")->EndObject(); 959 CheckOutput(timestamp); 960 } 961 962 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 963 TimestampWithInvalidOffset2) { 964 TimestampDuration timestamp; 965 966 EXPECT_CALL( 967 listener_, 968 InvalidValue(_, 969 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 970 StringPiece("Field 'ts', Invalid time format: " 971 "2016-03-07T15:14:23+08-10"))); 972 973 ow_->StartObject("") 974 ->RenderString("ts", "2016-03-07T15:14:23+08-10") 975 ->EndObject(); 976 CheckOutput(timestamp); 977 } 978 979 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 980 TimestampWithInvalidOffset3) { 981 TimestampDuration timestamp; 982 983 EXPECT_CALL( 984 listener_, 985 InvalidValue(_, 986 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 987 StringPiece("Field 'ts', Invalid time format: " 988 "2016-03-07T15:14:23+24:10"))); 989 990 ow_->StartObject("") 991 ->RenderString("ts", "2016-03-07T15:14:23+24:10") 992 ->EndObject(); 993 CheckOutput(timestamp); 994 } 995 996 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 997 TimestampWithInvalidOffset4) { 998 TimestampDuration timestamp; 999 1000 EXPECT_CALL( 1001 listener_, 1002 InvalidValue(_, 1003 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1004 StringPiece("Field 'ts', Invalid time format: " 1005 "2016-03-07T15:14:23+04:60"))); 1006 1007 ow_->StartObject("") 1008 ->RenderString("ts", "2016-03-07T15:14:23+04:60") 1009 ->EndObject(); 1010 CheckOutput(timestamp); 1011 } 1012 1013 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) { 1014 TimestampDuration timestamp; 1015 1016 EXPECT_CALL( 1017 listener_, 1018 InvalidValue(_, 1019 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1020 StringPiece("Field 'ts', Invalid time format: "))); 1021 1022 ow_->StartObject("")->RenderString("ts", "")->EndObject(); 1023 CheckOutput(timestamp); 1024 } 1025 1026 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError2) { 1027 TimestampDuration timestamp; 1028 1029 EXPECT_CALL( 1030 listener_, 1031 InvalidValue(_, 1032 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1033 StringPiece("Field 'ts', Invalid time format: Z"))); 1034 1035 ow_->StartObject("")->RenderString("ts", "Z")->EndObject(); 1036 CheckOutput(timestamp); 1037 } 1038 1039 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError3) { 1040 TimestampDuration timestamp; 1041 1042 EXPECT_CALL( 1043 listener_, 1044 InvalidValue(_, 1045 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1046 StringPiece("Field 'ts', Invalid time format: " 1047 "1970-01-01T00:00:00.ABZ"))); 1048 1049 ow_->StartObject("") 1050 ->RenderString("ts", "1970-01-01T00:00:00.ABZ") 1051 ->EndObject(); 1052 CheckOutput(timestamp); 1053 } 1054 1055 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) { 1056 TimestampDuration timestamp; 1057 1058 EXPECT_CALL( 1059 listener_, 1060 InvalidValue(_, 1061 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1062 StringPiece("Field 'ts', Invalid time format: " 1063 "-8031-10-18T00:00:00.000Z"))); 1064 1065 ow_->StartObject("") 1066 ->RenderString("ts", "-8031-10-18T00:00:00.000Z") 1067 ->EndObject(); 1068 CheckOutput(timestamp); 1069 } 1070 1071 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError5) { 1072 TimestampDuration timestamp; 1073 1074 EXPECT_CALL( 1075 listener_, 1076 InvalidValue(_, 1077 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1078 StringPiece("Field 'ts', Invalid time format: " 1079 "2015-11-23T03:37:35.033155 Z"))); 1080 1081 ow_->StartObject("") 1082 // Whitespace in the Timestamp nanos is not allowed. 1083 ->RenderString("ts", "2015-11-23T03:37:35.033155 Z") 1084 ->EndObject(); 1085 CheckOutput(timestamp); 1086 } 1087 1088 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError6) { 1089 TimestampDuration timestamp; 1090 1091 EXPECT_CALL( 1092 listener_, 1093 InvalidValue(_, 1094 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1095 StringPiece("Field 'ts', Invalid time format: " 1096 "2015-11-23T03:37:35.033155 1234Z"))); 1097 1098 ow_->StartObject("") 1099 // Whitespace in the Timestamp nanos is not allowed. 1100 ->RenderString("ts", "2015-11-23T03:37:35.033155 1234Z") 1101 ->EndObject(); 1102 CheckOutput(timestamp); 1103 } 1104 1105 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError7) { 1106 TimestampDuration timestamp; 1107 1108 EXPECT_CALL( 1109 listener_, 1110 InvalidValue(_, 1111 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1112 StringPiece("Field 'ts', Invalid time format: " 1113 "2015-11-23T03:37:35.033abc155Z"))); 1114 1115 ow_->StartObject("") 1116 // Non-numeric characters in the Timestamp nanos is not allowed. 1117 ->RenderString("ts", "2015-11-23T03:37:35.033abc155Z") 1118 ->EndObject(); 1119 CheckOutput(timestamp); 1120 } 1121 1122 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError8) { 1123 TimestampDuration timestamp; 1124 1125 EXPECT_CALL( 1126 listener_, 1127 InvalidValue(_, 1128 StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1129 StringPiece("Field 'ts', Invalid time format: " 1130 "0-12-31T23:59:59.000Z"))); 1131 1132 ow_->StartObject("") 1133 ->RenderString("ts", "0-12-31T23:59:59.000Z") 1134 ->EndObject(); 1135 CheckOutput(timestamp); 1136 } 1137 1138 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseDuration) { 1139 TimestampDuration duration; 1140 google::protobuf::Duration* dur = duration.mutable_dur(); 1141 dur->set_seconds(1448216930); 1142 dur->set_nanos(132262000); 1143 1144 ow_->StartObject("")->RenderString("dur", "1448216930.132262s")->EndObject(); 1145 CheckOutput(duration); 1146 } 1147 1148 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError1) { 1149 TimestampDuration duration; 1150 1151 EXPECT_CALL( 1152 listener_, 1153 InvalidValue( 1154 _, StringPiece("type.googleapis.com/google.protobuf.Duration"), 1155 StringPiece("Field 'dur', Illegal duration format; duration must " 1156 "end with 's'"))); 1157 1158 ow_->StartObject("")->RenderString("dur", "")->EndObject(); 1159 CheckOutput(duration); 1160 } 1161 1162 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError2) { 1163 TimestampDuration duration; 1164 1165 EXPECT_CALL( 1166 listener_, 1167 InvalidValue( 1168 _, StringPiece("type.googleapis.com/google.protobuf.Duration"), 1169 StringPiece("Field 'dur', Invalid duration format, failed to parse " 1170 "seconds"))); 1171 1172 ow_->StartObject("")->RenderString("dur", "s")->EndObject(); 1173 CheckOutput(duration); 1174 } 1175 1176 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError3) { 1177 TimestampDuration duration; 1178 1179 EXPECT_CALL( 1180 listener_, 1181 InvalidValue( 1182 _, StringPiece("type.googleapis.com/google.protobuf.Duration"), 1183 StringPiece("Field 'dur', Invalid duration format, failed to " 1184 "parse nano seconds"))); 1185 1186 ow_->StartObject("")->RenderString("dur", "123.DEFs")->EndObject(); 1187 CheckOutput(duration); 1188 } 1189 1190 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError4) { 1191 TimestampDuration duration; 1192 1193 EXPECT_CALL( 1194 listener_, 1195 InvalidValue(_, 1196 StringPiece("type.googleapis.com/google.protobuf.Duration"), 1197 StringPiece("Field 'dur', Duration value exceeds limits"))); 1198 1199 ow_->StartObject("")->RenderString("dur", "315576000002s")->EndObject(); 1200 CheckOutput(duration); 1201 } 1202 1203 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError5) { 1204 TimestampDuration duration; 1205 1206 EXPECT_CALL( 1207 listener_, 1208 InvalidValue(_, 1209 StringPiece("type.googleapis.com/google.protobuf.Duration"), 1210 StringPiece("Field 'dur', Duration value exceeds limits"))); 1211 1212 ow_->StartObject("")->RenderString("dur", "0.1000000001s")->EndObject(); 1213 CheckOutput(duration); 1214 } 1215 1216 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 1217 MismatchedTimestampTypeInput) { 1218 TimestampDuration timestamp; 1219 EXPECT_CALL( 1220 listener_, 1221 InvalidValue( 1222 _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), 1223 StringPiece( 1224 "Field 'ts', Invalid data type for timestamp, value is null"))) 1225 .With(Args<0>(HasObjectLocation("ts"))); 1226 ow_->StartObject("")->RenderNull("ts")->EndObject(); 1227 CheckOutput(timestamp); 1228 } 1229 1230 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, 1231 MismatchedDurationTypeInput) { 1232 TimestampDuration duration; 1233 EXPECT_CALL( 1234 listener_, 1235 InvalidValue( 1236 _, StringPiece("type.googleapis.com/google.protobuf.Duration"), 1237 StringPiece( 1238 "Field 'dur', Invalid data type for duration, value is null"))) 1239 .With(Args<0>(HasObjectLocation("dur"))); 1240 ow_->StartObject("")->RenderNull("dur")->EndObject(); 1241 CheckOutput(duration); 1242 } 1243 1244 class ProtoStreamObjectWriterStructTest 1245 : public BaseProtoStreamObjectWriterTest { 1246 protected: 1247 ProtoStreamObjectWriterStructTest() { ResetProtoWriter(); } 1248 1249 // Resets ProtoWriter with current set of options and other state. 1250 void ResetProtoWriter() { 1251 vector<const Descriptor*> descriptors; 1252 descriptors.push_back(StructType::descriptor()); 1253 descriptors.push_back(google::protobuf::Struct::descriptor()); 1254 ResetTypeInfo(descriptors); 1255 } 1256 }; 1257 1258 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 1259 ProtoStreamObjectWriterStructTest, 1260 ::testing::Values( 1261 testing::USE_TYPE_RESOLVER)); 1262 1263 // TODO(skarvaje): Write tests for failure cases. 1264 TEST_P(ProtoStreamObjectWriterStructTest, StructRenderSuccess) { 1265 StructType struct_type; 1266 google::protobuf::Struct* s = struct_type.mutable_object(); 1267 s->mutable_fields()->operator[]("k1").set_number_value(123); 1268 s->mutable_fields()->operator[]("k2").set_bool_value(true); 1269 1270 ow_->StartObject("") 1271 ->StartObject("object") 1272 ->RenderDouble("k1", 123) 1273 ->RenderBool("k2", true) 1274 ->EndObject() 1275 ->EndObject(); 1276 CheckOutput(struct_type); 1277 } 1278 1279 TEST_P(ProtoStreamObjectWriterStructTest, StructNullInputSuccess) { 1280 StructType struct_type; 1281 EXPECT_CALL(listener_, 1282 InvalidName(_, StringPiece(""), 1283 StringPiece("Proto fields must have a name."))) 1284 .With(Args<0>(HasObjectLocation(""))); 1285 ow_->StartObject("")->RenderNull("")->EndObject(); 1286 CheckOutput(struct_type); 1287 } 1288 1289 TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) { 1290 StructType struct_type; 1291 EXPECT_CALL( 1292 listener_, 1293 InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.Struct"), 1294 StringPiece("true"))) 1295 .With(Args<0>(HasObjectLocation("object"))); 1296 1297 ow_->StartObject("")->RenderBool("object", true)->EndObject(); 1298 CheckOutput(struct_type); 1299 } 1300 1301 TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) { 1302 EXPECT_CALL( 1303 listener_, 1304 InvalidName(_, StringPiece("gBike"), 1305 StringPiece("Repeated map key: 'gBike' is already set."))); 1306 ow_->StartObject("") 1307 ->StartObject("object") 1308 ->RenderString("gBike", "v1") 1309 ->RenderString("gBike", "v2") 1310 ->EndObject() 1311 ->EndObject(); 1312 } 1313 1314 TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapListKeyTest) { 1315 EXPECT_CALL( 1316 listener_, 1317 InvalidName(_, StringPiece("k1"), 1318 StringPiece("Repeated map key: 'k1' is already set."))); 1319 ow_->StartObject("") 1320 ->StartObject("object") 1321 ->RenderString("k1", "v1") 1322 ->StartList("k1") 1323 ->RenderString("", "v2") 1324 ->EndList() 1325 ->EndObject() 1326 ->EndObject(); 1327 } 1328 1329 TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) { 1330 EXPECT_CALL( 1331 listener_, 1332 InvalidName(_, StringPiece("k1"), 1333 StringPiece("Repeated map key: 'k1' is already set."))); 1334 ow_->StartObject("") 1335 ->StartObject("object") 1336 ->StartObject("k1") 1337 ->RenderString("sub_k1", "v1") 1338 ->EndObject() 1339 ->StartObject("k1") 1340 ->RenderString("sub_k2", "v2") 1341 ->EndObject() 1342 ->EndObject() 1343 ->EndObject(); 1344 } 1345 1346 TEST_P(ProtoStreamObjectWriterStructTest, OptionStructIntAsStringsTest) { 1347 StructType struct_type; 1348 google::protobuf::Struct* s = struct_type.mutable_object(); 1349 s->mutable_fields()->operator[]("k1").set_number_value(123); 1350 s->mutable_fields()->operator[]("k2").set_bool_value(true); 1351 s->mutable_fields()->operator[]("k3").set_string_value("-222222222"); 1352 s->mutable_fields()->operator[]("k4").set_string_value("33333333"); 1353 1354 options_.struct_integers_as_strings = true; 1355 ResetProtoWriter(); 1356 1357 ow_->StartObject("") 1358 ->StartObject("object") 1359 ->RenderDouble("k1", 123) 1360 ->RenderBool("k2", true) 1361 ->RenderInt64("k3", -222222222) 1362 ->RenderUint64("k4", 33333333) 1363 ->EndObject() 1364 ->EndObject(); 1365 CheckOutput(struct_type); 1366 } 1367 1368 class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest { 1369 protected: 1370 ProtoStreamObjectWriterMapTest() 1371 : BaseProtoStreamObjectWriterTest(MapIn::descriptor()) {} 1372 }; 1373 1374 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 1375 ProtoStreamObjectWriterMapTest, 1376 ::testing::Values( 1377 testing::USE_TYPE_RESOLVER)); 1378 1379 TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) { 1380 MapIn mm; 1381 EXPECT_CALL( 1382 listener_, 1383 InvalidValue( 1384 _, StringPiece("Map"), 1385 StringPiece("Cannot bind a list to map for field 'map_input'."))); 1386 ow_->StartObject("") 1387 ->StartList("map_input") 1388 ->RenderString("a", "b") 1389 ->EndList() 1390 ->EndObject(); 1391 CheckOutput(mm); 1392 } 1393 1394 TEST_P(ProtoStreamObjectWriterMapTest, RepeatedMapKeyTest) { 1395 EXPECT_CALL( 1396 listener_, 1397 InvalidName(_, StringPiece("k1"), 1398 StringPiece("Repeated map key: 'k1' is already set."))); 1399 ow_->StartObject("") 1400 ->RenderString("other", "test") 1401 ->StartObject("map_input") 1402 ->RenderString("k1", "v1") 1403 ->RenderString("k1", "v2") 1404 ->EndObject() 1405 ->EndObject(); 1406 } 1407 1408 class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest { 1409 protected: 1410 ProtoStreamObjectWriterAnyTest() { 1411 vector<const Descriptor*> descriptors; 1412 descriptors.push_back(AnyOut::descriptor()); 1413 descriptors.push_back(google::protobuf::DoubleValue::descriptor()); 1414 descriptors.push_back(google::protobuf::Timestamp::descriptor()); 1415 descriptors.push_back(google::protobuf::Any::descriptor()); 1416 descriptors.push_back(google::protobuf::Value::descriptor()); 1417 descriptors.push_back(google::protobuf::Struct::descriptor()); 1418 ResetTypeInfo(descriptors); 1419 } 1420 }; 1421 1422 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 1423 ProtoStreamObjectWriterAnyTest, 1424 ::testing::Values( 1425 testing::USE_TYPE_RESOLVER)); 1426 1427 TEST_P(ProtoStreamObjectWriterAnyTest, AnyRenderSuccess) { 1428 AnyOut any; 1429 google::protobuf::Any* any_type = any.mutable_any(); 1430 any_type->set_type_url("type.googleapis.com/google.protobuf.DoubleValue"); 1431 google::protobuf::DoubleValue d; 1432 d.set_value(40.2); 1433 any_type->set_value(d.SerializeAsString()); 1434 1435 ow_->StartObject("") 1436 ->StartObject("any") 1437 ->RenderString("@type", "type.googleapis.com/google.protobuf.DoubleValue") 1438 ->RenderDouble("value", 40.2) 1439 ->EndObject() 1440 ->EndObject(); 1441 CheckOutput(any); 1442 } 1443 1444 TEST_P(ProtoStreamObjectWriterAnyTest, RecursiveAny) { 1445 AnyOut out; 1446 ::google::protobuf::Any* any = out.mutable_any(); 1447 any->set_type_url("type.googleapis.com/google.protobuf.Any"); 1448 1449 ::google::protobuf::Any nested_any; 1450 nested_any.set_type_url( 1451 "type.googleapis.com/google.protobuf.testing.anys.AnyM"); 1452 1453 AnyM m; 1454 m.set_foo("foovalue"); 1455 nested_any.set_value(m.SerializeAsString()); 1456 1457 any->set_value(nested_any.SerializeAsString()); 1458 1459 ow_->StartObject("") 1460 ->StartObject("any") 1461 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") 1462 ->StartObject("value") 1463 ->RenderString("@type", 1464 "type.googleapis.com/google.protobuf.testing.anys.AnyM") 1465 ->RenderString("foo", "foovalue") 1466 ->EndObject() 1467 ->EndObject() 1468 ->EndObject(); 1469 } 1470 1471 TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) { 1472 AnyOut out; 1473 ::google::protobuf::Any* any = out.mutable_any(); 1474 any->set_type_url("type.googleapis.com/google.protobuf.Any"); 1475 1476 ::google::protobuf::Any nested_any; 1477 nested_any.set_type_url("type.googleapis.com/google.protobuf.Any"); 1478 1479 ::google::protobuf::Any second_nested_any; 1480 second_nested_any.set_type_url( 1481 "type.googleapis.com/google.protobuf.testing.anys.AnyM"); 1482 1483 AnyM m; 1484 m.set_foo("foovalue"); 1485 second_nested_any.set_value(m.SerializeAsString()); 1486 1487 nested_any.set_value(second_nested_any.SerializeAsString()); 1488 any->set_value(nested_any.SerializeAsString()); 1489 1490 ow_->StartObject("") 1491 ->StartObject("any") 1492 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") 1493 ->StartObject("value") 1494 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") 1495 ->StartObject("value") 1496 ->RenderString("@type", 1497 "type.googleapis.com/google.protobuf.testing.anys.AnyM") 1498 ->RenderString("foo", "foovalue") 1499 ->EndObject() 1500 ->EndObject() 1501 ->EndObject() 1502 ->EndObject(); 1503 } 1504 1505 TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) { 1506 AnyOut out; 1507 out.mutable_any(); 1508 1509 ow_->StartObject("")->StartObject("any")->EndObject()->EndObject(); 1510 1511 CheckOutput(out, 2); 1512 } 1513 1514 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) { 1515 AnyOut any; 1516 1517 EXPECT_CALL( 1518 listener_, 1519 InvalidValue(_, StringPiece("Any"), 1520 StringPiece("Missing or invalid @type for any field in " 1521 "google.protobuf.testing.anys.AnyOut"))); 1522 1523 ow_->StartObject("") 1524 ->StartObject("any") 1525 ->StartObject("another") 1526 ->EndObject() 1527 ->EndObject() 1528 ->EndObject(); 1529 CheckOutput(any); 1530 } 1531 1532 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails2) { 1533 AnyOut any; 1534 1535 EXPECT_CALL( 1536 listener_, 1537 InvalidValue(_, StringPiece("Any"), 1538 StringPiece("Missing or invalid @type for any field in " 1539 "google.protobuf.testing.anys.AnyOut"))); 1540 1541 ow_->StartObject("") 1542 ->StartObject("any") 1543 ->StartList("another") 1544 ->EndObject() 1545 ->EndObject() 1546 ->EndObject(); 1547 CheckOutput(any); 1548 } 1549 1550 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails3) { 1551 AnyOut any; 1552 1553 EXPECT_CALL( 1554 listener_, 1555 InvalidValue(_, StringPiece("Any"), 1556 StringPiece("Missing or invalid @type for any field in " 1557 "google.protobuf.testing.anys.AnyOut"))); 1558 1559 ow_->StartObject("") 1560 ->StartObject("any") 1561 ->RenderString("value", "somevalue") 1562 ->EndObject() 1563 ->EndObject(); 1564 CheckOutput(any); 1565 } 1566 1567 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithInvalidTypeUrlFails) { 1568 AnyOut any; 1569 1570 EXPECT_CALL(listener_, 1571 InvalidValue( 1572 _, StringPiece("Any"), 1573 StringPiece("Invalid type URL, type URLs must be of the form " 1574 "'type.googleapis.com/<typename>', got: " 1575 "type.other.com/some.Type"))); 1576 1577 ow_->StartObject("") 1578 ->StartObject("any") 1579 ->RenderString("@type", "type.other.com/some.Type") 1580 ->RenderDouble("value", 40.2) 1581 ->EndObject() 1582 ->EndObject(); 1583 CheckOutput(any); 1584 } 1585 1586 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithUnknownTypeFails) { 1587 AnyOut any; 1588 1589 EXPECT_CALL( 1590 listener_, 1591 InvalidValue(_, StringPiece("Any"), 1592 StringPiece("Invalid type URL, unknown type: some.Type"))); 1593 ow_->StartObject("") 1594 ->StartObject("any") 1595 ->RenderString("@type", "type.googleapis.com/some.Type") 1596 ->RenderDouble("value", 40.2) 1597 ->EndObject() 1598 ->EndObject(); 1599 CheckOutput(any); 1600 } 1601 1602 TEST_P(ProtoStreamObjectWriterAnyTest, AnyNullInputFails) { 1603 AnyOut any; 1604 1605 ow_->StartObject("")->RenderNull("any")->EndObject(); 1606 CheckOutput(any); 1607 } 1608 1609 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) { 1610 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"), 1611 StringPiece("Invalid time format: "))); 1612 1613 AnyOut any; 1614 google::protobuf::Any* any_type = any.mutable_any(); 1615 any_type->set_type_url("type.googleapis.com/google.protobuf.Timestamp"); 1616 1617 ow_->StartObject("") 1618 ->StartObject("any") 1619 ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp") 1620 ->RenderString("value", "") 1621 ->EndObject() 1622 ->EndObject(); 1623 CheckOutput(any); 1624 } 1625 1626 // Test the following case: 1627 // 1628 // { 1629 // "any": { 1630 // "@type": "type.googleapis.com/google.protobuf.Value", 1631 // "value": "abc" 1632 // } 1633 // } 1634 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedPrimitiveValue) { 1635 AnyOut out; 1636 ::google::protobuf::Any* any = out.mutable_any(); 1637 1638 ::google::protobuf::Value value; 1639 value.set_string_value("abc"); 1640 any->PackFrom(value); 1641 1642 ow_->StartObject("") 1643 ->StartObject("any") 1644 ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") 1645 ->RenderString("value", "abc") 1646 ->EndObject() 1647 ->EndObject(); 1648 CheckOutput(out); 1649 } 1650 1651 // Test the following case: 1652 // 1653 // { 1654 // "any": { 1655 // "@type": "type.googleapis.com/google.protobuf.Value", 1656 // "value": { 1657 // "foo": "abc" 1658 // } 1659 // } 1660 // } 1661 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedObjectValue) { 1662 AnyOut out; 1663 ::google::protobuf::Any* any = out.mutable_any(); 1664 1665 ::google::protobuf::Value value; 1666 (*value.mutable_struct_value()->mutable_fields())["foo"].set_string_value( 1667 "abc"); 1668 any->PackFrom(value); 1669 1670 ow_->StartObject("") 1671 ->StartObject("any") 1672 ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") 1673 ->StartObject("value") 1674 ->RenderString("foo", "abc") 1675 ->EndObject() 1676 ->EndObject() 1677 ->EndObject(); 1678 CheckOutput(out); 1679 } 1680 1681 // Test the following case: 1682 // 1683 // { 1684 // "any": { 1685 // "@type": "type.googleapis.com/google.protobuf.Value", 1686 // "value": ["hello"], 1687 // } 1688 // } 1689 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedArrayValue) { 1690 AnyOut out; 1691 ::google::protobuf::Any* any = out.mutable_any(); 1692 1693 ::google::protobuf::Value value; 1694 value.mutable_list_value()->add_values()->set_string_value("hello"); 1695 any->PackFrom(value); 1696 1697 ow_->StartObject("") 1698 ->StartObject("any") 1699 ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") 1700 ->StartList("value") 1701 ->RenderString("", "hello") 1702 ->EndList() 1703 ->EndObject() 1704 ->EndObject() 1705 ->EndObject(); 1706 CheckOutput(out); 1707 } 1708 1709 // Test the following case: 1710 // 1711 // { 1712 // "any": { 1713 // "@type": "type.googleapis.com/google.protobuf.Value", 1714 // "not_value": "" 1715 // } 1716 // } 1717 TEST_P(ProtoStreamObjectWriterAnyTest, 1718 AnyWellKnownTypesNoValueFieldForPrimitive) { 1719 EXPECT_CALL( 1720 listener_, 1721 InvalidValue( 1722 _, StringPiece("Any"), 1723 StringPiece("Expect a \"value\" field for well-known types."))); 1724 AnyOut any; 1725 google::protobuf::Any* any_type = any.mutable_any(); 1726 any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); 1727 1728 ow_->StartObject("") 1729 ->StartObject("any") 1730 ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") 1731 ->RenderString("not_value", "") 1732 ->EndObject() 1733 ->EndObject(); 1734 CheckOutput(any); 1735 } 1736 1737 // Test the following case: 1738 // 1739 // { 1740 // "any": { 1741 // "@type": "type.googleapis.com/google.protobuf.Value", 1742 // "not_value": {} 1743 // } 1744 // } 1745 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForObject) { 1746 EXPECT_CALL( 1747 listener_, 1748 InvalidValue( 1749 _, StringPiece("Any"), 1750 StringPiece("Expect a \"value\" field for well-known types."))); 1751 AnyOut any; 1752 google::protobuf::Any* any_type = any.mutable_any(); 1753 any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); 1754 1755 ow_->StartObject("") 1756 ->StartObject("any") 1757 ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") 1758 ->StartObject("not_value") 1759 ->EndObject() 1760 ->EndObject() 1761 ->EndObject(); 1762 CheckOutput(any); 1763 } 1764 1765 // Test the following case: 1766 // 1767 // { 1768 // "any": { 1769 // "@type": "type.googleapis.com/google.protobuf.Value", 1770 // "not_value": [], 1771 // } 1772 // } 1773 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForArray) { 1774 EXPECT_CALL( 1775 listener_, 1776 InvalidValue( 1777 _, StringPiece("Any"), 1778 StringPiece("Expect a \"value\" field for well-known types."))); 1779 AnyOut any; 1780 google::protobuf::Any* any_type = any.mutable_any(); 1781 any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); 1782 1783 ow_->StartObject("") 1784 ->StartObject("any") 1785 ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") 1786 ->StartList("not_value") 1787 ->EndList() 1788 ->EndObject() 1789 ->EndObject() 1790 ->EndObject(); 1791 CheckOutput(any); 1792 } 1793 1794 // Test the following case: 1795 // 1796 // { 1797 // "any": { 1798 // "@type": "type.googleapis.com/google.protobuf.Struct", 1799 // "value": "", 1800 // } 1801 // } 1802 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForStruct) { 1803 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"), 1804 StringPiece("Expect a JSON object."))); 1805 AnyOut any; 1806 google::protobuf::Any* any_type = any.mutable_any(); 1807 any_type->set_type_url("type.googleapis.com/google.protobuf.Struct"); 1808 1809 ow_->StartObject("") 1810 ->StartObject("any") 1811 ->RenderString("@type", "type.googleapis.com/google.protobuf.Struct") 1812 ->RenderString("value", "") 1813 ->EndObject() 1814 ->EndObject(); 1815 CheckOutput(any); 1816 } 1817 1818 // Test the following case: 1819 // 1820 // { 1821 // "any": { 1822 // "@type": "type.googleapis.com/google.protobuf.Any", 1823 // "value": "", 1824 // } 1825 // } 1826 TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForAny) { 1827 EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"), 1828 StringPiece("Expect a JSON object."))); 1829 AnyOut any; 1830 google::protobuf::Any* any_type = any.mutable_any(); 1831 any_type->set_type_url("type.googleapis.com/google.protobuf.Any"); 1832 1833 ow_->StartObject("") 1834 ->StartObject("any") 1835 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") 1836 ->RenderString("value", "") 1837 ->EndObject() 1838 ->EndObject(); 1839 CheckOutput(any); 1840 } 1841 1842 class ProtoStreamObjectWriterFieldMaskTest 1843 : public BaseProtoStreamObjectWriterTest { 1844 protected: 1845 ProtoStreamObjectWriterFieldMaskTest() { 1846 vector<const Descriptor*> descriptors; 1847 descriptors.push_back(FieldMaskTest::descriptor()); 1848 descriptors.push_back(google::protobuf::FieldMask::descriptor()); 1849 ResetTypeInfo(descriptors); 1850 } 1851 }; 1852 1853 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 1854 ProtoStreamObjectWriterFieldMaskTest, 1855 ::testing::Values( 1856 testing::USE_TYPE_RESOLVER)); 1857 1858 TEST_P(ProtoStreamObjectWriterFieldMaskTest, SimpleFieldMaskTest) { 1859 FieldMaskTest expected; 1860 expected.set_id("1"); 1861 expected.mutable_single_mask()->add_paths("path1"); 1862 1863 ow_->StartObject(""); 1864 ow_->RenderString("id", "1"); 1865 ow_->RenderString("single_mask", "path1"); 1866 ow_->EndObject(); 1867 1868 CheckOutput(expected); 1869 } 1870 1871 TEST_P(ProtoStreamObjectWriterFieldMaskTest, MutipleMasksInCompactForm) { 1872 FieldMaskTest expected; 1873 expected.set_id("1"); 1874 expected.mutable_single_mask()->add_paths("camel_case1"); 1875 expected.mutable_single_mask()->add_paths("camel_case2"); 1876 expected.mutable_single_mask()->add_paths("camel_case3"); 1877 1878 ow_->StartObject(""); 1879 ow_->RenderString("id", "1"); 1880 ow_->RenderString("single_mask", "camelCase1,camelCase2,camelCase3"); 1881 ow_->EndObject(); 1882 1883 CheckOutput(expected); 1884 } 1885 1886 TEST_P(ProtoStreamObjectWriterFieldMaskTest, RepeatedFieldMaskTest) { 1887 FieldMaskTest expected; 1888 expected.set_id("1"); 1889 google::protobuf::FieldMask* mask = expected.add_repeated_mask(); 1890 mask->add_paths("field1"); 1891 mask->add_paths("field2"); 1892 expected.add_repeated_mask()->add_paths("field3"); 1893 1894 ow_->StartObject(""); 1895 ow_->RenderString("id", "1"); 1896 ow_->StartList("repeated_mask"); 1897 ow_->RenderString("", "field1,field2"); 1898 ow_->RenderString("", "field3"); 1899 ow_->EndList(); 1900 ow_->EndObject(); 1901 1902 CheckOutput(expected); 1903 } 1904 1905 TEST_P(ProtoStreamObjectWriterFieldMaskTest, EmptyFieldMaskTest) { 1906 FieldMaskTest expected; 1907 expected.set_id("1"); 1908 1909 ow_->StartObject(""); 1910 ow_->RenderString("id", "1"); 1911 ow_->RenderString("single_mask", ""); 1912 ow_->EndObject(); 1913 1914 CheckOutput(expected); 1915 } 1916 1917 TEST_P(ProtoStreamObjectWriterFieldMaskTest, MaskUsingApiaryStyleShouldWork) { 1918 FieldMaskTest expected; 1919 expected.set_id("1"); 1920 1921 ow_->StartObject(""); 1922 ow_->RenderString("id", "1"); 1923 // Case1 1924 ow_->RenderString("single_mask", 1925 "outerField(camelCase1,camelCase2,camelCase3)"); 1926 expected.mutable_single_mask()->add_paths("outer_field.camel_case1"); 1927 expected.mutable_single_mask()->add_paths("outer_field.camel_case2"); 1928 expected.mutable_single_mask()->add_paths("outer_field.camel_case3"); 1929 1930 ow_->StartList("repeated_mask"); 1931 1932 ow_->RenderString("", "a(field1,field2)"); 1933 google::protobuf::FieldMask* mask = expected.add_repeated_mask(); 1934 mask->add_paths("a.field1"); 1935 mask->add_paths("a.field2"); 1936 1937 ow_->RenderString("", "a(field3)"); 1938 mask = expected.add_repeated_mask(); 1939 mask->add_paths("a.field3"); 1940 1941 ow_->RenderString("", "a()"); 1942 expected.add_repeated_mask(); 1943 1944 ow_->RenderString("", "a(,)"); 1945 expected.add_repeated_mask(); 1946 1947 ow_->RenderString("", "a(field1(field2(field3)))"); 1948 mask = expected.add_repeated_mask(); 1949 mask->add_paths("a.field1.field2.field3"); 1950 1951 ow_->RenderString("", "a(field1(field2(field3,field4),field5),field6)"); 1952 mask = expected.add_repeated_mask(); 1953 mask->add_paths("a.field1.field2.field3"); 1954 mask->add_paths("a.field1.field2.field4"); 1955 mask->add_paths("a.field1.field5"); 1956 mask->add_paths("a.field6"); 1957 1958 ow_->RenderString("", "a(id,field1(id,field2(field3,field4),field5),field6)"); 1959 mask = expected.add_repeated_mask(); 1960 mask->add_paths("a.id"); 1961 mask->add_paths("a.field1.id"); 1962 mask->add_paths("a.field1.field2.field3"); 1963 mask->add_paths("a.field1.field2.field4"); 1964 mask->add_paths("a.field1.field5"); 1965 mask->add_paths("a.field6"); 1966 1967 ow_->RenderString("", "a(((field3,field4)))"); 1968 mask = expected.add_repeated_mask(); 1969 mask->add_paths("a.field3"); 1970 mask->add_paths("a.field4"); 1971 1972 ow_->EndList(); 1973 ow_->EndObject(); 1974 1975 CheckOutput(expected); 1976 } 1977 1978 TEST_P(ProtoStreamObjectWriterFieldMaskTest, MoreCloseThanOpenParentheses) { 1979 EXPECT_CALL( 1980 listener_, 1981 InvalidValue( 1982 _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), 1983 StringPiece("Field 'single_mask', Invalid FieldMask 'a(b,c))'. " 1984 "Cannot find matching '(' for all ')'."))); 1985 1986 ow_->StartObject(""); 1987 ow_->RenderString("id", "1"); 1988 ow_->RenderString("single_mask", "a(b,c))"); 1989 ow_->EndObject(); 1990 } 1991 1992 TEST_P(ProtoStreamObjectWriterFieldMaskTest, MoreOpenThanCloseParentheses) { 1993 EXPECT_CALL( 1994 listener_, 1995 InvalidValue( 1996 _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), 1997 StringPiece( 1998 "Field 'single_mask', Invalid FieldMask 'a(((b,c)'. Cannot " 1999 "find matching ')' for all '('."))); 2000 2001 ow_->StartObject(""); 2002 ow_->RenderString("id", "1"); 2003 ow_->RenderString("single_mask", "a(((b,c)"); 2004 ow_->EndObject(); 2005 } 2006 2007 TEST_P(ProtoStreamObjectWriterFieldMaskTest, PathWithMapKeyShouldWork) { 2008 FieldMaskTest expected; 2009 expected.mutable_single_mask()->add_paths("path.to.map[\"key1\"]"); 2010 expected.mutable_single_mask()->add_paths( 2011 "path.to.map[\"e\\\"[]][scape\\\"\"]"); 2012 expected.mutable_single_mask()->add_paths("path.to.map[\"key2\"]"); 2013 2014 ow_->StartObject(""); 2015 ow_->RenderString("single_mask", 2016 "path.to.map[\"key1\"],path.to.map[\"e\\\"[]][scape\\\"\"]," 2017 "path.to.map[\"key2\"]"); 2018 ow_->EndObject(); 2019 2020 CheckOutput(expected); 2021 } 2022 2023 TEST_P(ProtoStreamObjectWriterFieldMaskTest, 2024 MapKeyMustBeAtTheEndOfAPathSegment) { 2025 EXPECT_CALL( 2026 listener_, 2027 InvalidValue( 2028 _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), 2029 StringPiece("Field 'single_mask', Invalid FieldMask " 2030 "'path.to.map[\"key1\"]a,path.to.map[\"key2\"]'. " 2031 "Map keys should be at the end of a path segment."))); 2032 2033 ow_->StartObject(""); 2034 ow_->RenderString("single_mask", 2035 "path.to.map[\"key1\"]a,path.to.map[\"key2\"]"); 2036 ow_->EndObject(); 2037 } 2038 2039 TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustEnd) { 2040 EXPECT_CALL( 2041 listener_, 2042 InvalidValue(_, 2043 StringPiece("type.googleapis.com/google.protobuf.FieldMask"), 2044 StringPiece("Field 'single_mask', Invalid FieldMask " 2045 "'path.to.map[\"key1\"'. Map keys should be " 2046 "represented as [\"some_key\"]."))); 2047 2048 ow_->StartObject(""); 2049 ow_->RenderString("single_mask", "path.to.map[\"key1\""); 2050 ow_->EndObject(); 2051 } 2052 2053 TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustBeEscapedCorrectly) { 2054 EXPECT_CALL( 2055 listener_, 2056 InvalidValue(_, 2057 StringPiece("type.googleapis.com/google.protobuf.FieldMask"), 2058 StringPiece("Field 'single_mask', Invalid FieldMask " 2059 "'path.to.map[\"ke\"y1\"]'. Map keys should be " 2060 "represented as [\"some_key\"]."))); 2061 2062 ow_->StartObject(""); 2063 ow_->RenderString("single_mask", "path.to.map[\"ke\"y1\"]"); 2064 ow_->EndObject(); 2065 } 2066 2067 TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyCanContainAnyChars) { 2068 FieldMaskTest expected; 2069 expected.mutable_single_mask()->add_paths( 2070 // \xE5\xAD\x99 is the UTF-8 byte sequence for chinese character . 2071 // We cannot embed non-ASCII characters in the code directly because 2072 // some windows compilers will try to interpret them using the system's 2073 // current encoding and end up with invalid UTF-8 byte sequence. 2074 "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"]"); 2075 expected.mutable_single_mask()->add_paths("path.to.map[\"key2\"]"); 2076 2077 ow_->StartObject(""); 2078 ow_->RenderString( 2079 "single_mask", 2080 "path.to.map[\"(),[],\\\"'!@#$%^&*123_|War\xE5\xAD\x99,./?><\\\\\"]," 2081 "path.to.map[\"key2\"]"); 2082 ow_->EndObject(); 2083 2084 CheckOutput(expected); 2085 } 2086 2087 class ProtoStreamObjectWriterOneOfsTest 2088 : public BaseProtoStreamObjectWriterTest { 2089 protected: 2090 ProtoStreamObjectWriterOneOfsTest() { 2091 vector<const Descriptor*> descriptors; 2092 descriptors.push_back(OneOfsRequest::descriptor()); 2093 descriptors.push_back(google::protobuf::Struct::descriptor()); 2094 ResetTypeInfo(descriptors); 2095 } 2096 }; 2097 2098 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 2099 ProtoStreamObjectWriterOneOfsTest, 2100 ::testing::Values( 2101 testing::USE_TYPE_RESOLVER)); 2102 2103 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2104 MultipleOneofsFailForPrimitiveTypesTest) { 2105 EXPECT_CALL( 2106 listener_, 2107 InvalidValue( 2108 _, StringPiece("oneof"), 2109 StringPiece( 2110 "oneof field 'data' is already set. Cannot set 'intData'"))); 2111 2112 ow_->StartObject(""); 2113 ow_->RenderString("strData", "blah"); 2114 ow_->RenderString("intData", "123"); 2115 ow_->EndObject(); 2116 } 2117 2118 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2119 MultipleOneofsFailForMessageTypesPrimitiveFirstTest) { 2120 // Test for setting primitive oneof field first and then message field. 2121 EXPECT_CALL(listener_, 2122 InvalidValue(_, StringPiece("oneof"), 2123 StringPiece("oneof field 'data' is already set. " 2124 "Cannot set 'messageData'"))); 2125 2126 // JSON: { "strData": "blah", "messageData": { "dataValue": 123 } } 2127 ow_->StartObject(""); 2128 ow_->RenderString("strData", "blah"); 2129 ow_->StartObject("messageData"); 2130 ow_->RenderInt32("dataValue", 123); 2131 ow_->EndObject(); 2132 ow_->EndObject(); 2133 } 2134 2135 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2136 MultipleOneofsFailForMessageTypesMessageFirstTest) { 2137 // Test for setting message oneof field first and then primitive field. 2138 EXPECT_CALL(listener_, 2139 InvalidValue(_, StringPiece("oneof"), 2140 StringPiece("oneof field 'data' is already set. " 2141 "Cannot set 'strData'"))); 2142 2143 // JSON: { "messageData": { "dataValue": 123 }, "strData": "blah" } 2144 ow_->StartObject(""); 2145 ow_->StartObject("messageData"); 2146 ow_->RenderInt32("dataValue", 123); 2147 ow_->EndObject(); 2148 ow_->RenderString("strData", "blah"); 2149 ow_->EndObject(); 2150 } 2151 2152 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2153 MultipleOneofsFailForStructTypesPrimitiveFirstTest) { 2154 EXPECT_CALL(listener_, 2155 InvalidValue(_, StringPiece("oneof"), 2156 StringPiece("oneof field 'data' is already set. " 2157 "Cannot set 'structData'"))); 2158 2159 // JSON: { "strData": "blah", "structData": { "a": "b" } } 2160 ow_->StartObject(""); 2161 ow_->RenderString("strData", "blah"); 2162 ow_->StartObject("structData"); 2163 ow_->RenderString("a", "b"); 2164 ow_->EndObject(); 2165 ow_->EndObject(); 2166 } 2167 2168 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2169 MultipleOneofsFailForStructTypesStructFirstTest) { 2170 EXPECT_CALL(listener_, 2171 InvalidValue(_, StringPiece("oneof"), 2172 StringPiece("oneof field 'data' is already set. " 2173 "Cannot set 'strData'"))); 2174 2175 // JSON: { "structData": { "a": "b" }, "strData": "blah" } 2176 ow_->StartObject(""); 2177 ow_->StartObject("structData"); 2178 ow_->RenderString("a", "b"); 2179 ow_->EndObject(); 2180 ow_->RenderString("strData", "blah"); 2181 ow_->EndObject(); 2182 } 2183 2184 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2185 MultipleOneofsFailForStructValueTypesTest) { 2186 EXPECT_CALL(listener_, 2187 InvalidValue(_, StringPiece("oneof"), 2188 StringPiece("oneof field 'data' is already set. " 2189 "Cannot set 'valueData'"))); 2190 2191 // JSON: { "messageData": { "dataValue": 123 }, "valueData": { "a": "b" } } 2192 ow_->StartObject(""); 2193 ow_->StartObject("messageData"); 2194 ow_->RenderInt32("dataValue", 123); 2195 ow_->EndObject(); 2196 ow_->StartObject("valueData"); 2197 ow_->RenderString("a", "b"); 2198 ow_->EndObject(); 2199 ow_->EndObject(); 2200 } 2201 2202 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2203 MultipleOneofsFailForWellKnownTypesPrimitiveFirstTest) { 2204 EXPECT_CALL(listener_, 2205 InvalidValue(_, StringPiece("oneof"), 2206 StringPiece("oneof field 'data' is already set. " 2207 "Cannot set 'tsData'"))); 2208 2209 // JSON: { "intData": 123, "tsData": "1970-01-02T01:00:00.000Z" } 2210 ow_->StartObject(""); 2211 ow_->RenderInt32("intData", 123); 2212 ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); 2213 ow_->EndObject(); 2214 } 2215 2216 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2217 MultipleOneofsFailForWellKnownTypesWktFirstTest) { 2218 EXPECT_CALL(listener_, 2219 InvalidValue(_, StringPiece("oneof"), 2220 StringPiece("oneof field 'data' is already set. " 2221 "Cannot set 'intData'"))); 2222 2223 // JSON: { "tsData": "1970-01-02T01:00:00.000Z", "intData": 123 } 2224 ow_->StartObject(""); 2225 ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); 2226 ow_->RenderInt32("intData", 123); 2227 ow_->EndObject(); 2228 } 2229 2230 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2231 MultipleOneofsFailForWellKnownTypesAndMessageTest) { 2232 EXPECT_CALL(listener_, 2233 InvalidValue(_, StringPiece("oneof"), 2234 StringPiece("oneof field 'data' is already set. " 2235 "Cannot set 'messageData'"))); 2236 2237 // JSON: { "tsData": "1970-01-02T01:00:00.000Z", 2238 // "messageData": { "dataValue": 123 } } 2239 ow_->StartObject(""); 2240 ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); 2241 ow_->StartObject("messageData"); 2242 ow_->RenderInt32("dataValue", 123); 2243 ow_->EndObject(); 2244 ow_->EndObject(); 2245 } 2246 2247 TEST_P(ProtoStreamObjectWriterOneOfsTest, 2248 MultipleOneofsFailForOneofWithinAnyTest) { 2249 EXPECT_CALL(listener_, 2250 InvalidValue(_, StringPiece("oneof"), 2251 StringPiece("oneof field 'data' is already set. " 2252 "Cannot set 'intData'"))); 2253 2254 using google::protobuf::testing::oneofs::OneOfsRequest; 2255 // JSON: 2256 // { "anyData": 2257 // { "@type": 2258 // "type.googleapis.com/google.protobuf.testing.oneofs.OneOfsRequest", 2259 // "strData": "blah", 2260 // "intData": 123 2261 // } 2262 // } 2263 ow_->StartObject(""); 2264 ow_->StartObject("anyData"); 2265 ow_->RenderString( 2266 "@type", 2267 "type.googleapis.com/google.protobuf.testing.oneofs.OneOfsRequest"); 2268 ow_->RenderString("strData", "blah"); 2269 ow_->RenderInt32("intData", 123); 2270 ow_->EndObject(); 2271 ow_->EndObject(); 2272 } 2273 2274 } // namespace converter 2275 } // namespace util 2276 } // namespace protobuf 2277 } // namespace google 2278