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