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