Merge pull request #101 from pah/feature/rfc7159
Move to RFC7159 (closes #90)
This commit is contained in:
commit
143bb83e74
@ -42,7 +42,7 @@ The JSON is now parsed into `document` as a *DOM tree*:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
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
|
|||||||
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 {
|
|||||||
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 @@
|
|||||||
#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
|
|||||||
} // 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:
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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 {
|
|||||||
/*! 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:
|
|||||||
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:
|
|||||||
IterativeParsingElementDelimiterState,
|
IterativeParsingElementDelimiterState,
|
||||||
IterativeParsingArrayFinishState,
|
IterativeParsingArrayFinishState,
|
||||||
|
|
||||||
|
// Single value state
|
||||||
|
IterativeParsingValueState,
|
||||||
|
|
||||||
cIterativeParsingStateCount
|
cIterativeParsingStateCount
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -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:
|
|||||||
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:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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:
|
|||||||
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](
|
|||||||
|
|
||||||
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) {
|
|||||||
|
|
||||||
// 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) {
|
|||||||
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) {
|
|||||||
|
|
||||||
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 @@
|
|||||||
|
|
||||||
#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++)
|
|||||||
#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) {
|
|||||||
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) {
|
|||||||
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<> {
|
|||||||
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<> {
|
|||||||
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<> {
|
|||||||
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<> {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
#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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
#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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
|
|
||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
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
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user