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