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 59namespace google { 60namespace protobuf { 61namespace util { 62namespace converter { 63 64using google::protobuf::testing::Author; 65using google::protobuf::testing::Book; 66using google::protobuf::testing::Book_Data; 67using google::protobuf::testing::Primitive; 68using google::protobuf::testing::Publisher; 69using google::protobuf::Descriptor; 70using google::protobuf::DescriptorPool; 71using google::protobuf::DynamicMessageFactory; 72using google::protobuf::FileDescriptorProto; 73using google::protobuf::Message; 74using google::protobuf::io::ArrayInputStream; 75using strings::GrowingArrayByteSink; 76using ::testing::_; 77using ::testing::Args; 78using google::protobuf::testing::anys::AnyM; 79using google::protobuf::testing::anys::AnyOut; 80using google::protobuf::testing::oneofs::OneOfsRequest; 81using google::protobuf::testing::FieldMaskTest; 82using google::protobuf::testing::maps::MapIn; 83using google::protobuf::testing::structs::StructType; 84using google::protobuf::testing::timestampduration::TimestampDuration; 85 86 87namespace { 88string 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 99class 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 173MATCHER_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 181class ProtoStreamObjectWriterTest : public BaseProtoStreamObjectWriterTest { 182 protected: 183 ProtoStreamObjectWriterTest() 184 : BaseProtoStreamObjectWriterTest(Book::descriptor()) {} 185 186 virtual ~ProtoStreamObjectWriterTest() {} 187}; 188 189INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 190 ProtoStreamObjectWriterTest, 191 ::testing::Values( 192 testing::USE_TYPE_RESOLVER)); 193 194TEST_P(ProtoStreamObjectWriterTest, EmptyObject) { 195 Book empty; 196 ow_->StartObject("")->EndObject(); 197 CheckOutput(empty, 0); 198} 199 200TEST_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 216TEST_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 252TEST_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 267TEST_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 367TEST_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 400TEST_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 434TEST_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 451TEST_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 466TEST_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 485TEST_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 506TEST_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 531TEST_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 553TEST_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 580TEST_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 607TEST_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 617TEST_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 651TEST_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 661TEST_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 682TEST_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 692TEST_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 712TEST_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 727TEST_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 737TEST_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 755TEST_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 766TEST_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 784TEST_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 800TEST_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 812TEST_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 823TEST_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 834TEST_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 845TEST_P(ProtoStreamObjectWriterTest, NullValue) { 846 Book empty; 847 848 ow_->RenderNull(""); 849 CheckOutput(empty, 0); 850} 851 852TEST_P(ProtoStreamObjectWriterTest, NullValueForMessageField) { 853 Book empty; 854 855 ow_->RenderNull("author"); 856 CheckOutput(empty, 0); 857} 858 859TEST_P(ProtoStreamObjectWriterTest, NullValueForPrimitiveField) { 860 Book empty; 861 862 ow_->RenderNull("length"); 863 CheckOutput(empty, 0); 864} 865 866class 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 878INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 879 ProtoStreamObjectWriterTimestampDurationTest, 880 ::testing::Values( 881 testing::USE_TYPE_RESOLVER)); 882 883TEST_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 895TEST_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 908TEST_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 921TEST_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 934TEST_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 947TEST_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 962TEST_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 979TEST_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 996TEST_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 1013TEST_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 1026TEST_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 1039TEST_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 1055TEST_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 1071TEST_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 1088TEST_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 1105TEST_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 1122TEST_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 1138TEST_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 1148TEST_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 1162TEST_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 1176TEST_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 1190TEST_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 1203TEST_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 1216TEST_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 1230TEST_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 1244class 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 1258INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 1259 ProtoStreamObjectWriterStructTest, 1260 ::testing::Values( 1261 testing::USE_TYPE_RESOLVER)); 1262 1263// TODO(skarvaje): Write tests for failure cases. 1264TEST_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 1279TEST_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 1289TEST_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 1301TEST_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 1314TEST_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 1329TEST_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 1346TEST_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 1368class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest { 1369 protected: 1370 ProtoStreamObjectWriterMapTest() 1371 : BaseProtoStreamObjectWriterTest(MapIn::descriptor()) {} 1372}; 1373 1374INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 1375 ProtoStreamObjectWriterMapTest, 1376 ::testing::Values( 1377 testing::USE_TYPE_RESOLVER)); 1378 1379TEST_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 1394TEST_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 1408class 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 1422INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 1423 ProtoStreamObjectWriterAnyTest, 1424 ::testing::Values( 1425 testing::USE_TYPE_RESOLVER)); 1426 1427TEST_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 1444TEST_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 1471TEST_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 1505TEST_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 1514TEST_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 1532TEST_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 1550TEST_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 1567TEST_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 1586TEST_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 1602TEST_P(ProtoStreamObjectWriterAnyTest, AnyNullInputFails) { 1603 AnyOut any; 1604 1605 ow_->StartObject("")->RenderNull("any")->EndObject(); 1606 CheckOutput(any); 1607} 1608 1609TEST_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// } 1634TEST_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// } 1661TEST_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// } 1689TEST_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// } 1717TEST_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// } 1745TEST_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// } 1773TEST_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// } 1802TEST_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// } 1826TEST_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 1842class 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 1853INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 1854 ProtoStreamObjectWriterFieldMaskTest, 1855 ::testing::Values( 1856 testing::USE_TYPE_RESOLVER)); 1857 1858TEST_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 1871TEST_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 1886TEST_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 1905TEST_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 1917TEST_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 1978TEST_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 1992TEST_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 2007TEST_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 2023TEST_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 2039TEST_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 2053TEST_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 2067TEST_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 2087class 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 2098INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, 2099 ProtoStreamObjectWriterOneOfsTest, 2100 ::testing::Values( 2101 testing::USE_TYPE_RESOLVER)); 2102 2103TEST_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 2118TEST_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 2135TEST_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 2152TEST_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 2168TEST_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 2184TEST_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 2202TEST_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 2216TEST_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 2230TEST_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 2247TEST_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