From cc8ca5b6a5478b40546d4206392eb1471454460d Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Mon, 19 Sep 2016 13:45:07 -0700 Subject: Integrate internal changes --- .../util/internal/protostream_objectwriter_test.cc | 459 +++++++++++++++++++-- 1 file changed, 418 insertions(+), 41 deletions(-) (limited to 'src/google/protobuf/util/internal/protostream_objectwriter_test.cc') diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc index 30e58e62..e7b38520 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc @@ -41,18 +41,20 @@ #include #include #include +#include #include #include +#include +#include +#include +#include +#include +#include #include #include #include #include #include -#include -#include -#include -#include -#include #include @@ -61,27 +63,28 @@ namespace protobuf { namespace util { namespace converter { +using google::protobuf::testing::AnyM; +using google::protobuf::testing::AnyOut; using google::protobuf::testing::Author; using google::protobuf::testing::Book; -using google::protobuf::testing::Book_Data; +using google::protobuf::testing::FieldMaskTest; +using google::protobuf::testing::Int32Wrapper; +using google::protobuf::testing::MapIn; using google::protobuf::testing::Primitive; +using google::protobuf::testing::Proto3Message; using google::protobuf::testing::Publisher; +using google::protobuf::testing::StructType; +using google::protobuf::testing::TimestampDuration; +using google::protobuf::testing::ValueWrapper; +using google::protobuf::testing::oneofs::OneOfsRequest; using google::protobuf::Descriptor; using google::protobuf::DescriptorPool; using google::protobuf::DynamicMessageFactory; using google::protobuf::FileDescriptorProto; using google::protobuf::Message; -using google::protobuf::io::ArrayInputStream; using strings::GrowingArrayByteSink; using ::testing::_; using ::testing::Args; -using google::protobuf::testing::anys::AnyM; -using google::protobuf::testing::anys::AnyOut; -using google::protobuf::testing::oneofs::OneOfsRequest; -using google::protobuf::testing::FieldMaskTest; -using google::protobuf::testing::maps::MapIn; -using google::protobuf::testing::structs::StructType; -using google::protobuf::testing::timestampduration::TimestampDuration; namespace { @@ -268,6 +271,84 @@ TEST_P(ProtoStreamObjectWriterTest, CustomJsonName) { CheckOutput(book); } +TEST_P(ProtoStreamObjectWriterTest, IntEnumValuesAreAccepted) { + Book book; + book.set_title("Some Book"); + book.set_type(google::protobuf::testing::Book_Type_KIDS); + Author* robert = book.mutable_author(); + robert->set_name("robert"); + + ow_->StartObject("") + ->RenderString("title", "Some Book") + ->RenderString("type", "2") + ->StartObject("author") + ->RenderString("name", "robert") + ->EndObject() + ->EndObject(); + CheckOutput(book); +} + +TEST_P(ProtoStreamObjectWriterTest, EnumValuesWithoutUnderscoreAreAccepted) { + Book book; + book.set_title("Some Book"); + book.set_type(google::protobuf::testing::Book_Type_ACTION_AND_ADVENTURE); + Author* robert = book.mutable_author(); + robert->set_name("robert"); + + options_.use_lower_camel_for_enums = true; + ResetProtoWriter(); + + ow_->StartObject("") + ->RenderString("title", "Some Book") + ->RenderString("type", "ACTIONANDADVENTURE") + ->StartObject("author") + ->RenderString("name", "robert") + ->EndObject() + ->EndObject(); + CheckOutput(book); +} + +TEST_P(ProtoStreamObjectWriterTest, EnumValuesInCamelCaseAreAccepted) { + Book book; + book.set_title("Some Book"); + book.set_type(google::protobuf::testing::Book_Type_ACTION_AND_ADVENTURE); + Author* robert = book.mutable_author(); + robert->set_name("robert"); + + options_.use_lower_camel_for_enums = true; + ResetProtoWriter(); + + ow_->StartObject("") + ->RenderString("title", "Some Book") + ->RenderString("type", "actionAndAdventure") + ->StartObject("author") + ->RenderString("name", "robert") + ->EndObject() + ->EndObject(); + CheckOutput(book); +} + +TEST_P(ProtoStreamObjectWriterTest, + EnumValuesInCamelCaseWithNameNotUppercaseAreAccepted) { + Book book; + book.set_title("Some Book"); + book.set_type(google::protobuf::testing::Book_Type_arts_and_photography); + Author* robert = book.mutable_author(); + robert->set_name("robert"); + + options_.use_lower_camel_for_enums = true; + ResetProtoWriter(); + + ow_->StartObject("") + ->RenderString("title", "Some Book") + ->RenderString("type", "artsAndPhotography") + ->StartObject("author") + ->RenderString("name", "robert") + ->EndObject() + ->EndObject(); + CheckOutput(book); +} + TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) { Primitive full; full.set_fix32(101); @@ -826,6 +907,19 @@ TEST_P(ProtoStreamObjectWriterTest, IgnoreUnknownListAtPublisher) { CheckOutput(expected); } +TEST_P(ProtoStreamObjectWriterTest, AcceptUnknownEnumValue) { + ResetTypeInfo(Proto3Message::descriptor()); + + Proto3Message expected; + expected.set_enum_value(static_cast(12345)); + + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("") + ->RenderInt32("enumValue", 12345) + ->EndObject(); + CheckOutput(expected); +} + TEST_P(ProtoStreamObjectWriterTest, MissingRequiredField) { Book expected; expected.set_title("My Title"); @@ -1338,9 +1432,9 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidValue( _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), StringPiece( - "Field 'ts', Invalid data type for timestamp, value is null"))) + "Field 'ts', Invalid data type for timestamp, value is 1"))) .With(Args<0>(HasObjectLocation("ts"))); - ow_->StartObject("")->RenderNull("ts")->EndObject(); + ow_->StartObject("")->RenderInt32("ts", 1)->EndObject(); CheckOutput(timestamp); } @@ -1352,8 +1446,22 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidValue( _, StringPiece("type.googleapis.com/google.protobuf.Duration"), StringPiece( - "Field 'dur', Invalid data type for duration, value is null"))) + "Field 'dur', Invalid data type for duration, value is 1"))) .With(Args<0>(HasObjectLocation("dur"))); + ow_->StartObject("")->RenderInt32("dur", 1)->EndObject(); + CheckOutput(duration); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, TimestampAcceptsNull) { + TimestampDuration timestamp; + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("")->RenderNull("ts")->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, DurationAcceptsNull) { + TimestampDuration duration; + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); ow_->StartObject("")->RenderNull("dur")->EndObject(); CheckOutput(duration); } @@ -1415,6 +1523,28 @@ TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) { CheckOutput(struct_type); } +TEST_P(ProtoStreamObjectWriterStructTest, StructAcceptsNull) { + StructType struct_type; + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + + ow_->StartObject("")->RenderNull("object")->EndObject(); + CheckOutput(struct_type); +} + +TEST_P(ProtoStreamObjectWriterStructTest, StructValuePreservesNull) { + StructType struct_type; + (*struct_type.mutable_object()->mutable_fields())["key"].set_null_value( + google::protobuf::NULL_VALUE); + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + + ow_->StartObject("") + ->StartObject("object") + ->RenderNull("key") + ->EndObject() + ->EndObject(); + CheckOutput(struct_type); +} + TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) { EXPECT_CALL( listener_, @@ -1482,6 +1612,15 @@ TEST_P(ProtoStreamObjectWriterStructTest, OptionStructIntAsStringsTest) { CheckOutput(struct_type); } +TEST_P(ProtoStreamObjectWriterStructTest, ValuePreservesNull) { + ValueWrapper value; + value.mutable_value()->set_null_value(google::protobuf::NULL_VALUE); + + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("")->RenderNull("value")->EndObject(); + CheckOutput(value); +} + class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest { protected: ProtoStreamObjectWriterMapTest() @@ -1527,11 +1666,14 @@ class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest { ProtoStreamObjectWriterAnyTest() { vector descriptors; descriptors.push_back(AnyOut::descriptor()); + descriptors.push_back(Book::descriptor()); + descriptors.push_back(google::protobuf::Any::descriptor()); descriptors.push_back(google::protobuf::DoubleValue::descriptor()); + descriptors.push_back(google::protobuf::FieldMask::descriptor()); + descriptors.push_back(google::protobuf::Int32Value::descriptor()); + descriptors.push_back(google::protobuf::Struct::descriptor()); descriptors.push_back(google::protobuf::Timestamp::descriptor()); - descriptors.push_back(google::protobuf::Any::descriptor()); descriptors.push_back(google::protobuf::Value::descriptor()); - descriptors.push_back(google::protobuf::Struct::descriptor()); ResetTypeInfo(descriptors); } }; @@ -1564,8 +1706,7 @@ TEST_P(ProtoStreamObjectWriterAnyTest, 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"); @@ -1578,11 +1719,12 @@ TEST_P(ProtoStreamObjectWriterAnyTest, 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() ->EndObject(); + CheckOutput(out, 107); } TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) { @@ -1595,7 +1737,7 @@ TEST_P(ProtoStreamObjectWriterAnyTest, 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"); @@ -1611,18 +1753,110 @@ TEST_P(ProtoStreamObjectWriterAnyTest, 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() ->EndObject() ->EndObject(); + CheckOutput(out, 151); +} + +TEST_P(ProtoStreamObjectWriterAnyTest, TypeUrlAtEnd) { + Book book; + book.set_title("C++"); + book.set_length(1234); + book.set_content("Hello World!"); + + ::google::protobuf::Any any; + any.PackFrom(book); + + ::google::protobuf::Any outer_any; + outer_any.PackFrom(any); + + AnyOut out; + out.mutable_any()->PackFrom(outer_any); + + // Put the @type field at the end of each Any message. Parsers should + // be able to accept that. + ow_->StartObject("") + ->StartObject("any") + ->StartObject("value") + ->StartObject("value") + ->RenderString("title", "C++") + ->RenderInt32("length", 1234) + ->RenderBytes("content", "Hello World!") + ->RenderString("@type", + "type.googleapis.com/google.protobuf.testing.Book") + ->EndObject() + ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") + ->EndObject() + ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// Same as TypeUrlAtEnd, but use temporary string values to make sure we don't +// mistakenly store StringPiece objects pointing to invalid memory. +TEST_P(ProtoStreamObjectWriterAnyTest, TypeUrlAtEndWithTemporaryStrings) { + Book book; + book.set_title("C++"); + book.set_length(1234); + book.set_content("Hello World!"); + + ::google::protobuf::Any any; + any.PackFrom(book); + + ::google::protobuf::Any outer_any; + outer_any.PackFrom(any); + + AnyOut out; + out.mutable_any()->PackFrom(outer_any); + + string name, value; + // Put the @type field at the end of each Any message. Parsers should + // be able to accept that. + ow_->StartObject("")->StartObject("any"); + { + ow_->StartObject("value"); + { + ow_->StartObject("value"); + { + name = "title"; + value = "C++"; + ow_->RenderString(name, value); + name = "length"; + ow_->RenderInt32(name, 1234); + name = "content"; + value = "Hello World!"; + ow_->RenderBytes(name, value); + name = "@type"; + value = "type.googleapis.com/google.protobuf.testing.Book"; + ow_->RenderString(name, value); + } + ow_->EndObject(); + + name = "@type"; + value = "type.googleapis.com/google.protobuf.Any"; + ow_->RenderString(name, value); + } + ow_->EndObject(); + + name = "@type"; + value = "type.googleapis.com/google.protobuf.Any"; + ow_->RenderString(name, value); + } + ow_->EndObject()->EndObject(); + CheckOutput(out); } TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) { AnyOut out; out.mutable_any(); + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("")->StartObject("any")->EndObject()->EndObject(); CheckOutput(out, 2); @@ -1631,11 +1865,10 @@ TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) { AnyOut any; - EXPECT_CALL( - listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece("Missing or invalid @type for any field in " - "google.protobuf.testing.anys.AnyOut"))); + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("Any"), + StringPiece("Missing @type for any field in " + "google.protobuf.testing.AnyOut"))); ow_->StartObject("") ->StartObject("any") @@ -1649,11 +1882,10 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails2) { AnyOut any; - EXPECT_CALL( - listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece("Missing or invalid @type for any field in " - "google.protobuf.testing.anys.AnyOut"))); + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("Any"), + StringPiece("Missing @type for any field in " + "google.protobuf.testing.AnyOut"))); ow_->StartObject("") ->StartObject("any") @@ -1667,11 +1899,10 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails2) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails3) { AnyOut any; - EXPECT_CALL( - listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece("Missing or invalid @type for any field in " - "google.protobuf.testing.anys.AnyOut"))); + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("Any"), + StringPiece("Missing @type for any field in " + "google.protobuf.testing.AnyOut"))); ow_->StartObject("") ->StartObject("any") @@ -1716,9 +1947,21 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithUnknownTypeFails) { CheckOutput(any); } -TEST_P(ProtoStreamObjectWriterAnyTest, AnyNullInputFails) { +TEST_P(ProtoStreamObjectWriterAnyTest, AnyIncorrectInputTypeFails) { + AnyOut any; + + EXPECT_CALL( + listener_, + InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.Any"), + StringPiece("1"))); + ow_->StartObject("")->RenderInt32("any", 1)->EndObject(); + CheckOutput(any); +} + +TEST_P(ProtoStreamObjectWriterAnyTest, AnyAcceptsNull) { AnyOut any; + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); ow_->StartObject("")->RenderNull("any")->EndObject(); CheckOutput(any); } @@ -1956,6 +2199,111 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForAny) { CheckOutput(any); } +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Any", +// "value": null +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyInAnyAcceptsNull) { + AnyOut out; + google::protobuf::Any empty; + out.mutable_any()->PackFrom(empty); + + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") + ->RenderNull("value") + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Timestamp", +// "value": null +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, TimestampInAnyAcceptsNull) { + AnyOut out; + google::protobuf::Timestamp empty; + out.mutable_any()->PackFrom(empty); + + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp") + ->RenderNull("value") + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": null +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, DurationInAnyAcceptsNull) { + AnyOut out; + google::protobuf::Duration empty; + out.mutable_any()->PackFrom(empty); + + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Duration") + ->RenderNull("value") + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.FieldMask", +// "value": null +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, FieldMaskInAnyAcceptsNull) { + AnyOut out; + google::protobuf::FieldMask empty; + out.mutable_any()->PackFrom(empty); + + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.FieldMask") + ->RenderNull("value") + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Int32Value", +// "value": null +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, WrapperInAnyAcceptsNull) { + AnyOut out; + google::protobuf::Int32Value empty; + out.mutable_any()->PackFrom(empty); + + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Int32Value") + ->RenderNull("value") + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + class ProtoStreamObjectWriterFieldMaskTest : public BaseProtoStreamObjectWriterTest { protected: @@ -2201,6 +2549,36 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyCanContainAnyChars) { CheckOutput(expected); } +TEST_P(ProtoStreamObjectWriterFieldMaskTest, FieldMaskAcceptsNull) { + FieldMaskTest expected; + EXPECT_CALL(listener_, InvalidValue(_, _, _)).Times(0); + ow_->StartObject("")->RenderNull("single_mask")->EndObject(); + CheckOutput(expected); +} + +class ProtoStreamObjectWriterWrappersTest + : public BaseProtoStreamObjectWriterTest { + protected: + ProtoStreamObjectWriterWrappersTest() { + vector descriptors; + descriptors.push_back(Int32Wrapper::descriptor()); + descriptors.push_back(google::protobuf::Int32Value::descriptor()); + ResetTypeInfo(descriptors); + } +}; + +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtoStreamObjectWriterWrappersTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + +TEST_P(ProtoStreamObjectWriterWrappersTest, WrapperAcceptsNull) { + Int32Wrapper wrapper; + EXPECT_CALL(listener_, InvalidName(_, _, _)).Times(0); + ow_->StartObject("")->RenderNull("int32")->EndObject(); + CheckOutput(wrapper); +} + class ProtoStreamObjectWriterOneOfsTest : public BaseProtoStreamObjectWriterTest { protected: @@ -2368,7 +2746,6 @@ TEST_P(ProtoStreamObjectWriterOneOfsTest, StringPiece("oneof field 'data' is already set. " "Cannot set 'intData'"))); - using google::protobuf::testing::oneofs::OneOfsRequest; // JSON: // { "anyData": // { "@type": -- cgit v1.2.3