@ -12,19 +12,18 @@
# include <vector>
# include "absl/log/absl_log.h"
# include "absl/log/die_if_null.h"
# include "absl/strings/str_cat.h"
# include "conformance_test.h"
# include "google/protobuf/test_messages_proto2.pb.h"
# include "google/protobuf/test_messages_proto3.pb.h"
# include "google/protobuf/text_format.h"
namespace proto2_messages = protobuf_test_messages : : proto2 ;
using conformance : : ConformanceRequest ;
using conformance : : ConformanceResponse ;
using conformance : : WireFormat ;
using proto2_messages : : TestAllTypesProto2 ;
using proto2_messages : : UnknownToTestAllTypes ;
using protobuf_test_messages : : proto2 : : TestAllTypesProto2 ;
using protobuf_test_messages : : proto2 : : UnknownToTestAllTypes ;
using protobuf_test_messages : : proto3 : : TestAllTypesProto3 ;
namespace google {
@ -111,10 +110,35 @@ bool TextFormatConformanceTestSuite::ParseResponse(
return true ;
}
void TextFormatConformanceTestSuite : : ExpectParseFailure (
void TextFormatConformanceTestSuite : : RunSuiteImpl ( ) {
TextFormatConformanceTestSuiteImpl < TestAllTypesProto2 > ( this ) ;
TextFormatConformanceTestSuiteImpl < TestAllTypesProto3 > ( this ) ;
}
template < typename MessageType >
TextFormatConformanceTestSuiteImpl < MessageType > : :
TextFormatConformanceTestSuiteImpl ( TextFormatConformanceTestSuite * suite )
: suite_ ( * ABSL_DIE_IF_NULL ( suite ) ) {
// Flag control performance tests to keep them internal and opt-in only
if ( suite_ . performance_ ) {
RunTextFormatPerformanceTests ( ) ;
} else {
if ( MessageType : : GetDescriptor ( ) - > name ( ) = = " TestAllTypesProto2 " ) {
RunGroupTests ( ) ;
}
if ( MessageType : : GetDescriptor ( ) - > name ( ) = = " TestAllTypesProto3 " ) {
RunAnyTests ( ) ;
// TODO Run these over proto2 also.
RunAllTests ( ) ;
}
}
}
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl < MessageType > : : ExpectParseFailure (
const std : : string & test_name , ConformanceLevel level ,
const std : : string & input ) {
TestAllTypesProto3 prototype ;
MessageType prototype ;
// We don't expect output, but if the program erroneously accepts the protobuf
// we let it send its response as this. We must not leave it unspecified.
ConformanceRequestSetting setting (
@ -122,89 +146,75 @@ void TextFormatConformanceTestSuite::ExpectParseFailure(
conformance : : TEXT_FORMAT_TEST , prototype , test_name , input ) ;
const ConformanceRequest & request = setting . GetRequest ( ) ;
ConformanceResponse response ;
std : : string effective_test_name =
absl : : StrCat ( setting . ConformanceLevelToString ( level ) ,
" .Proto3 .TextFormatInput." , test_name ) ;
std : : string effective_test_name = absl : : StrCat (
setting . ConformanceLevelToString ( level ) , " . " ,
setting . GetSyntaxIdentifier ( ) , " .TextFormatInput. " , test_name ) ;
RunTest ( effective_test_name , request , & response ) ;
suite_ . RunTest ( effective_test_name , request , & response ) ;
if ( response . result_case ( ) = = ConformanceResponse : : kParseError ) {
ReportSuccess ( effective_test_name ) ;
suite_ . ReportSuccess ( effective_test_name ) ;
} else if ( response . result_case ( ) = = ConformanceResponse : : kSkipped ) {
ReportSkip ( effective_test_name , request , response ) ;
suite_ . ReportSkip ( effective_test_name , request , response ) ;
} else {
ReportFailure ( effective_test_name , level , request , response ,
suite_ . ReportFailure ( effective_test_name , level , request , response ,
" Should have failed to parse, but didn't. " ) ;
}
}
void TextFormatConformanceTestSuite : : RunValidTextFormatTest (
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl < MessageType > : : RunValidTextFormatTest (
const std : : string & test_name , ConformanceLevel level ,
const std : : string & input_text ) {
TestAllTypesProto3 prototype ;
MessageType prototype ;
RunValidTextFormatTestWithMessage ( test_name , level , input_text , prototype ) ;
}
void TextFormatConformanceTestSuite : : RunValidTextFormatTestProto2 (
const std : : string & test_name , ConformanceLevel level ,
const std : : string & input_text ) {
TestAllTypesProto2 prototype ;
RunValidTextFormatTestWithMessage ( test_name , level , input_text , prototype ) ;
}
void TextFormatConformanceTestSuite : : RunValidTextFormatTestWithExpected (
const std : : string & test_name , ConformanceLevel level ,
const std : : string & input_text , const std : : string & expected_text ) {
TestAllTypesProto3 prototype ;
RunValidTextFormatTestWithMessage ( test_name , level , input_text , expected_text ,
prototype ) ;
}
void TextFormatConformanceTestSuite : : RunValidTextFormatTestProto2WithExpected (
const std : : string & test_name , ConformanceLevel level ,
const std : : string & input_text , const std : : string & expected_text ) {
TestAllTypesProto2 prototype ;
RunValidTextFormatTestWithMessage ( test_name , level , input_text , expected_text ,
prototype ) ;
}
void TextFormatConformanceTestSuite : : RunValidTextFormatTestWithMessage (
const std : : string & test_name , ConformanceLevel level ,
const std : : string & input_text , const Message & prototype ) {
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl < MessageType > : :
RunValidTextFormatTestWithMessage ( const std : : string & test_name ,
ConformanceLevel level ,
const std : : string & input_text ,
const Message & message ) {
ConformanceRequestSetting setting1 (
level , conformance : : TEXT_FORMAT , conformance : : PROTOBUF ,
conformance : : TEXT_FORMAT_TEST , prototyp e, test_name , input_text ) ;
RunValidInputTest ( setting1 , input_text ) ;
conformance : : TEXT_FORMAT_TEST , message , test_name , input_text ) ;
suite_ . RunValidInputTest ( setting1 , input_text ) ;
ConformanceRequestSetting setting2 (
level , conformance : : TEXT_FORMAT , conformance : : TEXT_FORMAT ,
conformance : : TEXT_FORMAT_TEST , prototyp e, test_name , input_text ) ;
RunValidInputTest ( setting2 , input_text ) ;
conformance : : TEXT_FORMAT_TEST , message , test_name , input_text ) ;
suite_ . RunValidInputTest ( setting2 , input_text ) ;
}
void TextFormatConformanceTestSuite : : RunValidTextFormatTestWithMessage (
const std : : string & test_name , ConformanceLevel level ,
const std : : string & input_text , const std : : string & expected_text ,
const Message & prototype ) {
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl < MessageType > : :
RunValidTextFormatTestWithExpected ( const std : : string & test_name ,
ConformanceLevel level ,
const std : : string & input_text ,
const std : : string & expected_text ) {
MessageType prototype ;
ConformanceRequestSetting setting1 (
level , conformance : : TEXT_FORMAT , conformance : : PROTOBUF ,
conformance : : TEXT_FORMAT_TEST , prototype , test_name , input_text ) ;
RunValidInputTest ( setting1 , expected_text ) ;
suite_ . RunValidInputTest ( setting1 , expected_text ) ;
ConformanceRequestSetting setting2 (
level , conformance : : TEXT_FORMAT , conformance : : TEXT_FORMAT ,
conformance : : TEXT_FORMAT_TEST , prototype , test_name , input_text ) ;
RunValidInputTest ( setting2 , expected_text ) ;
suite_ . RunValidInputTest ( setting2 , expected_text ) ;
}
void TextFormatConformanceTestSuite : : RunValidUnknownTextFormatTest (
const std : : string & test_name , const Message & message ) {
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl <
MessageType > : : RunValidUnknownTextFormatTest ( const std : : string & test_name ,
const Message & message ) {
std : : string serialized_input ;
message . SerializeToString ( & serialized_input ) ;
TestAllTypesProto3 prototype ;
MessageType prototype ;
ConformanceRequestSetting setting1 (
RECOMMENDED , conformance : : PROTOBUF , conformance : : TEXT_FORMAT ,
conformance : : TEXT_FORMAT_TEST , prototype ,
absl : : StrCat ( test_name , " _Drop " ) , serialized_input ) ;
setting1 . SetPrototypeMessageForCompare ( message ) ;
RunValidBinaryInputTest ( setting1 , " " ) ;
suite_ . RunValidBinaryInputTest ( setting1 , " " ) ;
ConformanceRequestSetting setting2 (
RECOMMENDED , conformance : : PROTOBUF , conformance : : TEXT_FORMAT ,
@ -212,11 +222,20 @@ void TextFormatConformanceTestSuite::RunValidUnknownTextFormatTest(
absl : : StrCat ( test_name , " _Print " ) , serialized_input ) ;
setting2 . SetPrototypeMessageForCompare ( message ) ;
setting2 . SetPrintUnknownFields ( true ) ;
RunValidBinaryInputTest ( setting2 , serialized_input ) ;
suite_ . RunValidBinaryInputTest ( setting2 , serialized_input ) ;
}
void TextFormatConformanceTestSuite : : RunSuiteImpl ( ) {
if ( ! performance_ ) {
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl < MessageType > : : RunGroupTests ( ) {
RunValidTextFormatTest ( " GroupFieldNoColon " , REQUIRED ,
" Data { group_int32: 1 } " ) ;
RunValidTextFormatTest ( " GroupFieldWithColon " , REQUIRED ,
" Data: { group_int32: 1 } " ) ;
RunValidTextFormatTest ( " GroupFieldEmpty " , REQUIRED , " Data {} " ) ;
}
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl < MessageType > : : RunAllTests ( ) {
RunValidTextFormatTest ( " HelloWorld " , REQUIRED ,
" optional_string: 'Hello, World!' " ) ;
// Integer fields.
@ -255,8 +274,7 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
" optional_float: 3.4028235e+38 " ) ;
RunValidTextFormatTest ( " FloatFieldMinValue " , REQUIRED ,
" optional_float: 1.17549e-38 " ) ;
RunValidTextFormatTest ( " FloatFieldNaNValue " , REQUIRED ,
" optional_float: NaN " ) ;
RunValidTextFormatTest ( " FloatFieldNaNValue " , REQUIRED , " optional_float: NaN " ) ;
RunValidTextFormatTest ( " FloatFieldPosInfValue " , REQUIRED ,
" optional_float: inf " ) ;
RunValidTextFormatTest ( " FloatFieldNegInfValue " , REQUIRED ,
@ -285,8 +303,8 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
RunValidTextFormatTest (
absl : : StrCat ( " StringLiteralOctalEscapes " , field_type ) , REQUIRED ,
absl : : StrCat ( field_name , " : ' \\ 341 \\ 210 \\ 264' " ) ) ;
RunValidTextFormatTest (
absl : : StrCat ( " StringLiteralHexEscapes " , field_type ) , REQUIRED ,
RunValidTextFormatTest ( absl : : StrCat ( " StringLiteralHexEscapes " , field_type ) ,
REQUIRED ,
absl : : StrCat ( field_name , " : ' \\ xe1 \\ x88 \\ xb4' " ) ) ;
RunValidTextFormatTest (
absl : : StrCat ( " StringLiteralShortUnicodeEscape " , field_type ) ,
@ -295,8 +313,8 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
absl : : StrCat ( " StringLiteralLongUnicodeEscapes " , field_type ) ,
RECOMMENDED , absl : : StrCat ( field_name , " : ' \\ U00001234 \\ U00010437' " ) ) ;
// String literals don't include line feeds.
ExpectParseFailure (
absl : : StrCat ( " StringLiteralIncludesLF " , field_type ) , REQUIRED ,
ExpectParseFailure ( absl : : StrCat ( " StringLiteralIncludesLF " , field_type ) ,
REQUIRED ,
absl : : StrCat ( field_name , " : 'first line \n second line' " ) ) ;
// Unicode escapes don't include code points that lie beyond the planes
// (> 0x10ffff).
@ -325,8 +343,7 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
field_type ) ,
RECOMMENDED , absl : : StrCat ( field_name , " : ' \\ U0000dc00' " ) ) ;
ExpectParseFailure (
absl : : StrCat ( " StringLiteralLongUnicodeEscapeSurrogatePair " ,
field_type ) ,
absl : : StrCat ( " StringLiteralLongUnicodeEscapeSurrogatePair " , field_type ) ,
RECOMMENDED , absl : : StrCat ( field_name , " : ' \\ U0000d801 \\ U00000dc37' " ) ) ;
ExpectParseFailure (
absl : : StrCat ( " StringLiteralUnicodeEscapeSurrogatePairLongShort " ,
@ -341,23 +358,16 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
// validation.
const auto test_method =
field_type = = " String "
? & TextFormatConformanceTestSuite : : ExpectParseFailure
: & TextFormatConformanceTestSuite : : RunValidTextFormatTest ;
? & TextFormatConformanceTestSuiteImpl : : ExpectParseFailure
: & TextFormatConformanceTestSuiteImpl : : RunValidTextFormatTest ;
// String fields reject invalid UTF-8 byte sequences; bytes fields don't.
( this - > * test_method ) ( absl : : StrCat ( field_type , " FieldBadUTF8Octal " ) ,
REQUIRED , absl : : StrCat ( field_name , " : ' \\ 300' " ) ) ;
( this - > * test_method ) ( absl : : StrCat ( field_type , " FieldBadUTF8Hex " ) ,
REQUIRED , absl : : StrCat ( field_name , " : ' \\ xc0' " ) ) ;
( this - > * test_method ) ( absl : : StrCat ( field_type , " FieldBadUTF8Hex " ) , REQUIRED ,
absl : : StrCat ( field_name , " : ' \\ xc0' " ) ) ;
}
// Group fields
RunValidTextFormatTestProto2 ( " GroupFieldNoColon " , REQUIRED ,
" Data { group_int32: 1 } " ) ;
RunValidTextFormatTestProto2 ( " GroupFieldWithColon " , REQUIRED ,
" Data: { group_int32: 1 } " ) ;
RunValidTextFormatTestProto2 ( " GroupFieldEmpty " , REQUIRED , " Data {} " ) ;
// Unknown Fields
UnknownToTestAllTypes message ;
// Unable to print unknown Fixed32/Fixed64 fields as if they are known.
@ -380,33 +390,8 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
message . add_repeated_int32 ( 3 ) ;
RunValidUnknownTextFormatTest ( " RepeatedUnknownFields " , message ) ;
// Any fields
RunValidTextFormatTest ( " AnyField " , REQUIRED ,
R " (
optional_any : {
[ type . googleapis . com / protobuf_test_messages . proto3 . TestAllTypesProto3 ] {
optional_int32 : 12345
}
}
) " );
RunValidTextFormatTest ( " AnyFieldWithRawBytes " , REQUIRED ,
R " (
optional_any : {
type_url : " type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3 "
value : " \b \271 ` "
}
) " );
ExpectParseFailure ( " AnyFieldWithInvalidType " , REQUIRED ,
R " (
optional_any : {
[ type . googleapis . com / unknown ] {
optional_int32 : 12345
}
}
) " );
// Map fields
TestAllTypesProto3 prototype ;
MessageType prototype ;
( * prototype . mutable_map_string_string ( ) ) [ " c " ] = " value " ;
( * prototype . mutable_map_string_string ( ) ) [ " b " ] = " value " ;
( * prototype . mutable_map_string_string ( ) ) [ " a " ] = " value " ;
@ -432,8 +417,7 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
( * prototype . mutable_map_int32_int32 ( ) ) [ 3 ] = 0 ;
( * prototype . mutable_map_int32_int32 ( ) ) [ 2 ] = 0 ;
( * prototype . mutable_map_int32_int32 ( ) ) [ 1 ] = 0 ;
RunValidTextFormatTestWithMessage ( " AlphabeticallySortedMapIntKeys " ,
REQUIRED ,
RunValidTextFormatTestWithMessage ( " AlphabeticallySortedMapIntKeys " , REQUIRED ,
R " (
map_int32_int32 {
key : 1
@ -453,8 +437,7 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
prototype . Clear ( ) ;
( * prototype . mutable_map_bool_bool ( ) ) [ true ] = false ;
( * prototype . mutable_map_bool_bool ( ) ) [ false ] = false ;
RunValidTextFormatTestWithMessage ( " AlphabeticallySortedMapBoolKeys " ,
REQUIRED ,
RunValidTextFormatTestWithMessage ( " AlphabeticallySortedMapBoolKeys " , REQUIRED ,
R " (
map_bool_bool {
key : false
@ -481,20 +464,46 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
}
) " );
// The last-specified value will be retained in a parsed map
RunValidInputTest ( setting_map , R " (
suite_ . RunValidInputTest ( setting_map , R " (
map_string_nested_message {
key : " duplicate "
value : { corecursive : { } }
}
) " );
}
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl < MessageType > : : RunAnyTests ( ) {
// Any fields
RunValidTextFormatTest ( " AnyField " , REQUIRED ,
R " (
optional_any : {
[ type . googleapis . com / protobuf_test_messages . proto3 . TestAllTypesProto3 ]
{ optional_int32 : 12345
}
// Flag control performance tests to keep them internal and opt-in only
if ( performance_ ) {
RunTextFormatPerformanceTests ( ) ;
}
) " );
RunValidTextFormatTest ( " AnyFieldWithRawBytes " , REQUIRED ,
R " (
optional_any : {
type_url :
" type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3 " value :
" \b \271 ` "
}
) " );
ExpectParseFailure ( " AnyFieldWithInvalidType " , REQUIRED ,
R " (
optional_any : {
[ type . googleapis . com / unknown ] {
optional_int32 : 12345
}
}
) " );
}
void TextFormatConformanceTestSuite : : RunTextFormatPerformanceTests ( ) {
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl <
MessageType > : : RunTextFormatPerformanceTests ( ) {
TestTextFormatPerformanceMergeMessageWithRepeatedField ( " Bool " ,
" repeated_bool: true " ) ;
TestTextFormatPerformanceMergeMessageWithRepeatedField (
@ -510,7 +519,8 @@ void TextFormatConformanceTestSuite::RunTextFormatPerformanceTests() {
}
// This is currently considered valid input by some languages but not others
void TextFormatConformanceTestSuite : :
template < typename MessageType >
void TextFormatConformanceTestSuiteImpl < MessageType > : :
TestTextFormatPerformanceMergeMessageWithRepeatedField (
const std : : string & test_type_name , const std : : string & message_field ) {
std : : string recursive_message =
@ -527,13 +537,9 @@ void TextFormatConformanceTestSuite::
}
absl : : StrAppend ( & expected , " } " ) ;
RunValidTextFormatTestProto2WithExpected (
absl : : StrCat ( " TestTextFormatPerformanceMergeMessageWithRepeatedField " ,
test_type_name , " Proto2 " ) ,
RECOMMENDED , input , expected ) ;
RunValidTextFormatTestWithExpected (
absl : : StrCat ( " TestTextFormatPerformanceMergeMessageWithRepeatedField " ,
test_type_name , " Proto3 " ) ,
test_type_name ) ,
RECOMMENDED , input , expected ) ;
}