Commit 2ff42dcf authored by Joshua Haberman's avatar Joshua Haberman Committed by GitHub

Added conformance testing for binary primitive types. (#2491)

This is basic and more tests will be added over time.
parent f983302c
...@@ -132,8 +132,8 @@ string fixed32(void *data) { return string(static_cast<char*>(data), 4); } ...@@ -132,8 +132,8 @@ string fixed32(void *data) { return string(static_cast<char*>(data), 4); }
string fixed64(void *data) { return string(static_cast<char*>(data), 8); } string fixed64(void *data) { return string(static_cast<char*>(data), 8); }
string delim(const string& buf) { return cat(varint(buf.size()), buf); } string delim(const string& buf) { return cat(varint(buf.size()), buf); }
string uint32(uint32_t u32) { return fixed32(&u32); } string u32(uint32_t u32) { return fixed32(&u32); }
string uint64(uint64_t u64) { return fixed64(&u64); } string u64(uint64_t u64) { return fixed64(&u64); }
string flt(float f) { return fixed32(&f); } string flt(float f) { return fixed32(&f); }
string dbl(double d) { return fixed64(&d); } string dbl(double d) { return fixed64(&d); }
string zz32(int32_t x) { return varint(WireFormatLite::ZigZagEncode32(x)); } string zz32(int32_t x) { return varint(WireFormatLite::ZigZagEncode32(x)); }
...@@ -149,16 +149,17 @@ string submsg(uint32_t fn, const string& buf) { ...@@ -149,16 +149,17 @@ string submsg(uint32_t fn, const string& buf) {
#define UNKNOWN_FIELD 666 #define UNKNOWN_FIELD 666
uint32_t GetFieldNumberForType(FieldDescriptor::Type type, bool repeated) { const FieldDescriptor* GetFieldForType(FieldDescriptor::Type type,
bool repeated) {
const Descriptor* d = TestAllTypes().GetDescriptor(); const Descriptor* d = TestAllTypes().GetDescriptor();
for (int i = 0; i < d->field_count(); i++) { for (int i = 0; i < d->field_count(); i++) {
const FieldDescriptor* f = d->field(i); const FieldDescriptor* f = d->field(i);
if (f->type() == type && f->is_repeated() == repeated) { if (f->type() == type && f->is_repeated() == repeated) {
return f->number(); return f;
} }
} }
GOOGLE_LOG(FATAL) << "Couldn't find field with type " << (int)type; GOOGLE_LOG(FATAL) << "Couldn't find field with type " << (int)type;
return 0; return nullptr;
} }
string UpperCase(string str) { string UpperCase(string str) {
...@@ -425,14 +426,22 @@ void ConformanceTestSuite::RunValidJsonTestWithProtobufInput( ...@@ -425,14 +426,22 @@ void ConformanceTestSuite::RunValidJsonTestWithProtobufInput(
} }
void ConformanceTestSuite::RunValidProtobufTest( void ConformanceTestSuite::RunValidProtobufTest(
const string& test_name, ConformanceLevel level,
const string& input_protobuf, const string& equivalent_text_format) {
RunValidInputTest(
ConformanceLevelToString(level) + ".ProtobufInput." + test_name +
".ProtobufOutput", level, input_protobuf, conformance::PROTOBUF,
equivalent_text_format, conformance::PROTOBUF);
RunValidInputTest(
ConformanceLevelToString(level) + ".ProtobufInput." + test_name +
".JsonOutput", level, input_protobuf, conformance::PROTOBUF,
equivalent_text_format, conformance::JSON);
}
void ConformanceTestSuite::RunValidProtobufTestWithMessage(
const string& test_name, ConformanceLevel level, const TestAllTypes& input, const string& test_name, ConformanceLevel level, const TestAllTypes& input,
const string& equivalent_text_format) { const string& equivalent_text_format) {
RunValidInputTest("ProtobufInput." + test_name + ".ProtobufOutput", level, RunValidProtobufTest(test_name, level, input.SerializeAsString(), equivalent_text_format);
input.SerializeAsString(), conformance::PROTOBUF,
equivalent_text_format, conformance::PROTOBUF);
RunValidInputTest("ProtobufInput." + test_name + ".JsonOutput", level,
input.SerializeAsString(), conformance::PROTOBUF,
equivalent_text_format, conformance::JSON);
} }
// According to proto3 JSON specification, JSON serializers follow more strict // According to proto3 JSON specification, JSON serializers follow more strict
...@@ -539,8 +548,8 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) { ...@@ -539,8 +548,8 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) {
string("abc") // 32BIT string("abc") // 32BIT
}; };
uint32_t fieldnum = GetFieldNumberForType(type, false); const FieldDescriptor* field = GetFieldForType(type, false);
uint32_t rep_fieldnum = GetFieldNumberForType(type, true); const FieldDescriptor* rep_field = GetFieldForType(type, true);
WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
static_cast<WireFormatLite::FieldType>(type)); static_cast<WireFormatLite::FieldType>(type));
const string& incomplete = incompletes[wire_type]; const string& incomplete = incompletes[wire_type];
...@@ -548,11 +557,11 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) { ...@@ -548,11 +557,11 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) {
UpperCase(string(".") + FieldDescriptor::TypeName(type)); UpperCase(string(".") + FieldDescriptor::TypeName(type));
ExpectParseFailureForProto( ExpectParseFailureForProto(
tag(fieldnum, wire_type), tag(field->number(), wire_type),
"PrematureEofBeforeKnownNonRepeatedValue" + type_name, REQUIRED); "PrematureEofBeforeKnownNonRepeatedValue" + type_name, REQUIRED);
ExpectParseFailureForProto( ExpectParseFailureForProto(
tag(rep_fieldnum, wire_type), tag(rep_field->number(), wire_type),
"PrematureEofBeforeKnownRepeatedValue" + type_name, REQUIRED); "PrematureEofBeforeKnownRepeatedValue" + type_name, REQUIRED);
ExpectParseFailureForProto( ExpectParseFailureForProto(
...@@ -560,11 +569,11 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) { ...@@ -560,11 +569,11 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) {
"PrematureEofBeforeUnknownValue" + type_name, REQUIRED); "PrematureEofBeforeUnknownValue" + type_name, REQUIRED);
ExpectParseFailureForProto( ExpectParseFailureForProto(
cat( tag(fieldnum, wire_type), incomplete ), cat( tag(field->number(), wire_type), incomplete ),
"PrematureEofInsideKnownNonRepeatedValue" + type_name, REQUIRED); "PrematureEofInsideKnownNonRepeatedValue" + type_name, REQUIRED);
ExpectParseFailureForProto( ExpectParseFailureForProto(
cat( tag(rep_fieldnum, wire_type), incomplete ), cat( tag(rep_field->number(), wire_type), incomplete ),
"PrematureEofInsideKnownRepeatedValue" + type_name, REQUIRED); "PrematureEofInsideKnownRepeatedValue" + type_name, REQUIRED);
ExpectParseFailureForProto( ExpectParseFailureForProto(
...@@ -573,12 +582,12 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) { ...@@ -573,12 +582,12 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) {
if (wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { if (wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
ExpectParseFailureForProto( ExpectParseFailureForProto(
cat( tag(fieldnum, wire_type), varint(1) ), cat( tag(field->number(), wire_type), varint(1) ),
"PrematureEofInDelimitedDataForKnownNonRepeatedValue" + type_name, "PrematureEofInDelimitedDataForKnownNonRepeatedValue" + type_name,
REQUIRED); REQUIRED);
ExpectParseFailureForProto( ExpectParseFailureForProto(
cat( tag(rep_fieldnum, wire_type), varint(1) ), cat( tag(rep_field->number(), wire_type), varint(1) ),
"PrematureEofInDelimitedDataForKnownRepeatedValue" + type_name, "PrematureEofInDelimitedDataForKnownRepeatedValue" + type_name,
REQUIRED); REQUIRED);
...@@ -593,7 +602,7 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) { ...@@ -593,7 +602,7 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) {
cat( tag(WireFormatLite::TYPE_INT32, WireFormatLite::WIRETYPE_VARINT), cat( tag(WireFormatLite::TYPE_INT32, WireFormatLite::WIRETYPE_VARINT),
incompletes[WireFormatLite::WIRETYPE_VARINT] ); incompletes[WireFormatLite::WIRETYPE_VARINT] );
ExpectHardParseFailureForProto( ExpectHardParseFailureForProto(
cat( tag(fieldnum, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), cat( tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
varint(incomplete_submsg.size()), varint(incomplete_submsg.size()),
incomplete_submsg ), incomplete_submsg ),
"PrematureEofInSubmessageValue" + type_name, REQUIRED); "PrematureEofInSubmessageValue" + type_name, REQUIRED);
...@@ -603,19 +612,50 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) { ...@@ -603,19 +612,50 @@ void ConformanceTestSuite::TestPrematureEOFForType(FieldDescriptor::Type type) {
// Packed region ends in the middle of a value. // Packed region ends in the middle of a value.
ExpectHardParseFailureForProto( ExpectHardParseFailureForProto(
cat( tag(rep_fieldnum, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
varint(incomplete.size()), varint(incomplete.size()), incomplete),
incomplete ),
"PrematureEofInPackedFieldValue" + type_name, REQUIRED); "PrematureEofInPackedFieldValue" + type_name, REQUIRED);
// EOF in the middle of packed region. // EOF in the middle of packed region.
ExpectParseFailureForProto( ExpectParseFailureForProto(
cat( tag(rep_fieldnum, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED),
varint(1) ), varint(1)),
"PrematureEofInPackedField" + type_name, REQUIRED); "PrematureEofInPackedField" + type_name, REQUIRED);
} }
} }
void ConformanceTestSuite::TestValidDataForType(
FieldDescriptor::Type type,
std::vector<std::pair<std::string, std::string>> values) {
const string type_name =
UpperCase(string(".") + FieldDescriptor::TypeName(type));
WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType(
static_cast<WireFormatLite::FieldType>(type));
const FieldDescriptor* field = GetFieldForType(type, false);
const FieldDescriptor* rep_field = GetFieldForType(type, true);
RunValidProtobufTest("ValidDataScalar" + type_name, REQUIRED,
cat(tag(field->number(), wire_type), values[0].first),
field->name() + ": " + values[0].second);
string proto;
string text = field->name() + ": " + values.back().second;
for (size_t i = 0; i < values.size(); i++) {
proto += cat(tag(field->number(), wire_type), values[i].first);
}
RunValidProtobufTest("RepeatedScalarSelectsLast" + type_name, REQUIRED,
proto, text);
proto.clear();
text.clear();
for (size_t i = 0; i < values.size(); i++) {
proto += cat(tag(rep_field->number(), wire_type), values[i].first);
text += rep_field->name() + ": " + values[i].second + " ";
}
RunValidProtobufTest("ValidDataRepeated" + type_name, REQUIRED, proto, text);
}
void ConformanceTestSuite::SetFailureList(const string& filename, void ConformanceTestSuite::SetFailureList(const string& filename,
const vector<string>& failure_list) { const vector<string>& failure_list) {
failure_list_filename_ = filename; failure_list_filename_ = filename;
...@@ -675,6 +715,86 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner, ...@@ -675,6 +715,86 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
TestPrematureEOFForType(static_cast<FieldDescriptor::Type>(i)); TestPrematureEOFForType(static_cast<FieldDescriptor::Type>(i));
} }
int64 kInt64Min = -9223372036854775808ULL;
int64 kInt64Max = 9223372036854775807ULL;
uint64 kUint64Max = 18446744073709551615ULL;
int32 kInt32Max = 2147483647;
int32 kInt32Min = -2147483648;
uint32 kUint32Max = 4294967295UL;
TestValidDataForType(FieldDescriptor::TYPE_DOUBLE, {
{dbl(0.1), "0.1"},
{dbl(1.7976931348623157e+308), "1.7976931348623157e+308"},
{dbl(2.22507385850720138309e-308), "2.22507385850720138309e-308"}
});
TestValidDataForType(FieldDescriptor::TYPE_FLOAT, {
{flt(0.1), "0.1"},
{flt(3.402823e+38), "3.402823e+38"}, // 3.40282347e+38
{flt(1.17549435e-38f), "1.17549435e-38"}
});
TestValidDataForType(FieldDescriptor::TYPE_INT64, {
{varint(12345), "12345"},
{varint(kInt64Max), std::to_string(kInt64Max)},
{varint(kInt64Min), std::to_string(kInt64Min)}
});
TestValidDataForType(FieldDescriptor::TYPE_UINT64, {
{varint(12345), "12345"},
{varint(kUint64Max), std::to_string(kUint64Max)},
{varint(0), "0"}
});
TestValidDataForType(FieldDescriptor::TYPE_INT32, {
{varint(12345), "12345"},
{varint(kInt32Max), std::to_string(kInt32Max)},
{varint(kInt32Min), std::to_string(kInt32Min)},
});
TestValidDataForType(FieldDescriptor::TYPE_UINT32, {
{varint(12345), "12345"},
{varint(kUint32Max), std::to_string(kUint32Max)}, // UINT32_MAX
{varint(0), "0"}
});
TestValidDataForType(FieldDescriptor::TYPE_FIXED64, {
{u64(12345), "12345"},
{u64(kUint64Max), std::to_string(kUint64Max)},
{u64(0), "0"}
});
TestValidDataForType(FieldDescriptor::TYPE_FIXED32, {
{u32(12345), "12345"},
{u32(kUint32Max), std::to_string(kUint32Max)}, // UINT32_MAX
{u32(0), "0"}
});
TestValidDataForType(FieldDescriptor::TYPE_SFIXED64, {
{u64(12345), "12345"},
{u64(kInt64Max), std::to_string(kInt64Max)},
{u64(kInt64Min), std::to_string(kInt64Min)}
});
TestValidDataForType(FieldDescriptor::TYPE_SFIXED32, {
{u32(12345), "12345"},
{u32(kInt32Max), std::to_string(kInt32Max)},
{u32(kInt32Min), std::to_string(kInt32Min)}
});
TestValidDataForType(FieldDescriptor::TYPE_BOOL, {
{varint(1), "true"},
{varint(0), "false"},
{varint(12345678), "true"}
});
TestValidDataForType(FieldDescriptor::TYPE_SINT32, {
{zz32(12345), "12345"},
{zz32(kInt32Max), std::to_string(kInt32Max)},
{zz32(kInt32Min), std::to_string(kInt32Min)}
});
TestValidDataForType(FieldDescriptor::TYPE_SINT64, {
{zz64(12345), "12345"},
{zz64(kInt64Max), std::to_string(kInt64Max)},
{zz64(kInt64Min), std::to_string(kInt64Min)}
});
// TODO(haberman):
// TestValidDataForType(FieldDescriptor::TYPE_STRING
// TestValidDataForType(FieldDescriptor::TYPE_GROUP
// TestValidDataForType(FieldDescriptor::TYPE_MESSAGE
// TestValidDataForType(FieldDescriptor::TYPE_BYTES
// TestValidDataForType(FieldDescriptor::TYPE_ENUM
RunValidJsonTest("HelloWorld", REQUIRED, RunValidJsonTest("HelloWorld", REQUIRED,
"{\"optionalString\":\"Hello, World!\"}", "{\"optionalString\":\"Hello, World!\"}",
"optional_string: 'Hello, World!'"); "optional_string: 'Hello, World!'");
...@@ -1374,31 +1494,31 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner, ...@@ -1374,31 +1494,31 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
{ {
TestAllTypes message; TestAllTypes message;
message.set_oneof_uint32(0); message.set_oneof_uint32(0);
RunValidProtobufTest( RunValidProtobufTestWithMessage(
"OneofZeroUint32", RECOMMENDED, message, "oneof_uint32: 0"); "OneofZeroUint32", RECOMMENDED, message, "oneof_uint32: 0");
message.mutable_oneof_nested_message()->set_a(0); message.mutable_oneof_nested_message()->set_a(0);
RunValidProtobufTest( RunValidProtobufTestWithMessage(
"OneofZeroMessage", RECOMMENDED, message, "oneof_nested_message: {}"); "OneofZeroMessage", RECOMMENDED, message, "oneof_nested_message: {}");
message.set_oneof_string(""); message.set_oneof_string("");
RunValidProtobufTest( RunValidProtobufTestWithMessage(
"OneofZeroString", RECOMMENDED, message, "oneof_string: \"\""); "OneofZeroString", RECOMMENDED, message, "oneof_string: \"\"");
message.set_oneof_bytes(""); message.set_oneof_bytes("");
RunValidProtobufTest( RunValidProtobufTestWithMessage(
"OneofZeroBytes", RECOMMENDED, message, "oneof_bytes: \"\""); "OneofZeroBytes", RECOMMENDED, message, "oneof_bytes: \"\"");
message.set_oneof_bool(false); message.set_oneof_bool(false);
RunValidProtobufTest( RunValidProtobufTestWithMessage(
"OneofZeroBool", RECOMMENDED, message, "oneof_bool: false"); "OneofZeroBool", RECOMMENDED, message, "oneof_bool: false");
message.set_oneof_uint64(0); message.set_oneof_uint64(0);
RunValidProtobufTest( RunValidProtobufTestWithMessage(
"OneofZeroUint64", RECOMMENDED, message, "oneof_uint64: 0"); "OneofZeroUint64", RECOMMENDED, message, "oneof_uint64: 0");
message.set_oneof_float(0.0f); message.set_oneof_float(0.0f);
RunValidProtobufTest( RunValidProtobufTestWithMessage(
"OneofZeroFloat", RECOMMENDED, message, "oneof_float: 0"); "OneofZeroFloat", RECOMMENDED, message, "oneof_float: 0");
message.set_oneof_double(0.0); message.set_oneof_double(0.0);
RunValidProtobufTest( RunValidProtobufTestWithMessage(
"OneofZeroDouble", RECOMMENDED, message, "oneof_double: 0"); "OneofZeroDouble", RECOMMENDED, message, "oneof_double: 0");
message.set_oneof_enum(TestAllTypes::FOO); message.set_oneof_enum(TestAllTypes::FOO);
RunValidProtobufTest( RunValidProtobufTestWithMessage(
"OneofZeroEnum", RECOMMENDED, message, "oneof_enum: FOO"); "OneofZeroEnum", RECOMMENDED, message, "oneof_enum: FOO");
} }
RunValidJsonTest( RunValidJsonTest(
......
...@@ -175,9 +175,11 @@ class ConformanceTestSuite { ...@@ -175,9 +175,11 @@ class ConformanceTestSuite {
ConformanceLevel level, ConformanceLevel level,
const protobuf_test_messages::proto3::TestAllTypes& input, const protobuf_test_messages::proto3::TestAllTypes& input,
const string& equivalent_text_format); const string& equivalent_text_format);
void RunValidProtobufTest( void RunValidProtobufTest(const string& test_name, ConformanceLevel level,
const string& test_name, const string& input_protobuf,
ConformanceLevel level, const string& equivalent_text_format);
void RunValidProtobufTestWithMessage(
const string& test_name, ConformanceLevel level,
const protobuf_test_messages::proto3::TestAllTypes& input, const protobuf_test_messages::proto3::TestAllTypes& input,
const string& equivalent_text_format); const string& equivalent_text_format);
...@@ -199,6 +201,9 @@ class ConformanceTestSuite { ...@@ -199,6 +201,9 @@ class ConformanceTestSuite {
const std::string& test_name, const std::string& test_name,
ConformanceLevel level); ConformanceLevel level);
void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type); void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type);
void TestValidDataForType(
google::protobuf::FieldDescriptor::Type,
std::vector<std::pair<std::string, std::string>> values);
bool CheckSetEmpty(const set<string>& set_to_check, bool CheckSetEmpty(const set<string>& set_to_check,
const std::string& write_to_file, const std::string& msg); const std::string& write_to_file, const std::string& msg);
ConformanceTestRunner* runner_; ConformanceTestRunner* runner_;
......
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