diff options
Diffstat (limited to 'src/google/protobuf/util/internal/protostream_objectsource_test.cc')
-rw-r--r-- | src/google/protobuf/util/internal/protostream_objectsource_test.cc | 307 |
1 files changed, 282 insertions, 25 deletions
diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc index 561f6763..df790728 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc @@ -31,9 +31,6 @@ #include <google/protobuf/util/internal/protostream_objectsource.h> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <sstream> #include <google/protobuf/stubs/casts.h> @@ -42,14 +39,16 @@ #include <google/protobuf/io/zero_copy_stream_impl_lite.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/util/internal/expecting_objectwriter.h> +#include <google/protobuf/util/internal/testdata/anys.pb.h> #include <google/protobuf/util/internal/testdata/books.pb.h> #include <google/protobuf/util/internal/testdata/field_mask.pb.h> +#include <google/protobuf/util/internal/testdata/maps.pb.h> +#include <google/protobuf/util/internal/testdata/proto3.pb.h> +#include <google/protobuf/util/internal/testdata/struct.pb.h> +#include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h> #include <google/protobuf/util/internal/type_info_test_helper.h> #include <google/protobuf/util/internal/constants.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/util/internal/testdata/anys.pb.h> -#include <google/protobuf/util/internal/testdata/maps.pb.h> -#include <google/protobuf/util/internal/testdata/struct.pb.h> #include <gtest/gtest.h> @@ -65,21 +64,24 @@ using google::protobuf::Message; using google::protobuf::io::ArrayInputStream; using google::protobuf::io::CodedInputStream; using util::Status; +using google::protobuf::testing::AnyM; +using google::protobuf::testing::AnyOut; using google::protobuf::testing::Author; using google::protobuf::testing::BadAuthor; using google::protobuf::testing::BadNestedBook; using google::protobuf::testing::Book; using google::protobuf::testing::Book_Label; +using google::protobuf::testing::Cyclic; +using google::protobuf::testing::FieldMaskTest; +using google::protobuf::testing::MapOut; +using google::protobuf::testing::MapOutWireFormat; using google::protobuf::testing::NestedBook; +using google::protobuf::testing::NestedFieldMask; using google::protobuf::testing::PackedPrimitive; using google::protobuf::testing::Primitive; -using google::protobuf::testing::more_author; -using google::protobuf::testing::maps::MapOut; -using google::protobuf::testing::anys::AnyOut; -using google::protobuf::testing::anys::AnyM; -using google::protobuf::testing::FieldMaskTest; -using google::protobuf::testing::NestedFieldMask; -using google::protobuf::testing::structs::StructType; +using google::protobuf::testing::Proto3Message; +using google::protobuf::testing::StructType; +using google::protobuf::testing::TimestampDuration; using ::testing::_; @@ -92,26 +94,36 @@ string GetTypeUrl(const Descriptor* descriptor) { class ProtostreamObjectSourceTest : public ::testing::TestWithParam<testing::TypeInfoSource> { protected: - ProtostreamObjectSourceTest() : helper_(GetParam()), mock_(), ow_(&mock_) { - helper_.ResetTypeInfo(Book::descriptor()); + ProtostreamObjectSourceTest() + : helper_(GetParam()), + mock_(), + ow_(&mock_), + use_lower_camel_for_enums_(false), + use_ints_for_enums_(false), + add_trailing_zeros_(false), + render_unknown_enum_values_(true) { + helper_.ResetTypeInfo(Book::descriptor(), Proto3Message::descriptor()); } virtual ~ProtostreamObjectSourceTest() {} void DoTest(const Message& msg, const Descriptor* descriptor) { Status status = ExecuteTest(msg, descriptor); - EXPECT_EQ(Status::OK, status); + EXPECT_EQ(util::Status(), status); } Status ExecuteTest(const Message& msg, const Descriptor* descriptor) { - ostringstream oss; + std::ostringstream oss; msg.SerializePartialToOstream(&oss); string proto = oss.str(); ArrayInputStream arr_stream(proto.data(), proto.size()); CodedInputStream in_stream(&arr_stream); - google::protobuf::scoped_ptr<ProtoStreamObjectSource> os( + std::unique_ptr<ProtoStreamObjectSource> os( helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor))); + if (use_lower_camel_for_enums_) os->set_use_lower_camel_for_enums(true); + if (use_ints_for_enums_) os->set_use_ints_for_enums(true); + os->set_max_recursion_depth(64); return os->WriteTo(&mock_); } @@ -256,10 +268,24 @@ class ProtostreamObjectSourceTest return primitive; } + void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; } + + void UseIntsForEnums() { use_ints_for_enums_ = true; } + + void AddTrailingZeros() { add_trailing_zeros_ = true; } + + void SetRenderUnknownEnumValues(bool value) { + render_unknown_enum_values_ = value; + } + testing::TypeInfoTestHelper helper_; ::testing::NiceMock<MockObjectWriter> mock_; ExpectingObjectWriter ow_; + bool use_lower_camel_for_enums_; + bool use_ints_for_enums_; + bool add_trailing_zeros_; + bool render_unknown_enum_values_; }; INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, @@ -461,6 +487,106 @@ TEST_P(ProtostreamObjectSourceTest, DoTest(book, Book::descriptor()); } +TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputMacroCase) { + Book book; + book.set_type(Book::ACTION_AND_ADVENTURE); + + UseLowerCamelForEnums(); + + ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject(); + DoTest(book, Book::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputSnakeCase) { + Book book; + book.set_type(Book::arts_and_photography); + + UseLowerCamelForEnums(); + + ow_.StartObject("")->RenderString("type", "artsAndPhotography")->EndObject(); + DoTest(book, Book::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputWithNumber) { + Book book; + book.set_type(Book::I18N_Tech); + + UseLowerCamelForEnums(); + + ow_.StartObject("")->RenderString("type", "i18nTech")->EndObject(); + DoTest(book, Book::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) { + Book book; + book.set_type(Book::ACTION_AND_ADVENTURE); + ow_.StartObject("") + ->RenderString("type", "ACTION_AND_ADVENTURE") + ->EndObject(); + DoTest(book, Book::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, UseIntsForEnumsTest) { + Book book; + book.set_type(Book::ACTION_AND_ADVENTURE); + + UseIntsForEnums(); + + ow_.StartObject("")->RenderInt32("type", 3)->EndObject(); + DoTest(book, Book::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, + UnknownEnumAreDroppedWhenRenderUnknownEnumValuesIsUnset) { + Proto3Message message; + message.set_enum_value(static_cast<Proto3Message::NestedEnum>(1234)); + + SetRenderUnknownEnumValues(false); + + // Unknown enum values are not output. + ow_.StartObject("")->EndObject(); + DoTest(message, Proto3Message::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, + UnknownEnumAreOutputWhenRenderUnknownEnumValuesIsSet) { + Proto3Message message; + message.set_enum_value(static_cast<Proto3Message::NestedEnum>(1234)); + + SetRenderUnknownEnumValues(true); + + // Unknown enum values are output. + ow_.StartObject("")->RenderInt32("enumValue", 1234)->EndObject(); + DoTest(message, Proto3Message::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) { + Cyclic cyclic; + cyclic.set_m_int(123); + + Book* book = cyclic.mutable_m_book(); + book->set_title("book title"); + Cyclic* current = cyclic.mutable_m_cyclic(); + Author* current_author = cyclic.add_m_author(); + for (int i = 0; i < 63; ++i) { + Author* next = current_author->add_friend_(); + next->set_id(i); + next->set_name(StrCat("author_name_", i)); + next->set_alive(true); + current_author = next; + } + + // Recursive message with depth (65) > max (max is 64). + for (int i = 0; i < 64; ++i) { + Cyclic* next = current->mutable_m_cyclic(); + next->set_m_str(StrCat("count_", i)); + current = next; + } + + Status status = ExecuteTest(cyclic, Cyclic::descriptor()); + EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code()); +} + class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest { protected: ProtostreamObjectSourceMapsTest() { @@ -541,6 +667,67 @@ TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) { DoTest(out, MapOut::descriptor()); } +TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) { + // MapOutWireFormat has the same wire representation with MapOut but uses + // repeated message fields to represent map fields so we can intentionally + // leave out the key field or the value field of a map entry. + MapOutWireFormat out; + // Create some map entries without keys. They will be rendered with the + // default values ("" for strings, "0" for integers, etc.). + // { + // "map1": { + // "": { + // "foo": "foovalue" + // } + // }, + // "map2": { + // "": { + // "map1": { + // "nested_key1": { + // "foo": "nested_foo" + // } + // } + // } + // }, + // "map3": { + // "0": "one one one" + // }, + // "map4": { + // "false": "bool" + // } + // } + out.add_map1()->mutable_value()->set_foo("foovalue"); + MapOut* nested = out.add_map2()->mutable_value(); + (*nested->mutable_map1())["nested_key1"].set_foo("nested_foo"); + out.add_map3()->set_value("one one one"); + out.add_map4()->set_value("bool"); + + ow_.StartObject("") + ->StartObject("map1") + ->StartObject("") + ->RenderString("foo", "foovalue") + ->EndObject() + ->EndObject() + ->StartObject("map2") + ->StartObject("") + ->StartObject("map1") + ->StartObject("nested_key1") + ->RenderString("foo", "nested_foo") + ->EndObject() + ->EndObject() + ->EndObject() + ->EndObject() + ->StartObject("map3") + ->RenderString("0", "one one one") + ->EndObject() + ->StartObject("map4") + ->RenderString("false", "bool") + ->EndObject() + ->EndObject(); + + DoTest(out, MapOut::descriptor()); +} + class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest { protected: ProtostreamObjectSourceAnysTest() { @@ -559,7 +746,7 @@ INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, // This is the example expected output. // { // "any": { -// "@type": "type.googleapis.com/google.protobuf.testing.anys.AnyM" +// "@type": "type.googleapis.com/google.protobuf.testing.AnyM" // "foo": "foovalue" // } // } @@ -574,7 +761,7 @@ TEST_P(ProtostreamObjectSourceAnysTest, BasicAny) { ow_.StartObject("") ->StartObject("any") ->RenderString("@type", - "type.googleapis.com/google.protobuf.testing.anys.AnyM") + "type.googleapis.com/google.protobuf.testing.AnyM") ->RenderString("foo", "foovalue") ->EndObject() ->EndObject(); @@ -588,8 +775,7 @@ TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) { any->set_type_url("type.googleapis.com/google.protobuf.Any"); ::google::protobuf::Any nested_any; - nested_any.set_type_url( - "type.googleapis.com/google.protobuf.testing.anys.AnyM"); + nested_any.set_type_url("type.googleapis.com/google.protobuf.testing.AnyM"); AnyM m; m.set_foo("foovalue"); @@ -602,7 +788,7 @@ TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) { ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") ->StartObject("value") ->RenderString("@type", - "type.googleapis.com/google.protobuf.testing.anys.AnyM") + "type.googleapis.com/google.protobuf.testing.AnyM") ->RenderString("foo", "foovalue") ->EndObject() ->EndObject() @@ -621,7 +807,7 @@ TEST_P(ProtostreamObjectSourceAnysTest, DoubleRecursiveAny) { ::google::protobuf::Any second_nested_any; second_nested_any.set_type_url( - "type.googleapis.com/google.protobuf.testing.anys.AnyM"); + "type.googleapis.com/google.protobuf.testing.AnyM"); AnyM m; m.set_foo("foovalue"); @@ -636,7 +822,7 @@ TEST_P(ProtostreamObjectSourceAnysTest, DoubleRecursiveAny) { ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") ->StartObject("value") ->RenderString("@type", - "type.googleapis.com/google.protobuf.testing.anys.AnyM") + "type.googleapis.com/google.protobuf.testing.AnyM") ->RenderString("foo", "foovalue") ->EndObject() ->EndObject() @@ -824,6 +1010,77 @@ TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) { DoTest(out, FieldMaskTest::descriptor()); } +class ProtostreamObjectSourceTimestampTest + : public ProtostreamObjectSourceTest { + protected: + ProtostreamObjectSourceTimestampTest() { + helper_.ResetTypeInfo(TimestampDuration::descriptor()); + } +}; + +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtostreamObjectSourceTimestampTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) { + TimestampDuration out; + google::protobuf::Timestamp* ts = out.mutable_ts(); + // Min allowed seconds - 1 + ts->set_seconds(kTimestampMinSeconds - 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) { + TimestampDuration out; + google::protobuf::Timestamp* ts = out.mutable_ts(); + // Max allowed seconds + 1 + ts->set_seconds(kTimestampMaxSeconds + 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) { + TimestampDuration out; + google::protobuf::Duration* dur = out.mutable_dur(); + // Min allowed seconds - 1 + dur->set_seconds(kDurationMinSeconds - 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) { + TimestampDuration out; + google::protobuf::Duration* dur = out.mutable_dur(); + // Min allowed seconds + 1 + dur->set_seconds(kDurationMaxSeconds + 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, TimestampDurationDefaultValue) { + TimestampDuration out; + out.mutable_ts()->set_seconds(0); + out.mutable_dur()->set_seconds(0); + + ow_.StartObject("") + ->RenderString("ts", "1970-01-01T00:00:00Z") + ->RenderString("dur", "0s") + ->EndObject(); + + DoTest(out, TimestampDuration::descriptor()); +} + + } // namespace converter } // namespace util } // namespace protobuf |