2011-11-18 17:01:23 +00:00
# include "unittest.h"
# define private public // For testing private members
# include "rapidjson/reader.h"
using namespace rapidjson ;
2014-07-03 00:59:35 +08:00
# ifdef __GNUC__
2014-07-08 14:45:19 +02:00
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF ( effc + + )
2014-07-03 00:59:35 +08:00
# endif
2011-11-18 17:01:23 +00:00
template < bool expect >
struct ParseBoolHandler : BaseReaderHandler < > {
ParseBoolHandler ( ) : step_ ( 0 ) { }
2014-07-11 00:37:55 +08:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
2014-06-25 00:04:24 +08:00
// gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest version.
// Workaround with EXPECT_TRUE().
2014-07-10 19:33:01 +08:00
bool Bool ( bool b ) { /*EXPECT_EQ(expect, b); */ EXPECT_TRUE ( expect = = b ) ; + + step_ ; return true ; }
2011-11-18 17:01:23 +00:00
unsigned step_ ;
} ;
TEST ( Reader , ParseTrue ) {
StringStream s ( " true " ) ;
ParseBoolHandler < true > h ;
Reader reader ;
reader . ParseTrue < 0 > ( s , h ) ;
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 1u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
}
TEST ( Reader , ParseFalse ) {
StringStream s ( " false " ) ;
ParseBoolHandler < false > h ;
Reader reader ;
reader . ParseFalse < 0 > ( s , h ) ;
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 1u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
}
struct ParseIntHandler : BaseReaderHandler < > {
2014-07-03 00:59:35 +08:00
ParseIntHandler ( ) : step_ ( 0 ) , actual_ ( ) { }
2014-07-10 19:33:01 +08:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Int ( int i ) { actual_ = i ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
unsigned step_ ;
int actual_ ;
} ;
struct ParseUintHandler : BaseReaderHandler < > {
2014-07-03 00:59:35 +08:00
ParseUintHandler ( ) : step_ ( 0 ) , actual_ ( ) { }
2014-07-10 19:33:01 +08:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Uint ( unsigned i ) { actual_ = i ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
unsigned step_ ;
unsigned actual_ ;
} ;
struct ParseInt64Handler : BaseReaderHandler < > {
2014-07-03 00:59:35 +08:00
ParseInt64Handler ( ) : step_ ( 0 ) , actual_ ( ) { }
2014-07-10 19:33:01 +08:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Int64 ( int64_t i ) { actual_ = i ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
unsigned step_ ;
int64_t actual_ ;
} ;
struct ParseUint64Handler : BaseReaderHandler < > {
2014-07-03 00:59:35 +08:00
ParseUint64Handler ( ) : step_ ( 0 ) , actual_ ( ) { }
2014-07-10 19:33:01 +08:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Uint64 ( uint64_t i ) { actual_ = i ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
unsigned step_ ;
uint64_t actual_ ;
} ;
struct ParseDoubleHandler : BaseReaderHandler < > {
2014-07-03 00:59:35 +08:00
ParseDoubleHandler ( ) : step_ ( 0 ) , actual_ ( ) { }
2014-07-10 19:33:01 +08:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Double ( double d ) { actual_ = d ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
unsigned step_ ;
double actual_ ;
} ;
TEST ( Reader , ParseNumberHandler ) {
# define TEST_NUMBER(Handler, str, x) \
{ \
StringStream s ( str ) ; \
Handler h ; \
Reader reader ; \
reader . ParseNumber < 0 > ( s , h ) ; \
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 1u , h . step_ ) ; \
EXPECT_EQ ( double ( x ) , h . actual_ ) ; \
2011-11-18 17:01:23 +00:00
}
# define TEST_DOUBLE(str, x) \
{ \
StringStream s ( str ) ; \
ParseDoubleHandler h ; \
Reader reader ; \
reader . ParseNumber < 0 > ( s , h ) ; \
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 1u , h . step_ ) ; \
2011-11-18 17:01:23 +00:00
EXPECT_DOUBLE_EQ ( x , h . actual_ ) ; \
}
TEST_NUMBER ( ParseUintHandler , " 0 " , 0 ) ;
TEST_NUMBER ( ParseUintHandler , " 123 " , 123 ) ;
TEST_NUMBER ( ParseUintHandler , " 2147483648 " , 2147483648u ) ; // 2^31 - 1 (cannot be stored in int)
TEST_NUMBER ( ParseUintHandler , " 4294967295 " , 4294967295u ) ;
TEST_NUMBER ( ParseIntHandler , " -123 " , - 123 ) ;
TEST_NUMBER ( ParseIntHandler , " -2147483648 " , - 2147483648LL ) ; // -2^31 (min of int)
TEST_NUMBER ( ParseUint64Handler , " 4294967296 " , 4294967296ULL ) ; // 2^32 (max of unsigned + 1, force to use uint64_t)
TEST_NUMBER ( ParseUint64Handler , " 18446744073709551615 " , 18446744073709551615ULL ) ; // 2^64 - 1 (max of uint64_t)
TEST_NUMBER ( ParseInt64Handler , " -2147483649 " , - 2147483649LL ) ; // -2^31 -1 (min of int - 1, force to use int64_t)
TEST_NUMBER ( ParseInt64Handler , " -9223372036854775808 " , ( - 9223372036854775807LL - 1 ) ) ; // -2^63 (min of int64_t)
TEST_DOUBLE ( " 0.0 " , 0.0 ) ;
TEST_DOUBLE ( " 1.0 " , 1.0 ) ;
TEST_DOUBLE ( " -1.0 " , - 1.0 ) ;
TEST_DOUBLE ( " 1.5 " , 1.5 ) ;
TEST_DOUBLE ( " -1.5 " , - 1.5 ) ;
TEST_DOUBLE ( " 3.1416 " , 3.1416 ) ;
TEST_DOUBLE ( " 1E10 " , 1E10 ) ;
TEST_DOUBLE ( " 1e10 " , 1e10 ) ;
TEST_DOUBLE ( " 1E+10 " , 1E+10 ) ;
TEST_DOUBLE ( " 1E-10 " , 1E-10 ) ;
TEST_DOUBLE ( " -1E10 " , - 1E10 ) ;
TEST_DOUBLE ( " -1e10 " , - 1e10 ) ;
TEST_DOUBLE ( " -1E+10 " , - 1E+10 ) ;
TEST_DOUBLE ( " -1E-10 " , - 1E-10 ) ;
TEST_DOUBLE ( " 1.234E+10 " , 1.234E+10 ) ;
TEST_DOUBLE ( " 1.234E-10 " , 1.234E-10 ) ;
TEST_DOUBLE ( " 1.79769e+308 " , 1.79769e+308 ) ;
2014-06-30 21:26:43 +08:00
TEST_DOUBLE ( " 2.22507e-308 " , 2.22507e-308 ) ;
2011-11-18 17:01:23 +00:00
TEST_DOUBLE ( " -1.79769e+308 " , - 1.79769e+308 ) ;
2014-06-30 21:26:43 +08:00
TEST_DOUBLE ( " -2.22507e-308 " , - 2.22507e-308 ) ;
2011-11-18 17:01:23 +00:00
TEST_DOUBLE ( " 18446744073709551616 " , 18446744073709551616.0 ) ; // 2^64 (max of uint64_t + 1, force to use double)
TEST_DOUBLE ( " -9223372036854775809 " , - 9223372036854775809.0 ) ; // -2^63 - 1(min of int64_t + 1, force to use double)
{
char n1e308 [ 310 ] ; // '1' followed by 308 '0'
n1e308 [ 0 ] = ' 1 ' ;
for ( int i = 1 ; i < 309 ; i + + )
n1e308 [ i ] = ' 0 ' ;
n1e308 [ 309 ] = ' \0 ' ;
TEST_DOUBLE ( n1e308 , 1E308 ) ;
}
# undef TEST_NUMBER
# undef TEST_DOUBLE
}
2014-06-27 16:19:04 +08:00
TEST ( Reader , ParseNumber_Error ) {
# define TEST_NUMBER_ERROR(errorCode, str) \
2011-11-18 17:01:23 +00:00
{ \
char buffer [ 1001 ] ; \
sprintf ( buffer , " [%s] " , str ) ; \
InsituStringStream s ( buffer ) ; \
BaseReaderHandler < > h ; \
Reader reader ; \
EXPECT_FALSE ( reader . Parse < 0 > ( s , h ) ) ; \
2014-06-27 16:19:04 +08:00
EXPECT_EQ ( errorCode , reader . GetParseErrorCode ( ) ) ; \
2011-11-18 17:01:23 +00:00
}
2014-06-27 16:19:04 +08:00
// Number too big to be stored in double.
2011-11-18 17:01:23 +00:00
{
char n1e309 [ 311 ] ; // '1' followed by 309 '0'
n1e309 [ 0 ] = ' 1 ' ;
for ( int i = 1 ; i < 310 ; i + + )
n1e309 [ i ] = ' 0 ' ;
n1e309 [ 310 ] = ' \0 ' ;
2014-07-02 00:54:36 +02:00
TEST_NUMBER_ERROR ( kParseErrorNumberTooBig , n1e309 ) ;
2011-11-18 17:01:23 +00:00
}
2014-07-02 00:54:36 +02:00
TEST_NUMBER_ERROR ( kParseErrorNumberTooBig , " 1e309 " ) ;
2011-11-18 17:01:23 +00:00
2014-06-27 16:19:04 +08:00
// Miss fraction part in number.
TEST_NUMBER_ERROR ( kParseErrorNumberMissFraction , " 1. " ) ;
TEST_NUMBER_ERROR ( kParseErrorNumberMissFraction , " 1.a " ) ;
// Miss exponent in number.
TEST_NUMBER_ERROR ( kParseErrorNumberMissExponent , " 1e " ) ;
TEST_NUMBER_ERROR ( kParseErrorNumberMissExponent , " 1e_ " ) ;
2011-11-18 17:01:23 +00:00
# undef TEST_NUMBER_ERROR
}
template < typename Encoding >
struct ParseStringHandler : BaseReaderHandler < Encoding > {
2014-07-03 00:59:35 +08:00
ParseStringHandler ( ) : str_ ( 0 ) , length_ ( 0 ) , copy_ ( ) { }
2011-11-18 17:01:23 +00:00
~ ParseStringHandler ( ) { EXPECT_TRUE ( str_ ! = 0 ) ; if ( copy_ ) free ( const_cast < typename Encoding : : Ch * > ( str_ ) ) ; }
2014-07-03 00:59:35 +08:00
ParseStringHandler ( const ParseStringHandler & ) ;
ParseStringHandler & operator = ( const ParseStringHandler & ) ;
2014-07-10 19:33:01 +08:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool String ( const typename Encoding : : Ch * str , size_t length , bool copy ) {
2011-11-18 17:01:23 +00:00
EXPECT_EQ ( 0 , str_ ) ;
if ( copy ) {
str_ = ( typename Encoding : : Ch * ) malloc ( ( length + 1 ) * sizeof ( typename Encoding : : Ch ) ) ;
2014-06-25 00:04:24 +08:00
memcpy ( const_cast < typename Encoding : : Ch * > ( str_ ) , str , ( length + 1 ) * sizeof ( typename Encoding : : Ch ) ) ;
2011-11-18 17:01:23 +00:00
}
else
str_ = str ;
length_ = length ;
2014-07-10 19:33:01 +08:00
copy_ = copy ;
return true ;
2011-11-18 17:01:23 +00:00
}
const typename Encoding : : Ch * str_ ;
size_t length_ ;
bool copy_ ;
} ;
TEST ( Reader , ParseString ) {
# define TEST_STRING(Encoding, e, x) \
{ \
Encoding : : Ch * buffer = StrDup ( x ) ; \
GenericInsituStringStream < Encoding > is ( buffer ) ; \
ParseStringHandler < Encoding > h ; \
2011-11-28 09:30:32 +00:00
GenericReader < Encoding , Encoding > reader ; \
2011-11-22 19:29:43 +00:00
reader . ParseString < kParseInsituFlag | kParseValidateEncodingFlag > ( is , h ) ; \
2011-11-18 17:01:23 +00:00
EXPECT_EQ ( 0 , StrCmp < Encoding : : Ch > ( e , h . str_ ) ) ; \
EXPECT_EQ ( StrLen ( e ) , h . length_ ) ; \
free ( buffer ) ; \
GenericStringStream < Encoding > s ( x ) ; \
ParseStringHandler < Encoding > h2 ; \
2011-11-28 09:30:32 +00:00
GenericReader < Encoding , Encoding > reader2 ; \
2011-11-18 17:01:23 +00:00
reader2 . ParseString < 0 > ( s , h2 ) ; \
EXPECT_EQ ( 0 , StrCmp < Encoding : : Ch > ( e , h2 . str_ ) ) ; \
EXPECT_EQ ( StrLen ( e ) , h2 . length_ ) ; \
}
// String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral.
// And old compiler does not support u"" and U"" string literal. So here specify string literal by array of Ch.
2014-06-25 00:04:24 +08:00
// In addition, GCC 4.8 generates -Wnarrowing warnings when character code >= 128 are assigned to signed integer types.
// Therefore, utype is added for declaring unsigned array, and then cast it to Encoding::Ch.
2011-11-18 17:01:23 +00:00
# define ARRAY(...) { __VA_ARGS__ }
2014-06-25 00:04:24 +08:00
# define TEST_STRINGARRAY(Encoding, utype, array, x) \
2011-11-18 17:01:23 +00:00
{ \
2014-06-25 00:04:24 +08:00
static const utype ue [ ] = array ; \
static const Encoding : : Ch * e = reinterpret_cast < const Encoding : : Ch * > ( & ue [ 0 ] ) ; \
2011-11-18 17:01:23 +00:00
TEST_STRING ( Encoding , e , x ) ; \
}
2014-06-25 00:04:24 +08:00
# define TEST_STRINGARRAY2(Encoding, utype, earray, xarray) \
2011-11-18 17:01:23 +00:00
{ \
2014-06-25 00:04:24 +08:00
static const utype ue [ ] = earray ; \
static const utype xe [ ] = xarray ; \
static const Encoding : : Ch * e = reinterpret_cast < const Encoding : : Ch * > ( & ue [ 0 ] ) ; \
static const Encoding : : Ch * x = reinterpret_cast < const Encoding : : Ch * > ( & xe [ 0 ] ) ; \
2011-11-18 17:01:23 +00:00
TEST_STRING ( Encoding , e , x ) ; \
}
TEST_STRING ( UTF8 < > , " " , " \" \" " ) ;
TEST_STRING ( UTF8 < > , " Hello " , " \" Hello \" " ) ;
TEST_STRING ( UTF8 < > , " Hello \n World " , " \" Hello \\ nWorld \" " ) ;
TEST_STRING ( UTF8 < > , " \" \\ / \b \f \n \r \t " , " \" \\ \" \\ \\ / \\ b \\ f \\ n \\ r \\ t \" " ) ;
TEST_STRING ( UTF8 < > , " \x24 " , " \" \\ u0024 \" " ) ; // Dollar sign U+0024
TEST_STRING ( UTF8 < > , " \xC2 \xA2 " , " \" \\ u00A2 \" " ) ; // Cents sign U+00A2
TEST_STRING ( UTF8 < > , " \xE2 \x82 \xAC " , " \" \\ u20AC \" " ) ; // Euro sign U+20AC
TEST_STRING ( UTF8 < > , " \xF0 \x9D \x84 \x9E " , " \" \\ uD834 \\ uDD1E \" " ) ; // G clef sign U+1D11E
// UTF16
TEST_STRING ( UTF16 < > , L " " , L " \" \" " ) ;
TEST_STRING ( UTF16 < > , L " Hello " , L " \" Hello \" " ) ;
TEST_STRING ( UTF16 < > , L " Hello \n World " , L " \" Hello \\ nWorld \" " ) ;
TEST_STRING ( UTF16 < > , L " \" \\ / \b \f \n \r \t " , L " \" \\ \" \\ \\ / \\ b \\ f \\ n \\ r \\ t \" " ) ;
2014-06-25 00:04:24 +08:00
TEST_STRINGARRAY ( UTF16 < > , wchar_t , ARRAY ( 0x0024 , 0x0000 ) , L " \" \\ u0024 \" " ) ;
TEST_STRINGARRAY ( UTF16 < > , wchar_t , ARRAY ( 0x00A2 , 0x0000 ) , L " \" \\ u00A2 \" " ) ; // Cents sign U+00A2
TEST_STRINGARRAY ( UTF16 < > , wchar_t , ARRAY ( 0x20AC , 0x0000 ) , L " \" \\ u20AC \" " ) ; // Euro sign U+20AC
TEST_STRINGARRAY ( UTF16 < > , wchar_t , ARRAY ( 0xD834 , 0xDD1E , 0x0000 ) , L " \" \\ uD834 \\ uDD1E \" " ) ; // G clef sign U+1D11E
2011-11-18 17:01:23 +00:00
// UTF32
2014-06-25 00:04:24 +08:00
TEST_STRINGARRAY2 ( UTF32 < > , unsigned , ARRAY ( ' \0 ' ) , ARRAY ( ' \" ' , ' \" ' , ' \0 ' ) ) ;
TEST_STRINGARRAY2 ( UTF32 < > , unsigned , ARRAY ( ' H ' , ' e ' , ' l ' , ' l ' , ' o ' , ' \0 ' ) , ARRAY ( ' \" ' , ' H ' , ' e ' , ' l ' , ' l ' , ' o ' , ' \" ' , ' \0 ' ) ) ;
TEST_STRINGARRAY2 ( UTF32 < > , unsigned , ARRAY ( ' H ' , ' e ' , ' l ' , ' l ' , ' o ' , ' \n ' , ' W ' , ' o ' , ' r ' , ' l ' , ' d ' , ' \0 ' ) , ARRAY ( ' \" ' , ' H ' , ' e ' , ' l ' , ' l ' , ' o ' , ' \\ ' , ' n ' , ' W ' , ' o ' , ' r ' , ' l ' , ' d ' , ' \" ' , ' \0 ' ) ) ;
TEST_STRINGARRAY2 ( UTF32 < > , unsigned , ARRAY ( ' \" ' , ' \\ ' , ' / ' , ' \b ' , ' \f ' , ' \n ' , ' \r ' , ' \t ' , ' \0 ' ) , ARRAY ( ' \" ' , ' \\ ' , ' \" ' , ' \\ ' , ' \\ ' , ' / ' , ' \\ ' , ' b ' , ' \\ ' , ' f ' , ' \\ ' , ' n ' , ' \\ ' , ' r ' , ' \\ ' , ' t ' , ' \" ' , ' \0 ' ) ) ;
TEST_STRINGARRAY2 ( UTF32 < > , unsigned , ARRAY ( 0x00024 , 0x0000 ) , ARRAY ( ' \" ' , ' \\ ' , ' u ' , ' 0 ' , ' 0 ' , ' 2 ' , ' 4 ' , ' \" ' , ' \0 ' ) ) ;
TEST_STRINGARRAY2 ( UTF32 < > , unsigned , ARRAY ( 0x000A2 , 0x0000 ) , ARRAY ( ' \" ' , ' \\ ' , ' u ' , ' 0 ' , ' 0 ' , ' A ' , ' 2 ' , ' \" ' , ' \0 ' ) ) ; // Cents sign U+00A2
TEST_STRINGARRAY2 ( UTF32 < > , unsigned , ARRAY ( 0x020AC , 0x0000 ) , ARRAY ( ' \" ' , ' \\ ' , ' u ' , ' 2 ' , ' 0 ' , ' A ' , ' C ' , ' \" ' , ' \0 ' ) ) ; // Euro sign U+20AC
TEST_STRINGARRAY2 ( UTF32 < > , unsigned , ARRAY ( 0x1D11E , 0x0000 ) , ARRAY ( ' \" ' , ' \\ ' , ' u ' , ' D ' , ' 8 ' , ' 3 ' , ' 4 ' , ' \\ ' , ' u ' , ' D ' , ' D ' , ' 1 ' , ' E ' , ' \" ' , ' \0 ' ) ) ; // G clef sign U+1D11E
2011-11-18 17:01:23 +00:00
# undef TEST_STRINGARRAY
# undef ARRAY
# undef TEST_STRING
// Support of null character in string
{
StringStream s ( " \" Hello \\ u0000World \" " ) ;
const char e [ ] = " Hello \0 World " ;
ParseStringHandler < UTF8 < > > h ;
Reader reader ;
reader . ParseString < 0 > ( s , h ) ;
EXPECT_EQ ( 0 , memcmp ( e , h . str_ , h . length_ + 1 ) ) ;
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 11u , h . length_ ) ;
2011-11-18 17:01:23 +00:00
}
}
2011-11-28 09:30:32 +00:00
TEST ( Reader , ParseString_Transcoding ) {
const char * x = " \" Hello \" " ;
const wchar_t * e = L " Hello " ;
GenericStringStream < UTF8 < > > is ( x ) ;
GenericReader < UTF8 < > , UTF16 < > > reader ;
ParseStringHandler < UTF16 < > > h ;
reader . ParseString < 0 > ( is , h ) ;
EXPECT_EQ ( 0 , StrCmp < UTF16 < > : : Ch > ( e , h . str_ ) ) ;
EXPECT_EQ ( StrLen ( e ) , h . length_ ) ;
}
2011-11-18 17:01:23 +00:00
TEST ( Reader , ParseString_NonDestructive ) {
StringStream s ( " \" Hello \\ nWorld \" " ) ;
ParseStringHandler < UTF8 < > > h ;
Reader reader ;
reader . ParseString < 0 > ( s , h ) ;
EXPECT_EQ ( 0 , StrCmp ( " Hello \n World " , h . str_ ) ) ;
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 11u , h . length_ ) ;
2011-11-18 17:01:23 +00:00
}
2014-06-27 16:19:04 +08:00
ParseErrorCode TestString ( const char * str ) {
2011-11-23 16:13:32 +00:00
StringStream s ( str ) ;
BaseReaderHandler < > h ;
Reader reader ;
2014-06-27 16:19:04 +08:00
reader . Parse < kParseValidateEncodingFlag > ( s , h ) ;
return reader . GetParseErrorCode ( ) ;
2011-11-23 16:13:32 +00:00
}
2011-11-18 17:01:23 +00:00
2011-11-23 16:13:32 +00:00
TEST ( Reader , ParseString_Error ) {
2014-06-27 16:19:04 +08:00
# define TEST_STRING_ERROR(errorCode, str)\
EXPECT_EQ ( errorCode , TestString ( str ) )
2011-11-22 19:29:43 +00:00
# define ARRAY(...) { __VA_ARGS__ }
2014-06-27 16:19:04 +08:00
# define TEST_STRINGENCODING_ERROR(Encoding, utype, array) \
2011-11-22 19:29:43 +00:00
{ \
2014-06-25 00:04:24 +08:00
static const utype ue [ ] = array ; \
static const Encoding : : Ch * e = reinterpret_cast < const Encoding : : Ch * > ( & ue [ 0 ] ) ; \
2014-06-27 16:19:04 +08:00
EXPECT_EQ ( kParseErrorStringInvalidEncoding , TestString ( e ) ) ; \
2011-11-22 19:29:43 +00:00
}
2014-06-27 16:19:04 +08:00
// Invalid escape character in string.
TEST_STRING_ERROR ( kParseErrorStringEscapeInvalid , " [ \" \\ a \" ] " ) ;
// Incorrect hex digit after \\u escape in string.
TEST_STRING_ERROR ( kParseErrorStringUnicodeEscapeInvalidHex , " [ \" \\ uABCG \" ] " ) ;
// The surrogate pair in string is invalid.
2014-06-27 22:27:18 +08:00
TEST_STRING_ERROR ( kParseErrorStringUnicodeSurrogateInvalid , " [ \" \\ uD800X \" ] " ) ;
TEST_STRING_ERROR ( kParseErrorStringUnicodeSurrogateInvalid , " [ \" \\ uD800 \\ uFFFF \" ] " ) ;
2014-06-27 16:19:04 +08:00
// Missing a closing quotation mark in string.
TEST_STRING_ERROR ( kParseErrorStringMissQuotationMark , " [ \" Test] " ) ;
2011-11-23 16:13:32 +00:00
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
// 3 Malformed sequences
// 3.1 Unexpected continuation bytes
{
char e [ ] = { ' [ ' , ' \" ' , 0 , ' \" ' , ' ] ' , ' \0 ' } ;
for ( unsigned char c = 0x80u ; c < = 0xBFu ; c + + ) {
e [ 2 ] = c ;
2014-06-27 16:19:04 +08:00
ParseErrorCode error = TestString ( e ) ;
EXPECT_EQ ( kParseErrorStringInvalidEncoding , error ) ;
2014-06-27 22:27:18 +08:00
if ( error ! = kParseErrorStringInvalidEncoding )
2011-11-23 16:13:32 +00:00
std : : cout < < ( unsigned ) ( unsigned char ) c < < std : : endl ;
}
}
// 3.2 Lonely start characters, 3.5 Impossible bytes
{
char e [ ] = { ' [ ' , ' \" ' , 0 , ' ' , ' \" ' , ' ] ' , ' \0 ' } ;
for ( unsigned c = 0xC0u ; c < = 0xFFu ; c + + ) {
e [ 2 ] = ( char ) c ;
2014-06-27 16:19:04 +08:00
TEST_STRING_ERROR ( kParseErrorStringInvalidEncoding , e ) ;
2011-11-23 16:13:32 +00:00
}
}
// 4 Overlong sequences
// 4.1 Examples of an overlong ASCII character
2014-06-27 16:19:04 +08:00
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xC0u , 0xAFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xE0u , 0x80u , 0xAFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xF0u , 0x80u , 0x80u , 0xAFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
2011-11-23 16:13:32 +00:00
// 4.2 Maximum overlong sequences
2014-06-27 16:19:04 +08:00
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xC1u , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xE0u , 0x9Fu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xF0u , 0x8Fu , 0xBFu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
2011-11-23 16:13:32 +00:00
// 4.3 Overlong representation of the NUL character
2014-06-27 16:19:04 +08:00
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xC0u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xE0u , 0x80u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xF0u , 0x80u , 0x80u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
2011-11-23 16:13:32 +00:00
// 5 Illegal code positions
// 5.1 Single UTF-16 surrogates
2014-06-27 16:19:04 +08:00
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xA0u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xADu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xAEu , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xAFu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xB0u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xBEu , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xBFu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
2011-11-18 17:01:23 +00:00
2011-11-22 19:29:43 +00:00
# undef ARRAY
# undef TEST_STRINGARRAY_ERROR
2011-11-18 17:01:23 +00:00
}
template < unsigned count >
struct ParseArrayHandler : BaseReaderHandler < > {
ParseArrayHandler ( ) : step_ ( 0 ) { }
2014-07-10 19:33:01 +08:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Uint ( unsigned i ) { EXPECT_EQ ( step_ , i ) ; step_ + + ; return true ; }
bool StartArray ( ) { EXPECT_EQ ( 0u , step_ ) ; step_ + + ; return true ; }
bool EndArray ( SizeType ) { step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
unsigned step_ ;
} ;
TEST ( Reader , ParseEmptyArray ) {
char * json = StrDup ( " [ ] " ) ;
InsituStringStream s ( json ) ;
ParseArrayHandler < 0 > h ;
Reader reader ;
reader . ParseArray < 0 > ( s , h ) ;
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 2u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
free ( json ) ;
}
TEST ( Reader , ParseArray ) {
char * json = StrDup ( " [1, 2, 3, 4] " ) ;
InsituStringStream s ( json ) ;
ParseArrayHandler < 4 > h ;
Reader reader ;
reader . ParseArray < 0 > ( s , h ) ;
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 6u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
free ( json ) ;
}
TEST ( Reader , ParseArray_Error ) {
2014-06-27 16:19:04 +08:00
# define TEST_ARRAY_ERROR(errorCode, str) \
2011-11-18 17:01:23 +00:00
{ \
char buffer [ 1001 ] ; \
strncpy ( buffer , str , 1000 ) ; \
InsituStringStream s ( buffer ) ; \
BaseReaderHandler < > h ; \
2011-11-28 09:30:32 +00:00
GenericReader < UTF8 < > , UTF8 < > , CrtAllocator > reader ; \
2011-11-22 19:29:43 +00:00
EXPECT_FALSE ( reader . Parse < 0 > ( s , h ) ) ; \
2014-06-27 16:19:04 +08:00
EXPECT_EQ ( errorCode , reader . GetParseErrorCode ( ) ) ; \
2011-11-18 17:01:23 +00:00
}
2014-06-27 16:19:04 +08:00
// Missing a comma or ']' after an array element.
2014-06-27 22:27:18 +08:00
TEST_ARRAY_ERROR ( kParseErrorArrayMissCommaOrSquareBracket , " [1 " ) ;
TEST_ARRAY_ERROR ( kParseErrorArrayMissCommaOrSquareBracket , " [1} " ) ;
2014-06-27 16:19:04 +08:00
TEST_ARRAY_ERROR ( kParseErrorArrayMissCommaOrSquareBracket , " [1 2] " ) ;
2011-11-18 17:01:23 +00:00
# undef TEST_ARRAY_ERROR
}
struct ParseObjectHandler : BaseReaderHandler < > {
ParseObjectHandler ( ) : step_ ( 0 ) { }
2014-07-10 19:33:01 +08:00
bool Null ( ) { EXPECT_EQ ( 8u , step_ ) ; step_ + + ; return true ; }
bool Bool ( bool b ) {
2011-11-18 17:01:23 +00:00
switch ( step_ ) {
2014-07-10 19:33:01 +08:00
case 4 : EXPECT_TRUE ( b ) ; step_ + + ; return true ;
case 6 : EXPECT_FALSE ( b ) ; step_ + + ; return true ;
default : ADD_FAILURE ( ) ; return false ;
2011-11-18 17:01:23 +00:00
}
}
2014-07-10 19:33:01 +08:00
bool Int ( int i ) {
2011-11-18 17:01:23 +00:00
switch ( step_ ) {
2014-07-10 19:33:01 +08:00
case 10 : EXPECT_EQ ( 123 , i ) ; step_ + + ; return true ;
case 15 : EXPECT_EQ ( 1 , i ) ; step_ + + ; return true ;
case 16 : EXPECT_EQ ( 2 , i ) ; step_ + + ; return true ;
case 17 : EXPECT_EQ ( 3 , i ) ; step_ + + ; return true ;
default : ADD_FAILURE ( ) ; return false ;
2011-11-18 17:01:23 +00:00
}
}
2014-07-10 19:33:01 +08:00
bool Uint ( unsigned i ) { return Int ( i ) ; }
bool Double ( double d ) { EXPECT_EQ ( 12u , step_ ) ; EXPECT_EQ ( 3.1416 , d ) ; step_ + + ; return true ; }
bool String ( const char * str , size_t , bool ) {
2011-11-18 17:01:23 +00:00
switch ( step_ ) {
2014-07-10 19:33:01 +08:00
case 1 : EXPECT_STREQ ( " hello " , str ) ; step_ + + ; return true ;
case 2 : EXPECT_STREQ ( " world " , str ) ; step_ + + ; return true ;
case 3 : EXPECT_STREQ ( " t " , str ) ; step_ + + ; return true ;
case 5 : EXPECT_STREQ ( " f " , str ) ; step_ + + ; return true ;
case 7 : EXPECT_STREQ ( " n " , str ) ; step_ + + ; return true ;
case 9 : EXPECT_STREQ ( " i " , str ) ; step_ + + ; return true ;
case 11 : EXPECT_STREQ ( " pi " , str ) ; step_ + + ; return true ;
case 13 : EXPECT_STREQ ( " a " , str ) ; step_ + + ; return true ;
default : ADD_FAILURE ( ) ; return false ;
2011-11-18 17:01:23 +00:00
}
}
2014-07-10 19:33:01 +08:00
bool StartObject ( ) { EXPECT_EQ ( 0u , step_ ) ; step_ + + ; return true ; }
bool EndObject ( SizeType memberCount ) { EXPECT_EQ ( 19u , step_ ) ; EXPECT_EQ ( 7u , memberCount ) ; step_ + + ; return true ; }
bool StartArray ( ) { EXPECT_EQ ( 14u , step_ ) ; step_ + + ; return true ; }
bool EndArray ( SizeType elementCount ) { EXPECT_EQ ( 18u , step_ ) ; EXPECT_EQ ( 3u , elementCount ) ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
unsigned step_ ;
} ;
TEST ( Reader , ParseObject ) {
const char * json = " { \" hello \" : \" world \" , \" t \" : true , \" f \" : false, \" n \" : null, \" i \" :123, \" pi \" : 3.1416, \" a \" :[1, 2, 3] } " ;
// Insitu
{
char * json2 = StrDup ( json ) ;
InsituStringStream s ( json2 ) ;
ParseObjectHandler h ;
Reader reader ;
reader . ParseObject < kParseInsituFlag > ( s , h ) ;
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 20u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
free ( json2 ) ;
}
// Normal
{
StringStream s ( json ) ;
ParseObjectHandler h ;
Reader reader ;
reader . ParseObject < 0 > ( s , h ) ;
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 20u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
}
}
struct ParseEmptyObjectHandler : BaseReaderHandler < > {
ParseEmptyObjectHandler ( ) : step_ ( 0 ) { }
2014-07-10 19:33:01 +08:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool StartObject ( ) { EXPECT_EQ ( 0u , step_ ) ; step_ + + ; return true ; }
bool EndObject ( SizeType ) { EXPECT_EQ ( 1u , step_ ) ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
unsigned step_ ;
} ;
TEST ( Reader , Parse_EmptyObject ) {
StringStream s ( " { } " ) ;
ParseEmptyObjectHandler h ;
Reader reader ;
reader . ParseObject < 0 > ( s , h ) ;
2012-11-13 08:02:22 +00:00
EXPECT_EQ ( 2u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
}
2014-06-27 16:19:04 +08:00
# define TEST_ERROR(errorCode, str) \
2011-11-18 17:01:23 +00:00
{ \
char buffer [ 1001 ] ; \
strncpy ( buffer , str , 1000 ) ; \
InsituStringStream s ( buffer ) ; \
BaseReaderHandler < > h ; \
Reader reader ; \
2011-11-22 19:29:43 +00:00
EXPECT_FALSE ( reader . Parse < 0 > ( s , h ) ) ; \
2014-06-27 16:19:04 +08:00
EXPECT_EQ ( errorCode , reader . GetParseErrorCode ( ) ) ; \
2011-11-18 17:01:23 +00:00
}
2014-06-27 16:19:04 +08:00
TEST ( Reader , ParseDocument_Error ) {
// The document is empty.
TEST_ERROR ( kParseErrorDocumentEmpty , " " ) ;
TEST_ERROR ( kParseErrorDocumentEmpty , " " ) ;
TEST_ERROR ( kParseErrorDocumentEmpty , " \n " ) ;
// The document root must be either object or array.
TEST_ERROR ( kParseErrorDocumentRootNotObjectOrArray , " null " ) ;
TEST_ERROR ( kParseErrorDocumentRootNotObjectOrArray , " true " ) ;
TEST_ERROR ( kParseErrorDocumentRootNotObjectOrArray , " false " ) ;
TEST_ERROR ( kParseErrorDocumentRootNotObjectOrArray , " \" s \" " ) ;
TEST_ERROR ( kParseErrorDocumentRootNotObjectOrArray , " 0 " ) ;
// The document root must not follow by other values.
TEST_ERROR ( kParseErrorDocumentRootNotSingular , " [] 0 " ) ;
TEST_ERROR ( kParseErrorDocumentRootNotSingular , " {} 0 " ) ;
}
2011-11-18 17:01:23 +00:00
2014-06-27 16:19:04 +08:00
TEST ( Reader , ParseValue_Error ) {
// Invalid value.
TEST_ERROR ( kParseErrorValueInvalid , " [nulL] " ) ;
TEST_ERROR ( kParseErrorValueInvalid , " [truE] " ) ;
TEST_ERROR ( kParseErrorValueInvalid , " [falsE] " ) ;
TEST_ERROR ( kParseErrorValueInvalid , " [a] " ) ;
TEST_ERROR ( kParseErrorValueInvalid , " [.1] " ) ;
}
2011-11-18 17:01:23 +00:00
2014-06-27 16:19:04 +08:00
TEST ( Reader , ParseObject_Error ) {
// Missing a name for object member.
TEST_ERROR ( kParseErrorObjectMissName , " {1} " ) ;
TEST_ERROR ( kParseErrorObjectMissName , " {:1} " ) ;
TEST_ERROR ( kParseErrorObjectMissName , " {null:1} " ) ;
TEST_ERROR ( kParseErrorObjectMissName , " {true:1} " ) ;
TEST_ERROR ( kParseErrorObjectMissName , " {false:1} " ) ;
TEST_ERROR ( kParseErrorObjectMissName , " {1:1} " ) ;
TEST_ERROR ( kParseErrorObjectMissName , " {[]:1} " ) ;
TEST_ERROR ( kParseErrorObjectMissName , " {{}:1} " ) ;
TEST_ERROR ( kParseErrorObjectMissName , " {xyz:1} " ) ;
// Missing a colon after a name of object member.
TEST_ERROR ( kParseErrorObjectMissColon , " { \" a \" 1} " ) ;
TEST_ERROR ( kParseErrorObjectMissColon , " { \" a \" ,1} " ) ;
2011-11-18 17:01:23 +00:00
2014-06-27 16:19:04 +08:00
// Must be a comma or '}' after an object member
TEST_ERROR ( kParseErrorObjectMissCommaOrCurlyBracket , " { \" a \" :1] " ) ;
}
2011-11-18 17:01:23 +00:00
# undef TEST_ERROR
2014-06-24 23:04:27 +08:00
TEST ( Reader , SkipWhitespace ) {
StringStream ss ( " A \t \t B \n \n \n C \r \r \r D \t \n \r E " ) ;
const char * expected = " ABCDE " ;
for ( size_t i = 0 ; i < 5 ; i + + ) {
SkipWhitespace ( ss ) ;
EXPECT_EQ ( expected [ i ] , ss . Take ( ) ) ;
}
2014-06-27 16:19:04 +08:00
}
2014-06-29 20:59:01 +08:00
// Test implementing a stream without copy stream optimization.
// Clone from GenericStringStream except that copy constructor is disabled.
template < typename Encoding >
class CustomStringStream {
public :
typedef typename Encoding : : Ch Ch ;
CustomStringStream ( const Ch * src ) : src_ ( src ) , head_ ( src ) { }
Ch Peek ( ) const { return * src_ ; }
Ch Take ( ) { return * src_ + + ; }
size_t Tell ( ) const { return static_cast < size_t > ( src_ - head_ ) ; }
Ch * PutBegin ( ) { RAPIDJSON_ASSERT ( false ) ; return 0 ; }
void Put ( Ch ) { RAPIDJSON_ASSERT ( false ) ; }
void Flush ( ) { RAPIDJSON_ASSERT ( false ) ; }
size_t PutEnd ( Ch * ) { RAPIDJSON_ASSERT ( false ) ; return 0 ; }
private :
2014-07-02 23:49:47 +08:00
// Prohibit copy constructor & assignment operator.
2014-06-29 20:59:01 +08:00
CustomStringStream ( const CustomStringStream & ) ;
2014-07-02 23:49:47 +08:00
CustomStringStream & operator = ( const CustomStringStream & ) ;
2014-06-29 20:59:01 +08:00
const Ch * src_ ; //!< Current read position.
const Ch * head_ ; //!< Original head of the string.
} ;
// If the following code is compiled, it should generate compilation error as predicted.
// Because CustomStringStream<> is not copyable via making copy constructor private.
#if 0
namespace rapidjson {
template < typename Encoding >
2014-06-29 21:18:31 +08:00
struct StreamTraits < CustomStringStream < Encoding > > {
2014-07-02 23:49:47 +08:00
enum { copyOptimization = 1 } ;
2014-06-29 20:59:01 +08:00
} ;
2014-07-06 21:15:38 +08:00
} // namespace rapidjson
2014-06-29 20:59:01 +08:00
# endif
TEST ( Reader , CustomStringStream ) {
const char * json = " { \" hello \" : \" world \" , \" t \" : true , \" f \" : false, \" n \" : null, \" i \" :123, \" pi \" : 3.1416, \" a \" :[1, 2, 3] } " ;
2014-06-29 21:18:31 +08:00
CustomStringStream < UTF8 < char > > s ( json ) ;
2014-06-29 20:59:01 +08:00
ParseObjectHandler h ;
Reader reader ;
reader . ParseObject < 0 > ( s , h ) ;
EXPECT_EQ ( 20u , h . step_ ) ;
}
2014-07-03 00:59:35 +08:00
2014-07-04 16:39:09 +08:00
# include <sstream>
class IStreamWrapper {
public :
typedef char Ch ;
IStreamWrapper ( std : : istream & is ) : is_ ( is ) { }
Ch Peek ( ) const {
int c = is_ . peek ( ) ;
return c = = std : : char_traits < char > : : eof ( ) ? ' \0 ' : ( Ch ) c ;
}
Ch Take ( ) {
int c = is_ . get ( ) ;
return c = = std : : char_traits < char > : : eof ( ) ? ' \0 ' : ( Ch ) c ;
}
size_t Tell ( ) const { return ( size_t ) is_ . tellg ( ) ; }
Ch * PutBegin ( ) { assert ( false ) ; return 0 ; }
void Put ( Ch ) { assert ( false ) ; }
void Flush ( ) { assert ( false ) ; }
size_t PutEnd ( Ch * ) { assert ( false ) ; return 0 ; }
private :
IStreamWrapper ( const IStreamWrapper & ) ;
IStreamWrapper & operator = ( const IStreamWrapper & ) ;
std : : istream & is_ ;
} ;
TEST ( Reader , Parse_IStreamWrapper_StringStream ) {
const char * json = " [1,2,3,4] " ;
std : : stringstream ss ( json ) ;
IStreamWrapper is ( ss ) ;
Reader reader ;
ParseArrayHandler < 4 > h ;
reader . ParseArray < 0 > ( is , h ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
}
2014-07-10 00:00:56 +08:00
# define TESTERRORHANDLING(text, errorCode)\
{ \
StringStream json ( text ) ; \
BaseReaderHandler < > handler ; \
Reader reader ; \
reader . IterativeParse < kParseDefaultFlags > ( json , handler ) ; \
EXPECT_TRUE ( reader . HasParseError ( ) ) ; \
EXPECT_EQ ( errorCode , reader . GetParseErrorCode ( ) ) ; \
}
TEST ( Reader , IterativeParsing_ErrorHandling ) {
TESTERRORHANDLING ( " { \" a \" : a} " , kParseErrorValueInvalid ) ;
TESTERRORHANDLING ( " " , kParseErrorDocumentEmpty ) ;
TESTERRORHANDLING ( " 1 " , kParseErrorDocumentRootNotObjectOrArray ) ;
TESTERRORHANDLING ( " {}{} " , kParseErrorDocumentRootNotSingular ) ;
TESTERRORHANDLING ( " {1} " , kParseErrorObjectMissName ) ;
TESTERRORHANDLING ( " { \" a \" , 1} " , kParseErrorObjectMissColon ) ;
TESTERRORHANDLING ( " { \" a \" } " , kParseErrorObjectMissColon ) ;
TESTERRORHANDLING ( " { \" a \" : 1 " , kParseErrorObjectMissCommaOrCurlyBracket ) ;
TESTERRORHANDLING ( " [1 2 3] " , kParseErrorArrayMissCommaOrSquareBracket ) ;
}
2014-07-10 22:27:25 +08:00
// Test iterative parsing.
template < typename Encoding = UTF8 < > >
struct IterativeParsingReaderHandler {
typedef typename Encoding : : Ch Ch ;
2014-07-11 16:03:38 +08:00
IterativeParsingReaderHandler ( ) {
Reset ( ) ;
}
void Reset ( ) {
IsNullTriggered = false ;
IsBoolTriggered = false ;
IsIntTriggered = false ;
IsUintTriggered = false ;
IsInt64Triggered = false ;
IsUint64Triggered = false ;
IsDoubleTriggered = false ;
IsStringTriggered = false ;
IsStartObjectTriggered = false ;
IsEndObjectTriggered = false ;
MemberCount = 0 ;
IsStartArrayTriggered = false ;
ElementCount = 0 ;
2014-07-10 22:27:25 +08:00
}
bool IsNullTriggered ;
2014-07-14 23:49:57 +08:00
bool Null ( ) { IsNullTriggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsBoolTriggered ;
2014-07-14 23:49:57 +08:00
bool Bool ( bool ) { IsBoolTriggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsIntTriggered ;
2014-07-14 23:49:57 +08:00
bool Int ( int ) { IsIntTriggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsUintTriggered ;
2014-07-14 23:49:57 +08:00
bool Uint ( unsigned ) { IsUintTriggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsInt64Triggered ;
2014-07-14 23:49:57 +08:00
bool Int64 ( int64_t ) { IsInt64Triggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsUint64Triggered ;
2014-07-14 23:49:57 +08:00
bool Uint64 ( uint64_t ) { IsUint64Triggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsDoubleTriggered ;
2014-07-14 23:49:57 +08:00
bool Double ( double ) { IsDoubleTriggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsStringTriggered ;
2014-07-14 23:49:57 +08:00
bool String ( const Ch * , SizeType , bool ) { IsStringTriggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsStartObjectTriggered ;
2014-07-14 23:49:57 +08:00
bool StartObject ( ) { IsStartObjectTriggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsEndObjectTriggered ;
SizeType MemberCount ;
2014-07-14 23:49:57 +08:00
bool EndObject ( SizeType c ) { IsEndObjectTriggered = true ; MemberCount = c ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsStartArrayTriggered ;
2014-07-14 23:49:57 +08:00
bool StartArray ( ) { IsStartArrayTriggered = true ; return true ; }
2014-07-10 22:27:25 +08:00
bool IsEndArrayTriggered ;
SizeType ElementCount ;
2014-07-14 23:49:57 +08:00
bool EndArray ( SizeType c ) { IsEndArrayTriggered = true ; ElementCount = c ; return true ; }
2014-07-10 22:27:25 +08:00
} ;
2014-07-11 11:43:09 +08:00
# define ITERATIVE_PARSING_PREPARE_STATE_UNTIL(text, pos)\
IterativeParsingReaderHandler < > handler ; \
Reader reader ; \
StringStream is ( text ) ; \
\
Reader : : IterativeParsingState state = Reader : : IterativeParsingStartState ; \
SkipWhitespace ( is ) ; \
while ( is . Tell ( ) ! = pos ) { \
Reader : : IterativeParsingToken token = reader . Tokenize ( is . Peek ( ) ) ; \
Reader : : IterativeParsingState n = reader . Predict ( state , token ) ; \
state = reader . Transit < kParseIterativeFlag > ( state , token , n , is , handler ) ; \
SkipWhitespace ( is ) ; \
}
2014-07-10 22:27:25 +08:00
TEST ( Reader , IterativeParsing_StateTransition_Start ) {
2014-07-11 16:33:32 +08:00
// Start -> ArrayInitial
2014-07-10 22:27:25 +08:00
{
IterativeParsingReaderHandler < > handler ;
Reader reader ;
2014-07-11 11:43:09 +08:00
StringStream is ( " [] " ) ;
2014-07-10 22:27:25 +08:00
Reader : : IterativeParsingState n = reader . Predict ( Reader : : IterativeParsingStartState , Reader : : IterativeParsingLeftBracketToken ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > ( Reader : : IterativeParsingStartState , Reader : : IterativeParsingLeftBracketToken , n , is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingArrayInitialState , d ) ;
EXPECT_TRUE ( handler . IsStartArrayTriggered ) ;
}
2014-07-11 16:33:32 +08:00
// Start -> ObjectInitial
2014-07-10 22:27:25 +08:00
{
IterativeParsingReaderHandler < > handler ;
Reader reader ;
2014-07-11 11:43:09 +08:00
StringStream is ( " {} " ) ;
2014-07-10 22:27:25 +08:00
Reader : : IterativeParsingState n = reader . Predict ( Reader : : IterativeParsingStartState , Reader : : IterativeParsingLeftCurlyBracketToken ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > ( Reader : : IterativeParsingStartState , Reader : : IterativeParsingLeftCurlyBracketToken , n , is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingObjectInitialState , d ) ;
EXPECT_TRUE ( handler . IsStartObjectTriggered ) ;
}
}
TEST ( Reader , IterativeParsing_StateTransition_ObjectInitial ) {
// ObjectInitial -> ObjectFinish -> Finish
{
2014-07-11 11:43:09 +08:00
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " {} " , 1 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-10 22:27:25 +08:00
2014-07-11 11:43:09 +08:00
EXPECT_EQ ( Reader : : IterativeParsingObjectInitialState , state ) ;
2014-07-10 22:27:25 +08:00
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
2014-07-11 11:43:09 +08:00
state ,
2014-07-10 22:27:25 +08:00
Reader : : IterativeParsingRightCurlyBracketToken ,
Reader : : IterativeParsingObjectFinishState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingFinishState , d ) ;
EXPECT_TRUE ( handler . IsEndObjectTriggered ) ;
EXPECT_EQ ( 0 , handler . MemberCount ) ;
}
// ObjectInitial -> MemberKey
2014-07-11 11:43:09 +08:00
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " { \" key \" : 1} " , 1 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_EQ ( Reader : : IterativeParsingObjectInitialState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingStringToken ,
Reader : : IterativeParsingMemberKeyState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingMemberKeyState , d ) ;
EXPECT_TRUE ( handler . IsStringTriggered ) ;
}
}
TEST ( Reader , IterativeParsing_StateTransition_MemberKey ) {
// MemberKey -> KeyValueDelimiter
2014-07-10 22:27:25 +08:00
{
IterativeParsingReaderHandler < > handler ;
Reader reader ;
2014-07-11 11:43:09 +08:00
StringStream is ( " : " ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
Reader : : IterativeParsingMemberKeyState ,
Reader : : IterativeParsingColonToken ,
Reader : : IterativeParsingKeyValueDelimiterState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingKeyValueDelimiterState , d ) ;
}
}
# define TEST_COMPOUNDTYPE_INITIAL_STATE_AUX(type, text, src, token, popstate, statesuffix, eventsuffix)\
{ \
IterativeParsingReaderHandler < > handler ; \
Reader reader ; \
StringStream is ( text ) ; \
\
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > ( \
src , \
token , \
Reader : : IterativeParsing # # type # # statesuffix , \
is , handler ) ; \
\
EXPECT_FALSE ( reader . HasParseError ( ) ) ; \
EXPECT_EQ ( Reader : : IterativeParsing # # type # # statesuffix , d ) ; \
EXPECT_TRUE ( handler . IsStart # # type # # eventsuffix ) ; \
\
int c = * reader . stack_ . template Pop < int > ( 1 ) ; \
EXPECT_EQ ( 0 , c ) ; \
Reader : : IterativeParsingState s = * reader . stack_ . template Pop < Reader : : IterativeParsingState > ( 1 ) ; \
EXPECT_EQ ( popstate , s ) ; \
}
# define TEST_COMPOUNDTYPE_INITIAL_STATE(type, text, src, token, popstate)\
TEST_COMPOUNDTYPE_INITIAL_STATE_AUX ( type , text , src , token , popstate , InitialState , Triggered )
# define TEST_PLAIN_VALUE_STATE_AUX(text, src, token, dst, event, eventsuffix)\
{ \
IterativeParsingReaderHandler < > handler ; \
Reader reader ; \
StringStream is ( text ) ; \
\
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > ( \
src , \
token , \
dst , \
is , handler ) ; \
\
EXPECT_FALSE ( reader . HasParseError ( ) ) ; \
EXPECT_EQ ( dst , d ) ; \
EXPECT_TRUE ( handler . Is # # event # # eventsuffix ) ; \
}
# define TEST_PLAIN_VALUE_STATE(text, src, token, dst, event)\
TEST_PLAIN_VALUE_STATE_AUX ( text , src , token , dst , event , Triggered )
TEST ( Reader , IterativeParsing_StateTransition_KeyValueDelimiter ) {
// KeyValueDelimiter -> ArrayInitial
TEST_COMPOUNDTYPE_INITIAL_STATE (
Array ,
" [ " ,
Reader : : IterativeParsingKeyValueDelimiterState ,
Reader : : IterativeParsingLeftBracketToken ,
Reader : : IterativeParsingMemberValueState ) ;
// KeyValueDelimiter -> ObjectInitial
TEST_COMPOUNDTYPE_INITIAL_STATE (
Object ,
" { " ,
Reader : : IterativeParsingKeyValueDelimiterState ,
Reader : : IterativeParsingLeftCurlyBracketToken ,
Reader : : IterativeParsingMemberValueState ) ;
// KeyValueDelimiter -> MemberValue
TEST_PLAIN_VALUE_STATE (
" 123, " ,
Reader : : IterativeParsingKeyValueDelimiterState ,
Reader : : IterativeParsingNumberToken ,
Reader : : IterativeParsingMemberValueState ,
Uint ) ;
}
TEST ( Reader , IterativeParsing_StateTransition_MemberValue ) {
2014-07-11 16:33:32 +08:00
// MemberValue -> ObjectFinish -> Finish
2014-07-11 11:43:09 +08:00
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " { \" k \" : 123} " , 9 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingMemberValueState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingRightCurlyBracketToken ,
Reader : : IterativeParsingObjectFinishState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingFinishState , d ) ;
EXPECT_TRUE ( handler . IsEndObjectTriggered ) ;
EXPECT_EQ ( 1 , handler . MemberCount ) ;
}
// MemberValue -> MemberDelimiter
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " { \" k \" : 1, \" e \" : 2} " , 7 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingMemberValueState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingCommaToken ,
Reader : : IterativeParsingMemberDelimiterState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingMemberDelimiterState , d ) ;
}
}
TEST ( Reader , IterativeParsing_StateTransition_MemberDelimiter ) {
// MemberDelimiter -> MemberKey
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " { \" k \" : 1, \" e \" : 2} " , 9 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingMemberDelimiterState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingStringToken ,
Reader : : IterativeParsingMemberKeyState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingMemberKeyState , d ) ;
}
TEST ( Reader , IterativeParsing_StateTransition_ArrayInitial ) {
// ArrayInitial -> ArrayInitial
{
2014-07-11 16:33:32 +08:00
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " [[1]] " , 1 ) ;
handler . Reset ( ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingArrayInitialState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
2014-07-11 11:43:09 +08:00
Reader : : IterativeParsingLeftBracketToken ,
2014-07-11 16:33:32 +08:00
Reader : : IterativeParsingArrayInitialState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingArrayInitialState , d ) ;
// Check initialized element count.
int c = * reader . stack_ . template Pop < int > ( 1 ) ;
EXPECT_EQ ( 0 , c ) ;
// Check pushed state.
Reader : : IterativeParsingState s = * reader . stack_ . template Pop < Reader : : IterativeParsingState > ( 1 ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementState , s ) ;
2014-07-11 11:43:09 +08:00
}
// ArrayInitial -> ArrayFinish -> Finish
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " [] " , 1 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-10 22:27:25 +08:00
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingArrayInitialState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingRightBracketToken ,
Reader : : IterativeParsingArrayFinishState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingFinishState , d ) ;
EXPECT_TRUE ( handler . IsEndArrayTriggered ) ;
EXPECT_EQ ( 0 , handler . ElementCount ) ;
}
// ArrayInitial -> ObjectInitial
{
2014-07-11 16:33:32 +08:00
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " [{ \" k \" : 1}] " , 1 ) ;
handler . Reset ( ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingArrayInitialState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
2014-07-10 22:27:25 +08:00
Reader : : IterativeParsingLeftCurlyBracketToken ,
2014-07-11 16:33:32 +08:00
Reader : : IterativeParsingObjectInitialState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingObjectInitialState , d ) ;
// Check initialized element count.
int c = * reader . stack_ . template Pop < int > ( 1 ) ;
EXPECT_EQ ( 0 , c ) ;
// Check pushed state.
Reader : : IterativeParsingState s = * reader . stack_ . template Pop < Reader : : IterativeParsingState > ( 1 ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementState , s ) ;
2014-07-11 11:43:09 +08:00
}
// ArrayInitial -> Element
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " [1] " , 1 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingArrayInitialState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingNumberToken ,
Reader : : IterativeParsingElementState ,
2014-07-10 22:27:25 +08:00
is , handler ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementState , d ) ;
}
}
TEST ( Reader , IterativeParsing_StateTransition_Element ) {
// Element -> ArrayFinish -> Finish
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " [1] " , 2 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementState , state ) ;
2014-07-10 22:27:25 +08:00
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
2014-07-11 11:43:09 +08:00
state ,
Reader : : IterativeParsingRightBracketToken ,
Reader : : IterativeParsingArrayFinishState ,
2014-07-10 22:27:25 +08:00
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
2014-07-11 11:43:09 +08:00
EXPECT_EQ ( Reader : : IterativeParsingFinishState , d ) ;
EXPECT_TRUE ( handler . IsEndArrayTriggered ) ;
EXPECT_EQ ( 1 , handler . ElementCount ) ;
}
// Element -> ElementDelimiter
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " [1, 2] " , 2 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingCommaToken ,
Reader : : IterativeParsingElementDelimiterState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementDelimiterState , d ) ;
}
}
TEST ( Reader , IterativeParsing_StateTransition_ElementDelimiter ) {
// ElementDelimiter -> ArrayInitial
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " [1, [1]] " , 4 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementDelimiterState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingLeftBracketToken ,
Reader : : IterativeParsingArrayInitialState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingArrayInitialState , d ) ;
int c = * reader . stack_ . template Pop < int > ( 1 ) ;
EXPECT_EQ ( 0 , c ) ;
Reader : : IterativeParsingState s = * reader . stack_ . template Pop < Reader : : IterativeParsingState > ( 1 ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementState , s ) ;
}
// ElementDelimiter -> ObjectInitial
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " [1, [1]] " , 4 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementDelimiterState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingLeftBracketToken ,
Reader : : IterativeParsingArrayInitialState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingArrayInitialState , d ) ;
int c = * reader . stack_ . template Pop < int > ( 1 ) ;
EXPECT_EQ ( 0 , c ) ;
Reader : : IterativeParsingState s = * reader . stack_ . template Pop < Reader : : IterativeParsingState > ( 1 ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementState , s ) ;
}
// ElementDelimiter -> Element
{
ITERATIVE_PARSING_PREPARE_STATE_UNTIL ( " [1, 2] " , 4 ) ;
2014-07-11 16:03:38 +08:00
handler . Reset ( ) ;
2014-07-11 11:43:09 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementDelimiterState , state ) ;
Reader : : IterativeParsingState d = reader . Transit < kParseIterativeFlag > (
state ,
Reader : : IterativeParsingNumberToken ,
Reader : : IterativeParsingElementState ,
is , handler ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( Reader : : IterativeParsingElementState , d ) ;
int c = * reader . stack_ . template Pop < int > ( 1 ) ;
EXPECT_EQ ( 1 , c ) ;
2014-07-10 22:27:25 +08:00
}
}
2014-07-03 00:59:35 +08:00
# ifdef __GNUC__
2014-07-08 14:45:19 +02:00
RAPIDJSON_DIAG_POP
2014-07-03 00:59:35 +08:00
# endif