2015-04-18 21:41:38 +08:00
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
2014-08-11 22:26:45 +08:00
//
2015-04-18 21:41:38 +08:00
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
2014-08-11 22:26:45 +08:00
//
2015-04-18 21:41:38 +08:00
// http://opensource.org/licenses/MIT
2014-08-11 22:26:45 +08:00
//
2015-04-18 21:41:38 +08:00
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
2014-08-11 22:26:45 +08:00
2011-11-18 17:01:23 +00:00
# include "unittest.h"
# include "rapidjson/reader.h"
2014-09-03 13:27:43 +08:00
# include "rapidjson/internal/dtoa.h"
# include "rapidjson/internal/itoa.h"
2014-10-23 00:24:32 +02:00
# include "rapidjson/memorystream.h"
2011-11-18 17:01:23 +00:00
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 + + )
2015-04-10 23:24:33 +08:00
RAPIDJSON_DIAG_OFF ( float - equal )
2014-07-03 00:59:35 +08:00
# endif
2011-11-18 17:01:23 +00:00
template < bool expect >
2014-08-11 15:50:47 +02:00
struct ParseBoolHandler : BaseReaderHandler < UTF8 < > , ParseBoolHandler < expect > > {
2014-08-11 22:26:45 +08:00
ParseBoolHandler ( ) : step_ ( 0 ) { }
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
// gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest version.
// Workaround with EXPECT_TRUE().
bool Bool ( bool b ) { /*EXPECT_EQ(expect, b); */ EXPECT_TRUE ( expect = = b ) ; + + step_ ; return true ; }
2011-11-18 17:01:23 +00:00
2014-08-11 22:26:45 +08:00
unsigned step_ ;
2011-11-18 17:01:23 +00:00
} ;
TEST ( Reader , ParseTrue ) {
2014-08-11 22:26:45 +08:00
StringStream s ( " true " ) ;
ParseBoolHandler < true > h ;
Reader reader ;
2014-08-11 17:11:59 +02:00
reader . Parse ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 1u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
}
TEST ( Reader , ParseFalse ) {
2014-08-11 22:26:45 +08:00
StringStream s ( " false " ) ;
ParseBoolHandler < false > h ;
Reader reader ;
2014-08-11 17:11:59 +02:00
reader . Parse ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 1u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
}
2014-08-11 15:43:50 +02:00
struct ParseIntHandler : BaseReaderHandler < UTF8 < > , ParseIntHandler > {
2014-08-11 22:26:45 +08:00
ParseIntHandler ( ) : step_ ( 0 ) , actual_ ( ) { }
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Int ( int i ) { actual_ = i ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
2014-08-11 22:26:45 +08:00
unsigned step_ ;
int actual_ ;
2011-11-18 17:01:23 +00:00
} ;
2014-08-11 15:50:47 +02:00
struct ParseUintHandler : BaseReaderHandler < UTF8 < > , ParseUintHandler > {
2014-08-11 22:26:45 +08:00
ParseUintHandler ( ) : step_ ( 0 ) , actual_ ( ) { }
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Uint ( unsigned i ) { actual_ = i ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
2014-08-11 22:26:45 +08:00
unsigned step_ ;
unsigned actual_ ;
2011-11-18 17:01:23 +00:00
} ;
2014-08-11 15:50:47 +02:00
struct ParseInt64Handler : BaseReaderHandler < UTF8 < > , ParseInt64Handler > {
2014-08-11 22:26:45 +08:00
ParseInt64Handler ( ) : step_ ( 0 ) , actual_ ( ) { }
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Int64 ( int64_t i ) { actual_ = i ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
2014-08-11 22:26:45 +08:00
unsigned step_ ;
int64_t actual_ ;
2011-11-18 17:01:23 +00:00
} ;
2014-08-11 15:50:47 +02:00
struct ParseUint64Handler : BaseReaderHandler < UTF8 < > , ParseUint64Handler > {
2014-08-11 22:26:45 +08:00
ParseUint64Handler ( ) : step_ ( 0 ) , actual_ ( ) { }
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Uint64 ( uint64_t i ) { actual_ = i ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
2014-08-11 22:26:45 +08:00
unsigned step_ ;
uint64_t actual_ ;
2011-11-18 17:01:23 +00:00
} ;
2014-08-11 15:50:47 +02:00
struct ParseDoubleHandler : BaseReaderHandler < UTF8 < > , ParseDoubleHandler > {
2014-08-11 22:26:45 +08:00
ParseDoubleHandler ( ) : step_ ( 0 ) , actual_ ( ) { }
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool Double ( double d ) { actual_ = d ; step_ + + ; return true ; }
2011-11-18 17:01:23 +00:00
2014-08-11 22:26:45 +08:00
unsigned step_ ;
double actual_ ;
2011-11-18 17:01:23 +00:00
} ;
2014-09-05 13:22:56 +08:00
TEST ( Reader , ParseNumber_Integer ) {
# define TEST_INTEGER(Handler, str, x) \
2014-08-11 22:26:45 +08:00
{ \
StringStream s ( str ) ; \
Handler h ; \
Reader reader ; \
2014-08-11 17:11:59 +02:00
reader . Parse ( s , h ) ; \
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 1u , h . step_ ) ; \
2014-09-05 20:06:03 +08:00
EXPECT_EQ ( x , h . actual_ ) ; \
2014-08-11 22:26:45 +08:00
}
2011-11-18 17:01:23 +00:00
2014-09-05 20:06:03 +08:00
TEST_INTEGER ( ParseUintHandler , " 0 " , 0u ) ;
TEST_INTEGER ( ParseUintHandler , " 123 " , 123u ) ;
2014-09-05 13:22:56 +08:00
TEST_INTEGER ( ParseUintHandler , " 2147483648 " , 2147483648u ) ; // 2^31 - 1 (cannot be stored in int)
TEST_INTEGER ( ParseUintHandler , " 4294967295 " , 4294967295u ) ;
2014-08-11 22:26:45 +08:00
2014-09-05 13:22:56 +08:00
TEST_INTEGER ( ParseIntHandler , " -123 " , - 123 ) ;
2014-09-10 09:28:52 +08:00
TEST_INTEGER ( ParseIntHandler , " -2147483648 " , static_cast < int32_t > ( 0x80000000 ) ) ; // -2^31 (min of int)
2014-08-11 22:26:45 +08:00
2014-09-10 09:28:52 +08:00
TEST_INTEGER ( ParseUint64Handler , " 4294967296 " , RAPIDJSON_UINT64_C2 ( 1 , 0 ) ) ; // 2^32 (max of unsigned + 1, force to use uint64_t)
TEST_INTEGER ( ParseUint64Handler , " 18446744073709551615 " , RAPIDJSON_UINT64_C2 ( 0xFFFFFFFF , 0xFFFFFFFF ) ) ; // 2^64 - 1 (max of uint64_t)
2014-09-05 13:22:56 +08:00
2014-09-10 09:28:52 +08:00
TEST_INTEGER ( ParseInt64Handler , " -2147483649 " , static_cast < int64_t > ( RAPIDJSON_UINT64_C2 ( 0xFFFFFFFF , 0x7FFFFFFF ) ) ) ; // -2^31 -1 (min of int - 1, force to use int64_t)
TEST_INTEGER ( ParseInt64Handler , " -9223372036854775808 " , static_cast < int64_t > ( RAPIDJSON_UINT64_C2 ( 0x80000000 , 0x00000000 ) ) ) ; // -2^63 (min of int64_t)
2014-09-03 13:27:43 +08:00
// Random test for uint32_t/int32_t
{
union {
uint32_t u ;
int32_t i ;
} u ;
Random r ;
for ( unsigned i = 0 ; i < 100000 ; i + + ) {
u . u = r ( ) ;
char buffer [ 32 ] ;
* internal : : u32toa ( u . u , buffer ) = ' \0 ' ;
2014-09-05 13:22:56 +08:00
TEST_INTEGER ( ParseUintHandler , buffer , u . u ) ;
2014-09-03 13:27:43 +08:00
if ( u . i < 0 ) {
* internal : : i32toa ( u . i , buffer ) = ' \0 ' ;
2014-09-05 13:22:56 +08:00
TEST_INTEGER ( ParseIntHandler , buffer , u . i ) ;
2014-09-03 13:27:43 +08:00
}
}
}
// Random test for uint64_t/int64_t
{
union {
uint64_t u ;
int64_t i ;
} u ;
Random r ;
for ( unsigned i = 0 ; i < 100000 ; i + + ) {
u . u = uint64_t ( r ( ) ) < < 32 ;
u . u | = r ( ) ;
char buffer [ 32 ] ;
if ( u . u > = 4294967296ULL ) {
* internal : : u64toa ( u . u , buffer ) = ' \0 ' ;
2014-09-05 13:22:56 +08:00
TEST_INTEGER ( ParseUint64Handler , buffer , u . u ) ;
2014-09-03 13:27:43 +08:00
}
if ( u . i < = - 2147483649LL ) {
* internal : : i64toa ( u . i , buffer ) = ' \0 ' ;
2014-09-05 13:22:56 +08:00
TEST_INTEGER ( ParseInt64Handler , buffer , u . i ) ;
2014-09-03 13:27:43 +08:00
}
}
}
2014-09-05 13:22:56 +08:00
# undef TEST_INTEGER
}
2014-09-03 13:27:43 +08:00
2014-09-05 13:22:56 +08:00
template < bool fullPrecision >
static void TestParseDouble ( ) {
# define TEST_DOUBLE(fullPrecision, str, x) \
2014-08-11 22:26:45 +08:00
{ \
StringStream s ( str ) ; \
ParseDoubleHandler h ; \
Reader reader ; \
2014-09-05 19:51:20 +08:00
ASSERT_EQ ( kParseErrorNone , reader . Parse < fullPrecision ? kParseFullPrecisionFlag : 0 > ( s , h ) . Code ( ) ) ; \
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 1u , h . step_ ) ; \
2015-04-10 21:24:29 +08:00
internal : : Double e ( x ) , a ( h . actual_ ) ; \
2014-09-05 13:22:56 +08:00
if ( fullPrecision ) { \
2015-04-11 11:26:47 +08:00
EXPECT_EQ ( e . Uint64Value ( ) , a . Uint64Value ( ) ) ; \
if ( e . Uint64Value ( ) ! = a . Uint64Value ( ) ) \
printf ( " String: %s \n Actual: %.17g \n Expected: %.17g \n " , str , h . actual_ , x ) ; \
2014-09-05 13:22:56 +08:00
} \
2015-04-11 11:26:47 +08:00
else { \
EXPECT_EQ ( e . Sign ( ) , a . Sign ( ) ) ; /* for 0.0 != -0.0 */ \
2014-09-05 13:22:56 +08:00
EXPECT_DOUBLE_EQ ( x , h . actual_ ) ; \
2015-04-11 11:26:47 +08:00
} \
2014-08-11 22:26:45 +08:00
}
2014-10-31 10:25:04 +08:00
2014-09-05 19:51:20 +08:00
TEST_DOUBLE ( fullPrecision , " 0.0 " , 0.0 ) ;
2015-04-10 21:24:29 +08:00
TEST_DOUBLE ( fullPrecision , " -0.0 " , - 0.0 ) ; // For checking issue #289
2014-09-05 19:51:20 +08:00
TEST_DOUBLE ( fullPrecision , " 1.0 " , 1.0 ) ;
TEST_DOUBLE ( fullPrecision , " -1.0 " , - 1.0 ) ;
TEST_DOUBLE ( fullPrecision , " 1.5 " , 1.5 ) ;
TEST_DOUBLE ( fullPrecision , " -1.5 " , - 1.5 ) ;
TEST_DOUBLE ( fullPrecision , " 3.1416 " , 3.1416 ) ;
TEST_DOUBLE ( fullPrecision , " 1E10 " , 1E10 ) ;
TEST_DOUBLE ( fullPrecision , " 1e10 " , 1e10 ) ;
TEST_DOUBLE ( fullPrecision , " 1E+10 " , 1E+10 ) ;
TEST_DOUBLE ( fullPrecision , " 1E-10 " , 1E-10 ) ;
TEST_DOUBLE ( fullPrecision , " -1E10 " , - 1E10 ) ;
TEST_DOUBLE ( fullPrecision , " -1e10 " , - 1e10 ) ;
TEST_DOUBLE ( fullPrecision , " -1E+10 " , - 1E+10 ) ;
TEST_DOUBLE ( fullPrecision , " -1E-10 " , - 1E-10 ) ;
TEST_DOUBLE ( fullPrecision , " 1.234E+10 " , 1.234E+10 ) ;
TEST_DOUBLE ( fullPrecision , " 1.234E-10 " , 1.234E-10 ) ;
TEST_DOUBLE ( fullPrecision , " 1.79769e+308 " , 1.79769e+308 ) ;
2014-09-13 23:24:40 +08:00
TEST_DOUBLE ( fullPrecision , " 2.22507e-308 " , 2.22507e-308 ) ;
2014-09-05 19:51:20 +08:00
TEST_DOUBLE ( fullPrecision , " -1.79769e+308 " , - 1.79769e+308 ) ;
2014-09-13 23:24:40 +08:00
TEST_DOUBLE ( fullPrecision , " -2.22507e-308 " , - 2.22507e-308 ) ;
TEST_DOUBLE ( fullPrecision , " 4.9406564584124654e-324 " , 4.9406564584124654e-324 ) ; // minimum denormal
TEST_DOUBLE ( fullPrecision , " 2.2250738585072009e-308 " , 2.2250738585072009e-308 ) ; // Max subnormal double
TEST_DOUBLE ( fullPrecision , " 2.2250738585072014e-308 " , 2.2250738585072014e-308 ) ; // Min normal positive double
TEST_DOUBLE ( fullPrecision , " 1.7976931348623157e+308 " , 1.7976931348623157e+308 ) ; // Max double
2015-04-24 21:44:42 +08:00
TEST_DOUBLE ( fullPrecision , " 1e-10000 " , 0.0 ) ; // must underflow
TEST_DOUBLE ( fullPrecision , " 18446744073709551616 " , 18446744073709551616.0 ) ; // 2^64 (max of uint64_t + 1, force to use double)
TEST_DOUBLE ( fullPrecision , " -9223372036854775809 " , - 9223372036854775809.0 ) ; // -2^63 - 1(min of int64_t + 1, force to use double)
TEST_DOUBLE ( fullPrecision , " 0.9868011474609375 " , 0.9868011474609375 ) ; // https://github.com/miloyip/rapidjson/issues/120
TEST_DOUBLE ( fullPrecision , " 123e34 " , 123e34 ) ; // Fast Path Cases In Disguise
2014-09-05 19:51:20 +08:00
TEST_DOUBLE ( fullPrecision , " 45913141877270640000.0 " , 45913141877270640000.0 ) ;
2014-09-13 23:24:40 +08:00
TEST_DOUBLE ( fullPrecision , " 2.2250738585072011e-308 " , 2.2250738585072011e-308 ) ; // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
2015-04-24 21:44:42 +08:00
TEST_DOUBLE ( fullPrecision , " 1e-00011111111111 " , 0.0 ) ; // Issue #313
TEST_DOUBLE ( fullPrecision , " -1e-00011111111111 " , - 0.0 ) ;
2015-04-25 00:13:09 +08:00
TEST_DOUBLE ( fullPrecision , " 1e-214748363 " , 0.0 ) ; // Maximum supported negative exponent
TEST_DOUBLE ( fullPrecision , " 1e-214748364 " , 0.0 ) ;
TEST_DOUBLE ( fullPrecision , " 1e-21474836311 " , 0.0 ) ;
2015-04-24 22:50:42 +08:00
TEST_DOUBLE ( fullPrecision , " 0.017976931348623157e+310 " , 1.7976931348623157e+308 ) ; // Max double in another form
2014-09-15 00:30:22 +08:00
// Since
// abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... <20> <> 10^-324
// abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... <20> <> 10 ^ -324
// So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308
TEST_DOUBLE ( fullPrecision , " 2.2250738585072012e-308 " , 2.2250738585072014e-308 ) ; // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
// More closer to normal/subnormal boundary
// boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... <20> <> 10^-308
TEST_DOUBLE ( fullPrecision , " 2.22507385850720113605740979670913197593481954635164564e-308 " , 2.2250738585072009e-308 ) ;
TEST_DOUBLE ( fullPrecision , " 2.22507385850720113605740979670913197593481954635164565e-308 " , 2.2250738585072014e-308 ) ;
// 1.0 is in (1.0 - 2^-54, 1.0 + 2^-53)
// 1.0 - 2^-54 = 0.999999999999999944488848768742172978818416595458984375
TEST_DOUBLE ( fullPrecision , " 0.999999999999999944488848768742172978818416595458984375 " , 1.0 ) ; // round to even
TEST_DOUBLE ( fullPrecision , " 0.999999999999999944488848768742172978818416595458984374 " , 0.99999999999999989 ) ; // previous double
TEST_DOUBLE ( fullPrecision , " 0.999999999999999944488848768742172978818416595458984376 " , 1.0 ) ; // next double
// 1.0 + 2^-53 = 1.00000000000000011102230246251565404236316680908203125
TEST_DOUBLE ( fullPrecision , " 1.00000000000000011102230246251565404236316680908203125 " , 1.0 ) ; // round to even
TEST_DOUBLE ( fullPrecision , " 1.00000000000000011102230246251565404236316680908203124 " , 1.0 ) ; // previous double
TEST_DOUBLE ( fullPrecision , " 1.00000000000000011102230246251565404236316680908203126 " , 1.00000000000000022 ) ; // next double
2014-09-03 13:27:43 +08:00
2015-04-14 13:22:39 +08:00
// Numbers from https://github.com/floitsch/double-conversion/blob/master/test/cctest/test-strtod.cc
TEST_DOUBLE ( fullPrecision , " 72057594037927928.0 " , 72057594037927928.0 ) ;
TEST_DOUBLE ( fullPrecision , " 72057594037927936.0 " , 72057594037927936.0 ) ;
TEST_DOUBLE ( fullPrecision , " 72057594037927932.0 " , 72057594037927936.0 ) ;
TEST_DOUBLE ( fullPrecision , " 7205759403792793199999e-5 " , 72057594037927928.0 ) ;
TEST_DOUBLE ( fullPrecision , " 7205759403792793200001e-5 " , 72057594037927936.0 ) ;
TEST_DOUBLE ( fullPrecision , " 9223372036854774784.0 " , 9223372036854774784.0 ) ;
TEST_DOUBLE ( fullPrecision , " 9223372036854775808.0 " , 9223372036854775808.0 ) ;
TEST_DOUBLE ( fullPrecision , " 9223372036854775296.0 " , 9223372036854775808.0 ) ;
TEST_DOUBLE ( fullPrecision , " 922337203685477529599999e-5 " , 9223372036854774784.0 ) ;
TEST_DOUBLE ( fullPrecision , " 922337203685477529600001e-5 " , 9223372036854775808.0 ) ;
TEST_DOUBLE ( fullPrecision , " 10141204801825834086073718800384 " , 10141204801825834086073718800384.0 ) ;
TEST_DOUBLE ( fullPrecision , " 10141204801825835211973625643008 " , 10141204801825835211973625643008.0 ) ;
TEST_DOUBLE ( fullPrecision , " 10141204801825834649023672221696 " , 10141204801825835211973625643008.0 ) ;
TEST_DOUBLE ( fullPrecision , " 1014120480182583464902367222169599999e-5 " , 10141204801825834086073718800384.0 ) ;
TEST_DOUBLE ( fullPrecision , " 1014120480182583464902367222169600001e-5 " , 10141204801825835211973625643008.0 ) ;
TEST_DOUBLE ( fullPrecision , " 5708990770823838890407843763683279797179383808 " , 5708990770823838890407843763683279797179383808.0 ) ;
TEST_DOUBLE ( fullPrecision , " 5708990770823839524233143877797980545530986496 " , 5708990770823839524233143877797980545530986496.0 ) ;
TEST_DOUBLE ( fullPrecision , " 5708990770823839207320493820740630171355185152 " , 5708990770823839524233143877797980545530986496.0 ) ;
TEST_DOUBLE ( fullPrecision , " 5708990770823839207320493820740630171355185151999e-3 " , 5708990770823838890407843763683279797179383808.0 ) ;
TEST_DOUBLE ( fullPrecision , " 5708990770823839207320493820740630171355185152001e-3 " , 5708990770823839524233143877797980545530986496.0 ) ;
2014-09-05 19:51:20 +08:00
{
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 ( fullPrecision , n1e308 , 1E308 ) ;
}
2014-09-05 13:22:56 +08:00
2015-04-14 13:59:05 +08:00
// Cover trimming
TEST_DOUBLE ( fullPrecision ,
" 2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508 "
" 7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012 "
" 9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306 "
" 6665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505 "
" 1080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621 "
" 5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844 "
" 2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042 "
" 7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901 "
" e-308 " ,
2.2250738585072014e-308 ) ;
2014-09-05 19:51:20 +08:00
{
2015-04-15 14:41:33 +08:00
static const unsigned count = 100 ; // Tested with 1000000 locally
2014-09-05 19:51:20 +08:00
Random r ;
2015-04-15 14:23:00 +08:00
Reader reader ; // Reusing reader to prevent heap allocation
2014-09-05 19:51:20 +08:00
2015-04-15 14:23:00 +08:00
// Exhaustively test different exponents with random significant
for ( uint64_t exp = 0 ; exp < 2047 ; exp + + ) {
;
for ( unsigned i = 0 ; i < count ; i + + ) {
2014-09-05 19:51:20 +08:00
// Need to call r() in two statements for cross-platform coherent sequence.
2015-04-15 14:23:00 +08:00
uint64_t u = ( exp < < 52 ) | uint64_t ( r ( ) & 0x000FFFFF ) < < 32 ;
2014-09-13 23:24:40 +08:00
u | = uint64_t ( r ( ) ) ;
2015-04-15 14:23:00 +08:00
internal : : Double d = internal : : Double ( u ) ;
char buffer [ 32 ] ;
* internal : : dtoa ( d . Value ( ) , buffer ) = ' \0 ' ;
StringStream s ( buffer ) ;
ParseDoubleHandler h ;
ASSERT_EQ ( kParseErrorNone , reader . Parse < fullPrecision ? kParseFullPrecisionFlag : 0 > ( s , h ) . Code ( ) ) ;
EXPECT_EQ ( 1u , h . step_ ) ;
internal : : Double a ( h . actual_ ) ;
if ( fullPrecision ) {
EXPECT_EQ ( d . Uint64Value ( ) , a . Uint64Value ( ) ) ;
if ( d . Uint64Value ( ) ! = a . Uint64Value ( ) )
printf ( " String: %sn Actual: %.17gnExpected: %.17gn " , buffer , h . actual_ , d . Value ( ) ) ;
}
else {
EXPECT_EQ ( d . Sign ( ) , a . Sign ( ) ) ; /* for 0.0 != -0.0 */
EXPECT_DOUBLE_EQ ( d . Value ( ) , h . actual_ ) ;
}
}
2014-09-05 19:51:20 +08:00
}
2014-09-03 13:27:43 +08:00
}
2011-11-18 17:01:23 +00:00
# undef TEST_DOUBLE
}
2014-09-05 13:22:56 +08:00
TEST ( Reader , ParseNumber_NormalPrecisionDouble ) {
TestParseDouble < false > ( ) ;
}
TEST ( Reader , ParseNumber_FullPrecisionDouble ) {
TestParseDouble < true > ( ) ;
}
2014-09-05 22:18:40 +08:00
TEST ( Reader , ParseNumber_NormalPrecisionError ) {
static unsigned count = 1000000 ;
Random r ;
double ulpSum = 0.0 ;
double ulpMax = 0.0 ;
for ( unsigned i = 0 ; i < count ; i + + ) {
2014-09-13 23:24:40 +08:00
internal : : Double e , a ;
2014-09-05 22:18:40 +08:00
do {
// Need to call r() in two statements for cross-platform coherent sequence.
2014-09-13 23:24:40 +08:00
uint64_t u = uint64_t ( r ( ) ) < < 32 ;
u | = uint64_t ( r ( ) ) ;
e = u ;
} while ( e . IsNan ( ) | | e . IsInf ( ) | | ! e . IsNormal ( ) ) ;
2014-09-05 22:18:40 +08:00
char buffer [ 32 ] ;
2014-09-13 23:24:40 +08:00
* internal : : dtoa ( e . Value ( ) , buffer ) = ' \0 ' ;
2014-09-05 22:18:40 +08:00
StringStream s ( buffer ) ;
ParseDoubleHandler h ;
Reader reader ;
ASSERT_EQ ( kParseErrorNone , reader . Parse ( s , h ) . Code ( ) ) ;
EXPECT_EQ ( 1u , h . step_ ) ;
2014-09-13 23:24:40 +08:00
a = h . actual_ ;
uint64_t bias1 = e . ToBias ( ) ;
2014-09-05 22:18:40 +08:00
uint64_t bias2 = a . ToBias ( ) ;
double ulp = bias1 > = bias2 ? bias1 - bias2 : bias2 - bias1 ;
ulpMax = std : : max ( ulpMax , ulp ) ;
ulpSum + = ulp ;
}
printf ( " ULP Average = %g, Max = %g \n " , ulpSum / count , ulpMax ) ;
}
2014-06-27 16:19:04 +08:00
TEST ( Reader , ParseNumber_Error ) {
# define TEST_NUMBER_ERROR(errorCode, str) \
2014-08-11 22:26:45 +08:00
{ \
char buffer [ 1001 ] ; \
2014-08-11 17:11:59 +02:00
sprintf ( buffer , " %s " , str ) ; \
2014-08-11 22:26:45 +08:00
InsituStringStream s ( buffer ) ; \
BaseReaderHandler < > h ; \
Reader reader ; \
2014-08-11 17:11:59 +02:00
EXPECT_FALSE ( reader . Parse ( s , h ) ) ; \
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( errorCode , reader . GetParseErrorCode ( ) ) ; \
}
// Number too big to be stored in double.
{
char n1e309 [ 311 ] ; // '1' followed by 309 '0'
n1e309 [ 0 ] = ' 1 ' ;
for ( int i = 1 ; i < 310 ; i + + )
n1e309 [ i ] = ' 0 ' ;
n1e309 [ 310 ] = ' \0 ' ;
TEST_NUMBER_ERROR ( kParseErrorNumberTooBig , n1e309 ) ;
}
TEST_NUMBER_ERROR ( kParseErrorNumberTooBig , " 1e309 " ) ;
// 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 >
2014-08-11 15:50:47 +02:00
struct ParseStringHandler : BaseReaderHandler < Encoding , ParseStringHandler < Encoding > > {
2014-08-11 22:26:45 +08:00
ParseStringHandler ( ) : str_ ( 0 ) , length_ ( 0 ) , copy_ ( ) { }
~ ParseStringHandler ( ) { EXPECT_TRUE ( str_ ! = 0 ) ; if ( copy_ ) free ( const_cast < typename Encoding : : Ch * > ( str_ ) ) ; }
ParseStringHandler ( const ParseStringHandler & ) ;
ParseStringHandler & operator = ( const ParseStringHandler & ) ;
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
bool String ( const typename Encoding : : Ch * str , size_t length , bool copy ) {
EXPECT_EQ ( 0 , str_ ) ;
if ( copy ) {
str_ = ( typename Encoding : : Ch * ) malloc ( ( length + 1 ) * sizeof ( typename Encoding : : Ch ) ) ;
memcpy ( const_cast < typename Encoding : : Ch * > ( str_ ) , str , ( length + 1 ) * sizeof ( typename Encoding : : Ch ) ) ;
}
else
str_ = str ;
length_ = length ;
copy_ = copy ;
return true ;
}
const typename Encoding : : Ch * str_ ;
size_t length_ ;
bool copy_ ;
2011-11-18 17:01:23 +00:00
} ;
TEST ( Reader , ParseString ) {
# define TEST_STRING(Encoding, e, x) \
2014-08-11 22:26:45 +08:00
{ \
Encoding : : Ch * buffer = StrDup ( x ) ; \
GenericInsituStringStream < Encoding > is ( buffer ) ; \
ParseStringHandler < Encoding > h ; \
GenericReader < Encoding , Encoding > reader ; \
2014-08-11 17:11:59 +02:00
reader . Parse < kParseInsituFlag | kParseValidateEncodingFlag > ( is , h ) ; \
2014-08-11 22:26:45 +08: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 ; \
GenericReader < Encoding , Encoding > reader2 ; \
2014-08-11 17:11:59 +02:00
reader2 . Parse ( s , h2 ) ; \
2014-08-11 22:26:45 +08:00
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.
// 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) \
2014-08-11 22:26:45 +08:00
{ \
static const utype ue [ ] = array ; \
static const Encoding : : Ch * e = reinterpret_cast < const Encoding : : Ch * > ( & ue [ 0 ] ) ; \
TEST_STRING ( Encoding , e , x ) ; \
}
2011-11-18 17:01:23 +00:00
2014-06-25 00:04:24 +08:00
# define TEST_STRINGARRAY2(Encoding, utype, earray, xarray) \
2014-08-11 22:26:45 +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 ] ) ; \
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 \" " ) ;
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
// UTF32
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
2014-08-11 22:26:45 +08:00
// Support of null character in string
{
StringStream s ( " \" Hello \\ u0000World \" " ) ;
const char e [ ] = " Hello \0 World " ;
ParseStringHandler < UTF8 < > > h ;
Reader reader ;
2014-08-11 17:11:59 +02:00
reader . Parse ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 0 , memcmp ( e , h . str_ , h . length_ + 1 ) ) ;
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 ) {
2014-08-11 22:26:45 +08:00
const char * x = " \" Hello \" " ;
const wchar_t * e = L " Hello " ;
GenericStringStream < UTF8 < > > is ( x ) ;
GenericReader < UTF8 < > , UTF16 < > > reader ;
ParseStringHandler < UTF16 < > > h ;
2014-08-11 17:11:59 +02:00
reader . Parse ( is , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 0 , StrCmp < UTF16 < > : : Ch > ( e , h . str_ ) ) ;
EXPECT_EQ ( StrLen ( e ) , h . length_ ) ;
2011-11-28 09:30:32 +00:00
}
2015-04-13 23:03:00 +08:00
TEST ( Reader , ParseString_TranscodingWithValidation ) {
const char * x = " \" Hello \" " ;
const wchar_t * e = L " Hello " ;
GenericStringStream < UTF8 < > > is ( x ) ;
GenericReader < UTF8 < > , UTF16 < > > reader ;
ParseStringHandler < UTF16 < > > h ;
reader . Parse < kParseValidateEncodingFlag > ( 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 ) {
2014-08-11 22:26:45 +08:00
StringStream s ( " \" Hello \\ nWorld \" " ) ;
ParseStringHandler < UTF8 < > > h ;
Reader reader ;
2014-08-11 17:11:59 +02:00
reader . Parse ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 0 , StrCmp ( " Hello \n World " , h . str_ ) ) ;
EXPECT_EQ ( 11u , h . length_ ) ;
2011-11-18 17:01:23 +00:00
}
2015-04-14 00:39:54 +08:00
template < typename Encoding >
ParseErrorCode TestString ( const typename Encoding : : Ch * str ) {
GenericStringStream < Encoding > s ( str ) ;
BaseReaderHandler < Encoding > h ;
GenericReader < Encoding , Encoding > reader ;
reader . template Parse < kParseValidateEncodingFlag > ( s , h ) ;
2014-08-11 22:26:45 +08:00
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)\
2015-04-14 00:39:54 +08:00
EXPECT_EQ ( errorCode , TestString < UTF8 < > > ( str ) )
2014-06-27 16:19:04 +08:00
2011-11-22 19:29:43 +00:00
# define ARRAY(...) { __VA_ARGS__ }
2015-04-14 00:39:54 +08:00
# define TEST_STRINGENCODING_ERROR(Encoding, TargetEncoding, utype, array) \
2014-08-11 22:26:45 +08:00
{ \
static const utype ue [ ] = array ; \
static const Encoding : : Ch * e = reinterpret_cast < const Encoding : : Ch * > ( & ue [ 0 ] ) ; \
2015-04-14 00:39:54 +08:00
EXPECT_EQ ( kParseErrorStringInvalidEncoding , TestString < Encoding > ( e ) ) ; \
/* decode error */ \
GenericStringStream < Encoding > s ( e ) ; \
BaseReaderHandler < TargetEncoding > h ; \
GenericReader < Encoding , TargetEncoding > reader ; \
reader . Parse ( s , h ) ; \
EXPECT_EQ ( kParseErrorStringInvalidEncoding , reader . GetParseErrorCode ( ) ) ; \
2014-08-11 22:26:45 +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 \" ] " ) ;
2015-04-10 20:36:27 +08:00
// Quotation in \\u escape in string (Issue #288)
TEST_STRING_ERROR ( kParseErrorStringUnicodeEscapeInvalidHex , " [ \" \\ uaaa \" ] " ) ;
TEST_STRING_ERROR ( kParseErrorStringUnicodeEscapeInvalidHex , " [ \" \\ uD800 \\ uFFF \" ] " ) ;
2014-08-11 22:26:45 +08:00
// The surrogate pair in string is invalid.
TEST_STRING_ERROR ( kParseErrorStringUnicodeSurrogateInvalid , " [ \" \\ uD800X \" ] " ) ;
TEST_STRING_ERROR ( kParseErrorStringUnicodeSurrogateInvalid , " [ \" \\ uD800 \\ uFFFF \" ] " ) ;
// Missing a closing quotation mark in string.
TEST_STRING_ERROR ( kParseErrorStringMissQuotationMark , " [ \" Test] " ) ;
// 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 ;
2015-04-14 00:39:54 +08:00
ParseErrorCode error = TestString < UTF8 < > > ( e ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( kParseErrorStringInvalidEncoding , error ) ;
if ( error ! = kParseErrorStringInvalidEncoding )
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 ;
TEST_STRING_ERROR ( kParseErrorStringInvalidEncoding , e ) ;
}
}
// 4 Overlong sequences
// 4.1 Examples of an overlong ASCII character
2015-04-14 00:39:54 +08:00
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xC0u , 0xAFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xE0u , 0x80u , 0xAFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xF0u , 0x80u , 0x80u , 0xAFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
2014-08-11 22:26:45 +08:00
// 4.2 Maximum overlong sequences
2015-04-14 00:39:54 +08:00
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xC1u , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xE0u , 0x9Fu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xF0u , 0x8Fu , 0xBFu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
2014-08-11 22:26:45 +08:00
// 4.3 Overlong representation of the NUL character
2015-04-14 00:39:54 +08:00
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xC0u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xE0u , 0x80u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xF0u , 0x80u , 0x80u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
2014-08-11 22:26:45 +08:00
// 5 Illegal code positions
// 5.1 Single UTF-16 surrogates
2015-04-14 00:39:54 +08:00
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xA0u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xADu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xAEu , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xAFu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xB0u , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xBEu , 0x80u , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF8 < > , UTF16 < > , unsigned char , ARRAY ( ' [ ' , ' \" ' , 0xEDu , 0xBFu , 0xBFu , ' \" ' , ' ] ' , ' \0 ' ) ) ;
// Malform UTF-16 sequences
TEST_STRINGENCODING_ERROR ( UTF16 < > , UTF8 < > , wchar_t , ARRAY ( ' [ ' , ' \" ' , 0xDC00 , 0xDC00 , ' \" ' , ' ] ' , ' \0 ' ) ) ;
TEST_STRINGENCODING_ERROR ( UTF16 < > , UTF8 < > , wchar_t , ARRAY ( ' [ ' , ' \" ' , 0xD800 , 0xD800 , ' \" ' , ' ] ' , ' \0 ' ) ) ;
// Malform UTF-32 sequence
TEST_STRINGENCODING_ERROR ( UTF32 < > , UTF8 < > , unsigned , ARRAY ( ' [ ' , ' \" ' , 0x110000 , ' \" ' , ' ] ' , ' \0 ' ) ) ;
// Malform ASCII sequence
2015-04-15 14:23:00 +08:00
TEST_STRINGENCODING_ERROR ( ASCII < > , UTF8 < > , char , ARRAY ( ' [ ' , ' \" ' , char ( 0x80 ) , ' \" ' , ' ] ' , ' \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 >
2014-08-11 15:50:47 +02:00
struct ParseArrayHandler : BaseReaderHandler < UTF8 < > , ParseArrayHandler < count > > {
2014-08-11 22:26:45 +08:00
ParseArrayHandler ( ) : step_ ( 0 ) { }
2011-11-18 17:01:23 +00:00
2014-08-11 22:26:45 +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
2014-08-11 22:26:45 +08:00
unsigned step_ ;
2011-11-18 17:01:23 +00:00
} ;
TEST ( Reader , ParseEmptyArray ) {
2014-08-11 22:26:45 +08:00
char * json = StrDup ( " [ ] " ) ;
InsituStringStream s ( json ) ;
ParseArrayHandler < 0 > h ;
Reader reader ;
2014-08-11 17:11:59 +02:00
reader . Parse ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 2u , h . step_ ) ;
free ( json ) ;
2011-11-18 17:01:23 +00:00
}
TEST ( Reader , ParseArray ) {
2014-08-11 22:26:45 +08:00
char * json = StrDup ( " [1, 2, 3, 4] " ) ;
InsituStringStream s ( json ) ;
ParseArrayHandler < 4 > h ;
Reader reader ;
2014-08-11 17:11:59 +02:00
reader . Parse ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 6u , h . step_ ) ;
free ( json ) ;
2011-11-18 17:01:23 +00:00
}
TEST ( Reader , ParseArray_Error ) {
2014-06-27 16:19:04 +08:00
# define TEST_ARRAY_ERROR(errorCode, str) \
2014-08-11 22:26:45 +08:00
{ \
char buffer [ 1001 ] ; \
strncpy ( buffer , str , 1000 ) ; \
InsituStringStream s ( buffer ) ; \
BaseReaderHandler < > h ; \
GenericReader < UTF8 < > , UTF8 < > , CrtAllocator > reader ; \
2014-08-11 17:11:59 +02:00
EXPECT_FALSE ( reader . Parse ( s , h ) ) ; \
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( errorCode , reader . GetParseErrorCode ( ) ) ; \
}
// Missing a comma or ']' after an array element.
TEST_ARRAY_ERROR ( kParseErrorArrayMissCommaOrSquareBracket , " [1 " ) ;
TEST_ARRAY_ERROR ( kParseErrorArrayMissCommaOrSquareBracket , " [1} " ) ;
TEST_ARRAY_ERROR ( kParseErrorArrayMissCommaOrSquareBracket , " [1 2] " ) ;
2011-11-18 17:01:23 +00:00
# undef TEST_ARRAY_ERROR
}
2014-08-11 15:50:47 +02:00
struct ParseObjectHandler : BaseReaderHandler < UTF8 < > , ParseObjectHandler > {
2014-08-11 22:26:45 +08:00
ParseObjectHandler ( ) : step_ ( 0 ) { }
2014-08-11 17:11:59 +02:00
bool Default ( ) { ADD_FAILURE ( ) ; return false ; }
2014-08-11 22:26:45 +08:00
bool Null ( ) { EXPECT_EQ ( 8u , step_ ) ; step_ + + ; return true ; }
bool Bool ( bool b ) {
switch ( step_ ) {
case 4 : EXPECT_TRUE ( b ) ; step_ + + ; return true ;
case 6 : EXPECT_FALSE ( b ) ; step_ + + ; return true ;
default : ADD_FAILURE ( ) ; return false ;
}
}
bool Int ( int i ) {
switch ( step_ ) {
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 ;
}
}
bool Uint ( unsigned i ) { return Int ( i ) ; }
2015-04-10 23:37:20 +08:00
bool Double ( double d ) { EXPECT_EQ ( 12u , step_ ) ; EXPECT_DOUBLE_EQ ( 3.1416 , d ) ; step_ + + ; return true ; }
2014-08-11 22:26:45 +08:00
bool String ( const char * str , size_t , bool ) {
switch ( step_ ) {
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 ;
}
}
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 ; }
unsigned step_ ;
2011-11-18 17:01:23 +00:00
} ;
TEST ( Reader , ParseObject ) {
2014-08-11 22:26:45 +08:00
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 ;
2014-08-11 17:11:59 +02:00
reader . Parse < kParseInsituFlag > ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 20u , h . step_ ) ;
free ( json2 ) ;
}
// Normal
{
StringStream s ( json ) ;
ParseObjectHandler h ;
Reader reader ;
2014-08-11 17:11:59 +02:00
reader . Parse ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 20u , h . step_ ) ;
}
2011-11-18 17:01:23 +00:00
}
2014-08-11 15:50:47 +02:00
struct ParseEmptyObjectHandler : BaseReaderHandler < UTF8 < > , ParseEmptyObjectHandler > {
2014-08-11 22:26:45 +08:00
ParseEmptyObjectHandler ( ) : step_ ( 0 ) { }
2011-11-18 17:01:23 +00:00
2014-08-11 22:26:45 +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
2014-08-11 22:26:45 +08:00
unsigned step_ ;
2011-11-18 17:01:23 +00:00
} ;
TEST ( Reader , Parse_EmptyObject ) {
2014-08-11 22:26:45 +08:00
StringStream s ( " { } " ) ;
ParseEmptyObjectHandler h ;
Reader reader ;
2014-08-11 17:11:59 +02:00
reader . Parse ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 2u , h . step_ ) ;
2011-11-18 17:01:23 +00:00
}
2014-08-11 15:50:47 +02:00
struct ParseMultipleRootHandler : BaseReaderHandler < UTF8 < > , ParseMultipleRootHandler > {
2014-08-11 22:26:45 +08:00
ParseMultipleRootHandler ( ) : step_ ( 0 ) { }
2014-07-27 17:10:32 +08:00
2014-08-11 22:26:45 +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 ; }
bool StartArray ( ) { EXPECT_EQ ( 2u , step_ ) ; step_ + + ; return true ; }
bool EndArray ( SizeType ) { EXPECT_EQ ( 3u , step_ ) ; step_ + + ; return true ; }
2014-07-27 17:10:32 +08:00
2014-08-11 22:26:45 +08:00
unsigned step_ ;
2014-07-27 17:10:32 +08:00
} ;
template < unsigned parseFlags >
void TestMultipleRoot ( ) {
2014-08-11 22:26:45 +08:00
StringStream s ( " {}[] a " ) ;
ParseMultipleRootHandler h ;
Reader reader ;
EXPECT_TRUE ( reader . Parse < parseFlags > ( s , h ) ) ;
EXPECT_EQ ( 2u , h . step_ ) ;
EXPECT_TRUE ( reader . Parse < parseFlags > ( s , h ) ) ;
EXPECT_EQ ( 4u , h . step_ ) ;
EXPECT_EQ ( ' ' , s . Take ( ) ) ;
EXPECT_EQ ( ' a ' , s . Take ( ) ) ;
2014-07-27 17:10:32 +08:00
}
TEST ( Reader , Parse_MultipleRoot ) {
2014-08-11 22:26:45 +08:00
TestMultipleRoot < kParseStopWhenDoneFlag > ( ) ;
2014-07-27 17:10:32 +08:00
}
TEST ( Reader , ParseIterative_MultipleRoot ) {
2014-08-11 22:26:45 +08:00
TestMultipleRoot < kParseIterativeFlag | kParseStopWhenDoneFlag > ( ) ;
2014-07-27 17:10:32 +08:00
}
2014-07-29 13:01:35 +08:00
template < unsigned parseFlags >
void TestInsituMultipleRoot ( ) {
2014-08-11 22:26:45 +08:00
char * buffer = strdup ( " {}[] a " ) ;
InsituStringStream s ( buffer ) ;
ParseMultipleRootHandler h ;
Reader reader ;
EXPECT_TRUE ( reader . Parse < kParseInsituFlag | parseFlags > ( s , h ) ) ;
EXPECT_EQ ( 2u , h . step_ ) ;
EXPECT_TRUE ( reader . Parse < kParseInsituFlag | parseFlags > ( s , h ) ) ;
EXPECT_EQ ( 4u , h . step_ ) ;
EXPECT_EQ ( ' ' , s . Take ( ) ) ;
EXPECT_EQ ( ' a ' , s . Take ( ) ) ;
free ( buffer ) ;
2014-07-29 13:01:35 +08:00
}
TEST ( Reader , ParseInsitu_MultipleRoot ) {
2014-08-11 22:26:45 +08:00
TestInsituMultipleRoot < kParseStopWhenDoneFlag > ( ) ;
2014-07-29 13:01:35 +08:00
}
TEST ( Reader , ParseInsituIterative_MultipleRoot ) {
2014-08-11 22:26:45 +08:00
TestInsituMultipleRoot < kParseIterativeFlag | kParseStopWhenDoneFlag > ( ) ;
2014-07-29 13:01:35 +08:00
}
2014-06-27 16:19:04 +08:00
# define TEST_ERROR(errorCode, str) \
2014-08-11 22:26:45 +08:00
{ \
char buffer [ 1001 ] ; \
strncpy ( buffer , str , 1000 ) ; \
InsituStringStream s ( buffer ) ; \
BaseReaderHandler < > h ; \
Reader reader ; \
2014-08-11 17:11:59 +02:00
EXPECT_FALSE ( reader . Parse ( s , h ) ) ; \
2014-08-11 22:26:45 +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 ) {
2014-08-11 22:26:45 +08:00
// The document is empty.
TEST_ERROR ( kParseErrorDocumentEmpty , " " ) ;
TEST_ERROR ( kParseErrorDocumentEmpty , " " ) ;
TEST_ERROR ( kParseErrorDocumentEmpty , " \n " ) ;
// The document root must not follow by other values.
TEST_ERROR ( kParseErrorDocumentRootNotSingular , " [] 0 " ) ;
TEST_ERROR ( kParseErrorDocumentRootNotSingular , " {} 0 " ) ;
2014-08-11 17:11:59 +02:00
TEST_ERROR ( kParseErrorDocumentRootNotSingular , " null [] " ) ;
TEST_ERROR ( kParseErrorDocumentRootNotSingular , " 0 {} " ) ;
2014-06-27 16:19:04 +08:00
}
2011-11-18 17:01:23 +00:00
2014-06-27 16:19:04 +08:00
TEST ( Reader , ParseValue_Error ) {
2014-08-11 22:26:45 +08:00
// Invalid value.
2014-08-11 17:11:59 +02:00
TEST_ERROR ( kParseErrorValueInvalid , " nulL " ) ;
TEST_ERROR ( kParseErrorValueInvalid , " truE " ) ;
TEST_ERROR ( kParseErrorValueInvalid , " falsE " ) ;
TEST_ERROR ( kParseErrorValueInvalid , " a] " ) ;
TEST_ERROR ( kParseErrorValueInvalid , " .1 " ) ;
2014-06-27 16:19:04 +08:00
}
2011-11-18 17:01:23 +00:00
2014-06-27 16:19:04 +08:00
TEST ( Reader , ParseObject_Error ) {
2014-08-11 22:26:45 +08:00
// 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} " ) ;
// Must be a comma or '}' after an object member
TEST_ERROR ( kParseErrorObjectMissCommaOrCurlyBracket , " { \" a \" :1] " ) ;
2014-10-23 00:24:32 +02:00
// This tests that MemoryStream is checking the length in Peek().
{
MemoryStream ms ( " { \" a \" " , 1 ) ;
BaseReaderHandler < > h ;
Reader reader ;
EXPECT_FALSE ( reader . Parse < kParseStopWhenDoneFlag > ( ms , h ) ) ;
EXPECT_EQ ( kParseErrorObjectMissName , reader . GetParseErrorCode ( ) ) ;
}
2014-06-27 16:19:04 +08:00
}
2011-11-18 17:01:23 +00:00
# undef TEST_ERROR
2014-06-24 23:04:27 +08:00
TEST ( Reader , SkipWhitespace ) {
2014-08-11 22:26:45 +08:00
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 :
2014-08-11 22:26:45 +08:00
typedef typename Encoding : : Ch Ch ;
2014-06-29 20:59:01 +08:00
2014-08-11 22:26:45 +08:00
CustomStringStream ( const Ch * src ) : src_ ( src ) , head_ ( src ) { }
2014-06-29 20:59:01 +08:00
2014-08-11 22:26:45 +08:00
Ch Peek ( ) const { return * src_ ; }
Ch Take ( ) { return * src_ + + ; }
size_t Tell ( ) const { return static_cast < size_t > ( src_ - head_ ) ; }
2014-06-29 20:59:01 +08:00
2014-08-11 22:26:45 +08:00
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 ; }
2014-06-29 20:59:01 +08:00
private :
2014-08-11 22:26:45 +08:00
// Prohibit copy constructor & assignment operator.
CustomStringStream ( const CustomStringStream & ) ;
CustomStringStream & operator = ( const CustomStringStream & ) ;
2014-06-29 20:59:01 +08:00
2014-08-11 22:26:45 +08:00
const Ch * src_ ; //!< Current read position.
const Ch * head_ ; //!< Original head of the string.
2014-06-29 20:59:01 +08:00
} ;
// 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-08-11 22:26:45 +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 ) {
2014-08-11 22:26:45 +08:00
const char * json = " { \" hello \" : \" world \" , \" t \" : true , \" f \" : false, \" n \" : null, \" i \" :123, \" pi \" : 3.1416, \" a \" :[1, 2, 3] } " ;
CustomStringStream < UTF8 < char > > s ( json ) ;
ParseObjectHandler h ;
Reader reader ;
2014-08-11 17:27:38 +02:00
reader . Parse ( s , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_EQ ( 20u , h . step_ ) ;
2014-06-29 20:59:01 +08:00
}
2014-07-03 00:59:35 +08:00
2014-07-04 16:39:09 +08:00
# include <sstream>
class IStreamWrapper {
public :
2014-08-11 22:26:45 +08:00
typedef char Ch ;
2014-07-04 16:39:09 +08:00
2014-08-11 22:26:45 +08:00
IStreamWrapper ( std : : istream & is ) : is_ ( is ) { }
2014-07-04 16:39:09 +08:00
2014-08-11 22:26:45 +08:00
Ch Peek ( ) const {
int c = is_ . peek ( ) ;
return c = = std : : char_traits < char > : : eof ( ) ? ' \0 ' : ( Ch ) c ;
}
2014-07-04 16:39:09 +08:00
2014-08-11 22:26:45 +08:00
Ch Take ( ) {
int c = is_ . get ( ) ;
return c = = std : : char_traits < char > : : eof ( ) ? ' \0 ' : ( Ch ) c ;
}
2014-07-04 16:39:09 +08:00
2014-08-11 22:26:45 +08:00
size_t Tell ( ) const { return ( size_t ) is_ . tellg ( ) ; }
2014-07-04 16:39:09 +08:00
2014-08-11 22:26:45 +08:00
Ch * PutBegin ( ) { assert ( false ) ; return 0 ; }
void Put ( Ch ) { assert ( false ) ; }
void Flush ( ) { assert ( false ) ; }
size_t PutEnd ( Ch * ) { assert ( false ) ; return 0 ; }
2014-07-04 16:39:09 +08:00
private :
2014-08-11 22:26:45 +08:00
IStreamWrapper ( const IStreamWrapper & ) ;
IStreamWrapper & operator = ( const IStreamWrapper & ) ;
2014-07-04 16:39:09 +08:00
2014-08-11 22:26:45 +08:00
std : : istream & is_ ;
2014-07-04 16:39:09 +08:00
} ;
TEST ( Reader , Parse_IStreamWrapper_StringStream ) {
2014-08-11 22:26:45 +08:00
const char * json = " [1,2,3,4] " ;
2014-07-04 16:39:09 +08:00
2014-08-11 22:26:45 +08:00
std : : stringstream ss ( json ) ;
IStreamWrapper is ( ss ) ;
2014-07-04 16:39:09 +08:00
2014-08-11 22:26:45 +08:00
Reader reader ;
ParseArrayHandler < 4 > h ;
2014-08-11 17:27:38 +02:00
reader . Parse ( is , h ) ;
2014-08-11 22:26:45 +08:00
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
2014-07-04 16:39:09 +08:00
}
2014-07-16 23:10:16 +08:00
// Test iterative parsing.
2014-07-15 00:51:34 +08:00
# define TESTERRORHANDLING(text, errorCode, offset)\
2014-07-16 23:10:16 +08:00
{ \
2014-08-11 22:26:45 +08:00
StringStream json ( text ) ; \
BaseReaderHandler < > handler ; \
Reader reader ; \
2014-08-11 17:27:38 +02:00
reader . Parse < kParseIterativeFlag > ( json , handler ) ; \
2014-08-11 22:26:45 +08:00
EXPECT_TRUE ( reader . HasParseError ( ) ) ; \
EXPECT_EQ ( errorCode , reader . GetParseErrorCode ( ) ) ; \
EXPECT_EQ ( offset , reader . GetErrorOffset ( ) ) ; \
2014-07-16 23:10:16 +08:00
}
2014-07-10 00:00:56 +08:00
TEST ( Reader , IterativeParsing_ErrorHandling ) {
2014-08-11 22:26:45 +08:00
TESTERRORHANDLING ( " { \" a \" : a} " , kParseErrorValueInvalid , 6u ) ;
2014-07-10 00:00:56 +08:00
2014-08-11 22:26:45 +08:00
TESTERRORHANDLING ( " " , kParseErrorDocumentEmpty , 0u ) ;
TESTERRORHANDLING ( " {}{} " , kParseErrorDocumentRootNotSingular , 2u ) ;
2014-07-10 00:00:56 +08:00
2014-08-11 22:26:45 +08:00
TESTERRORHANDLING ( " {1} " , kParseErrorObjectMissName , 1u ) ;
TESTERRORHANDLING ( " { \" a \" , 1} " , kParseErrorObjectMissColon , 4u ) ;
TESTERRORHANDLING ( " { \" a \" } " , kParseErrorObjectMissColon , 4u ) ;
TESTERRORHANDLING ( " { \" a \" : 1 " , kParseErrorObjectMissCommaOrCurlyBracket , 7u ) ;
TESTERRORHANDLING ( " [1 2 3] " , kParseErrorArrayMissCommaOrSquareBracket , 3u ) ;
2015-04-15 14:51:48 +08:00
TESTERRORHANDLING ( " { \" a: 1 " , kParseErrorStringMissQuotationMark , 5u ) ;
2015-04-15 14:45:07 +08:00
// Any JSON value can be a valid root element in RFC7159.
TESTERRORHANDLING ( " \" ab " , kParseErrorStringMissQuotationMark , 2u ) ;
TESTERRORHANDLING ( " truE " , kParseErrorValueInvalid , 3u ) ;
TESTERRORHANDLING ( " False " , kParseErrorValueInvalid , 0u ) ;
TESTERRORHANDLING ( " true, false " , kParseErrorDocumentRootNotSingular , 4u ) ;
TESTERRORHANDLING ( " false, false " , kParseErrorDocumentRootNotSingular , 5u ) ;
TESTERRORHANDLING ( " nulL " , kParseErrorValueInvalid , 3u ) ;
TESTERRORHANDLING ( " null , null " , kParseErrorDocumentRootNotSingular , 5u ) ;
2015-04-15 15:46:31 +08:00
TESTERRORHANDLING ( " 1a " , kParseErrorDocumentRootNotSingular , 1u ) ;
2014-07-10 00:00:56 +08:00
}
2014-07-10 22:27:25 +08:00
template < typename Encoding = UTF8 < > >
struct IterativeParsingReaderHandler {
2014-08-11 22:26:45 +08:00
typedef typename Encoding : : Ch Ch ;
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
const static int LOG_NULL = - 1 ;
const static int LOG_BOOL = - 2 ;
const static int LOG_INT = - 3 ;
const static int LOG_UINT = - 4 ;
const static int LOG_INT64 = - 5 ;
const static int LOG_UINT64 = - 6 ;
const static int LOG_DOUBLE = - 7 ;
const static int LOG_STRING = - 8 ;
const static int LOG_STARTOBJECT = - 9 ;
2014-09-04 15:51:09 +02:00
const static int LOG_KEY = - 10 ;
const static int LOG_ENDOBJECT = - 11 ;
const static int LOG_STARTARRAY = - 12 ;
const static int LOG_ENDARRAY = - 13 ;
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
const static size_t LogCapacity = 256 ;
int Logs [ LogCapacity ] ;
size_t LogCount ;
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
IterativeParsingReaderHandler ( ) : LogCount ( 0 ) {
}
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool Null ( ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_NULL ; return true ; }
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool Bool ( bool ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_BOOL ; return true ; }
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool Int ( int ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_INT ; return true ; }
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool Uint ( unsigned ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_INT ; return true ; }
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool Int64 ( int64_t ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_INT64 ; return true ; }
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool Uint64 ( uint64_t ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_UINT64 ; return true ; }
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool Double ( double ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_DOUBLE ; return true ; }
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool String ( const Ch * , SizeType , bool ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_STRING ; return true ; }
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool StartObject ( ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_STARTOBJECT ; return true ; }
2014-07-10 22:27:25 +08:00
2014-09-04 15:56:21 +02:00
bool Key ( const Ch * , SizeType , bool ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_KEY ; return true ; }
2014-09-04 15:24:52 +02:00
2014-08-11 22:26:45 +08:00
bool EndObject ( SizeType c ) {
RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ;
Logs [ LogCount + + ] = LOG_ENDOBJECT ;
Logs [ LogCount + + ] = ( int ) c ;
return true ;
}
2014-07-11 11:43:09 +08:00
2014-08-11 22:26:45 +08:00
bool StartArray ( ) { RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ; Logs [ LogCount + + ] = LOG_STARTARRAY ; return true ; }
2014-07-10 22:27:25 +08:00
2014-08-11 22:26:45 +08:00
bool EndArray ( SizeType c ) {
RAPIDJSON_ASSERT ( LogCount < LogCapacity ) ;
Logs [ LogCount + + ] = LOG_ENDARRAY ;
Logs [ LogCount + + ] = ( int ) c ;
return true ;
}
2014-07-16 23:10:16 +08:00
} ;
2014-07-10 22:27:25 +08:00
2014-07-16 23:10:16 +08:00
TEST ( Reader , IterativeParsing_General ) {
2014-08-11 22:26:45 +08:00
{
StringStream is ( " [1, { \" k \" : [1, 2]}, null, false, true, \" string \" , 1.2] " ) ;
Reader reader ;
IterativeParsingReaderHandler < > handler ;
2014-08-11 17:27:38 +02:00
ParseResult r = reader . Parse < kParseIterativeFlag > ( is , handler ) ;
2014-08-11 22:26:45 +08:00
EXPECT_FALSE ( r . IsError ( ) ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
int e [ ] = {
handler . LOG_STARTARRAY ,
handler . LOG_INT ,
handler . LOG_STARTOBJECT ,
2014-09-04 15:51:09 +02:00
handler . LOG_KEY ,
2014-08-11 22:26:45 +08:00
handler . LOG_STARTARRAY ,
handler . LOG_INT ,
handler . LOG_INT ,
handler . LOG_ENDARRAY , 2 ,
handler . LOG_ENDOBJECT , 1 ,
handler . LOG_NULL ,
handler . LOG_BOOL ,
handler . LOG_BOOL ,
handler . LOG_STRING ,
handler . LOG_DOUBLE ,
handler . LOG_ENDARRAY , 7
} ;
EXPECT_EQ ( sizeof ( e ) / sizeof ( int ) , handler . LogCount ) ;
for ( size_t i = 0 ; i < handler . LogCount ; + + i ) {
EXPECT_EQ ( e [ i ] , handler . Logs [ i ] ) < < " i = " < < i ;
}
}
2014-07-11 11:43:09 +08:00
}
2014-07-16 23:10:16 +08:00
TEST ( Reader , IterativeParsing_Count ) {
2014-08-11 22:26:45 +08:00
{
StringStream is ( " [{}, { \" k \" : 1}, [1], []] " ) ;
Reader reader ;
IterativeParsingReaderHandler < > handler ;
2014-08-11 17:27:38 +02:00
ParseResult r = reader . Parse < kParseIterativeFlag > ( is , handler ) ;
2014-08-11 22:26:45 +08:00
EXPECT_FALSE ( r . IsError ( ) ) ;
EXPECT_FALSE ( reader . HasParseError ( ) ) ;
int e [ ] = {
handler . LOG_STARTARRAY ,
handler . LOG_STARTOBJECT ,
handler . LOG_ENDOBJECT , 0 ,
handler . LOG_STARTOBJECT ,
2014-09-04 15:51:09 +02:00
handler . LOG_KEY ,
2014-08-11 22:26:45 +08:00
handler . LOG_INT ,
handler . LOG_ENDOBJECT , 1 ,
handler . LOG_STARTARRAY ,
handler . LOG_INT ,
handler . LOG_ENDARRAY , 1 ,
handler . LOG_STARTARRAY ,
handler . LOG_ENDARRAY , 0 ,
handler . LOG_ENDARRAY , 4
} ;
EXPECT_EQ ( sizeof ( e ) / sizeof ( int ) , handler . LogCount ) ;
for ( size_t i = 0 ; i < handler . LogCount ; + + i ) {
EXPECT_EQ ( e [ i ] , handler . Logs [ i ] ) < < " i = " < < i ;
}
}
2014-07-10 22:27:25 +08:00
}
2014-07-15 00:51:34 +08:00
// Test iterative parsing on kParseErrorTermination.
struct HandlerTerminateAtStartObject : public IterativeParsingReaderHandler < > {
2014-08-11 22:26:45 +08:00
bool StartObject ( ) { return false ; }
2014-07-15 00:51:34 +08:00
} ;
struct HandlerTerminateAtStartArray : public IterativeParsingReaderHandler < > {
2014-08-11 22:26:45 +08:00
bool StartArray ( ) { return false ; }
2014-07-15 00:51:34 +08:00
} ;
struct HandlerTerminateAtEndObject : public IterativeParsingReaderHandler < > {
2014-08-11 22:26:45 +08:00
bool EndObject ( SizeType ) { return false ; }
2014-07-15 00:51:34 +08:00
} ;
struct HandlerTerminateAtEndArray : public IterativeParsingReaderHandler < > {
2014-08-11 22:26:45 +08:00
bool EndArray ( SizeType ) { return false ; }
2014-07-15 00:51:34 +08:00
} ;
TEST ( Reader , IterativeParsing_ShortCircuit ) {
2014-08-11 22:26:45 +08:00
{
HandlerTerminateAtStartObject handler ;
Reader reader ;
StringStream is ( " [1, {}] " ) ;
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
ParseResult r = reader . Parse < kParseIterativeFlag > ( is , handler ) ;
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
EXPECT_TRUE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( kParseErrorTermination , r . Code ( ) ) ;
EXPECT_EQ ( 4u , r . Offset ( ) ) ;
}
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
{
HandlerTerminateAtStartArray handler ;
Reader reader ;
StringStream is ( " { \" a \" : []} " ) ;
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
ParseResult r = reader . Parse < kParseIterativeFlag > ( is , handler ) ;
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
EXPECT_TRUE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( kParseErrorTermination , r . Code ( ) ) ;
EXPECT_EQ ( 6u , r . Offset ( ) ) ;
}
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
{
HandlerTerminateAtEndObject handler ;
Reader reader ;
StringStream is ( " [1, {}] " ) ;
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
ParseResult r = reader . Parse < kParseIterativeFlag > ( is , handler ) ;
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
EXPECT_TRUE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( kParseErrorTermination , r . Code ( ) ) ;
EXPECT_EQ ( 5u , r . Offset ( ) ) ;
}
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
{
HandlerTerminateAtEndArray handler ;
Reader reader ;
StringStream is ( " { \" a \" : []} " ) ;
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
ParseResult r = reader . Parse < kParseIterativeFlag > ( is , handler ) ;
2014-07-15 00:51:34 +08:00
2014-08-11 22:26:45 +08:00
EXPECT_TRUE ( reader . HasParseError ( ) ) ;
EXPECT_EQ ( kParseErrorTermination , r . Code ( ) ) ;
EXPECT_EQ ( 7u , r . Offset ( ) ) ;
}
2014-07-15 00:51:34 +08:00
}
2015-04-13 16:45:00 +08:00
// For covering BaseReaderHandler default functions
TEST ( Reader , BaseReaderHandler_Default ) {
BaseReaderHandler < > h ;
Reader reader ;
StringStream is ( " [null, true, -1, 1, -1234567890123456789, 1234567890123456789, 3.14, \" s \" , { \" a \" : 1 }] " ) ;
EXPECT_TRUE ( reader . Parse ( is , h ) ) ;
}
template < int e >
struct TerminateHandler {
bool Null ( ) { return e ! = 0 ; }
bool Bool ( bool ) { return e ! = 1 ; }
bool Int ( int ) { return e ! = 2 ; }
bool Uint ( unsigned ) { return e ! = 3 ; }
bool Int64 ( int64_t ) { return e ! = 4 ; }
bool Uint64 ( uint64_t ) { return e ! = 5 ; }
bool Double ( double ) { return e ! = 6 ; }
bool String ( const char * , SizeType , bool ) { return e ! = 7 ; }
bool StartObject ( ) { return e ! = 8 ; }
2015-04-13 16:49:10 +08:00
bool Key ( const char * , SizeType , bool ) { return e ! = 9 ; }
bool EndObject ( SizeType ) { return e ! = 10 ; }
2015-04-13 16:45:00 +08:00
bool StartArray ( ) { return e ! = 11 ; }
2015-04-13 16:49:10 +08:00
bool EndArray ( SizeType ) { return e ! = 12 ; }
2015-04-13 16:45:00 +08:00
} ;
# define TEST_TERMINATION(e, json)\
{ \
Reader reader ; \
TerminateHandler < e > h ; \
StringStream is ( json ) ; \
EXPECT_FALSE ( reader . Parse ( is , h ) ) ; \
EXPECT_EQ ( kParseErrorTermination , reader . GetParseErrorCode ( ) ) ; \
}
TEST ( Reader , ParseTerminationByHandler ) {
TEST_TERMINATION ( 0 , " [null " ) ;
TEST_TERMINATION ( 1 , " [true " ) ;
2015-04-13 17:07:15 +08:00
TEST_TERMINATION ( 1 , " [false " ) ;
2015-04-13 16:45:00 +08:00
TEST_TERMINATION ( 2 , " [-1 " ) ;
TEST_TERMINATION ( 3 , " [1 " ) ;
TEST_TERMINATION ( 4 , " [-1234567890123456789 " ) ;
TEST_TERMINATION ( 5 , " [1234567890123456789 " ) ;
TEST_TERMINATION ( 6 , " [0.5] " ) ;
TEST_TERMINATION ( 7 , " [ \" a \" " ) ;
TEST_TERMINATION ( 8 , " [{ " ) ;
TEST_TERMINATION ( 9 , " [{ \" a \" " ) ;
TEST_TERMINATION ( 10 , " [{} " ) ;
2015-04-13 17:07:15 +08:00
TEST_TERMINATION ( 10 , " [{ \" a \" :1} " ) ; // non-empty object
2015-04-13 16:45:00 +08:00
TEST_TERMINATION ( 11 , " { \" a \" :[ " ) ;
TEST_TERMINATION ( 12 , " { \" a \" :[] " ) ;
2015-04-13 17:07:15 +08:00
TEST_TERMINATION ( 12 , " { \" a \" :[1] " ) ; // non-empty array
2015-04-13 16:45:00 +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