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 <memory>
34 #ifndef _SHARED_PTR_H
35 #include <google/protobuf/stubs/shared_ptr.h>
36 #endif
37 #include <sstream>
38
39 #include <google/protobuf/stubs/casts.h>
40 #include <google/protobuf/any.pb.h>
41 #include <google/protobuf/io/coded_stream.h>
42 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
43 #include <google/protobuf/descriptor.h>
44 #include <google/protobuf/util/internal/expecting_objectwriter.h>
45 #include <google/protobuf/util/internal/testdata/books.pb.h>
46 #include <google/protobuf/util/internal/testdata/field_mask.pb.h>
47 #include <google/protobuf/util/internal/type_info_test_helper.h>
48 #include <google/protobuf/util/internal/constants.h>
49 #include <google/protobuf/stubs/strutil.h>
50 #include <google/protobuf/util/internal/testdata/anys.pb.h>
51 #include <google/protobuf/util/internal/testdata/maps.pb.h>
52 #include <google/protobuf/util/internal/testdata/struct.pb.h>
53 #include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h>
54 #include <gtest/gtest.h>
55
56
57 namespace google {
58 namespace protobuf {
59 namespace util {
60 namespace converter {
61
62 using google::protobuf::Descriptor;
63 using google::protobuf::DescriptorPool;
64 using google::protobuf::FileDescriptorProto;
65 using google::protobuf::Message;
66 using google::protobuf::io::ArrayInputStream;
67 using google::protobuf::io::CodedInputStream;
68 using util::Status;
69 using google::protobuf::testing::Author;
70 using google::protobuf::testing::BadAuthor;
71 using google::protobuf::testing::BadNestedBook;
72 using google::protobuf::testing::Book;
73 using google::protobuf::testing::Cyclic;
74 using google::protobuf::testing::Book_Label;
75 using google::protobuf::testing::NestedBook;
76 using google::protobuf::testing::PackedPrimitive;
77 using google::protobuf::testing::Primitive;
78 using google::protobuf::testing::more_author;
79 using google::protobuf::testing::maps::MapOut;
80 using google::protobuf::testing::maps::MapOutWireFormat;
81 using google::protobuf::testing::timestampduration::TimestampDuration;
82 using google::protobuf::testing::anys::AnyOut;
83 using google::protobuf::testing::anys::AnyM;
84 using google::protobuf::testing::FieldMaskTest;
85 using google::protobuf::testing::NestedFieldMask;
86 using google::protobuf::testing::structs::StructType;
87 using ::testing::_;
88
89
90 namespace {
GetTypeUrl(const Descriptor * descriptor)91 string GetTypeUrl(const Descriptor* descriptor) {
92 return string(kTypeServiceBaseUrl) + "/" + descriptor->full_name();
93 }
94 } // namespace
95
96 class ProtostreamObjectSourceTest
97 : public ::testing::TestWithParam<testing::TypeInfoSource> {
98 protected:
ProtostreamObjectSourceTest()99 ProtostreamObjectSourceTest()
100 : helper_(GetParam()),
101 mock_(),
102 ow_(&mock_),
103 use_lower_camel_for_enums_(false) {
104 helper_.ResetTypeInfo(Book::descriptor());
105 }
106
~ProtostreamObjectSourceTest()107 virtual ~ProtostreamObjectSourceTest() {}
108
DoTest(const Message & msg,const Descriptor * descriptor)109 void DoTest(const Message& msg, const Descriptor* descriptor) {
110 Status status = ExecuteTest(msg, descriptor);
111 EXPECT_EQ(Status::OK, status);
112 }
113
ExecuteTest(const Message & msg,const Descriptor * descriptor)114 Status ExecuteTest(const Message& msg, const Descriptor* descriptor) {
115 ostringstream oss;
116 msg.SerializePartialToOstream(&oss);
117 string proto = oss.str();
118 ArrayInputStream arr_stream(proto.data(), proto.size());
119 CodedInputStream in_stream(&arr_stream);
120
121 google::protobuf::scoped_ptr<ProtoStreamObjectSource> os(
122 helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor)));
123 if (use_lower_camel_for_enums_) os->set_use_lower_camel_for_enums(true);
124 os->set_max_recursion_depth(64);
125 return os->WriteTo(&mock_);
126 }
127
PrepareExpectingObjectWriterForRepeatedPrimitive()128 void PrepareExpectingObjectWriterForRepeatedPrimitive() {
129 ow_.StartObject("")
130 ->StartList("repFix32")
131 ->RenderUint32("", bit_cast<uint32>(3201))
132 ->RenderUint32("", bit_cast<uint32>(0))
133 ->RenderUint32("", bit_cast<uint32>(3202))
134 ->EndList()
135 ->StartList("repU32")
136 ->RenderUint32("", bit_cast<uint32>(3203))
137 ->RenderUint32("", bit_cast<uint32>(0))
138 ->EndList()
139 ->StartList("repI32")
140 ->RenderInt32("", 0)
141 ->RenderInt32("", 3204)
142 ->RenderInt32("", 3205)
143 ->EndList()
144 ->StartList("repSf32")
145 ->RenderInt32("", 3206)
146 ->RenderInt32("", 0)
147 ->EndList()
148 ->StartList("repS32")
149 ->RenderInt32("", 0)
150 ->RenderInt32("", 3207)
151 ->RenderInt32("", 3208)
152 ->EndList()
153 ->StartList("repFix64")
154 ->RenderUint64("", bit_cast<uint64>(6401LL))
155 ->RenderUint64("", bit_cast<uint64>(0LL))
156 ->EndList()
157 ->StartList("repU64")
158 ->RenderUint64("", bit_cast<uint64>(0LL))
159 ->RenderUint64("", bit_cast<uint64>(6402LL))
160 ->RenderUint64("", bit_cast<uint64>(6403LL))
161 ->EndList()
162 ->StartList("repI64")
163 ->RenderInt64("", 6404L)
164 ->RenderInt64("", 0L)
165 ->EndList()
166 ->StartList("repSf64")
167 ->RenderInt64("", 0L)
168 ->RenderInt64("", 6405L)
169 ->RenderInt64("", 6406L)
170 ->EndList()
171 ->StartList("repS64")
172 ->RenderInt64("", 6407L)
173 ->RenderInt64("", 0L)
174 ->EndList()
175 ->StartList("repFloat")
176 ->RenderFloat("", 0.0f)
177 ->RenderFloat("", 32.1f)
178 ->RenderFloat("", 32.2f)
179 ->EndList()
180 ->StartList("repDouble")
181 ->RenderDouble("", 64.1L)
182 ->RenderDouble("", 0.0L)
183 ->EndList()
184 ->StartList("repBool")
185 ->RenderBool("", true)
186 ->RenderBool("", false)
187 ->EndList()
188 ->EndObject();
189 }
190
PrepareRepeatedPrimitive()191 Primitive PrepareRepeatedPrimitive() {
192 Primitive primitive;
193 primitive.add_rep_fix32(3201);
194 primitive.add_rep_fix32(0);
195 primitive.add_rep_fix32(3202);
196 primitive.add_rep_u32(3203);
197 primitive.add_rep_u32(0);
198 primitive.add_rep_i32(0);
199 primitive.add_rep_i32(3204);
200 primitive.add_rep_i32(3205);
201 primitive.add_rep_sf32(3206);
202 primitive.add_rep_sf32(0);
203 primitive.add_rep_s32(0);
204 primitive.add_rep_s32(3207);
205 primitive.add_rep_s32(3208);
206 primitive.add_rep_fix64(6401L);
207 primitive.add_rep_fix64(0L);
208 primitive.add_rep_u64(0L);
209 primitive.add_rep_u64(6402L);
210 primitive.add_rep_u64(6403L);
211 primitive.add_rep_i64(6404L);
212 primitive.add_rep_i64(0L);
213 primitive.add_rep_sf64(0L);
214 primitive.add_rep_sf64(6405L);
215 primitive.add_rep_sf64(6406L);
216 primitive.add_rep_s64(6407L);
217 primitive.add_rep_s64(0L);
218 primitive.add_rep_float(0.0f);
219 primitive.add_rep_float(32.1f);
220 primitive.add_rep_float(32.2f);
221 primitive.add_rep_double(64.1L);
222 primitive.add_rep_double(0.0);
223 primitive.add_rep_bool(true);
224 primitive.add_rep_bool(false);
225
226 PrepareExpectingObjectWriterForRepeatedPrimitive();
227 return primitive;
228 }
229
PreparePackedPrimitive()230 PackedPrimitive PreparePackedPrimitive() {
231 PackedPrimitive primitive;
232 primitive.add_rep_fix32(3201);
233 primitive.add_rep_fix32(0);
234 primitive.add_rep_fix32(3202);
235 primitive.add_rep_u32(3203);
236 primitive.add_rep_u32(0);
237 primitive.add_rep_i32(0);
238 primitive.add_rep_i32(3204);
239 primitive.add_rep_i32(3205);
240 primitive.add_rep_sf32(3206);
241 primitive.add_rep_sf32(0);
242 primitive.add_rep_s32(0);
243 primitive.add_rep_s32(3207);
244 primitive.add_rep_s32(3208);
245 primitive.add_rep_fix64(6401L);
246 primitive.add_rep_fix64(0L);
247 primitive.add_rep_u64(0L);
248 primitive.add_rep_u64(6402L);
249 primitive.add_rep_u64(6403L);
250 primitive.add_rep_i64(6404L);
251 primitive.add_rep_i64(0L);
252 primitive.add_rep_sf64(0L);
253 primitive.add_rep_sf64(6405L);
254 primitive.add_rep_sf64(6406L);
255 primitive.add_rep_s64(6407L);
256 primitive.add_rep_s64(0L);
257 primitive.add_rep_float(0.0f);
258 primitive.add_rep_float(32.1f);
259 primitive.add_rep_float(32.2f);
260 primitive.add_rep_double(64.1L);
261 primitive.add_rep_double(0.0);
262 primitive.add_rep_bool(true);
263 primitive.add_rep_bool(false);
264
265 PrepareExpectingObjectWriterForRepeatedPrimitive();
266 return primitive;
267 }
268
UseLowerCamelForEnums()269 void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; }
270
271 testing::TypeInfoTestHelper helper_;
272
273 ::testing::NiceMock<MockObjectWriter> mock_;
274 ExpectingObjectWriter ow_;
275 bool use_lower_camel_for_enums_;
276 };
277
278 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
279 ProtostreamObjectSourceTest,
280 ::testing::Values(
281 testing::USE_TYPE_RESOLVER));
282
TEST_P(ProtostreamObjectSourceTest,EmptyMessage)283 TEST_P(ProtostreamObjectSourceTest, EmptyMessage) {
284 Book empty;
285 ow_.StartObject("")->EndObject();
286 DoTest(empty, Book::descriptor());
287 }
288
TEST_P(ProtostreamObjectSourceTest,Primitives)289 TEST_P(ProtostreamObjectSourceTest, Primitives) {
290 Primitive primitive;
291 primitive.set_fix32(3201);
292 primitive.set_u32(3202);
293 primitive.set_i32(3203);
294 primitive.set_sf32(3204);
295 primitive.set_s32(3205);
296 primitive.set_fix64(6401L);
297 primitive.set_u64(6402L);
298 primitive.set_i64(6403L);
299 primitive.set_sf64(6404L);
300 primitive.set_s64(6405L);
301 primitive.set_str("String Value");
302 primitive.set_bytes("Some Bytes");
303 primitive.set_float_(32.1f);
304 primitive.set_double_(64.1L);
305 primitive.set_bool_(true);
306
307 ow_.StartObject("")
308 ->RenderUint32("fix32", bit_cast<uint32>(3201))
309 ->RenderUint32("u32", bit_cast<uint32>(3202))
310 ->RenderInt32("i32", 3203)
311 ->RenderInt32("sf32", 3204)
312 ->RenderInt32("s32", 3205)
313 ->RenderUint64("fix64", bit_cast<uint64>(6401LL))
314 ->RenderUint64("u64", bit_cast<uint64>(6402LL))
315 ->RenderInt64("i64", 6403L)
316 ->RenderInt64("sf64", 6404L)
317 ->RenderInt64("s64", 6405L)
318 ->RenderString("str", "String Value")
319 ->RenderBytes("bytes", "Some Bytes")
320 ->RenderFloat("float", 32.1f)
321 ->RenderDouble("double", 64.1L)
322 ->RenderBool("bool", true)
323 ->EndObject();
324 DoTest(primitive, Primitive::descriptor());
325 }
326
TEST_P(ProtostreamObjectSourceTest,RepeatingPrimitives)327 TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) {
328 Primitive primitive = PrepareRepeatedPrimitive();
329 primitive.add_rep_str("String One");
330 primitive.add_rep_str("String Two");
331 primitive.add_rep_bytes("Some Bytes");
332
333 ow_.StartList("repStr")
334 ->RenderString("", "String One")
335 ->RenderString("", "String Two")
336 ->EndList()
337 ->StartList("repBytes")
338 ->RenderBytes("", "Some Bytes")
339 ->EndList();
340 DoTest(primitive, Primitive::descriptor());
341 }
342
TEST_P(ProtostreamObjectSourceTest,CustomJsonName)343 TEST_P(ProtostreamObjectSourceTest, CustomJsonName) {
344 Author author;
345 author.set_id(12345);
346
347 ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject();
348 DoTest(author, Author::descriptor());
349 }
350
TEST_P(ProtostreamObjectSourceTest,NestedMessage)351 TEST_P(ProtostreamObjectSourceTest, NestedMessage) {
352 Author* author = new Author();
353 author->set_name("Tolstoy");
354 Book book;
355 book.set_title("My Book");
356 book.set_allocated_author(author);
357
358 ow_.StartObject("")
359 ->RenderString("title", "My Book")
360 ->StartObject("author")
361 ->RenderString("name", "Tolstoy")
362 ->EndObject()
363 ->EndObject();
364 DoTest(book, Book::descriptor());
365 }
366
TEST_P(ProtostreamObjectSourceTest,RepeatingField)367 TEST_P(ProtostreamObjectSourceTest, RepeatingField) {
368 Author author;
369 author.set_alive(false);
370 author.set_name("john");
371 author.add_pseudonym("phil");
372 author.add_pseudonym("bob");
373
374 ow_.StartObject("")
375 ->RenderBool("alive", false)
376 ->RenderString("name", "john")
377 ->StartList("pseudonym")
378 ->RenderString("", "phil")
379 ->RenderString("", "bob")
380 ->EndList()
381 ->EndObject();
382 DoTest(author, Author::descriptor());
383 }
384
TEST_P(ProtostreamObjectSourceTest,PackedRepeatingFields)385 TEST_P(ProtostreamObjectSourceTest, PackedRepeatingFields) {
386 DoTest(PreparePackedPrimitive(), PackedPrimitive::descriptor());
387 }
388
TEST_P(ProtostreamObjectSourceTest,NonPackedPackableFieldsActuallyPacked)389 TEST_P(ProtostreamObjectSourceTest, NonPackedPackableFieldsActuallyPacked) {
390 // Protostream is packed, but parse with non-packed Primitive.
391 DoTest(PreparePackedPrimitive(), Primitive::descriptor());
392 }
393
TEST_P(ProtostreamObjectSourceTest,PackedPackableFieldNotActuallyPacked)394 TEST_P(ProtostreamObjectSourceTest, PackedPackableFieldNotActuallyPacked) {
395 // Protostream is not packed, but parse with PackedPrimitive.
396 DoTest(PrepareRepeatedPrimitive(), PackedPrimitive::descriptor());
397 }
398
TEST_P(ProtostreamObjectSourceTest,BadAuthor)399 TEST_P(ProtostreamObjectSourceTest, BadAuthor) {
400 Author author;
401 author.set_alive(false);
402 author.set_name("john");
403 author.set_id(1234L);
404 author.add_pseudonym("phil");
405 author.add_pseudonym("bob");
406
407 ow_.StartObject("")
408 ->StartList("alive")
409 ->RenderBool("", false)
410 ->EndList()
411 ->StartList("name")
412 ->RenderUint64("", static_cast<uint64>('j'))
413 ->RenderUint64("", static_cast<uint64>('o'))
414 ->RenderUint64("", static_cast<uint64>('h'))
415 ->RenderUint64("", static_cast<uint64>('n'))
416 ->EndList()
417 ->RenderString("pseudonym", "phil")
418 ->RenderString("pseudonym", "bob")
419 ->EndObject();
420 // Protostream created with Author, but parsed with BadAuthor.
421 DoTest(author, BadAuthor::descriptor());
422 }
423
TEST_P(ProtostreamObjectSourceTest,NestedBookToBadNestedBook)424 TEST_P(ProtostreamObjectSourceTest, NestedBookToBadNestedBook) {
425 Book* book = new Book();
426 book->set_length(250);
427 book->set_published(2014L);
428 NestedBook nested;
429 nested.set_allocated_book(book);
430
431 ow_.StartObject("")
432 ->StartList("book")
433 ->RenderUint32("", 24) // tag for field length (3 << 3)
434 ->RenderUint32("", 250)
435 ->RenderUint32("", 32) // tag for field published (4 << 3)
436 ->RenderUint32("", 2014)
437 ->EndList()
438 ->EndObject();
439 // Protostream created with NestedBook, but parsed with BadNestedBook.
440 DoTest(nested, BadNestedBook::descriptor());
441 }
442
TEST_P(ProtostreamObjectSourceTest,BadNestedBookToNestedBook)443 TEST_P(ProtostreamObjectSourceTest, BadNestedBookToNestedBook) {
444 BadNestedBook nested;
445 nested.add_book(1);
446 nested.add_book(2);
447 nested.add_book(3);
448 nested.add_book(4);
449 nested.add_book(5);
450 nested.add_book(6);
451 nested.add_book(7);
452
453 ow_.StartObject("")->StartObject("book")->EndObject()->EndObject();
454 // Protostream created with BadNestedBook, but parsed with NestedBook.
455 DoTest(nested, NestedBook::descriptor());
456 }
457
TEST_P(ProtostreamObjectSourceTest,LongRepeatedListDoesNotBreakIntoMultipleJsonLists)458 TEST_P(ProtostreamObjectSourceTest,
459 LongRepeatedListDoesNotBreakIntoMultipleJsonLists) {
460 Book book;
461
462 int repeat = 10000;
463 for (int i = 0; i < repeat; ++i) {
464 Book_Label* label = book.add_labels();
465 label->set_key(StrCat("i", i));
466 label->set_value(StrCat("v", i));
467 }
468
469 // Make sure StartList and EndList are called exactly once (see b/18227499 for
470 // problems when this doesn't happen)
471 EXPECT_CALL(mock_, StartList(_)).Times(1);
472 EXPECT_CALL(mock_, EndList()).Times(1);
473
474 DoTest(book, Book::descriptor());
475 }
476
TEST_P(ProtostreamObjectSourceTest,LowerCamelEnumOutputTest)477 TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputTest) {
478 Book book;
479 book.set_type(Book::ACTION_AND_ADVENTURE);
480
481 UseLowerCamelForEnums();
482
483 ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject();
484 DoTest(book, Book::descriptor());
485 }
486
TEST_P(ProtostreamObjectSourceTest,EnumCaseIsUnchangedByDefault)487 TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) {
488 Book book;
489 book.set_type(Book::ACTION_AND_ADVENTURE);
490 ow_.StartObject("")
491 ->RenderString("type", "ACTION_AND_ADVENTURE")
492 ->EndObject();
493 DoTest(book, Book::descriptor());
494 }
495
TEST_P(ProtostreamObjectSourceTest,CyclicMessageDepthTest)496 TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) {
497 Cyclic cyclic;
498 cyclic.set_m_int(123);
499
500 Book* book = cyclic.mutable_m_book();
501 book->set_title("book title");
502 Cyclic* current = cyclic.mutable_m_cyclic();
503 Author* current_author = cyclic.add_m_author();
504 for (int i = 0; i < 63; ++i) {
505 Author* next = current_author->add_friend_();
506 next->set_id(i);
507 next->set_name(StrCat("author_name_", i));
508 next->set_alive(true);
509 current_author = next;
510 }
511
512 // Recursive message with depth (65) > max (max is 64).
513 for (int i = 0; i < 64; ++i) {
514 Cyclic* next = current->mutable_m_cyclic();
515 next->set_m_str(StrCat("count_", i));
516 current = next;
517 }
518
519 Status status = ExecuteTest(cyclic, Cyclic::descriptor());
520 EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code());
521 }
522
523 class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest {
524 protected:
ProtostreamObjectSourceMapsTest()525 ProtostreamObjectSourceMapsTest() {
526 helper_.ResetTypeInfo(MapOut::descriptor());
527 }
528 };
529
530 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
531 ProtostreamObjectSourceMapsTest,
532 ::testing::Values(
533 testing::USE_TYPE_RESOLVER));
534
535 // Tests JSON map.
536 //
537 // This is the example expected output.
538 // {
539 // "map1": {
540 // "key1": {
541 // "foo": "foovalue"
542 // },
543 // "key2": {
544 // "foo": "barvalue"
545 // }
546 // },
547 // "map2": {
548 // "nestedself": {
549 // "map1": {
550 // "nested_key1": {
551 // "foo": "nested_foo"
552 // }
553 // },
554 // "bar": "nested_bar_string"
555 // }
556 // },
557 // "map3": {
558 // "111": "one one one"
559 // },
560 // "bar": "top bar"
561 // }
TEST_P(ProtostreamObjectSourceMapsTest,MapsTest)562 TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) {
563 MapOut out;
564 (*out.mutable_map1())["key1"].set_foo("foovalue");
565 (*out.mutable_map1())["key2"].set_foo("barvalue");
566
567 MapOut* nested_value = &(*out.mutable_map2())["nestedself"];
568 (*nested_value->mutable_map1())["nested_key1"].set_foo("nested_foo");
569 nested_value->set_bar("nested_bar_string");
570
571 (*out.mutable_map3())[111] = "one one one";
572
573 out.set_bar("top bar");
574
575 ow_.StartObject("")
576 ->StartObject("map1")
577 ->StartObject("key1")
578 ->RenderString("foo", "foovalue")
579 ->EndObject()
580 ->StartObject("key2")
581 ->RenderString("foo", "barvalue")
582 ->EndObject()
583 ->StartObject("map2")
584 ->StartObject("nestedself")
585 ->StartObject("map1")
586 ->StartObject("nested_key1")
587 ->RenderString("foo", "nested_foo")
588 ->EndObject()
589 ->EndObject()
590 ->RenderString("bar", "nested_bar_string")
591 ->EndObject()
592 ->EndObject()
593 ->StartObject("map3")
594 ->RenderString("111", "one one one")
595 ->EndObject()
596 ->EndObject()
597 ->RenderString("bar", "top bar")
598 ->EndObject();
599
600 DoTest(out, MapOut::descriptor());
601 }
602
TEST_P(ProtostreamObjectSourceMapsTest,MissingKeysTest)603 TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) {
604 // MapOutWireFormat has the same wire representation with MapOut but uses
605 // repeated message fields to represent map fields so we can intentionally
606 // leave out the key field or the value field of a map entry.
607 MapOutWireFormat out;
608 // Create some map entries without keys. They will be rendered with the
609 // default values ("" for strings, "0" for integers, etc.).
610 // {
611 // "map1": {
612 // "": {
613 // "foo": "foovalue"
614 // }
615 // },
616 // "map2": {
617 // "": {
618 // "map1": {
619 // "nested_key1": {
620 // "foo": "nested_foo"
621 // }
622 // }
623 // }
624 // },
625 // "map3": {
626 // "0": "one one one"
627 // },
628 // "map4": {
629 // "false": "bool"
630 // }
631 // }
632 out.add_map1()->mutable_value()->set_foo("foovalue");
633 MapOut* nested = out.add_map2()->mutable_value();
634 (*nested->mutable_map1())["nested_key1"].set_foo("nested_foo");
635 out.add_map3()->set_value("one one one");
636 out.add_map4()->set_value("bool");
637
638 ow_.StartObject("")
639 ->StartObject("map1")
640 ->StartObject("")
641 ->RenderString("foo", "foovalue")
642 ->EndObject()
643 ->EndObject()
644 ->StartObject("map2")
645 ->StartObject("")
646 ->StartObject("map1")
647 ->StartObject("nested_key1")
648 ->RenderString("foo", "nested_foo")
649 ->EndObject()
650 ->EndObject()
651 ->EndObject()
652 ->EndObject()
653 ->StartObject("map3")
654 ->RenderString("0", "one one one")
655 ->EndObject()
656 ->StartObject("map4")
657 ->RenderString("false", "bool")
658 ->EndObject()
659 ->EndObject();
660
661 DoTest(out, MapOut::descriptor());
662 }
663
664 class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest {
665 protected:
ProtostreamObjectSourceAnysTest()666 ProtostreamObjectSourceAnysTest() {
667 helper_.ResetTypeInfo(AnyOut::descriptor(),
668 google::protobuf::Any::descriptor());
669 }
670 };
671
672 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
673 ProtostreamObjectSourceAnysTest,
674 ::testing::Values(
675 testing::USE_TYPE_RESOLVER));
676
677 // Tests JSON any support.
678 //
679 // This is the example expected output.
680 // {
681 // "any": {
682 // "@type": "type.googleapis.com/google.protobuf.testing.anys.AnyM"
683 // "foo": "foovalue"
684 // }
685 // }
TEST_P(ProtostreamObjectSourceAnysTest,BasicAny)686 TEST_P(ProtostreamObjectSourceAnysTest, BasicAny) {
687 AnyOut out;
688 ::google::protobuf::Any* any = out.mutable_any();
689
690 AnyM m;
691 m.set_foo("foovalue");
692 any->PackFrom(m);
693
694 ow_.StartObject("")
695 ->StartObject("any")
696 ->RenderString("@type",
697 "type.googleapis.com/google.protobuf.testing.anys.AnyM")
698 ->RenderString("foo", "foovalue")
699 ->EndObject()
700 ->EndObject();
701
702 DoTest(out, AnyOut::descriptor());
703 }
704
TEST_P(ProtostreamObjectSourceAnysTest,RecursiveAny)705 TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) {
706 AnyOut out;
707 ::google::protobuf::Any* any = out.mutable_any();
708 any->set_type_url("type.googleapis.com/google.protobuf.Any");
709
710 ::google::protobuf::Any nested_any;
711 nested_any.set_type_url(
712 "type.googleapis.com/google.protobuf.testing.anys.AnyM");
713
714 AnyM m;
715 m.set_foo("foovalue");
716 nested_any.set_value(m.SerializeAsString());
717
718 any->set_value(nested_any.SerializeAsString());
719
720 ow_.StartObject("")
721 ->StartObject("any")
722 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
723 ->StartObject("value")
724 ->RenderString("@type",
725 "type.googleapis.com/google.protobuf.testing.anys.AnyM")
726 ->RenderString("foo", "foovalue")
727 ->EndObject()
728 ->EndObject()
729 ->EndObject();
730
731 DoTest(out, AnyOut::descriptor());
732 }
733
TEST_P(ProtostreamObjectSourceAnysTest,DoubleRecursiveAny)734 TEST_P(ProtostreamObjectSourceAnysTest, DoubleRecursiveAny) {
735 AnyOut out;
736 ::google::protobuf::Any* any = out.mutable_any();
737 any->set_type_url("type.googleapis.com/google.protobuf.Any");
738
739 ::google::protobuf::Any nested_any;
740 nested_any.set_type_url("type.googleapis.com/google.protobuf.Any");
741
742 ::google::protobuf::Any second_nested_any;
743 second_nested_any.set_type_url(
744 "type.googleapis.com/google.protobuf.testing.anys.AnyM");
745
746 AnyM m;
747 m.set_foo("foovalue");
748 second_nested_any.set_value(m.SerializeAsString());
749 nested_any.set_value(second_nested_any.SerializeAsString());
750 any->set_value(nested_any.SerializeAsString());
751
752 ow_.StartObject("")
753 ->StartObject("any")
754 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
755 ->StartObject("value")
756 ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
757 ->StartObject("value")
758 ->RenderString("@type",
759 "type.googleapis.com/google.protobuf.testing.anys.AnyM")
760 ->RenderString("foo", "foovalue")
761 ->EndObject()
762 ->EndObject()
763 ->EndObject()
764 ->EndObject();
765
766 DoTest(out, AnyOut::descriptor());
767 }
768
TEST_P(ProtostreamObjectSourceAnysTest,EmptyAnyOutputsEmptyObject)769 TEST_P(ProtostreamObjectSourceAnysTest, EmptyAnyOutputsEmptyObject) {
770 AnyOut out;
771 out.mutable_any();
772
773 ow_.StartObject("")->StartObject("any")->EndObject()->EndObject();
774
775 DoTest(out, AnyOut::descriptor());
776 }
777
TEST_P(ProtostreamObjectSourceAnysTest,EmptyWithTypeAndNoValueOutputsType)778 TEST_P(ProtostreamObjectSourceAnysTest, EmptyWithTypeAndNoValueOutputsType) {
779 AnyOut out;
780 out.mutable_any()->set_type_url("foo.googleapis.com/my.Type");
781
782 ow_.StartObject("")
783 ->StartObject("any")
784 ->RenderString("@type", "foo.googleapis.com/my.Type")
785 ->EndObject()
786 ->EndObject();
787
788 DoTest(out, AnyOut::descriptor());
789 }
790
TEST_P(ProtostreamObjectSourceAnysTest,MissingTypeUrlError)791 TEST_P(ProtostreamObjectSourceAnysTest, MissingTypeUrlError) {
792 AnyOut out;
793 ::google::protobuf::Any* any = out.mutable_any();
794
795 AnyM m;
796 m.set_foo("foovalue");
797 any->set_value(m.SerializeAsString());
798
799 // We start the "AnyOut" part and then fail when we hit the Any object.
800 ow_.StartObject("");
801
802 Status status = ExecuteTest(out, AnyOut::descriptor());
803 EXPECT_EQ(util::error::INTERNAL, status.error_code());
804 }
805
TEST_P(ProtostreamObjectSourceAnysTest,UnknownTypeServiceError)806 TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeServiceError) {
807 AnyOut out;
808 ::google::protobuf::Any* any = out.mutable_any();
809 any->set_type_url("foo.googleapis.com/my.own.Type");
810
811 AnyM m;
812 m.set_foo("foovalue");
813 any->set_value(m.SerializeAsString());
814
815 // We start the "AnyOut" part and then fail when we hit the Any object.
816 ow_.StartObject("");
817
818 Status status = ExecuteTest(out, AnyOut::descriptor());
819 EXPECT_EQ(util::error::INTERNAL, status.error_code());
820 }
821
TEST_P(ProtostreamObjectSourceAnysTest,UnknownTypeError)822 TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeError) {
823 AnyOut out;
824 ::google::protobuf::Any* any = out.mutable_any();
825 any->set_type_url("type.googleapis.com/unknown.Type");
826
827 AnyM m;
828 m.set_foo("foovalue");
829 any->set_value(m.SerializeAsString());
830
831 // We start the "AnyOut" part and then fail when we hit the Any object.
832 ow_.StartObject("");
833
834 Status status = ExecuteTest(out, AnyOut::descriptor());
835 EXPECT_EQ(util::error::INTERNAL, status.error_code());
836 }
837
838 class ProtostreamObjectSourceStructTest : public ProtostreamObjectSourceTest {
839 protected:
ProtostreamObjectSourceStructTest()840 ProtostreamObjectSourceStructTest() {
841 helper_.ResetTypeInfo(StructType::descriptor(),
842 google::protobuf::Struct::descriptor());
843 }
844 };
845
846 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
847 ProtostreamObjectSourceStructTest,
848 ::testing::Values(
849 testing::USE_TYPE_RESOLVER));
850
851 // Tests struct
852 //
853 // "object": {
854 // "k1": 123,
855 // "k2": true
856 // }
TEST_P(ProtostreamObjectSourceStructTest,StructRenderSuccess)857 TEST_P(ProtostreamObjectSourceStructTest, StructRenderSuccess) {
858 StructType out;
859 google::protobuf::Struct* s = out.mutable_object();
860 s->mutable_fields()->operator[]("k1").set_number_value(123);
861 s->mutable_fields()->operator[]("k2").set_bool_value(true);
862
863 ow_.StartObject("")
864 ->StartObject("object")
865 ->RenderDouble("k1", 123)
866 ->RenderBool("k2", true)
867 ->EndObject()
868 ->EndObject();
869
870 DoTest(out, StructType::descriptor());
871 }
872
TEST_P(ProtostreamObjectSourceStructTest,MissingValueSkipsField)873 TEST_P(ProtostreamObjectSourceStructTest, MissingValueSkipsField) {
874 StructType out;
875 google::protobuf::Struct* s = out.mutable_object();
876 s->mutable_fields()->operator[]("k1");
877
878 ow_.StartObject("")->StartObject("object")->EndObject()->EndObject();
879
880 DoTest(out, StructType::descriptor());
881 }
882
883 class ProtostreamObjectSourceFieldMaskTest
884 : public ProtostreamObjectSourceTest {
885 protected:
ProtostreamObjectSourceFieldMaskTest()886 ProtostreamObjectSourceFieldMaskTest() {
887 helper_.ResetTypeInfo(FieldMaskTest::descriptor(),
888 google::protobuf::FieldMask::descriptor());
889 }
890 };
891
892 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
893 ProtostreamObjectSourceFieldMaskTest,
894 ::testing::Values(
895 testing::USE_TYPE_RESOLVER));
896
TEST_P(ProtostreamObjectSourceFieldMaskTest,FieldMaskRenderSuccess)897 TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) {
898 FieldMaskTest out;
899 out.set_id("1");
900 out.mutable_single_mask()->add_paths("path1");
901 out.mutable_single_mask()->add_paths("snake_case_path2");
902 ::google::protobuf::FieldMask* mask = out.add_repeated_mask();
903 mask->add_paths("path3");
904 mask = out.add_repeated_mask();
905 mask->add_paths("snake_case_path4");
906 mask->add_paths("path5");
907 NestedFieldMask* nested = out.add_nested_mask();
908 nested->set_data("data");
909 nested->mutable_single_mask()->add_paths("nested.path1");
910 nested->mutable_single_mask()->add_paths("nested_field.snake_case_path2");
911 mask = nested->add_repeated_mask();
912 mask->add_paths("nested_field.path3");
913 mask->add_paths("nested.snake_case_path4");
914 mask = nested->add_repeated_mask();
915 mask->add_paths("nested.path5");
916 mask = nested->add_repeated_mask();
917 mask->add_paths(
918 "snake_case.map_field[\"map_key_should_be_ignored\"].nested_snake_case."
919 "map_field[\"map_key_sho\\\"uld_be_ignored\"]");
920
921 ow_.StartObject("")
922 ->RenderString("id", "1")
923 ->RenderString("singleMask", "path1,snakeCasePath2")
924 ->StartList("repeatedMask")
925 ->RenderString("", "path3")
926 ->RenderString("", "snakeCasePath4,path5")
927 ->EndList()
928 ->StartList("nestedMask")
929 ->StartObject("")
930 ->RenderString("data", "data")
931 ->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2")
932 ->StartList("repeatedMask")
933 ->RenderString("", "nestedField.path3,nested.snakeCasePath4")
934 ->RenderString("", "nested.path5")
935 ->RenderString("",
936 "snakeCase.mapField[\"map_key_should_be_ignored\"]."
937 "nestedSnakeCase.mapField[\"map_key_sho\\\"uld_be_"
938 "ignored\"]")
939 ->EndList()
940 ->EndObject()
941 ->EndList()
942 ->EndObject();
943
944 DoTest(out, FieldMaskTest::descriptor());
945 }
946
947 class ProtostreamObjectSourceTimestampTest
948 : public ProtostreamObjectSourceTest {
949 protected:
ProtostreamObjectSourceTimestampTest()950 ProtostreamObjectSourceTimestampTest() {
951 helper_.ResetTypeInfo(TimestampDuration::descriptor());
952 }
953 };
954
955 INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
956 ProtostreamObjectSourceTimestampTest,
957 ::testing::Values(
958 testing::USE_TYPE_RESOLVER));
959
TEST_P(ProtostreamObjectSourceTimestampTest,InvalidTimestampBelowMinTest)960 TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) {
961 TimestampDuration out;
962 google::protobuf::Timestamp* ts = out.mutable_ts();
963 // Min allowed seconds - 1
964 ts->set_seconds(kTimestampMinSeconds - 1);
965 ow_.StartObject("");
966
967 Status status = ExecuteTest(out, TimestampDuration::descriptor());
968 EXPECT_EQ(util::error::INTERNAL, status.error_code());
969 }
970
TEST_P(ProtostreamObjectSourceTimestampTest,InvalidTimestampAboveMaxTest)971 TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) {
972 TimestampDuration out;
973 google::protobuf::Timestamp* ts = out.mutable_ts();
974 // Max allowed seconds + 1
975 ts->set_seconds(kTimestampMaxSeconds + 1);
976 ow_.StartObject("");
977
978 Status status = ExecuteTest(out, TimestampDuration::descriptor());
979 EXPECT_EQ(util::error::INTERNAL, status.error_code());
980 }
981
TEST_P(ProtostreamObjectSourceTimestampTest,InvalidDurationBelowMinTest)982 TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) {
983 TimestampDuration out;
984 google::protobuf::Duration* dur = out.mutable_dur();
985 // Min allowed seconds - 1
986 dur->set_seconds(kDurationMinSeconds - 1);
987 ow_.StartObject("");
988
989 Status status = ExecuteTest(out, TimestampDuration::descriptor());
990 EXPECT_EQ(util::error::INTERNAL, status.error_code());
991 }
992
TEST_P(ProtostreamObjectSourceTimestampTest,InvalidDurationAboveMaxTest)993 TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) {
994 TimestampDuration out;
995 google::protobuf::Duration* dur = out.mutable_dur();
996 // Min allowed seconds + 1
997 dur->set_seconds(kDurationMaxSeconds + 1);
998 ow_.StartObject("");
999
1000 Status status = ExecuteTest(out, TimestampDuration::descriptor());
1001 EXPECT_EQ(util::error::INTERNAL, status.error_code());
1002 }
1003
1004 } // namespace converter
1005 } // namespace util
1006 } // namespace protobuf
1007 } // namespace google
1008