diff --git a/conformance/binary_json_conformance_suite.cc b/conformance/binary_json_conformance_suite.cc index 09bc91f772..07d8e91ad1 100644 --- a/conformance/binary_json_conformance_suite.cc +++ b/conformance/binary_json_conformance_suite.cc @@ -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]); @@ -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(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 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 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 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(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 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 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[] = { @@ -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 diff --git a/conformance/binary_json_conformance_suite.h b/conformance/binary_json_conformance_suite.h index 1d8cca8d15..1720c1dd15 100644 --- a/conformance/binary_json_conformance_suite.h +++ b/conformance/binary_json_conformance_suite.h @@ -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 diff --git a/conformance/failure_list_php.txt b/conformance/failure_list_php.txt index 11512de675..d30fb3d8bb 100644 --- a/conformance/failure_list_php.txt +++ b/conformance/failure_list_php.txt @@ -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 @@ -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 diff --git a/conformance/failure_list_php_c.txt b/conformance/failure_list_php_c.txt index cb60d37262..0f28ae6c69 100644 --- a/conformance/failure_list_php_c.txt +++ b/conformance/failure_list_php_c.txt @@ -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