Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement binary conformance test for oneof fields #6622

Merged
merged 3 commits into from Sep 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
166 changes: 166 additions & 0 deletions conformance/binary_json_conformance_suite.cc
Expand Up @@ -280,6 +280,25 @@ const FieldDescriptor* GetFieldForMapType(
return nullptr;
}

const FieldDescriptor* GetFieldForOneofType(
FieldDescriptor::Type type, bool is_proto3, bool exclusive = false) {
const Descriptor* d = is_proto3 ?
TestAllTypesProto3().GetDescriptor() : TestAllTypesProto2().GetDescriptor();
for (int i = 0; i < d->field_count(); i++) {
const FieldDescriptor* f = d->field(i);
if (f->containing_oneof() && ((f->type() == type) ^ exclusive)) {
return f;
}
}

const string proto_string = is_proto3 ? "Proto3" : "Proto2";
GOOGLE_LOG(FATAL) << "Couldn't find oneof field with type: "
<< FieldDescriptor::TypeName(type)
<< " for "
<< proto_string.c_str();
return nullptr;
}

string UpperCase(string str) {
for (int i = 0; i < str.size(); i++) {
str[i] = toupper(str[i]);
Expand Down Expand Up @@ -1111,6 +1130,141 @@ void BinaryAndJsonConformanceSuite::TestOverwriteMessageValueMap() {
}
}

void BinaryAndJsonConformanceSuite::TestValidDataForOneofType(
FieldDescriptor::Type type) {
const string type_name =
UpperCase(string(".") + FieldDescriptor::TypeName(type));
WireFormatLite::WireType wire_type =
WireFormatLite::WireTypeForFieldType(
static_cast<WireFormatLite::FieldType>(type));

for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) {
const FieldDescriptor* field = GetFieldForOneofType(type, is_proto3);
const string default_value =
cat(tag(field->number(), wire_type), GetDefaultValue(type));
const string non_default_value =
cat(tag(field->number(), wire_type), GetNonDefaultValue(type));

{
// Tests oneof with default value.
const string proto = default_value;
std::unique_ptr<Message> test_message = NewTestMessage(is_proto3);
test_message->MergeFromString(proto);
string text = test_message->DebugString();

RunValidProtobufTest(StrCat("ValidDataOneof", type_name, ".DefaultValue"),
REQUIRED, proto, text, is_proto3);
RunValidBinaryProtobufTest(
StrCat("ValidDataOneofBinary", type_name, ".DefaultValue"),
RECOMMENDED, proto, proto, is_proto3);
}

{
// Tests oneof with non-default value.
const string proto = non_default_value;
std::unique_ptr<Message> test_message = NewTestMessage(is_proto3);
test_message->MergeFromString(proto);
string text = test_message->DebugString();

RunValidProtobufTest(
StrCat("ValidDataOneof", type_name, ".NonDefaultValue"),
REQUIRED, proto, text, is_proto3);
RunValidBinaryProtobufTest(
StrCat("ValidDataOneofBinary", type_name, ".NonDefaultValue"),
RECOMMENDED, proto, proto, is_proto3);
}

{
// Tests oneof with multiple values of the same field.
const string proto = StrCat(default_value, non_default_value);
const string expected_proto = non_default_value;
std::unique_ptr<Message> test_message = NewTestMessage(is_proto3);
test_message->MergeFromString(expected_proto);
string text = test_message->DebugString();

RunValidProtobufTest(
StrCat("ValidDataOneof", type_name, ".MultipleValuesForSameField"),
REQUIRED, proto, text, is_proto3);
RunValidBinaryProtobufTest(
StrCat("ValidDataOneofBinary", type_name,
".MultipleValuesForSameField"),
RECOMMENDED, proto, expected_proto, is_proto3);
}

{
// Tests oneof with multiple values of the different fields.
const FieldDescriptor* other_field =
GetFieldForOneofType(type, is_proto3, true);
FieldDescriptor::Type other_type = other_field->type();
WireFormatLite::WireType other_wire_type =
WireFormatLite::WireTypeForFieldType(
static_cast<WireFormatLite::FieldType>(other_type));
const string other_value =
cat(tag(other_field->number(), other_wire_type),
GetDefaultValue(other_type));

const string proto = StrCat(other_value, non_default_value);
const string expected_proto = non_default_value;
std::unique_ptr<Message> test_message = NewTestMessage(is_proto3);
test_message->MergeFromString(expected_proto);
string text = test_message->DebugString();

RunValidProtobufTest(
StrCat("ValidDataOneof", type_name,
".MultipleValuesForDifferentField"),
REQUIRED, proto, text, is_proto3);
RunValidBinaryProtobufTest(
StrCat("ValidDataOneofBinary", type_name,
".MultipleValuesForDifferentField"),
RECOMMENDED, proto, expected_proto, is_proto3);
}
}
}

void BinaryAndJsonConformanceSuite::TestMergeOneofMessage() {
string field1_data = cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1));
string field2a_data = cat(tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1));
string field2b_data = cat(tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1));
string field89_data = cat(tag(89, WireFormatLite::WIRETYPE_VARINT),
varint(1));
string submsg1_data =
cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
delim(cat(field1_data, field2a_data, field89_data)));
string submsg2_data =
cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
delim(cat(field2b_data, field89_data)));
string merged_data = cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
delim(cat(field1_data, field2b_data,
field89_data, field89_data)));

for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) {
const FieldDescriptor* field =
GetFieldForOneofType(FieldDescriptor::TYPE_MESSAGE, is_proto3);

string proto1 = cat(tag(field->number(),
WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
delim(submsg1_data));
string proto2 = cat(tag(field->number(),
WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
delim(submsg2_data));
string proto = cat(proto1, proto2);
string expected_proto =
cat(tag(field->number(),
WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
delim(merged_data));

std::unique_ptr<Message> test_message = NewTestMessage(is_proto3);
test_message->MergeFromString(expected_proto);
string text = test_message->DebugString();
RunValidProtobufTest(
"ValidDataOneof.MESSAGE.Merge",
REQUIRED, proto, text, is_proto3);
RunValidBinaryProtobufTest(
"ValidDataOneofBinary.MESSAGE.Merge",
RECOMMENDED, proto, expected_proto, is_proto3);
}
}

void BinaryAndJsonConformanceSuite::TestIllegalTags() {
// field num 0 is illegal
string nullfield[] = {
Expand Down Expand Up @@ -1369,6 +1523,18 @@ void BinaryAndJsonConformanceSuite::RunSuiteImpl() {
// Additional test to check overwriting message value map.
TestOverwriteMessageValueMap();

TestValidDataForOneofType(FieldDescriptor::TYPE_UINT32);
TestValidDataForOneofType(FieldDescriptor::TYPE_BOOL);
TestValidDataForOneofType(FieldDescriptor::TYPE_UINT64);
TestValidDataForOneofType(FieldDescriptor::TYPE_FLOAT);
TestValidDataForOneofType(FieldDescriptor::TYPE_DOUBLE);
TestValidDataForOneofType(FieldDescriptor::TYPE_STRING);
TestValidDataForOneofType(FieldDescriptor::TYPE_BYTES);
TestValidDataForOneofType(FieldDescriptor::TYPE_ENUM);
TestValidDataForOneofType(FieldDescriptor::TYPE_MESSAGE);
// Additional test to check merging oneof message.
TestMergeOneofMessage();

// TODO(haberman):
// TestValidDataForType(FieldDescriptor::TYPE_GROUP

Expand Down
3 changes: 3 additions & 0 deletions conformance/binary_json_conformance_suite.h
Expand Up @@ -118,6 +118,9 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite {
void TestValidDataForMapType(
google::protobuf::FieldDescriptor::Type,
google::protobuf::FieldDescriptor::Type);
void TestValidDataForOneofType(
google::protobuf::FieldDescriptor::Type);
void TestMergeOneofMessage();
void TestOverwriteMessageValueMap();

std::unique_ptr<google::protobuf::util::TypeResolver>
Expand Down
3 changes: 3 additions & 0 deletions conformance/failure_list_php.txt
Expand Up @@ -4,6 +4,7 @@ Recommended.FieldMaskTooManyUnderscore.JsonOutput
Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
Recommended.Proto3.ProtobufInput.ValidDataOneofBinary.MESSAGE.Merge.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.DefaultOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.PackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.DefaultOutput.ProtobufOutput
Expand Down Expand Up @@ -78,3 +79,5 @@ Required.Proto3.ProtobufInput.RepeatedScalarMessageMerge.ProtobufOutput
Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.JsonOutput
Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.JsonOutput
Required.Proto3.ProtobufInput.ValidDataScalar.FLOAT[2].JsonOutput
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.Merge.JsonOutput
Required.Proto3.ProtobufInput.ValidDataOneof.MESSAGE.Merge.ProtobufOutput
1 change: 1 addition & 0 deletions conformance/failure_list_php_c.txt
Expand Up @@ -107,3 +107,4 @@ Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.PackedInput.PackedOutp
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT32.UnpackedInput.PackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.PackedOutput.ProtobufOutput
Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.PackedOutput.ProtobufOutput
Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.DefaultValue.JsonOutput