aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/util/internal
diff options
context:
space:
mode:
authorGravatar Jisi Liu <jisi.liu@gmail.com>2015-10-05 11:59:43 -0700
committerGravatar Jisi Liu <jisi.liu@gmail.com>2015-10-05 11:59:43 -0700
commit46e8ff63cb67a6520711da5317aaaef04d0414d0 (patch)
tree64370726fe469f8dfca7b14f8b8cb80b6cc856f6 /src/google/protobuf/util/internal
parent0087da9d4775f79c67362cc89c653f3a33a9bae2 (diff)
Down-integrate from google internal.
Diffstat (limited to 'src/google/protobuf/util/internal')
-rw-r--r--src/google/protobuf/util/internal/default_value_objectwriter.h2
-rw-r--r--src/google/protobuf/util/internal/json_objectwriter.cc6
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource.cc22
-rw-r--r--src/google/protobuf/util/internal/protostream_objectsource.h4
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.cc41
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter.h20
-rw-r--r--src/google/protobuf/util/internal/protostream_objectwriter_test.cc137
-rw-r--r--src/google/protobuf/util/internal/utility.cc15
-rw-r--r--src/google/protobuf/util/internal/utility.h6
9 files changed, 207 insertions, 46 deletions
diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h
index d4547601..bcb526e8 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter.h
+++ b/src/google/protobuf/util/internal/default_value_objectwriter.h
@@ -110,7 +110,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter {
// "Node" represents a node in the tree that holds the input of
// DefaultValueObjectWriter.
- class Node {
+ class LIBPROTOBUF_EXPORT Node {
public:
Node(const string& name, const google::protobuf::Type* type, NodeKind kind,
const DataPiece& data, bool is_placeholder);
diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc
index f81e3306..94d2ab7a 100644
--- a/src/google/protobuf/util/internal/json_objectwriter.cc
+++ b/src/google/protobuf/util/internal/json_objectwriter.cc
@@ -37,8 +37,8 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/util/internal/json_escaping.h>
-#include <google/protobuf/stubs/mathlimits.h>
#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/mathlimits.h>
namespace google {
namespace protobuf {
@@ -116,7 +116,7 @@ JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name,
JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
double value) {
- if (google::protobuf::MathLimits<double>::IsFinite(value)) {
+ if (MathLimits<double>::IsFinite(value)) {
return RenderSimple(name, SimpleDtoa(value));
}
@@ -126,7 +126,7 @@ JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name,
JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name,
float value) {
- if (google::protobuf::MathLimits<float>::IsFinite(value)) {
+ if (MathLimits<float>::IsFinite(value)) {
return RenderSimple(name, SimpleFtoa(value));
}
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 996e1f8c..aebf19a1 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -47,7 +47,6 @@
#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h>
-#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/status_macros.h>
@@ -140,6 +139,7 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type,
const uint32 end_tag,
bool include_start_and_end,
ObjectWriter* ow) const {
+
const TypeRenderer* type_renderer = FindTypeRenderer(type.name());
if (type_renderer != NULL) {
return (*type_renderer)(this, type, name, ow);
@@ -332,10 +332,9 @@ Status ProtoStreamObjectSource::RenderDuration(
if (seconds < 0) {
if (nanos > 0) {
return Status(util::error::INTERNAL,
- StrCat(
- "Duration nanos is non-negative, but seconds is "
- "negative for field: ",
- field_name));
+ StrCat("Duration nanos is non-negative, but seconds is "
+ "negative for field: ",
+ field_name));
}
sign = "-";
seconds = -seconds;
@@ -648,6 +647,7 @@ Status ProtoStreamObjectSource::RenderFieldMask(
return Status::OK;
}
+
hash_map<string, ProtoStreamObjectSource::TypeRenderer>*
ProtoStreamObjectSource::renderers_ = NULL;
GOOGLE_PROTOBUF_DECLARE_ONCE(source_renderers_init_);
@@ -670,13 +670,16 @@ void ProtoStreamObjectSource::InitRendererMap() {
&ProtoStreamObjectSource::RenderInt32;
(*renderers_)["google.protobuf.UInt32Value"] =
&ProtoStreamObjectSource::RenderUInt32;
- (*renderers_)["google.protobuf.BoolValue"] = &ProtoStreamObjectSource::RenderBool;
+ (*renderers_)["google.protobuf.BoolValue"] =
+ &ProtoStreamObjectSource::RenderBool;
(*renderers_)["google.protobuf.StringValue"] =
&ProtoStreamObjectSource::RenderString;
(*renderers_)["google.protobuf.BytesValue"] =
&ProtoStreamObjectSource::RenderBytes;
- (*renderers_)["google.protobuf.Any"] = &ProtoStreamObjectSource::RenderAny;
- (*renderers_)["google.protobuf.Struct"] = &ProtoStreamObjectSource::RenderStruct;
+ (*renderers_)["google.protobuf.Any"] =
+ &ProtoStreamObjectSource::RenderAny;
+ (*renderers_)["google.protobuf.Struct"] =
+ &ProtoStreamObjectSource::RenderStruct;
(*renderers_)["google.protobuf.Value"] =
&ProtoStreamObjectSource::RenderStructValue;
(*renderers_)["google.protobuf.ListValue"] =
@@ -835,6 +838,7 @@ Status ProtoStreamObjectSource::RenderField(
StrCat("Invalid configuration. Could not find the type: ",
field->type_url()));
}
+
RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow));
if (!stream_->ConsumedEntireMessage()) {
return Status(util::error::INVALID_ARGUMENT,
@@ -988,7 +992,7 @@ std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos(
uint32 nanos = 0;
uint32 tag = 0;
int64 signed_seconds = 0;
- int64 signed_nanos = 0;
+ int32 signed_nanos = 0;
for (tag = stream_->ReadTag(); tag != 0; tag = stream_->ReadTag()) {
const google::protobuf::Field* field = FindAndVerifyField(type, tag);
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index f52383a1..3cd37aa1 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -188,8 +188,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
// Helper to render google.protobuf.Struct's ListValue fields to ObjectWriter.
static util::Status RenderStructListValue(
- const ProtoStreamObjectSource* os,
- const google::protobuf::Type& type,
+ const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
StringPiece name, ObjectWriter* ow);
// Render the "Any" type.
@@ -211,6 +210,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource {
util::Status RenderField(const google::protobuf::Field* field,
StringPiece field_name, ObjectWriter* ow) const;
+
// Reads field value according to Field spec in 'field' and returns the read
// value as string. This only works for primitive datatypes (no message
// types).
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index a935ac39..bd245999 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -33,13 +33,13 @@
#include <functional>
#include <stack>
+#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/time.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/util/internal/field_mask_utility.h>
#include <google/protobuf/util/internal/object_location_tracker.h>
#include <google/protobuf/util/internal/constants.h>
#include <google/protobuf/util/internal/utility.h>
-#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/statusor.h>
@@ -397,8 +397,8 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
const TypeRenderer* type_renderer =
FindTypeRenderer(GetFullTypeWithUrl(ow_->master_type_.name()));
if (type_renderer) {
- // TODO(rikka): Don't just ignore the util::Status object!
- (*type_renderer)(ow_.get(), value);
+ Status status = (*type_renderer)(ow_.get(), value);
+ if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
} else {
ow_->RenderDataPiece(name, value);
}
@@ -600,6 +600,11 @@ void ProtoStreamObjectWriter::ProtoElement::TakeOneofIndex(int32 index) {
InsertIfNotPresent(&oneof_indices_, index);
}
+bool ProtoStreamObjectWriter::ProtoElement::InsertMapKeyIfNotPresent(
+ StringPiece map_key) {
+ return InsertIfNotPresent(&map_keys_, map_key);
+}
+
inline void ProtoStreamObjectWriter::InvalidName(StringPiece unknown_name,
StringPiece message) {
listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
@@ -643,6 +648,11 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
return this;
} else if (element_ != NULL &&
(element_->IsMap() || element_->IsStructMap())) {
+ if (!ValidMapKey(name)) {
+ ++invalid_depth_;
+ return this;
+ }
+
field = StartMapEntry(name);
if (element_->IsStructMapEntry()) {
// If the top element is a map entry, this means we are starting another
@@ -698,7 +708,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
element_.reset(
new ProtoElement(element_.release(), field, *type, ProtoElement::MAP));
} else {
- WriteTag(*field);
+ WriteTag(*field);
element_.reset(new ProtoElement(element_.release(), field, *type,
ProtoElement::MESSAGE));
}
@@ -863,6 +873,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
// struct.
SkipElements();
+
// If ending the root element,
// then serialize the full message with calculated sizes.
if (element_ == NULL) {
@@ -914,6 +925,11 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
// Check if we need to start a map. This can heppen when there is either a map
// or a struct type within a list.
if (element_->IsMap() || element_->IsStructMap()) {
+ if (!ValidMapKey(name)) {
+ ++invalid_depth_;
+ return this;
+ }
+
field = StartMapEntry(name);
if (field == NULL) return this;
@@ -969,7 +985,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
ProtoElement::MESSAGE));
InvalidValue("Map", "Cannot bind a list to map.");
++invalid_depth_;
- element_->pop();
+ element_.reset(element_->pop());
return this;
}
@@ -1188,6 +1204,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
type_url = GetFullTypeWithUrl(master_type_.name());
} else {
if (element_->IsMap() || element_->IsStructMap()) {
+ if (!ValidMapKey(name)) return this;
is_map_entry = true;
field = StartMapEntry(name);
} else {
@@ -1462,6 +1479,19 @@ bool ProtoStreamObjectWriter::ValidOneof(const google::protobuf::Field& field,
return true;
}
+bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
+ if (element_ == NULL) return true;
+
+ if (!element_->InsertMapKeyIfNotPresent(unnormalized_name)) {
+ InvalidName(
+ unnormalized_name,
+ StrCat("Repeated map key: '", unnormalized_name, "' is already set."));
+ return false;
+ }
+
+ return true;
+}
+
const google::protobuf::Field* ProtoStreamObjectWriter::BeginNamed(
StringPiece name, bool is_list) {
if (invalid_depth_ > 0) {
@@ -1614,6 +1644,7 @@ void ProtoStreamObjectWriter::WriteTag(const google::protobuf::Field& field) {
stream_->WriteTag(WireFormatLite::MakeTag(field.number(), wire_type));
}
+
} // namespace converter
} // namespace util
} // namespace protobuf
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
index 8f49120b..19f747fe 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.h
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -259,6 +259,13 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
// generate an error.
void TakeOneofIndex(int32 index);
+ // Inserts map key into hash set if and only if the key did NOT already
+ // exist in hash set.
+ // The hash set (map_keys_) is ONLY used to keep track of map keys.
+ // Return true if insert successfully; returns false if the map key was
+ // already present.
+ bool InsertMapKeyIfNotPresent(StringPiece map_key);
+
private:
// Used for access to variables of the enclosing instance of
// ProtoStreamObjectWriter.
@@ -296,6 +303,10 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
// incoming messages so no more than one oneof is set.
hash_set<int32> oneof_indices_;
+ // Set of map keys already seen for the type_. Used to validate incoming
+ // messages so no map key appears more than once.
+ hash_set<StringPiece> map_keys_;
+
GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement);
};
@@ -378,6 +389,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
// Helper method to write proto tags based on the given field.
void WriteTag(const google::protobuf::Field& field);
+
// Helper function to render primitive data types in DataPiece.
void RenderSimpleDataPiece(const google::protobuf::Field& field,
const google::protobuf::Type& type,
@@ -424,6 +436,14 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter
bool ValidOneof(const google::protobuf::Field& field,
StringPiece unnormalized_name);
+ // Returns true if the map key for type_ is not duplicated key.
+ // If map key is duplicated key, this function returns false.
+ // Note that caller should make sure that the current proto element (element_)
+ // is of element type MAP or STRUCT_MAP.
+ // It also calls the appropriate error callback and unnormalzied_name is used
+ // for error string.
+ bool ValidMapKey(StringPiece unnormalized_name);
+
// Variables for describing the structure of the input tree:
// master_type_: descriptor for the whole protobuf message.
// typeinfo_ : the TypeInfo object to lookup types.
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
index 96e5ccfb..941fa71a 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -45,6 +45,7 @@
#include <google/protobuf/util/internal/testdata/field_mask.pb.h>
#include <google/protobuf/util/internal/type_info_test_helper.h>
#include <google/protobuf/util/internal/constants.h>
+#include <google/protobuf/util/message_differencer.h>
#include <google/protobuf/stubs/bytestream.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/util/internal/testdata/anys.pb.h>
@@ -139,7 +140,9 @@ class BaseProtoStreamObjectWriterTest
google::protobuf::scoped_ptr<Message> message(expected.New());
message->ParsePartialFromIstream(&istream);
- EXPECT_EQ(expected.DebugString(), message->DebugString());
+ if (!MessageDifferencer::Equivalent(expected, *message)) {
+ EXPECT_EQ(expected.DebugString(), message->DebugString());
+ }
}
void CheckOutput(const Message& expected) { CheckOutput(expected, -1); }
@@ -851,15 +854,19 @@ class ProtoStreamObjectWriterTimestampDurationTest
}
};
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+ ProtoStreamObjectWriterTimestampDurationTest,
+ ::testing::Values(
+ testing::USE_TYPE_RESOLVER));
+
TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) {
TimestampDuration timestamp;
EXPECT_CALL(
listener_,
- InvalidValue(
- _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
- StringPiece("Field 'ts', Illegal timestamp format; timestamps "
- "must end with 'Z'")));
+ InvalidValue(_,
+ StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+ StringPiece("Field 'ts', Invalid time format: ")));
ow_->StartObject("")->RenderString("ts", "")->EndObject();
CheckOutput(timestamp);
@@ -870,10 +877,9 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError2) {
EXPECT_CALL(
listener_,
- InvalidValue(
- _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
- StringPiece(
- "Field 'ts', Invalid time format: Failed to parse input")));
+ InvalidValue(_,
+ StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+ StringPiece("Field 'ts', Invalid time format: Z")));
ow_->StartObject("")->RenderString("ts", "Z")->EndObject();
CheckOutput(timestamp);
@@ -884,10 +890,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError3) {
EXPECT_CALL(
listener_,
- InvalidValue(
- _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
- StringPiece("Field 'ts', Invalid time format, failed to parse nano "
- "seconds")));
+ InvalidValue(_,
+ StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
+ StringPiece("Field 'ts', Invalid time format: "
+ "1970-01-01T00:00:00.ABZ")));
ow_->StartObject("")
->RenderString("ts", "1970-01-01T00:00:00.ABZ")
@@ -902,7 +908,8 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) {
listener_,
InvalidValue(_,
StringPiece("type.googleapis.com/google.protobuf.Timestamp"),
- StringPiece("Field 'ts', Timestamp value exceeds limits")));
+ StringPiece("Field 'ts', Invalid time format: "
+ "-8032-10-18T00:00:00.000Z")));
ow_->StartObject("")
->RenderString("ts", "-8032-10-18T00:00:00.000Z")
@@ -1008,6 +1015,11 @@ class ProtoStreamObjectWriterStructTest
}
};
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+ ProtoStreamObjectWriterStructTest,
+ ::testing::Values(
+ testing::USE_TYPE_RESOLVER));
+
// TODO(skarvaje): Write tests for failure cases.
TEST_P(ProtoStreamObjectWriterStructTest, StructRenderSuccess) {
StructType struct_type;
@@ -1046,12 +1058,62 @@ TEST_P(ProtoStreamObjectWriterStructTest, StructInvalidInputFailure) {
CheckOutput(struct_type);
}
+TEST_P(ProtoStreamObjectWriterStructTest, SimpleRepeatedStructMapKeyTest) {
+ EXPECT_CALL(
+ listener_,
+ InvalidName(_, StringPiece("k1"),
+ StringPiece("Repeated map key: 'k1' is already set.")));
+ ow_->StartObject("")
+ ->StartObject("object")
+ ->RenderString("k1", "v1")
+ ->RenderString("k1", "v2")
+ ->EndObject()
+ ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapListKeyTest) {
+ EXPECT_CALL(
+ listener_,
+ InvalidName(_, StringPiece("k1"),
+ StringPiece("Repeated map key: 'k1' is already set.")));
+ ow_->StartObject("")
+ ->StartObject("object")
+ ->RenderString("k1", "v1")
+ ->StartList("k1")
+ ->RenderString("", "v2")
+ ->EndList()
+ ->EndObject()
+ ->EndObject();
+}
+
+TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) {
+ EXPECT_CALL(
+ listener_,
+ InvalidName(_, StringPiece("k1"),
+ StringPiece("Repeated map key: 'k1' is already set.")));
+ ow_->StartObject("")
+ ->StartObject("object")
+ ->StartObject("k1")
+ ->RenderString("sub_k1", "v1")
+ ->EndObject()
+ ->StartObject("k1")
+ ->RenderString("sub_k2", "v2")
+ ->EndObject()
+ ->EndObject()
+ ->EndObject();
+}
+
class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest {
protected:
ProtoStreamObjectWriterMapTest()
: BaseProtoStreamObjectWriterTest(MapIn::descriptor()) {}
};
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+ ProtoStreamObjectWriterMapTest,
+ ::testing::Values(
+ testing::USE_TYPE_RESOLVER));
+
TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) {
MapIn mm;
EXPECT_CALL(listener_,
@@ -1066,17 +1128,37 @@ TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) {
CheckOutput(mm);
}
+TEST_P(ProtoStreamObjectWriterMapTest, RepeatedMapKeyTest) {
+ EXPECT_CALL(
+ listener_,
+ InvalidName(_, StringPiece("k1"),
+ StringPiece("Repeated map key: 'k1' is already set.")));
+ ow_->StartObject("")
+ ->RenderString("other", "test")
+ ->StartObject("map_input")
+ ->RenderString("k1", "v1")
+ ->RenderString("k1", "v2")
+ ->EndObject()
+ ->EndObject();
+}
+
class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest {
protected:
ProtoStreamObjectWriterAnyTest() {
vector<const Descriptor*> descriptors;
descriptors.push_back(AnyOut::descriptor());
descriptors.push_back(google::protobuf::DoubleValue::descriptor());
+ descriptors.push_back(google::protobuf::Timestamp::descriptor());
descriptors.push_back(google::protobuf::Any::descriptor());
ResetTypeInfo(descriptors);
}
};
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+ ProtoStreamObjectWriterAnyTest,
+ ::testing::Values(
+ testing::USE_TYPE_RESOLVER));
+
TEST_P(ProtoStreamObjectWriterAnyTest, AnyRenderSuccess) {
AnyOut any;
google::protobuf::Any* any_type = any.mutable_any();
@@ -1119,8 +1201,6 @@ TEST_P(ProtoStreamObjectWriterAnyTest, RecursiveAny) {
->EndObject()
->EndObject()
->EndObject();
-
- CheckOutput(out, 115);
}
TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) {
@@ -1155,8 +1235,6 @@ TEST_P(ProtoStreamObjectWriterAnyTest, DoubleRecursiveAny) {
->EndObject()
->EndObject()
->EndObject();
-
- CheckOutput(out, 159);
}
TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) {
@@ -1263,6 +1341,23 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyNullInputFails) {
CheckOutput(any);
}
+TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) {
+ EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"),
+ StringPiece("Invalid time format: ")));
+
+ AnyOut any;
+ google::protobuf::Any* any_type = any.mutable_any();
+ any_type->set_type_url("type.googleapis.com/google.protobuf.Timestamp");
+
+ ow_->StartObject("")
+ ->StartObject("any")
+ ->RenderString("@type", "type.googleapis.com/google.protobuf.Timestamp")
+ ->RenderString("value", "")
+ ->EndObject()
+ ->EndObject();
+ CheckOutput(any);
+}
+
class ProtoStreamObjectWriterFieldMaskTest
: public BaseProtoStreamObjectWriterTest {
protected:
@@ -1274,6 +1369,11 @@ class ProtoStreamObjectWriterFieldMaskTest
}
};
+INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
+ ProtoStreamObjectWriterFieldMaskTest,
+ ::testing::Values(
+ testing::USE_TYPE_RESOLVER));
+
TEST_P(ProtoStreamObjectWriterFieldMaskTest, SimpleFieldMaskTest) {
FieldMaskTest expected;
expected.set_id("1");
@@ -1683,6 +1783,7 @@ TEST_P(ProtoStreamObjectWriterOneOfsTest,
ow_->RenderString("strData", "blah");
ow_->RenderInt32("intData", 123);
ow_->EndObject();
+ ow_->EndObject();
}
} // namespace converter
diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc
index 5d7dcc87..61899c24 100644
--- a/src/google/protobuf/util/internal/utility.cc
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -298,16 +298,21 @@ bool IsMap(const google::protobuf::Field& field,
"google.protobuf.MessageOptions.map_entry", false));
}
+bool IsMessageSetWireFormat(const google::protobuf::Type& type) {
+ return GetBoolOptionOrDefault(
+ type.options(), "google.protobuf.MessageOptions.message_set_wire_format", false);
+}
+
string DoubleAsString(double value) {
- if (google::protobuf::MathLimits<double>::IsPosInf(value)) return "Infinity";
- if (google::protobuf::MathLimits<double>::IsNegInf(value)) return "-Infinity";
- if (google::protobuf::MathLimits<double>::IsNaN(value)) return "NaN";
+ if (MathLimits<double>::IsPosInf(value)) return "Infinity";
+ if (MathLimits<double>::IsNegInf(value)) return "-Infinity";
+ if (MathLimits<double>::IsNaN(value)) return "NaN";
return SimpleDtoa(value);
}
string FloatAsString(float value) {
- if (google::protobuf::MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
+ if (MathLimits<float>::IsFinite(value)) return SimpleFtoa(value);
return DoubleAsString(value);
}
@@ -318,7 +323,7 @@ bool SafeStrToFloat(StringPiece str, float *value) {
}
*value = static_cast<float>(double_value);
- if (google::protobuf::MathLimits<float>::IsInf(*value)) {
+ if (MathLimits<float>::IsInf(*value)) {
return false;
}
return true;
diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h
index 87f7602a..5ba97bd2 100644
--- a/src/google/protobuf/util/internal/utility.h
+++ b/src/google/protobuf/util/internal/utility.h
@@ -138,9 +138,6 @@ const google::protobuf::EnumValue* FindEnumValueByNumberOrNull(
const google::protobuf::Enum* enum_type, int32 value);
// Converts input to camel-case and returns it.
-// Tests are in wrappers/translator/snake2camel_objectwriter_test.cc
-// TODO(skarvaje): Isolate tests for this function and put them in
-// utility_test.cc
LIBPROTOBUF_EXPORT string ToCamelCase(const StringPiece input);
// Converts input to snake_case and returns it.
@@ -157,6 +154,9 @@ LIBPROTOBUF_EXPORT bool IsValidBoolString(const string& bool_string);
LIBPROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field,
const google::protobuf::Type& type);
+// Returns true if the given type has special MessageSet wire format.
+bool IsMessageSetWireFormat(const google::protobuf::Type& type);
+
// Infinity/NaN-aware conversion to string.
LIBPROTOBUF_EXPORT string DoubleAsString(double value);
LIBPROTOBUF_EXPORT string FloatAsString(float value);