Commit 02452db7 authored by Alexey Malov's avatar Alexey Malov Committed by Alexey Malov

The JsonParseOptions::ignore_unknown_fields option behavior treats

unrecognized string values in enum fields as default ones.
parent 47b7d2c7
...@@ -272,7 +272,8 @@ StatusOr<string> DataPiece::ToBytes() const { ...@@ -272,7 +272,8 @@ StatusOr<string> DataPiece::ToBytes() const {
} }
StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type, StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type,
bool use_lower_camel_for_enums) const { bool use_lower_camel_for_enums,
bool ignore_unknown_enum_values) const {
if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE; if (type_ == TYPE_NULL) return google::protobuf::NULL_VALUE;
if (type_ == TYPE_STRING) { if (type_ == TYPE_STRING) {
...@@ -305,6 +306,10 @@ StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type, ...@@ -305,6 +306,10 @@ StatusOr<int> DataPiece::ToEnum(const google::protobuf::Enum* enum_type,
value = FindEnumValueByNameWithoutUnderscoreOrNull(enum_type, enum_name); value = FindEnumValueByNameWithoutUnderscoreOrNull(enum_type, enum_name);
if (value != NULL) return value->number(); if (value != NULL) return value->number();
} }
// If ignore_unknown_enum_values is true an unknown enum value is treated
// as the default
if (ignore_unknown_enum_values) return enum_type->enumvalue(0).number();
} else { } else {
// We don't need to check whether the value is actually declared in the // We don't need to check whether the value is actually declared in the
// enum because we preserve unknown enum values as well. // enum because we preserve unknown enum values as well.
......
...@@ -164,7 +164,8 @@ class LIBPROTOBUF_EXPORT DataPiece { ...@@ -164,7 +164,8 @@ class LIBPROTOBUF_EXPORT DataPiece {
// If the value is not a string, attempts to convert to a 32-bit integer. // If the value is not a string, attempts to convert to a 32-bit integer.
// If none of these succeeds, returns a conversion error status. // If none of these succeeds, returns a conversion error status.
util::StatusOr<int> ToEnum(const google::protobuf::Enum* enum_type, util::StatusOr<int> ToEnum(const google::protobuf::Enum* enum_type,
bool use_lower_camel_for_enums) const; bool use_lower_camel_for_enums,
bool ignore_unknown_enum_values) const;
private: private:
// Disallow implicit constructor. // Disallow implicit constructor.
......
...@@ -267,8 +267,9 @@ inline Status WriteString(int field_number, const DataPiece& data, ...@@ -267,8 +267,9 @@ inline Status WriteString(int field_number, const DataPiece& data,
inline Status WriteEnum(int field_number, const DataPiece& data, inline Status WriteEnum(int field_number, const DataPiece& data,
const google::protobuf::Enum* enum_type, const google::protobuf::Enum* enum_type,
CodedOutputStream* stream, CodedOutputStream* stream,
bool use_lower_camel_for_enums) { bool use_lower_camel_for_enums,
StatusOr<int> e = data.ToEnum(enum_type, use_lower_camel_for_enums); bool ignore_unknown_values) {
StatusOr<int> e = data.ToEnum(enum_type, use_lower_camel_for_enums, ignore_unknown_values);
if (e.ok()) { if (e.ok()) {
WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream); WireFormatLite::WriteEnum(field_number, e.ValueOrDie(), stream);
} }
...@@ -665,7 +666,8 @@ ProtoWriter* ProtoWriter::RenderPrimitiveField( ...@@ -665,7 +666,8 @@ ProtoWriter* ProtoWriter::RenderPrimitiveField(
case google::protobuf::Field_Kind_TYPE_ENUM: { case google::protobuf::Field_Kind_TYPE_ENUM: {
status = WriteEnum(field.number(), data, status = WriteEnum(field.number(), data,
typeinfo_->GetEnumByTypeUrl(field.type_url()), typeinfo_->GetEnumByTypeUrl(field.type_url()),
stream_.get(), use_lower_camel_for_enums_); stream_.get(), use_lower_camel_for_enums_,
ignore_unknown_fields_);
break; break;
} }
default: // TYPE_GROUP or TYPE_MESSAGE default: // TYPE_GROUP or TYPE_MESSAGE
......
...@@ -309,7 +309,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { ...@@ -309,7 +309,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter {
// Indicates whether we finished writing root message completely. // Indicates whether we finished writing root message completely.
bool done_; bool done_;
// If true, don't report unknown field names to the listener. // If true, don't report unknown field names and enum values to the listener.
bool ignore_unknown_fields_; bool ignore_unknown_fields_;
// If true, check if enum name in camel case or without underscore matches the // If true, check if enum name in camel case or without underscore matches the
......
...@@ -333,6 +333,64 @@ TEST_F(JsonUtilTest, TestDynamicMessage) { ...@@ -333,6 +333,64 @@ TEST_F(JsonUtilTest, TestDynamicMessage) {
EXPECT_EQ(ToJson(generated, options), ToJson(*message, options)); EXPECT_EQ(ToJson(generated, options), ToJson(*message, options));
} }
TEST_F(JsonUtilTest, TestParsingUnknownEnumsAs0) {
TestMessage m;
{
JsonParseOptions options;
ASSERT_FALSE(options.ignore_unknown_fields);
string input =
"{\n"
" \"enum_value\":\"UNKNOWN_VALUE\"\n"
"}";
m.set_enum_value(proto3::BAR);
EXPECT_FALSE(FromJson(input, &m, options));
ASSERT_EQ(proto3::BAR, m.enum_value()); // Keep previous value
options.ignore_unknown_fields = true;
EXPECT_TRUE(FromJson(input, &m, options));
EXPECT_EQ(0, m.enum_value()); // Unknown enum value must be decoded as 0
}
// Integer values are read as usual
{
JsonParseOptions options;
string input =
"{\n"
" \"enum_value\":12345\n"
"}";
m.set_enum_value(proto3::BAR);
EXPECT_TRUE(FromJson(input, &m, options));
ASSERT_EQ(12345, m.enum_value());
options.ignore_unknown_fields = true;
EXPECT_TRUE(FromJson(input, &m, options));
EXPECT_EQ(12345, m.enum_value());
}
// Trying to pass an object as an enum field value is always treated as an error
{
JsonParseOptions options;
string input =
"{\n"
" \"enum_value\":{}\n"
"}";
options.ignore_unknown_fields = true;
EXPECT_FALSE(FromJson(input, &m, options));
options.ignore_unknown_fields = false;
EXPECT_FALSE(FromJson(input, &m, options));
}
// Trying to pass an array as an enum field value is always treated as an error
{
JsonParseOptions options;
string input =
"{\n"
" \"enum_value\":[]\n"
"}";
EXPECT_FALSE(FromJson(input, &m, options));
options.ignore_unknown_fields = true;
EXPECT_FALSE(FromJson(input, &m, options));
}
}
typedef std::pair<char*, int> Segment; typedef std::pair<char*, int> Segment;
// A ZeroCopyOutputStream that writes to multiple buffers. // A ZeroCopyOutputStream that writes to multiple buffers.
class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream { class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment