"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "test/unittest/readertest.cpp" between
rapidjson-1.0.2.tar.gz and rapidjson-1.1.0.tar.gz

About: RapidJSON is a fast JSON parser/generator for C++ with both SAX/DOM style API.

readertest.cpp  (rapidjson-1.0.2):readertest.cpp  (rapidjson-1.1.0)
skipping to change at line 22 skipping to change at line 22
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#include "unittest.h" #include "unittest.h"
#include "rapidjson/reader.h" #include "rapidjson/reader.h"
#include "rapidjson/internal/dtoa.h" #include "rapidjson/internal/dtoa.h"
#include "rapidjson/internal/itoa.h" #include "rapidjson/internal/itoa.h"
#include "rapidjson/memorystream.h" #include "rapidjson/memorystream.h"
#include <limits>
using namespace rapidjson; using namespace rapidjson;
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
#ifdef __GNUC__
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(float-equal) RAPIDJSON_DIAG_OFF(float-equal)
RAPIDJSON_DIAG_OFF(missing-noreturn)
#if __GNUC__ >= 7
RAPIDJSON_DIAG_OFF(dangling-else)
#endif
#endif // __GNUC__
#ifdef __clang__
RAPIDJSON_DIAG_OFF(variadic-macros)
RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
#endif #endif
template<bool expect> template<bool expect>
struct ParseBoolHandler : BaseReaderHandler<UTF8<>, ParseBoolHandler<expect> > { struct ParseBoolHandler : BaseReaderHandler<UTF8<>, ParseBoolHandler<expect> > {
ParseBoolHandler() : step_(0) {} ParseBoolHandler() : step_(0) {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
// gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest versio n. // gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest versio n.
// Workaround with EXPECT_TRUE(). // Workaround with EXPECT_TRUE().
bool Bool(bool b) { /*EXPECT_EQ(expect, b); */EXPECT_TRUE(expect == b); ++s tep_; return true; } bool Bool(bool b) { /*EXPECT_EQ(expect, b); */EXPECT_TRUE(expect == b); ++s tep_; return true; }
skipping to change at line 162 skipping to change at line 173
uint64_t u; uint64_t u;
int64_t i; int64_t i;
}u; }u;
Random r; Random r;
for (unsigned i = 0; i < 100000; i++) { for (unsigned i = 0; i < 100000; i++) {
u.u = uint64_t(r()) << 32; u.u = uint64_t(r()) << 32;
u.u |= r(); u.u |= r();
char buffer[32]; char buffer[32];
if (u.u >= 4294967296ULL) { if (u.u > uint64_t(4294967295u)) {
*internal::u64toa(u.u, buffer) = '\0'; *internal::u64toa(u.u, buffer) = '\0';
TEST_INTEGER(ParseUint64Handler, buffer, u.u); TEST_INTEGER(ParseUint64Handler, buffer, u.u);
} }
if (u.i <= -2147483649LL) { if (u.i < -int64_t(2147483648u)) {
*internal::i64toa(u.i, buffer) = '\0'; *internal::i64toa(u.i, buffer) = '\0';
TEST_INTEGER(ParseInt64Handler, buffer, u.i); TEST_INTEGER(ParseInt64Handler, buffer, u.i);
} }
} }
} }
#undef TEST_INTEGER #undef TEST_INTEGER
} }
template<bool fullPrecision> template<bool fullPrecision>
static void TestParseDouble() { static void TestParseDouble() {
skipping to change at line 237 skipping to change at line 248
TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0) ; TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0) ;
TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-30 8); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072 011e-308/ TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-30 8); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072 011e-308/
TEST_DOUBLE(fullPrecision, "1e-00011111111111", 0.0); // Issue #313 TEST_DOUBLE(fullPrecision, "1e-00011111111111", 0.0); // Issue #313
TEST_DOUBLE(fullPrecision, "-1e-00011111111111", -0.0); TEST_DOUBLE(fullPrecision, "-1e-00011111111111", -0.0);
TEST_DOUBLE(fullPrecision, "1e-214748363", 0.0); // Maximum supported negative exponent TEST_DOUBLE(fullPrecision, "1e-214748363", 0.0); // Maximum supported negative exponent
TEST_DOUBLE(fullPrecision, "1e-214748364", 0.0); TEST_DOUBLE(fullPrecision, "1e-214748364", 0.0);
TEST_DOUBLE(fullPrecision, "1e-21474836311", 0.0); TEST_DOUBLE(fullPrecision, "1e-21474836311", 0.0);
TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+ 308); // Max double in another form TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+ 308); // Max double in another form
// Since // Since
// abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401 // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401
123495768877590405345064751974375599... 10^-324 123495768877590405345064751974375599... �� 10^-324
// abs((2^-1022) - 2.2250738585072012e-308) = 1.8309023271733240406421921598 // abs((2^-1022) - 2.2250738585072012e-308) = 1.8309023271733240406421921598
04623318305533274168872044... 10 ^ -324 04623318305533274168872044... �� 10 ^ -324
// So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e- 308 // So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e- 308
TEST_DOUBLE(fullPrecision, "2.2250738585072012e-308", 2.2250738585072014e-30 8); // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072 012e-308/ TEST_DOUBLE(fullPrecision, "2.2250738585072012e-308", 2.2250738585072014e-30 8); // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072 012e-308/
// More closer to normal/subnormal boundary // More closer to normal/subnormal boundary
// boundary = 2^-1022 - 2^-1075 = 2.2250738585072011360574097967091319759348 19546351645648... 10^-308 // boundary = 2^-1022 - 2^-1075 = 2.2250738585072011360574097967091319759348 19546351645648... �� 10^-308
TEST_DOUBLE(fullPrecision, "2.2250738585072011360574097967091319759348195463 5164564e-308", 2.2250738585072009e-308); TEST_DOUBLE(fullPrecision, "2.2250738585072011360574097967091319759348195463 5164564e-308", 2.2250738585072009e-308);
TEST_DOUBLE(fullPrecision, "2.2250738585072011360574097967091319759348195463 5164565e-308", 2.2250738585072014e-308); TEST_DOUBLE(fullPrecision, "2.2250738585072011360574097967091319759348195463 5164565e-308", 2.2250738585072014e-308);
// 1.0 is in (1.0 - 2^-54, 1.0 + 2^-53) // 1.0 is in (1.0 - 2^-54, 1.0 + 2^-53)
// 1.0 - 2^-54 = 0.999999999999999944488848768742172978818416595458984375 // 1.0 - 2^-54 = 0.999999999999999944488848768742172978818416595458984375
TEST_DOUBLE(fullPrecision, "0.9999999999999999444888487687421729788184165954 58984375", 1.0); // round to even TEST_DOUBLE(fullPrecision, "0.9999999999999999444888487687421729788184165954 58984375", 1.0); // round to even
TEST_DOUBLE(fullPrecision, "0.9999999999999999444888487687421729788184165954 58984374", 0.99999999999999989); // previous double TEST_DOUBLE(fullPrecision, "0.9999999999999999444888487687421729788184165954 58984374", 0.99999999999999989); // previous double
TEST_DOUBLE(fullPrecision, "0.9999999999999999444888487687421729788184165954 58984376", 1.0); // next double TEST_DOUBLE(fullPrecision, "0.9999999999999999444888487687421729788184165954 58984376", 1.0); // next double
// 1.0 + 2^-53 = 1.00000000000000011102230246251565404236316680908203125 // 1.0 + 2^-53 = 1.00000000000000011102230246251565404236316680908203125
TEST_DOUBLE(fullPrecision, "1.0000000000000001110223024625156540423631668090 8203125", 1.0); // round to even TEST_DOUBLE(fullPrecision, "1.0000000000000001110223024625156540423631668090 8203125", 1.0); // round to even
skipping to change at line 405 skipping to change at line 416
StringStream s(buffer); StringStream s(buffer);
ParseDoubleHandler h; ParseDoubleHandler h;
Reader reader; Reader reader;
ASSERT_EQ(kParseErrorNone, reader.Parse(s, h).Code()); ASSERT_EQ(kParseErrorNone, reader.Parse(s, h).Code());
EXPECT_EQ(1u, h.step_); EXPECT_EQ(1u, h.step_);
a = h.actual_; a = h.actual_;
uint64_t bias1 = e.ToBias(); uint64_t bias1 = e.ToBias();
uint64_t bias2 = a.ToBias(); uint64_t bias2 = a.ToBias();
double ulp = bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1; double ulp = static_cast<double>(bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1);
ulpMax = std::max(ulpMax, ulp); ulpMax = std::max(ulpMax, ulp);
ulpSum += ulp; ulpSum += ulp;
} }
printf("ULP Average = %g, Max = %g \n", ulpSum / count, ulpMax); printf("ULP Average = %g, Max = %g \n", ulpSum / count, ulpMax);
} }
TEST(Reader, ParseNumber_Error) { TEST(Reader, ParseNumber_Error) {
#define TEST_NUMBER_ERROR(errorCode, str) \ #define TEST_NUMBER_ERROR(errorCode, str, errorOffset, streamPos) \
{ \ { \
char buffer[1001]; \ char buffer[1001]; \
sprintf(buffer, "%s", str); \ sprintf(buffer, "%s", str); \
InsituStringStream s(buffer); \ InsituStringStream s(buffer); \
BaseReaderHandler<> h; \ BaseReaderHandler<> h; \
Reader reader; \ Reader reader; \
EXPECT_FALSE(reader.Parse(s, h)); \ EXPECT_FALSE(reader.Parse(s, h)); \
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
EXPECT_EQ(streamPos, s.Tell());\
} }
// Number too big to be stored in double. // Number too big to be stored in double.
{ {
char n1e309[311]; // '1' followed by 309 '0' char n1e309[311]; // '1' followed by 309 '0'
n1e309[0] = '1'; n1e309[0] = '1';
for (int i = 1; i < 310; i++) for (int i = 1; i < 310; i++)
n1e309[i] = '0'; n1e309[i] = '0';
n1e309[310] = '\0'; n1e309[310] = '\0';
TEST_NUMBER_ERROR(kParseErrorNumberTooBig, n1e309); TEST_NUMBER_ERROR(kParseErrorNumberTooBig, n1e309, 0, 309);
} }
TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309"); TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309", 0, 5);
// Miss fraction part in number. // Miss fraction part in number.
TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1."); TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.", 2, 2);
TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a"); TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a", 2, 2);
// Miss exponent in number. // Miss exponent in number.
TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e"); TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e", 2, 2);
TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_"); TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_", 2, 2);
#undef TEST_NUMBER_ERROR #undef TEST_NUMBER_ERROR
} }
template <typename Encoding> template <typename Encoding>
struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encod ing> > { struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encod ing> > {
ParseStringHandler() : str_(0), length_(0), copy_() {} ParseStringHandler() : str_(0), length_(0), copy_() {}
~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<t ypename Encoding::Ch*>(str_)); } ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<t ypename Encoding::Ch*>(str_)); }
ParseStringHandler(const ParseStringHandler&); ParseStringHandler(const ParseStringHandler&);
ParseStringHandler& operator=(const ParseStringHandler&); ParseStringHandler& operator=(const ParseStringHandler&);
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
bool String(const typename Encoding::Ch* str, size_t length, bool copy) { bool String(const typename Encoding::Ch* str, size_t length, bool copy) {
EXPECT_EQ(0, str_); EXPECT_EQ(0, str_);
if (copy) { if (copy) {
str_ = (typename Encoding::Ch*)malloc((length + 1) * sizeof(typename Encoding::Ch)); str_ = static_cast<typename Encoding::Ch*>(malloc((length + 1) * siz eof(typename Encoding::Ch)));
memcpy(const_cast<typename Encoding::Ch*>(str_), str, (length + 1) * sizeof(typename Encoding::Ch)); memcpy(const_cast<typename Encoding::Ch*>(str_), str, (length + 1) * sizeof(typename Encoding::Ch));
} }
else else
str_ = str; str_ = str;
length_ = length; length_ = length;
copy_ = copy; copy_ = copy;
return true; return true;
} }
const typename Encoding::Ch* str_; const typename Encoding::Ch* str_;
skipping to change at line 599 skipping to change at line 612
template <typename Encoding> template <typename Encoding>
ParseErrorCode TestString(const typename Encoding::Ch* str) { ParseErrorCode TestString(const typename Encoding::Ch* str) {
GenericStringStream<Encoding> s(str); GenericStringStream<Encoding> s(str);
BaseReaderHandler<Encoding> h; BaseReaderHandler<Encoding> h;
GenericReader<Encoding, Encoding> reader; GenericReader<Encoding, Encoding> reader;
reader.template Parse<kParseValidateEncodingFlag>(s, h); reader.template Parse<kParseValidateEncodingFlag>(s, h);
return reader.GetParseErrorCode(); return reader.GetParseErrorCode();
} }
TEST(Reader, ParseString_Error) { TEST(Reader, ParseString_Error) {
#define TEST_STRING_ERROR(errorCode, str)\ #define TEST_STRING_ERROR(errorCode, str, errorOffset, streamPos)\
EXPECT_EQ(errorCode, TestString<UTF8<> >(str)) {\
GenericStringStream<UTF8<> > s(str);\
BaseReaderHandler<UTF8<> > h;\
GenericReader<UTF8<> , UTF8<> > reader;\
reader.Parse<kParseValidateEncodingFlag>(s, h);\
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
EXPECT_EQ(streamPos, s.Tell());\
}
#define ARRAY(...) { __VA_ARGS__ } #define ARRAY(...) { __VA_ARGS__ }
#define TEST_STRINGENCODING_ERROR(Encoding, TargetEncoding, utype, array) \ #define TEST_STRINGENCODING_ERROR(Encoding, TargetEncoding, utype, array) \
{ \ { \
static const utype ue[] = array; \ static const utype ue[] = array; \
static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&u e[0]); \ static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&u e[0]); \
EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString<Encoding>(e));\ EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString<Encoding>(e));\
/* decode error */\ /* decode error */\
GenericStringStream<Encoding> s(e);\ GenericStringStream<Encoding> s(e);\
BaseReaderHandler<TargetEncoding> h;\ BaseReaderHandler<TargetEncoding> h;\
GenericReader<Encoding, TargetEncoding> reader;\ GenericReader<Encoding, TargetEncoding> reader;\
reader.Parse(s, h);\ reader.Parse(s, h);\
EXPECT_EQ(kParseErrorStringInvalidEncoding, reader.GetParseErrorCode()); \ EXPECT_EQ(kParseErrorStringInvalidEncoding, reader.GetParseErrorCode()); \
} }
// Invalid escape character in string. // Invalid escape character in string.
TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]"); TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]", 2, 3);
// Incorrect hex digit after \\u escape in string. // Incorrect hex digit after \\u escape in string.
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]") ; TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]", 2, 7);
// Quotation in \\u escape in string (Issue #288) // Quotation in \\u escape in string (Issue #288)
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]"); TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]",
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFF 2, 7);
F\"]"); TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFF
F\"]", 2, 13);
// The surrogate pair in string is invalid. // The surrogate pair in string is invalid.
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]" TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]"
); , 2, 8);
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFF TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFF
FF\"]"); FF\"]", 2, 14);
// Missing a closing quotation mark in string. // Missing a closing quotation mark in string.
TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]"); TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]", 7, 7);
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
// 3 Malformed sequences // 3 Malformed sequences
// 3.1 Unexpected continuation bytes // 3.1 Unexpected continuation bytes
{ {
char e[] = { '[', '\"', 0, '\"', ']', '\0' }; char e[] = { '[', '\"', 0, '\"', ']', '\0' };
for (unsigned char c = 0x80u; c <= 0xBFu; c++) { for (unsigned char c = 0x80u; c <= 0xBFu; c++) {
e[2] = c; e[2] = static_cast<char>(c);
ParseErrorCode error = TestString<UTF8<> >(e); ParseErrorCode error = TestString<UTF8<> >(e);
EXPECT_EQ(kParseErrorStringInvalidEncoding, error); EXPECT_EQ(kParseErrorStringInvalidEncoding, error);
if (error != kParseErrorStringInvalidEncoding) if (error != kParseErrorStringInvalidEncoding)
std::cout << (unsigned)(unsigned char)c << std::endl; std::cout << static_cast<unsigned>(c) << std::endl;
} }
} }
// 3.2 Lonely start characters, 3.5 Impossible bytes // 3.2 Lonely start characters, 3.5 Impossible bytes
{ {
char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' }; char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' };
for (unsigned c = 0xC0u; c <= 0xFFu; c++) { for (unsigned c = 0xC0u; c <= 0xFFu; c++) {
e[2] = (char)c; e[2] = static_cast<char>(c);
TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e); int streamPos;
if (c <= 0xC1u)
streamPos = 3; // 0xC0 - 0xC1
else if (c <= 0xDFu)
streamPos = 4; // 0xC2 - 0xDF
else if (c <= 0xEFu)
streamPos = 5; // 0xE0 - 0xEF
else if (c <= 0xF4u)
streamPos = 6; // 0xF0 - 0xF4
else
streamPos = 3; // 0xF5 - 0xFF
TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e, 2, streamPos)
;
} }
} }
// 4 Overlong sequences // 4 Overlong sequences
// 4.1 Examples of an overlong ASCII character // 4.1 Examples of an overlong ASCII character
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0 xC0u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0 xC0u, 0xAFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0 xE0u, 0x80u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0 xE0u, 0x80u, 0xAFu, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0 xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0 xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0'));
skipping to change at line 694 skipping to change at line 726
TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0 xEDu, 0xBFu, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0 xEDu, 0xBFu, 0xBFu, '\"', ']', '\0'));
// Malform UTF-16 sequences // Malform UTF-16 sequences
TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xDC00, 0xDC00, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xDC00, 0xDC00, '\"', ']', '\0'));
TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xD800, 0xD800, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xD800, 0xD800, '\"', ']', '\0'));
// Malform UTF-32 sequence // Malform UTF-32 sequence
TEST_STRINGENCODING_ERROR(UTF32<>, UTF8<>, unsigned, ARRAY('[', '\"', 0x1100 00, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF32<>, UTF8<>, unsigned, ARRAY('[', '\"', 0x1100 00, '\"', ']', '\0'));
// Malform ASCII sequence // Malform ASCII sequence
TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x80) , '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x80u ), '\"', ']', '\0'));
#undef ARRAY #undef ARRAY
#undef TEST_STRINGARRAY_ERROR #undef TEST_STRINGARRAY_ERROR
} }
template <unsigned count> template <unsigned count>
struct ParseArrayHandler : BaseReaderHandler<UTF8<>, ParseArrayHandler<count> > { struct ParseArrayHandler : BaseReaderHandler<UTF8<>, ParseArrayHandler<count> > {
ParseArrayHandler() : step_(0) {} ParseArrayHandler() : step_(0) {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
skipping to change at line 733 skipping to change at line 765
char *json = StrDup("[1, 2, 3, 4]"); char *json = StrDup("[1, 2, 3, 4]");
InsituStringStream s(json); InsituStringStream s(json);
ParseArrayHandler<4> h; ParseArrayHandler<4> h;
Reader reader; Reader reader;
reader.Parse(s, h); reader.Parse(s, h);
EXPECT_EQ(6u, h.step_); EXPECT_EQ(6u, h.step_);
free(json); free(json);
} }
TEST(Reader, ParseArray_Error) { TEST(Reader, ParseArray_Error) {
#define TEST_ARRAY_ERROR(errorCode, str) \ #define TEST_ARRAY_ERROR(errorCode, str, errorOffset) \
{ \ { \
int streamPos = errorOffset; \
char buffer[1001]; \ char buffer[1001]; \
strncpy(buffer, str, 1000); \ strncpy(buffer, str, 1000); \
InsituStringStream s(buffer); \ InsituStringStream s(buffer); \
BaseReaderHandler<> h; \ BaseReaderHandler<> h; \
GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \ GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \
EXPECT_FALSE(reader.Parse(s, h)); \ EXPECT_FALSE(reader.Parse(s, h)); \
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
EXPECT_EQ(streamPos, s.Tell());\
} }
// Missing a comma or ']' after an array element. // Missing a comma or ']' after an array element.
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1"); TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1", 2);
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}"); TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}", 2);
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]"); TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]", 3);
// Array cannot have a trailing comma (without kParseTrailingCommasFlag);
// a value must follow a comma
TEST_ARRAY_ERROR(kParseErrorValueInvalid, "[1,]", 3);
#undef TEST_ARRAY_ERROR #undef TEST_ARRAY_ERROR
} }
struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> { struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
ParseObjectHandler() : step_(0) {} ParseObjectHandler() : step_(0) {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
bool Null() { EXPECT_EQ(8u, step_); step_++; return true; } bool Null() { EXPECT_EQ(8u, step_); step_++; return true; }
bool Bool(bool b) { bool Bool(bool b) {
skipping to change at line 773 skipping to change at line 812
} }
bool Int(int i) { bool Int(int i) {
switch(step_) { switch(step_) {
case 10: EXPECT_EQ(123, i); step_++; return true; case 10: EXPECT_EQ(123, i); step_++; return true;
case 15: EXPECT_EQ(1, i); step_++; return true; case 15: EXPECT_EQ(1, i); step_++; return true;
case 16: EXPECT_EQ(2, i); step_++; return true; case 16: EXPECT_EQ(2, i); step_++; return true;
case 17: EXPECT_EQ(3, i); step_++; return true; case 17: EXPECT_EQ(3, i); step_++; return true;
default: ADD_FAILURE(); return false; default: ADD_FAILURE(); return false;
} }
} }
bool Uint(unsigned i) { return Int(i); } bool Uint(unsigned i) { return Int(static_cast<int>(i)); }
bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; } bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; }
bool String(const char* str, size_t, bool) { bool String(const char* str, size_t, bool) {
switch(step_) { switch(step_) {
case 1: EXPECT_STREQ("hello", str); step_++; return true; case 1: EXPECT_STREQ("hello", str); step_++; return true;
case 2: EXPECT_STREQ("world", str); step_++; return true; case 2: EXPECT_STREQ("world", str); step_++; return true;
case 3: EXPECT_STREQ("t", str); step_++; return true; case 3: EXPECT_STREQ("t", str); step_++; return true;
case 5: EXPECT_STREQ("f", str); step_++; return true; case 5: EXPECT_STREQ("f", str); step_++; return true;
case 7: EXPECT_STREQ("n", str); step_++; return true; case 7: EXPECT_STREQ("n", str); step_++; return true;
case 9: EXPECT_STREQ("i", str); step_++; return true; case 9: EXPECT_STREQ("i", str); step_++; return true;
case 11: EXPECT_STREQ("pi", str); step_++; return true; case 11: EXPECT_STREQ("pi", str); step_++; return true;
skipping to change at line 894 skipping to change at line 933
} }
TEST(Reader, ParseInsitu_MultipleRoot) { TEST(Reader, ParseInsitu_MultipleRoot) {
TestInsituMultipleRoot<kParseStopWhenDoneFlag>(); TestInsituMultipleRoot<kParseStopWhenDoneFlag>();
} }
TEST(Reader, ParseInsituIterative_MultipleRoot) { TEST(Reader, ParseInsituIterative_MultipleRoot) {
TestInsituMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>(); TestInsituMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>();
} }
#define TEST_ERROR(errorCode, str) \ #define TEST_ERROR(errorCode, str, errorOffset) \
{ \ { \
int streamPos = errorOffset; \
char buffer[1001]; \ char buffer[1001]; \
strncpy(buffer, str, 1000); \ strncpy(buffer, str, 1000); \
InsituStringStream s(buffer); \ InsituStringStream s(buffer); \
BaseReaderHandler<> h; \ BaseReaderHandler<> h; \
Reader reader; \ Reader reader; \
EXPECT_FALSE(reader.Parse(s, h)); \ EXPECT_FALSE(reader.Parse(s, h)); \
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
EXPECT_EQ(streamPos, s.Tell());\
} }
TEST(Reader, ParseDocument_Error) { TEST(Reader, ParseDocument_Error) {
// The document is empty. // The document is empty.
TEST_ERROR(kParseErrorDocumentEmpty, ""); TEST_ERROR(kParseErrorDocumentEmpty, "", 0);
TEST_ERROR(kParseErrorDocumentEmpty, " "); TEST_ERROR(kParseErrorDocumentEmpty, " ", 1);
TEST_ERROR(kParseErrorDocumentEmpty, " \n"); TEST_ERROR(kParseErrorDocumentEmpty, " \n", 2);
// The document root must not follow by other values. // The document root must not follow by other values.
TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0"); TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0", 3);
TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0"); TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0", 3);
TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []"); TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []", 5);
TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}"); TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}", 2);
} }
TEST(Reader, ParseValue_Error) { TEST(Reader, ParseValue_Error) {
// Invalid value. // Invalid value.
TEST_ERROR(kParseErrorValueInvalid, "nulL"); TEST_ERROR(kParseErrorValueInvalid, "nulL", 3);
TEST_ERROR(kParseErrorValueInvalid, "truE"); TEST_ERROR(kParseErrorValueInvalid, "truE", 3);
TEST_ERROR(kParseErrorValueInvalid, "falsE"); TEST_ERROR(kParseErrorValueInvalid, "falsE", 4);
TEST_ERROR(kParseErrorValueInvalid, "a]"); TEST_ERROR(kParseErrorValueInvalid, "a]", 0);
TEST_ERROR(kParseErrorValueInvalid, ".1"); TEST_ERROR(kParseErrorValueInvalid, ".1", 0);
} }
TEST(Reader, ParseObject_Error) { TEST(Reader, ParseObject_Error) {
// Missing a name for object member. // Missing a name for object member.
TEST_ERROR(kParseErrorObjectMissName, "{1}"); TEST_ERROR(kParseErrorObjectMissName, "{1}", 1);
TEST_ERROR(kParseErrorObjectMissName, "{:1}"); TEST_ERROR(kParseErrorObjectMissName, "{:1}", 1);
TEST_ERROR(kParseErrorObjectMissName, "{null:1}"); TEST_ERROR(kParseErrorObjectMissName, "{null:1}", 1);
TEST_ERROR(kParseErrorObjectMissName, "{true:1}"); TEST_ERROR(kParseErrorObjectMissName, "{true:1}", 1);
TEST_ERROR(kParseErrorObjectMissName, "{false:1}"); TEST_ERROR(kParseErrorObjectMissName, "{false:1}", 1);
TEST_ERROR(kParseErrorObjectMissName, "{1:1}"); TEST_ERROR(kParseErrorObjectMissName, "{1:1}", 1);
TEST_ERROR(kParseErrorObjectMissName, "{[]:1}"); TEST_ERROR(kParseErrorObjectMissName, "{[]:1}", 1);
TEST_ERROR(kParseErrorObjectMissName, "{{}:1}"); TEST_ERROR(kParseErrorObjectMissName, "{{}:1}", 1);
TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}"); TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}", 1);
// Missing a colon after a name of object member. // Missing a colon after a name of object member.
TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}"); TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}", 5);
TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}"); TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}", 4);
// Must be a comma or '}' after an object member // Must be a comma or '}' after an object member
TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]"); TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]", 6);
// Object cannot have a trailing comma (without kParseTrailingCommasFlag);
// an object member name must follow a comma
TEST_ERROR(kParseErrorObjectMissName, "{\"a\":1,}", 7);
// This tests that MemoryStream is checking the length in Peek(). // This tests that MemoryStream is checking the length in Peek().
{ {
MemoryStream ms("{\"a\"", 1); MemoryStream ms("{\"a\"", 1);
BaseReaderHandler<> h; BaseReaderHandler<> h;
Reader reader; Reader reader;
EXPECT_FALSE(reader.Parse<kParseStopWhenDoneFlag>(ms, h)); EXPECT_FALSE(reader.Parse<kParseStopWhenDoneFlag>(ms, h));
EXPECT_EQ(kParseErrorObjectMissName, reader.GetParseErrorCode()); EXPECT_EQ(kParseErrorObjectMissName, reader.GetParseErrorCode());
} }
} }
skipping to change at line 1026 skipping to change at line 1072
#include <sstream> #include <sstream>
class IStreamWrapper { class IStreamWrapper {
public: public:
typedef char Ch; typedef char Ch;
IStreamWrapper(std::istream& is) : is_(is) {} IStreamWrapper(std::istream& is) : is_(is) {}
Ch Peek() const { Ch Peek() const {
int c = is_.peek(); int c = is_.peek();
return c == std::char_traits<char>::eof() ? '\0' : (Ch)c; return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
} }
Ch Take() { Ch Take() {
int c = is_.get(); int c = is_.get();
return c == std::char_traits<char>::eof() ? '\0' : (Ch)c; return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
} }
size_t Tell() const { return (size_t)is_.tellg(); } size_t Tell() const { return static_cast<size_t>(is_.tellg()); }
Ch* PutBegin() { assert(false); return 0; } Ch* PutBegin() { assert(false); return 0; }
void Put(Ch) { assert(false); } void Put(Ch) { assert(false); }
void Flush() { assert(false); } void Flush() { assert(false); }
size_t PutEnd(Ch*) { assert(false); return 0; } size_t PutEnd(Ch*) { assert(false); return 0; }
private: private:
IStreamWrapper(const IStreamWrapper&); IStreamWrapper(const IStreamWrapper&);
IStreamWrapper& operator=(const IStreamWrapper&); IStreamWrapper& operator=(const IStreamWrapper&);
skipping to change at line 1064 skipping to change at line 1110
Reader reader; Reader reader;
ParseArrayHandler<4> h; ParseArrayHandler<4> h;
reader.Parse(is, h); reader.Parse(is, h);
EXPECT_FALSE(reader.HasParseError()); EXPECT_FALSE(reader.HasParseError());
} }
// Test iterative parsing. // Test iterative parsing.
#define TESTERRORHANDLING(text, errorCode, offset)\ #define TESTERRORHANDLING(text, errorCode, offset)\
{\ {\
int streamPos = offset; \
StringStream json(text); \ StringStream json(text); \
BaseReaderHandler<> handler; \ BaseReaderHandler<> handler; \
Reader reader; \ Reader reader; \
reader.Parse<kParseIterativeFlag>(json, handler); \ reader.Parse<kParseIterativeFlag>(json, handler); \
EXPECT_TRUE(reader.HasParseError()); \ EXPECT_TRUE(reader.HasParseError()); \
EXPECT_EQ(errorCode, reader.GetParseErrorCode()); \ EXPECT_EQ(errorCode, reader.GetParseErrorCode()); \
EXPECT_EQ(offset, reader.GetErrorOffset()); \ EXPECT_EQ(offset, reader.GetErrorOffset()); \
EXPECT_EQ(streamPos, json.Tell()); \
} }
TEST(Reader, IterativeParsing_ErrorHandling) { TEST(Reader, IterativeParsing_ErrorHandling) {
TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid, 6u); TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid, 6u);
TESTERRORHANDLING("", kParseErrorDocumentEmpty, 0u); TESTERRORHANDLING("", kParseErrorDocumentEmpty, 0u);
TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular, 2u); TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular, 2u);
TESTERRORHANDLING("{1}", kParseErrorObjectMissName, 1u); TESTERRORHANDLING("{1}", kParseErrorObjectMissName, 1u);
TESTERRORHANDLING("{\"a\", 1}", kParseErrorObjectMissColon, 4u); TESTERRORHANDLING("{\"a\", 1}", kParseErrorObjectMissColon, 4u);
TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u); TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u);
TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u) ; TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u) ;
TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u); TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u);
TESTERRORHANDLING("{\"a: 1", kParseErrorStringMissQuotationMark, 5u); TESTERRORHANDLING("{\"a: 1", kParseErrorStringMissQuotationMark, 6u);
TESTERRORHANDLING("{\"a\":}", kParseErrorValueInvalid, 5u);
TESTERRORHANDLING("{\"a\":]", kParseErrorValueInvalid, 5u);
TESTERRORHANDLING("[1,2,}", kParseErrorValueInvalid, 5u);
TESTERRORHANDLING("[}]", kParseErrorValueInvalid, 1u);
TESTERRORHANDLING("[,]", kParseErrorValueInvalid, 1u);
TESTERRORHANDLING("[1,,]", kParseErrorValueInvalid, 3u);
// Trailing commas are not allowed without kParseTrailingCommasFlag
TESTERRORHANDLING("{\"a\": 1,}", kParseErrorObjectMissName, 8u);
TESTERRORHANDLING("[1,2,3,]", kParseErrorValueInvalid, 7u);
// Any JSON value can be a valid root element in RFC7159. // Any JSON value can be a valid root element in RFC7159.
TESTERRORHANDLING("\"ab", kParseErrorStringMissQuotationMark, 2u); TESTERRORHANDLING("\"ab", kParseErrorStringMissQuotationMark, 3u);
TESTERRORHANDLING("truE", kParseErrorValueInvalid, 3u); TESTERRORHANDLING("truE", kParseErrorValueInvalid, 3u);
TESTERRORHANDLING("False", kParseErrorValueInvalid, 0u); TESTERRORHANDLING("False", kParseErrorValueInvalid, 0u);
TESTERRORHANDLING("true, false", kParseErrorDocumentRootNotSingular, 4u); TESTERRORHANDLING("true, false", kParseErrorDocumentRootNotSingular, 4u);
TESTERRORHANDLING("false, false", kParseErrorDocumentRootNotSingular, 5u); TESTERRORHANDLING("false, false", kParseErrorDocumentRootNotSingular, 5u);
TESTERRORHANDLING("nulL", kParseErrorValueInvalid, 3u); TESTERRORHANDLING("nulL", kParseErrorValueInvalid, 3u);
TESTERRORHANDLING("null , null", kParseErrorDocumentRootNotSingular, 5u); TESTERRORHANDLING("null , null", kParseErrorDocumentRootNotSingular, 5u);
TESTERRORHANDLING("1a", kParseErrorDocumentRootNotSingular, 1u); TESTERRORHANDLING("1a", kParseErrorDocumentRootNotSingular, 1u);
} }
template<typename Encoding = UTF8<> > template<typename Encoding = UTF8<> >
skipping to change at line 1136 skipping to change at line 1194
bool Int(int) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; } bool Int(int) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; }
bool Uint(unsigned) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCoun t++] = LOG_INT; return true; } bool Uint(unsigned) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCoun t++] = LOG_INT; return true; }
bool Int64(int64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCoun t++] = LOG_INT64; return true; } bool Int64(int64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCoun t++] = LOG_INT64; return true; }
bool Uint64(uint64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCo unt++] = LOG_UINT64; return true; } bool Uint64(uint64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCo unt++] = LOG_UINT64; return true; }
bool Double(double) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCoun t++] = LOG_DOUBLE; return true; } bool Double(double) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCoun t++] = LOG_DOUBLE; return true; }
bool RawNumber(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogC
apacity); Logs[LogCount++] = LOG_STRING; return true; }
bool String(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapa city); Logs[LogCount++] = LOG_STRING; return true; } bool String(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapa city); Logs[LogCount++] = LOG_STRING; return true; }
bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount ++] = LOG_STARTOBJECT; return true; } bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount ++] = LOG_STARTOBJECT; return true; }
bool Key (const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapaci ty); Logs[LogCount++] = LOG_KEY; return true; } bool Key (const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapaci ty); Logs[LogCount++] = LOG_KEY; return true; }
bool EndObject(SizeType c) { bool EndObject(SizeType c) {
RAPIDJSON_ASSERT(LogCount < LogCapacity); RAPIDJSON_ASSERT(LogCount < LogCapacity);
Logs[LogCount++] = LOG_ENDOBJECT; Logs[LogCount++] = LOG_ENDOBJECT;
Logs[LogCount++] = (int)c; Logs[LogCount++] = static_cast<int>(c);
return true; return true;
} }
bool StartArray() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount+ +] = LOG_STARTARRAY; return true; } bool StartArray() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount+ +] = LOG_STARTARRAY; return true; }
bool EndArray(SizeType c) { bool EndArray(SizeType c) {
RAPIDJSON_ASSERT(LogCount < LogCapacity); RAPIDJSON_ASSERT(LogCount < LogCapacity);
Logs[LogCount++] = LOG_ENDARRAY; Logs[LogCount++] = LOG_ENDARRAY;
Logs[LogCount++] = (int)c; Logs[LogCount++] = static_cast<int>(c);
return true; return true;
} }
}; };
TEST(Reader, IterativeParsing_General) { TEST(Reader, IterativeParsing_General) {
{ {
StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2 ]"); StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2 ]");
Reader reader; Reader reader;
IterativeParsingReaderHandler<> handler; IterativeParsingReaderHandler<> handler;
skipping to change at line 1315 skipping to change at line 1375
template <int e> template <int e>
struct TerminateHandler { struct TerminateHandler {
bool Null() { return e != 0; } bool Null() { return e != 0; }
bool Bool(bool) { return e != 1; } bool Bool(bool) { return e != 1; }
bool Int(int) { return e != 2; } bool Int(int) { return e != 2; }
bool Uint(unsigned) { return e != 3; } bool Uint(unsigned) { return e != 3; }
bool Int64(int64_t) { return e != 4; } bool Int64(int64_t) { return e != 4; }
bool Uint64(uint64_t) { return e != 5; } bool Uint64(uint64_t) { return e != 5; }
bool Double(double) { return e != 6; } bool Double(double) { return e != 6; }
bool String(const char*, SizeType, bool) { return e != 7; } bool RawNumber(const char*, SizeType, bool) { return e != 7; }
bool StartObject() { return e != 8; } bool String(const char*, SizeType, bool) { return e != 8; }
bool Key(const char*, SizeType, bool) { return e != 9; } bool StartObject() { return e != 9; }
bool EndObject(SizeType) { return e != 10; } bool Key(const char*, SizeType, bool) { return e != 10; }
bool StartArray() { return e != 11; } bool EndObject(SizeType) { return e != 11; }
bool EndArray(SizeType) { return e != 12; } bool StartArray() { return e != 12; }
bool EndArray(SizeType) { return e != 13; }
}; };
#define TEST_TERMINATION(e, json)\ #define TEST_TERMINATION(e, json)\
{\ {\
Reader reader;\ Reader reader;\
TerminateHandler<e> h;\ TerminateHandler<e> h;\
StringStream is(json);\ StringStream is(json);\
EXPECT_FALSE(reader.Parse(is, h));\ EXPECT_FALSE(reader.Parse(is, h));\
EXPECT_EQ(kParseErrorTermination, reader.GetParseErrorCode());\ EXPECT_EQ(kParseErrorTermination, reader.GetParseErrorCode());\
} }
TEST(Reader, ParseTerminationByHandler) { TEST(Reader, ParseTerminationByHandler) {
TEST_TERMINATION(0, "[null"); TEST_TERMINATION(0, "[null");
TEST_TERMINATION(1, "[true"); TEST_TERMINATION(1, "[true");
TEST_TERMINATION(1, "[false"); TEST_TERMINATION(1, "[false");
TEST_TERMINATION(2, "[-1"); TEST_TERMINATION(2, "[-1");
TEST_TERMINATION(3, "[1"); TEST_TERMINATION(3, "[1");
TEST_TERMINATION(4, "[-1234567890123456789"); TEST_TERMINATION(4, "[-1234567890123456789");
TEST_TERMINATION(5, "[1234567890123456789"); TEST_TERMINATION(5, "[1234567890123456789");
TEST_TERMINATION(6, "[0.5]"); TEST_TERMINATION(6, "[0.5]");
TEST_TERMINATION(7, "[\"a\""); // RawNumber() is never called
TEST_TERMINATION(8, "[{"); TEST_TERMINATION(8, "[\"a\"");
TEST_TERMINATION(9, "[{\"a\""); TEST_TERMINATION(9, "[{");
TEST_TERMINATION(10, "[{}"); TEST_TERMINATION(10, "[{\"a\"");
TEST_TERMINATION(10, "[{\"a\":1}"); // non-empty object TEST_TERMINATION(11, "[{}");
TEST_TERMINATION(11, "{\"a\":["); TEST_TERMINATION(11, "[{\"a\":1}"); // non-empty object
TEST_TERMINATION(12, "{\"a\":[]"); TEST_TERMINATION(12, "{\"a\":[");
TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array TEST_TERMINATION(13, "{\"a\":[]");
TEST_TERMINATION(13, "{\"a\":[1]"); // non-empty array
}
TEST(Reader, ParseComments) {
const char* json =
"// Here is a one-line comment.\n"
"{// And here's another one\n"
" /*And here's an in-line one.*/\"hello\" : \"world\","
" \"t\" :/* And one with '*' symbol*/true ,"
"/* A multiline comment\n"
" goes here*/"
" \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3]"
"}/*And the last one to be sure */";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
EXPECT_EQ(20u, h.step_);
}
TEST(Reader, ParseEmptyInlineComment) {
const char* json = "{/**/\"hello\" : \"world\", \"t\" : true, \"f\" : false,
\"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
EXPECT_EQ(20u, h.step_);
}
TEST(Reader, ParseEmptyOnelineComment) {
const char* json = "{//\n\"hello\" : \"world\", \"t\" : true, \"f\" : false,
\"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
EXPECT_EQ(20u, h.step_);
}
TEST(Reader, ParseMultipleCommentsInARow) {
const char* json =
"{/* first comment *//* second */\n"
"/* third */ /*fourth*/// last one\n"
"\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123,
\"pi\": 3.1416, \"a\":[1, 2, 3] }";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
EXPECT_EQ(20u, h.step_);
}
TEST(Reader, InlineCommentsAreDisabledByDefault) {
{
const char* json = "{/* Inline comment. */\"hello\" : \"world\", \"t\" :
true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"
;
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
}
{
const char* json =
"{\"hello\" : /* Multiline comment starts here\n"
" continues here\n"
" and ends here */\"world\", \"t\" :true , \"f\" : false, \"n\": null, \
"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
}
}
TEST(Reader, OnelineCommentsAreDisabledByDefault) {
const char* json = "{// One-line comment\n\"hello\" : \"world\", \"t\" : tru
e , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
}
TEST(Reader, EofAfterOneLineComment) {
const char* json = "{\"hello\" : \"world\" // EOF is here -->\0 \n}";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
EXPECT_EQ(kParseErrorObjectMissCommaOrCurlyBracket, reader.GetParseErrorCode
());
}
TEST(Reader, IncompleteMultilineComment) {
const char* json = "{\"hello\" : \"world\" /* EOF is here -->\0 */}";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
}
TEST(Reader, IncompleteMultilineComment2) {
const char* json = "{\"hello\" : \"world\" /* *\0 */}";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
}
TEST(Reader, UnrecognizedComment) {
const char* json = "{\"hello\" : \"world\" /! }";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
}
struct NumbersAsStringsHandler {
bool Null() { return true; }
bool Bool(bool) { return true; }
bool Int(int) { return true; }
bool Uint(unsigned) { return true; }
bool Int64(int64_t) { return true; }
bool Uint64(uint64_t) { return true; }
bool Double(double) { return true; }
// 'str' is not null-terminated
bool RawNumber(const char* str, SizeType length, bool) {
EXPECT_TRUE(str != 0);
EXPECT_TRUE(expected_len_ == length);
EXPECT_TRUE(strncmp(str, expected_, length) == 0);
return true;
}
bool String(const char*, SizeType, bool) { return true; }
bool StartObject() { return true; }
bool Key(const char*, SizeType, bool) { return true; }
bool EndObject(SizeType) { return true; }
bool StartArray() { return true; }
bool EndArray(SizeType) { return true; }
NumbersAsStringsHandler(const char* expected)
: expected_(expected)
, expected_len_(strlen(expected)) {}
const char* expected_;
size_t expected_len_;
};
TEST(Reader, NumbersAsStrings) {
{
const char* json = "{ \"pi\": 3.1416 } ";
StringStream s(json);
NumbersAsStringsHandler h("3.1416");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
{
char* json = StrDup("{ \"pi\": 3.1416 } ");
InsituStringStream s(json);
NumbersAsStringsHandler h("3.1416");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s,
h));
free(json);
}
{
const char* json = "{ \"gigabyte\": 1.0e9 } ";
StringStream s(json);
NumbersAsStringsHandler h("1.0e9");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
{
char* json = StrDup("{ \"gigabyte\": 1.0e9 } ");
InsituStringStream s(json);
NumbersAsStringsHandler h("1.0e9");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s,
h));
free(json);
}
{
const char* json = "{ \"pi\": 314.159e-2 } ";
StringStream s(json);
NumbersAsStringsHandler h("314.159e-2");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
{
char* json = StrDup("{ \"gigabyte\": 314.159e-2 } ");
InsituStringStream s(json);
NumbersAsStringsHandler h("314.159e-2");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s,
h));
free(json);
}
{
const char* json = "{ \"negative\": -1.54321 } ";
StringStream s(json);
NumbersAsStringsHandler h("-1.54321");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
{
char* json = StrDup("{ \"negative\": -1.54321 } ");
InsituStringStream s(json);
NumbersAsStringsHandler h("-1.54321");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s,
h));
free(json);
}
{
const char* json = "{ \"pi\": 314.159e-2 } ";
std::stringstream ss(json);
IStreamWrapper s(ss);
NumbersAsStringsHandler h("314.159e-2");
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
}
template <unsigned extraFlags>
void TestTrailingCommas() {
{
StringStream s("[1,2,3,]");
ParseArrayHandler<3> h;
Reader reader;
EXPECT_TRUE(reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h));
EXPECT_EQ(5u, h.step_);
}
{
const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : fals
e,"
"\"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3],}";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_TRUE(reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h));
EXPECT_EQ(20u, h.step_);
}
{
// whitespace around trailing commas
const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : fals
e,"
"\"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3\n,\n]\n,
\n} ";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_TRUE(reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h));
EXPECT_EQ(20u, h.step_);
}
{
// comments around trailing commas
const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : fals
e, \"n\": null,"
"\"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3/*test*/,/*test*/]/*te
st*/,/*test*/}";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
EXPECT_TRUE(reader.Parse<extraFlags|kParseTrailingCommasFlag|kParseComme
ntsFlag>(s, h));
EXPECT_EQ(20u, h.step_);
}
}
TEST(Reader, TrailingCommas) {
TestTrailingCommas<kParseNoFlags>();
}
TEST(Reader, TrailingCommasIterative) {
TestTrailingCommas<kParseIterativeFlag>();
}
template <unsigned extraFlags>
void TestMultipleTrailingCommaErrors() {
// only a single trailing comma is allowed.
{
StringStream s("[1,2,3,,]");
ParseArrayHandler<3> h;
Reader reader;
ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h);
EXPECT_TRUE(reader.HasParseError());
EXPECT_EQ(kParseErrorValueInvalid, r.Code());
EXPECT_EQ(7u, r.Offset());
}
{
const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : fals
e,"
"\"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3,],,}";
StringStream s(json);
ParseObjectHandler h;
Reader reader;
ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h);
EXPECT_TRUE(reader.HasParseError());
EXPECT_EQ(kParseErrorObjectMissName, r.Code());
EXPECT_EQ(95u, r.Offset());
}
}
TEST(Reader, MultipleTrailingCommaErrors) {
TestMultipleTrailingCommaErrors<kParseNoFlags>();
}
TEST(Reader, MultipleTrailingCommaErrorsIterative) {
TestMultipleTrailingCommaErrors<kParseIterativeFlag>();
}
template <unsigned extraFlags>
void TestEmptyExceptForCommaErrors() {
// not allowed even with trailing commas enabled; the
// trailing comma must follow a value.
{
StringStream s("[,]");
ParseArrayHandler<3> h;
Reader reader;
ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h);
EXPECT_TRUE(reader.HasParseError());
EXPECT_EQ(kParseErrorValueInvalid, r.Code());
EXPECT_EQ(1u, r.Offset());
}
{
StringStream s("{,}");
ParseObjectHandler h;
Reader reader;
ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h);
EXPECT_TRUE(reader.HasParseError());
EXPECT_EQ(kParseErrorObjectMissName, r.Code());
EXPECT_EQ(1u, r.Offset());
}
}
TEST(Reader, EmptyExceptForCommaErrors) {
TestEmptyExceptForCommaErrors<kParseNoFlags>();
}
TEST(Reader, EmptyExceptForCommaErrorsIterative) {
TestEmptyExceptForCommaErrors<kParseIterativeFlag>();
}
template <unsigned extraFlags>
void TestTrailingCommaHandlerTermination() {
{
HandlerTerminateAtEndArray h;
Reader reader;
StringStream s("[1,2,3,]");
ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h);
EXPECT_TRUE(reader.HasParseError());
EXPECT_EQ(kParseErrorTermination, r.Code());
EXPECT_EQ(7u, r.Offset());
}
{
HandlerTerminateAtEndObject h;
Reader reader;
StringStream s("{\"t\": true, \"f\": false,}");
ParseResult r = reader.Parse<extraFlags|kParseTrailingCommasFlag>(s, h);
EXPECT_TRUE(reader.HasParseError());
EXPECT_EQ(kParseErrorTermination, r.Code());
EXPECT_EQ(23u, r.Offset());
}
}
TEST(Reader, TrailingCommaHandlerTermination) {
TestTrailingCommaHandlerTermination<kParseNoFlags>();
}
TEST(Reader, TrailingCommaHandlerTerminationIterative) {
TestTrailingCommaHandlerTermination<kParseIterativeFlag>();
}
TEST(Reader, ParseNanAndInfinity) {
#define TEST_NAN_INF(str, x) \
{ \
{ \
StringStream s(str); \
ParseDoubleHandler h; \
Reader reader; \
ASSERT_EQ(kParseErrorNone, reader.Parse<kParseNanAndInfFlag>(s, h).C
ode()); \
EXPECT_EQ(1u, h.step_); \
internal::Double e(x), a(h.actual_); \
EXPECT_EQ(e.IsNan(), a.IsNan()); \
EXPECT_EQ(e.IsInf(), a.IsInf()); \
if (!e.IsNan()) \
EXPECT_EQ(e.Sign(), a.Sign()); \
} \
{ \
const char* json = "{ \"naninfdouble\": " str " } "; \
StringStream s(json); \
NumbersAsStringsHandler h(str); \
Reader reader; \
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag|kParseNanAndInfF
lag>(s, h)); \
} \
{ \
char* json = StrDup("{ \"naninfdouble\": " str " } "); \
InsituStringStream s(json); \
NumbersAsStringsHandler h(str); \
Reader reader; \
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag
|kParseNanAndInfFlag>(s, h)); \
free(json); \
} \
}
#define TEST_NAN_INF_ERROR(errorCode, str, errorOffset) \
{ \
int streamPos = errorOffset; \
char buffer[1001]; \
strncpy(buffer, str, 1000); \
InsituStringStream s(buffer); \
BaseReaderHandler<> h; \
Reader reader; \
EXPECT_FALSE(reader.Parse<kParseNanAndInfFlag>(s, h)); \
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
EXPECT_EQ(streamPos, s.Tell());\
}
double nan = std::numeric_limits<double>::quiet_NaN();
double inf = std::numeric_limits<double>::infinity();
TEST_NAN_INF("NaN", nan);
TEST_NAN_INF("-NaN", nan);
TEST_NAN_INF("Inf", inf);
TEST_NAN_INF("Infinity", inf);
TEST_NAN_INF("-Inf", -inf);
TEST_NAN_INF("-Infinity", -inf);
TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "nan", 1);
TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-nan", 1);
TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1);
TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-Infinty", 6);
#undef TEST_NAN_INF_ERROR
#undef TEST_NAN_INF
} }
#ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif
 End of changes. 54 change blocks. 
86 lines changed or deleted 602 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)