Commit 143bb83e authored by Milo Yip's avatar Milo Yip

Merge pull request #101 from pah/feature/rfc7159

Move to RFC7159 (closes #90)
parents 12da5ecb 68630336
...@@ -42,7 +42,7 @@ The JSON is now parsed into `document` as a *DOM tree*: ...@@ -42,7 +42,7 @@ The JSON is now parsed into `document` as a *DOM tree*:
![DOM in the tutorial](diagram/tutorial.png) ![DOM in the tutorial](diagram/tutorial.png)
The root of a conforming JSON should be either an object or an array. In this case, the root is an object. Since the update to RFC7159, the root of a conforming JSON document can be any JSON value. In RFC4627, only objects or arrays were allowed as root values. In this case, the root is an object.
~~~~~~~~~~cpp ~~~~~~~~~~cpp
assert(document.IsObject()); assert(document.IsObject());
~~~~~~~~~~ ~~~~~~~~~~
......
...@@ -37,7 +37,6 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro ...@@ -37,7 +37,6 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotObjectOrArray: return RAPIDJSON_ERROR_STRING("The document root must be either object or array.");
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
......
...@@ -57,7 +57,6 @@ enum ParseErrorCode { ...@@ -57,7 +57,6 @@ enum ParseErrorCode {
kParseErrorNone = 0, //!< No error. kParseErrorNone = 0, //!< No error.
kParseErrorDocumentEmpty, //!< The document is empty. kParseErrorDocumentEmpty, //!< The document is empty.
kParseErrorDocumentRootNotObjectOrArray, //!< The document root must be either object or array.
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
kParseErrorValueInvalid, //!< Invalid value. kParseErrorValueInvalid, //!< Invalid value.
......
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
#ifndef RAPIDJSON_INTERNAL_META_H_ #ifndef RAPIDJSON_INTERNAL_META_H_
#define RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
//@cond RAPIDJSON_INTERNAL //@cond RAPIDJSON_INTERNAL
namespace rapidjson { namespace rapidjson {
namespace internal { namespace internal {
...@@ -94,4 +99,8 @@ template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef ...@@ -94,4 +99,8 @@ template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef
} // namespace rapidjson } // namespace rapidjson
//@endcond //@endcond
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_INTERNAL_META_H_ #endif // RAPIDJSON_INTERNAL_META_H_
...@@ -174,7 +174,6 @@ protected: ...@@ -174,7 +174,6 @@ protected:
level->valueCount++; level->valueCount++;
} }
else { else {
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
Base::hasRoot_ = true; Base::hasRoot_ = true;
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "rapidjson.h" #include "rapidjson.h"
#include "encodings.h" #include "encodings.h"
#include "internal/meta.h"
#include "internal/pow10.h" #include "internal/pow10.h"
#include "internal/stack.h" #include "internal/stack.h"
...@@ -122,23 +123,25 @@ concept Handler { ...@@ -122,23 +123,25 @@ concept Handler {
/*! This can be used as base class of any reader handler. /*! This can be used as base class of any reader handler.
\note implements Handler concept \note implements Handler concept
*/ */
template<typename Encoding = UTF8<> > template<typename Encoding = UTF8<>, typename Derived = void>
struct BaseReaderHandler { struct BaseReaderHandler {
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;
bool Default() { return true; } bool Default() { return true; }
bool Null() { return Default(); } bool Null() { return static_cast<Override&>(*this).Default(); }
bool Bool(bool) { return Default(); } bool Bool(bool) { return static_cast<Override&>(*this).Default(); }
bool Int(int) { return Default(); } bool Int(int) { return static_cast<Override&>(*this).Default(); }
bool Uint(unsigned) { return Default(); } bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }
bool Int64(int64_t) { return Default(); } bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
bool Uint64(uint64_t) { return Default(); } bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
bool Double(double) { return Default(); } bool Double(double) { return static_cast<Override&>(*this).Default(); }
bool String(const Ch*, SizeType, bool) { return Default(); } bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
bool StartObject() { return Default(); } bool StartObject() { return static_cast<Override&>(*this).Default(); }
bool EndObject(SizeType) { return Default(); } bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
bool StartArray() { return Default(); } bool StartArray() { return static_cast<Override&>(*this).Default(); }
bool EndArray(SizeType) { return Default(); } bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
...@@ -381,11 +384,7 @@ public: ...@@ -381,11 +384,7 @@ public:
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
} }
else { else {
switch (is.Peek()) { ParseValue<parseFlags>(is, handler);
case '{': ParseObject<parseFlags>(is, handler); break;
case '[': ParseArray<parseFlags>(is, handler); break;
default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell());
}
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (!(parseFlags & kParseStopWhenDoneFlag)) { if (!(parseFlags & kParseStopWhenDoneFlag)) {
...@@ -907,6 +906,9 @@ private: ...@@ -907,6 +906,9 @@ private:
IterativeParsingElementDelimiterState, IterativeParsingElementDelimiterState,
IterativeParsingArrayFinishState, IterativeParsingArrayFinishState,
// Single value state
IterativeParsingValueState,
cIterativeParsingStateCount cIterativeParsingStateCount
}; };
...@@ -965,11 +967,11 @@ private: ...@@ -965,11 +967,11 @@ private:
IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Right curly bracket
IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Comma
IterativeParsingErrorState, // Colon IterativeParsingErrorState, // Colon
IterativeParsingErrorState, // String IterativeParsingValueState, // String
IterativeParsingErrorState, // False IterativeParsingValueState, // False
IterativeParsingErrorState, // True IterativeParsingValueState, // True
IterativeParsingErrorState, // Null IterativeParsingValueState, // Null
IterativeParsingErrorState // Number IterativeParsingValueState // Number
}, },
// Finish(sink state) // Finish(sink state)
{ {
...@@ -1102,6 +1104,12 @@ private: ...@@ -1102,6 +1104,12 @@ private:
IterativeParsingElementState // Number IterativeParsingElementState // Number
}, },
// ArrayFinish(sink state) // ArrayFinish(sink state)
{
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
IterativeParsingErrorState
},
// Single Value (sink state)
{ {
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
...@@ -1242,6 +1250,14 @@ private: ...@@ -1242,6 +1250,14 @@ private:
} }
} }
case IterativeParsingValueState:
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
ParseValue<parseFlags>(is, handler);
if (HasParseError()) {
return IterativeParsingErrorState;
}
return IterativeParsingFinishState;
default: default:
RAPIDJSON_ASSERT(false); RAPIDJSON_ASSERT(false);
return IterativeParsingErrorState; return IterativeParsingErrorState;
...@@ -1256,7 +1272,7 @@ private: ...@@ -1256,7 +1272,7 @@ private:
} }
switch (src) { switch (src) {
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(is.Peek() == '\0' ? kParseErrorDocumentEmpty : kParseErrorDocumentRootNotObjectOrArray, is.Tell()); case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell());
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell());
case IterativeParsingObjectInitialState: case IterativeParsingObjectInitialState:
case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
......
...@@ -321,7 +321,6 @@ protected: ...@@ -321,7 +321,6 @@ protected:
level->valueCount++; level->valueCount++;
} }
else { else {
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
hasRoot_ = true; hasRoot_ = true;
} }
......
...@@ -22,9 +22,9 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml]( ...@@ -22,9 +22,9 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](
More features can be read [here](doc/features.md). More features can be read [here](doc/features.md).
JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC4627/ECMA-404. More information about JSON can be obtained at JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404. More information about JSON can be obtained at
* [Introducing JSON](http://json.org/) * [Introducing JSON](http://json.org/)
* [RFC4627: The application/json Media Type for JavaScript Object Notation (JSON)](http://www.ietf.org/rfc/rfc4627.txt) * [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt)
* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm) * [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm)
## Compatibility ## Compatibility
......
...@@ -46,6 +46,8 @@ TEST(JsonChecker, Reader) { ...@@ -46,6 +46,8 @@ TEST(JsonChecker, Reader) {
// jsonchecker/failXX.json // jsonchecker/failXX.json
for (int i = 1; i <= 33; i++) { for (int i = 1; i <= 33; i++) {
if (i == 1) // fail1.json is valid in rapidjson, which has no limitation on type of root element (RFC 7159).
continue;
if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting. if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting.
continue; continue;
...@@ -57,14 +59,18 @@ TEST(JsonChecker, Reader) { ...@@ -57,14 +59,18 @@ TEST(JsonChecker, Reader) {
json = ReadFile(filename, length); json = ReadFile(filename, length);
if (!json) { if (!json) {
printf("jsonchecker file %s not found", filename); printf("jsonchecker file %s not found", filename);
ADD_FAILURE();
continue; continue;
} }
} }
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
if (!document.Parse((const char*)json).HasParseError()) document.Parse((const char*)json);
FAIL(); EXPECT_TRUE(document.HasParseError());
//printf("%s(%u):%s\n", filename, (unsigned)document.GetErrorOffset(), document.GetParseError());
document.Parse<kParseIterativeFlag>((const char*)json);
EXPECT_TRUE(document.HasParseError());
free(json); free(json);
} }
...@@ -84,7 +90,11 @@ TEST(JsonChecker, Reader) { ...@@ -84,7 +90,11 @@ TEST(JsonChecker, Reader) {
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
document.Parse((const char*)json); document.Parse((const char*)json);
EXPECT_TRUE(!document.HasParseError()); EXPECT_FALSE(document.HasParseError());
document.Parse<kParseIterativeFlag>((const char*)json);
EXPECT_FALSE(document.HasParseError());
free(json); free(json);
} }
} }
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "unittest.h" #include "unittest.h"
#define private public // For testing private members
#include "rapidjson/reader.h" #include "rapidjson/reader.h"
using namespace rapidjson; using namespace rapidjson;
...@@ -31,7 +30,7 @@ RAPIDJSON_DIAG_OFF(effc++) ...@@ -31,7 +30,7 @@ RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
template<bool expect> template<bool expect>
struct ParseBoolHandler : BaseReaderHandler<> { 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 version. // gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest version.
...@@ -45,7 +44,7 @@ TEST(Reader, ParseTrue) { ...@@ -45,7 +44,7 @@ TEST(Reader, ParseTrue) {
StringStream s("true"); StringStream s("true");
ParseBoolHandler<true> h; ParseBoolHandler<true> h;
Reader reader; Reader reader;
reader.ParseTrue<0>(s, h); reader.Parse(s, h);
EXPECT_EQ(1u, h.step_); EXPECT_EQ(1u, h.step_);
} }
...@@ -53,11 +52,11 @@ TEST(Reader, ParseFalse) { ...@@ -53,11 +52,11 @@ TEST(Reader, ParseFalse) {
StringStream s("false"); StringStream s("false");
ParseBoolHandler<false> h; ParseBoolHandler<false> h;
Reader reader; Reader reader;
reader.ParseFalse<0>(s, h); reader.Parse(s, h);
EXPECT_EQ(1u, h.step_); EXPECT_EQ(1u, h.step_);
} }
struct ParseIntHandler : BaseReaderHandler<> { struct ParseIntHandler : BaseReaderHandler<UTF8<>, ParseIntHandler> {
ParseIntHandler() : step_(0), actual_() {} ParseIntHandler() : step_(0), actual_() {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
bool Int(int i) { actual_ = i; step_++; return true; } bool Int(int i) { actual_ = i; step_++; return true; }
...@@ -66,7 +65,7 @@ struct ParseIntHandler : BaseReaderHandler<> { ...@@ -66,7 +65,7 @@ struct ParseIntHandler : BaseReaderHandler<> {
int actual_; int actual_;
}; };
struct ParseUintHandler : BaseReaderHandler<> { struct ParseUintHandler : BaseReaderHandler<UTF8<>, ParseUintHandler> {
ParseUintHandler() : step_(0), actual_() {} ParseUintHandler() : step_(0), actual_() {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
bool Uint(unsigned i) { actual_ = i; step_++; return true; } bool Uint(unsigned i) { actual_ = i; step_++; return true; }
...@@ -75,7 +74,7 @@ struct ParseUintHandler : BaseReaderHandler<> { ...@@ -75,7 +74,7 @@ struct ParseUintHandler : BaseReaderHandler<> {
unsigned actual_; unsigned actual_;
}; };
struct ParseInt64Handler : BaseReaderHandler<> { struct ParseInt64Handler : BaseReaderHandler<UTF8<>, ParseInt64Handler> {
ParseInt64Handler() : step_(0), actual_() {} ParseInt64Handler() : step_(0), actual_() {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
bool Int64(int64_t i) { actual_ = i; step_++; return true; } bool Int64(int64_t i) { actual_ = i; step_++; return true; }
...@@ -84,7 +83,7 @@ struct ParseInt64Handler : BaseReaderHandler<> { ...@@ -84,7 +83,7 @@ struct ParseInt64Handler : BaseReaderHandler<> {
int64_t actual_; int64_t actual_;
}; };
struct ParseUint64Handler : BaseReaderHandler<> { struct ParseUint64Handler : BaseReaderHandler<UTF8<>, ParseUint64Handler> {
ParseUint64Handler() : step_(0), actual_() {} ParseUint64Handler() : step_(0), actual_() {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
bool Uint64(uint64_t i) { actual_ = i; step_++; return true; } bool Uint64(uint64_t i) { actual_ = i; step_++; return true; }
...@@ -93,7 +92,7 @@ struct ParseUint64Handler : BaseReaderHandler<> { ...@@ -93,7 +92,7 @@ struct ParseUint64Handler : BaseReaderHandler<> {
uint64_t actual_; uint64_t actual_;
}; };
struct ParseDoubleHandler : BaseReaderHandler<> { struct ParseDoubleHandler : BaseReaderHandler<UTF8<>, ParseDoubleHandler> {
ParseDoubleHandler() : step_(0), actual_() {} ParseDoubleHandler() : step_(0), actual_() {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
bool Double(double d) { actual_ = d; step_++; return true; } bool Double(double d) { actual_ = d; step_++; return true; }
...@@ -108,7 +107,7 @@ TEST(Reader, ParseNumberHandler) { ...@@ -108,7 +107,7 @@ TEST(Reader, ParseNumberHandler) {
StringStream s(str); \ StringStream s(str); \
Handler h; \ Handler h; \
Reader reader; \ Reader reader; \
reader.ParseNumber<0>(s, h); \ reader.Parse(s, h); \
EXPECT_EQ(1u, h.step_); \ EXPECT_EQ(1u, h.step_); \
EXPECT_EQ(double(x), h.actual_); \ EXPECT_EQ(double(x), h.actual_); \
} }
...@@ -118,7 +117,7 @@ TEST(Reader, ParseNumberHandler) { ...@@ -118,7 +117,7 @@ TEST(Reader, ParseNumberHandler) {
StringStream s(str); \ StringStream s(str); \
ParseDoubleHandler h; \ ParseDoubleHandler h; \
Reader reader; \ Reader reader; \
reader.ParseNumber<0>(s, h); \ reader.Parse(s, h); \
EXPECT_EQ(1u, h.step_); \ EXPECT_EQ(1u, h.step_); \
EXPECT_DOUBLE_EQ(x, h.actual_); \ EXPECT_DOUBLE_EQ(x, h.actual_); \
} }
...@@ -178,11 +177,11 @@ TEST(Reader, ParseNumber_Error) { ...@@ -178,11 +177,11 @@ TEST(Reader, ParseNumber_Error) {
#define TEST_NUMBER_ERROR(errorCode, str) \ #define TEST_NUMBER_ERROR(errorCode, str) \
{ \ { \
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<0>(s, h)); \ EXPECT_FALSE(reader.Parse(s, h)); \
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
} }
...@@ -209,7 +208,7 @@ TEST(Reader, ParseNumber_Error) { ...@@ -209,7 +208,7 @@ TEST(Reader, ParseNumber_Error) {
} }
template <typename Encoding> template <typename Encoding>
struct ParseStringHandler : BaseReaderHandler<Encoding> { struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encoding> > {
ParseStringHandler() : str_(0), length_(0), copy_() {} ParseStringHandler() : str_(0), length_(0), copy_() {}
~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(str_)); } ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(str_)); }
...@@ -242,14 +241,14 @@ TEST(Reader, ParseString) { ...@@ -242,14 +241,14 @@ TEST(Reader, ParseString) {
GenericInsituStringStream<Encoding> is(buffer); \ GenericInsituStringStream<Encoding> is(buffer); \
ParseStringHandler<Encoding> h; \ ParseStringHandler<Encoding> h; \
GenericReader<Encoding, Encoding> reader; \ GenericReader<Encoding, Encoding> reader; \
reader.ParseString<kParseInsituFlag | kParseValidateEncodingFlag>(is, h); \ reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag>(is, h); \
EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h.str_)); \ EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h.str_)); \
EXPECT_EQ(StrLen(e), h.length_); \ EXPECT_EQ(StrLen(e), h.length_); \
free(buffer); \ free(buffer); \
GenericStringStream<Encoding> s(x); \ GenericStringStream<Encoding> s(x); \
ParseStringHandler<Encoding> h2; \ ParseStringHandler<Encoding> h2; \
GenericReader<Encoding, Encoding> reader2; \ GenericReader<Encoding, Encoding> reader2; \
reader2.ParseString<0>(s, h2); \ reader2.Parse(s, h2); \
EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h2.str_)); \ EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h2.str_)); \
EXPECT_EQ(StrLen(e), h2.length_); \ EXPECT_EQ(StrLen(e), h2.length_); \
} }
...@@ -314,7 +313,7 @@ TEST(Reader, ParseString) { ...@@ -314,7 +313,7 @@ TEST(Reader, ParseString) {
const char e[] = "Hello\0World"; const char e[] = "Hello\0World";
ParseStringHandler<UTF8<> > h; ParseStringHandler<UTF8<> > h;
Reader reader; Reader reader;
reader.ParseString<0>(s, h); reader.Parse(s, h);
EXPECT_EQ(0, memcmp(e, h.str_, h.length_ + 1)); EXPECT_EQ(0, memcmp(e, h.str_, h.length_ + 1));
EXPECT_EQ(11u, h.length_); EXPECT_EQ(11u, h.length_);
} }
...@@ -326,7 +325,7 @@ TEST(Reader, ParseString_Transcoding) { ...@@ -326,7 +325,7 @@ TEST(Reader, ParseString_Transcoding) {
GenericStringStream<UTF8<> > is(x); GenericStringStream<UTF8<> > is(x);
GenericReader<UTF8<>, UTF16<> > reader; GenericReader<UTF8<>, UTF16<> > reader;
ParseStringHandler<UTF16<> > h; ParseStringHandler<UTF16<> > h;
reader.ParseString<0>(is, h); reader.Parse(is, h);
EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_)); EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_));
EXPECT_EQ(StrLen(e), h.length_); EXPECT_EQ(StrLen(e), h.length_);
} }
...@@ -335,7 +334,7 @@ TEST(Reader, ParseString_NonDestructive) { ...@@ -335,7 +334,7 @@ TEST(Reader, ParseString_NonDestructive) {
StringStream s("\"Hello\\nWorld\""); StringStream s("\"Hello\\nWorld\"");
ParseStringHandler<UTF8<> > h; ParseStringHandler<UTF8<> > h;
Reader reader; Reader reader;
reader.ParseString<0>(s, h); reader.Parse(s, h);
EXPECT_EQ(0, StrCmp("Hello\nWorld", h.str_)); EXPECT_EQ(0, StrCmp("Hello\nWorld", h.str_));
EXPECT_EQ(11u, h.length_); EXPECT_EQ(11u, h.length_);
} }
...@@ -431,7 +430,7 @@ TEST(Reader, ParseString_Error) { ...@@ -431,7 +430,7 @@ TEST(Reader, ParseString_Error) {
} }
template <unsigned count> template <unsigned count>
struct ParseArrayHandler : BaseReaderHandler<> { struct ParseArrayHandler : BaseReaderHandler<UTF8<>, ParseArrayHandler<count> > {
ParseArrayHandler() : step_(0) {} ParseArrayHandler() : step_(0) {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
...@@ -447,7 +446,7 @@ TEST(Reader, ParseEmptyArray) { ...@@ -447,7 +446,7 @@ TEST(Reader, ParseEmptyArray) {
InsituStringStream s(json); InsituStringStream s(json);
ParseArrayHandler<0> h; ParseArrayHandler<0> h;
Reader reader; Reader reader;
reader.ParseArray<0>(s, h); reader.Parse(s, h);
EXPECT_EQ(2u, h.step_); EXPECT_EQ(2u, h.step_);
free(json); free(json);
} }
...@@ -457,7 +456,7 @@ TEST(Reader, ParseArray) { ...@@ -457,7 +456,7 @@ TEST(Reader, ParseArray) {
InsituStringStream s(json); InsituStringStream s(json);
ParseArrayHandler<4> h; ParseArrayHandler<4> h;
Reader reader; Reader reader;
reader.ParseArray<0>(s, h); reader.Parse(s, h);
EXPECT_EQ(6u, h.step_); EXPECT_EQ(6u, h.step_);
free(json); free(json);
} }
...@@ -470,7 +469,7 @@ TEST(Reader, ParseArray_Error) { ...@@ -470,7 +469,7 @@ TEST(Reader, ParseArray_Error) {
InsituStringStream s(buffer); \ InsituStringStream s(buffer); \
BaseReaderHandler<> h; \ BaseReaderHandler<> h; \
GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \ GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \
EXPECT_FALSE(reader.Parse<0>(s, h)); \ EXPECT_FALSE(reader.Parse(s, h)); \
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
} }
...@@ -482,9 +481,10 @@ TEST(Reader, ParseArray_Error) { ...@@ -482,9 +481,10 @@ TEST(Reader, ParseArray_Error) {
#undef TEST_ARRAY_ERROR #undef TEST_ARRAY_ERROR
} }
struct ParseObjectHandler : BaseReaderHandler<> { struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
ParseObjectHandler() : step_(0) {} ParseObjectHandler() : step_(0) {}
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) {
switch(step_) { switch(step_) {
...@@ -534,7 +534,7 @@ TEST(Reader, ParseObject) { ...@@ -534,7 +534,7 @@ TEST(Reader, ParseObject) {
InsituStringStream s(json2); InsituStringStream s(json2);
ParseObjectHandler h; ParseObjectHandler h;
Reader reader; Reader reader;
reader.ParseObject<kParseInsituFlag>(s, h); reader.Parse<kParseInsituFlag>(s, h);
EXPECT_EQ(20u, h.step_); EXPECT_EQ(20u, h.step_);
free(json2); free(json2);
} }
...@@ -544,12 +544,12 @@ TEST(Reader, ParseObject) { ...@@ -544,12 +544,12 @@ TEST(Reader, ParseObject) {
StringStream s(json); StringStream s(json);
ParseObjectHandler h; ParseObjectHandler h;
Reader reader; Reader reader;
reader.ParseObject<0>(s, h); reader.Parse(s, h);
EXPECT_EQ(20u, h.step_); EXPECT_EQ(20u, h.step_);
} }
} }
struct ParseEmptyObjectHandler : BaseReaderHandler<> { struct ParseEmptyObjectHandler : BaseReaderHandler<UTF8<>, ParseEmptyObjectHandler> {
ParseEmptyObjectHandler() : step_(0) {} ParseEmptyObjectHandler() : step_(0) {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
...@@ -563,11 +563,11 @@ TEST(Reader, Parse_EmptyObject) { ...@@ -563,11 +563,11 @@ TEST(Reader, Parse_EmptyObject) {
StringStream s("{ } "); StringStream s("{ } ");
ParseEmptyObjectHandler h; ParseEmptyObjectHandler h;
Reader reader; Reader reader;
reader.ParseObject<0>(s, h); reader.Parse(s, h);
EXPECT_EQ(2u, h.step_); EXPECT_EQ(2u, h.step_);
} }
struct ParseMultipleRootHandler : BaseReaderHandler<> { struct ParseMultipleRootHandler : BaseReaderHandler<UTF8<>, ParseMultipleRootHandler> {
ParseMultipleRootHandler() : step_(0) {} ParseMultipleRootHandler() : step_(0) {}
bool Default() { ADD_FAILURE(); return false; } bool Default() { ADD_FAILURE(); return false; }
...@@ -630,7 +630,7 @@ TEST(Reader, ParseInsituIterative_MultipleRoot) { ...@@ -630,7 +630,7 @@ TEST(Reader, ParseInsituIterative_MultipleRoot) {
InsituStringStream s(buffer); \ InsituStringStream s(buffer); \
BaseReaderHandler<> h; \ BaseReaderHandler<> h; \
Reader reader; \ Reader reader; \
EXPECT_FALSE(reader.Parse<0>(s, h)); \ EXPECT_FALSE(reader.Parse(s, h)); \
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
} }
...@@ -640,25 +640,20 @@ TEST(Reader, ParseDocument_Error) { ...@@ -640,25 +640,20 @@ TEST(Reader, ParseDocument_Error) {
TEST_ERROR(kParseErrorDocumentEmpty, " "); TEST_ERROR(kParseErrorDocumentEmpty, " ");
TEST_ERROR(kParseErrorDocumentEmpty, " \n"); TEST_ERROR(kParseErrorDocumentEmpty, " \n");
// The document root must be either object or array.
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "null");
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "true");
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "false");
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "\"s\"");
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "0");
// The document root must not follow by other values. // The document root must not follow by other values.
TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0"); TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0");
TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0"); TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0");
TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []");
TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}");
} }
TEST(Reader, ParseValue_Error) { TEST(Reader, ParseValue_Error) {
// Invalid value. // Invalid value.
TEST_ERROR(kParseErrorValueInvalid, "[nulL]"); TEST_ERROR(kParseErrorValueInvalid, "nulL");
TEST_ERROR(kParseErrorValueInvalid, "[truE]"); TEST_ERROR(kParseErrorValueInvalid, "truE");
TEST_ERROR(kParseErrorValueInvalid, "[falsE]"); TEST_ERROR(kParseErrorValueInvalid, "falsE");
TEST_ERROR(kParseErrorValueInvalid, "[a]"); TEST_ERROR(kParseErrorValueInvalid, "a]");
TEST_ERROR(kParseErrorValueInvalid, "[.1]"); TEST_ERROR(kParseErrorValueInvalid, ".1");
} }
TEST(Reader, ParseObject_Error) { TEST(Reader, ParseObject_Error) {
...@@ -737,7 +732,7 @@ TEST(Reader, CustomStringStream) { ...@@ -737,7 +732,7 @@ TEST(Reader, CustomStringStream) {
CustomStringStream<UTF8<char> > s(json); CustomStringStream<UTF8<char> > s(json);
ParseObjectHandler h; ParseObjectHandler h;
Reader reader; Reader reader;
reader.ParseObject<0>(s, h); reader.Parse(s, h);
EXPECT_EQ(20u, h.step_); EXPECT_EQ(20u, h.step_);
} }
...@@ -781,7 +776,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) { ...@@ -781,7 +776,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) {
Reader reader; Reader reader;
ParseArrayHandler<4> h; ParseArrayHandler<4> h;
reader.ParseArray<0>(is, h); reader.Parse(is, h);
EXPECT_FALSE(reader.HasParseError()); EXPECT_FALSE(reader.HasParseError());
} }
...@@ -792,7 +787,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) { ...@@ -792,7 +787,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) {
StringStream json(text); \ StringStream json(text); \
BaseReaderHandler<> handler; \ BaseReaderHandler<> handler; \
Reader reader; \ Reader reader; \
reader.IterativeParse<kParseDefaultFlags>(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()); \
...@@ -802,7 +797,6 @@ TEST(Reader, IterativeParsing_ErrorHandling) { ...@@ -802,7 +797,6 @@ TEST(Reader, IterativeParsing_ErrorHandling) {
TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid, 6u); TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid, 6u);
TESTERRORHANDLING("", kParseErrorDocumentEmpty, 0u); TESTERRORHANDLING("", kParseErrorDocumentEmpty, 0u);
TESTERRORHANDLING("1", kParseErrorDocumentRootNotObjectOrArray, 0u);
TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular, 2u); TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular, 2u);
TESTERRORHANDLING("{1}", kParseErrorObjectMissName, 1u); TESTERRORHANDLING("{1}", kParseErrorObjectMissName, 1u);
...@@ -877,7 +871,7 @@ TEST(Reader, IterativeParsing_General) { ...@@ -877,7 +871,7 @@ TEST(Reader, IterativeParsing_General) {
Reader reader; Reader reader;
IterativeParsingReaderHandler<> handler; IterativeParsingReaderHandler<> handler;
ParseResult r = reader.IterativeParse<kParseIterativeFlag>(is, handler); ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler);
EXPECT_FALSE(r.IsError()); EXPECT_FALSE(r.IsError());
EXPECT_FALSE(reader.HasParseError()); EXPECT_FALSE(reader.HasParseError());
...@@ -914,7 +908,7 @@ TEST(Reader, IterativeParsing_Count) { ...@@ -914,7 +908,7 @@ TEST(Reader, IterativeParsing_Count) {
Reader reader; Reader reader;
IterativeParsingReaderHandler<> handler; IterativeParsingReaderHandler<> handler;
ParseResult r = reader.IterativeParse<kParseIterativeFlag>(is, handler); ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler);
EXPECT_FALSE(r.IsError()); EXPECT_FALSE(r.IsError());
EXPECT_FALSE(reader.HasParseError()); EXPECT_FALSE(reader.HasParseError());
......
...@@ -50,6 +50,16 @@ TEST(Writer, Compact) { ...@@ -50,6 +50,16 @@ TEST(Writer, Compact) {
EXPECT_TRUE(writer.IsComplete()); \ EXPECT_TRUE(writer.IsComplete()); \
} }
TEST(Writer, Root) {
TEST_ROUNDTRIP("null");
TEST_ROUNDTRIP("true");
TEST_ROUNDTRIP("false");
TEST_ROUNDTRIP("0");
TEST_ROUNDTRIP("\"foo\"");
TEST_ROUNDTRIP("[]");
TEST_ROUNDTRIP("{}");
}
TEST(Writer, Int) { TEST(Writer, Int) {
TEST_ROUNDTRIP("[-1]"); TEST_ROUNDTRIP("[-1]");
TEST_ROUNDTRIP("[-123]"); TEST_ROUNDTRIP("[-123]");
...@@ -155,12 +165,12 @@ TEST(Writer, OStreamWrapper) { ...@@ -155,12 +165,12 @@ TEST(Writer, OStreamWrapper) {
EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", actual.c_str()); EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", actual.c_str());
} }
TEST(Writer, AssertRootMustBeArrayOrObject) { TEST(Writer, AssertRootMayBeAnyValue) {
#define T(x)\ #define T(x)\
{\ {\
StringBuffer buffer;\ StringBuffer buffer;\
Writer<StringBuffer> writer(buffer);\ Writer<StringBuffer> writer(buffer);\
ASSERT_THROW(x, AssertException);\ EXPECT_TRUE(x);\
} }
T(writer.Bool(false)); T(writer.Bool(false));
T(writer.Bool(true)); T(writer.Bool(true));
...@@ -228,9 +238,23 @@ TEST(Writer, AssertObjectKeyNotString) { ...@@ -228,9 +238,23 @@ TEST(Writer, AssertObjectKeyNotString) {
TEST(Writer, AssertMultipleRoot) { TEST(Writer, AssertMultipleRoot) {
StringBuffer buffer; StringBuffer buffer;
Writer<StringBuffer> writer(buffer); Writer<StringBuffer> writer(buffer);
writer.StartObject(); writer.StartObject();
writer.EndObject(); writer.EndObject();
ASSERT_THROW(writer.StartObject(), AssertException); ASSERT_THROW(writer.StartObject(), AssertException);
writer.Reset(buffer);
writer.Null();
ASSERT_THROW(writer.Int(0), AssertException);
writer.Reset(buffer);
writer.String("foo");
ASSERT_THROW(writer.StartArray(), AssertException);
writer.Reset(buffer);
writer.StartArray();
writer.EndArray();
ASSERT_THROW(writer.Double(3.14), AssertException);
} }
TEST(Writer, RootObjectIsComplete) { TEST(Writer, RootObjectIsComplete) {
...@@ -260,3 +284,24 @@ TEST(Writer, RootArrayIsComplete) { ...@@ -260,3 +284,24 @@ TEST(Writer, RootArrayIsComplete) {
writer.EndArray(); writer.EndArray();
EXPECT_TRUE(writer.IsComplete()); EXPECT_TRUE(writer.IsComplete());
} }
TEST(Writer, RootValueIsComplete) {
#define T(x)\
{\
StringBuffer buffer;\
Writer<StringBuffer> writer(buffer);\
EXPECT_FALSE(writer.IsComplete()); \
x; \
EXPECT_TRUE(writer.IsComplete()); \
}
T(writer.Null());
T(writer.Bool(true));
T(writer.Bool(false));
T(writer.Int(0));
T(writer.Uint(0));
T(writer.Int64(0));
T(writer.Uint64(0));
T(writer.Double(0));
T(writer.String(""));
#undef T
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment