diff --git a/doc/tutorial.md b/doc/tutorial.md index 66c9a50..d22b6a3 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -42,7 +42,7 @@ The JSON is now parsed into `document` as a *DOM tree*: ![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 assert(document.IsObject()); ~~~~~~~~~~ diff --git a/include/rapidjson/error/en.h b/include/rapidjson/error/en.h index b4a3ae1..c668ac7 100644 --- a/include/rapidjson/error/en.h +++ b/include/rapidjson/error/en.h @@ -37,7 +37,6 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 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 kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index bc5462a..3db6f16 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -57,7 +57,6 @@ enum ParseErrorCode { kParseErrorNone = 0, //!< No error. 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. kParseErrorValueInvalid, //!< Invalid value. diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h index 62d5224..b19a9f4 100644 --- a/include/rapidjson/internal/meta.h +++ b/include/rapidjson/internal/meta.h @@ -21,6 +21,11 @@ #ifndef RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_ +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + //@cond RAPIDJSON_INTERNAL namespace rapidjson { namespace internal { @@ -94,4 +99,8 @@ template struct RemoveSfinaeFptr { typedef } // namespace rapidjson //@endcond +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index b9d7510..eb778b3 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -174,7 +174,6 @@ protected: level->valueCount++; } else { - RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. Base::hasRoot_ = true; } diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index d0f7ea4..eacdacb 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -26,6 +26,7 @@ #include "rapidjson.h" #include "encodings.h" +#include "internal/meta.h" #include "internal/pow10.h" #include "internal/stack.h" @@ -122,23 +123,25 @@ concept Handler { /*! This can be used as base class of any reader handler. \note implements Handler concept */ -template > +template, typename Derived = void> struct BaseReaderHandler { typedef typename Encoding::Ch Ch; + typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; + bool Default() { return true; } - bool Null() { return Default(); } - bool Bool(bool) { return Default(); } - bool Int(int) { return Default(); } - bool Uint(unsigned) { return Default(); } - bool Int64(int64_t) { return Default(); } - bool Uint64(uint64_t) { return Default(); } - bool Double(double) { return Default(); } - bool String(const Ch*, SizeType, bool) { return Default(); } - bool StartObject() { return Default(); } - bool EndObject(SizeType) { return Default(); } - bool StartArray() { return Default(); } - bool EndArray(SizeType) { return Default(); } + bool Null() { return static_cast(*this).Default(); } + bool Bool(bool) { return static_cast(*this).Default(); } + bool Int(int) { return static_cast(*this).Default(); } + bool Uint(unsigned) { return static_cast(*this).Default(); } + bool Int64(int64_t) { return static_cast(*this).Default(); } + bool Uint64(uint64_t) { return static_cast(*this).Default(); } + bool Double(double) { return static_cast(*this).Default(); } + bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } + bool StartObject() { return static_cast(*this).Default(); } + bool EndObject(SizeType) { return static_cast(*this).Default(); } + bool StartArray() { return static_cast(*this).Default(); } + bool EndArray(SizeType) { return static_cast(*this).Default(); } }; /////////////////////////////////////////////////////////////////////////////// @@ -381,11 +384,7 @@ public: RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } else { - switch (is.Peek()) { - case '{': ParseObject(is, handler); break; - case '[': ParseArray(is, handler); break; - default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell()); - } + ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (!(parseFlags & kParseStopWhenDoneFlag)) { @@ -907,6 +906,9 @@ private: IterativeParsingElementDelimiterState, IterativeParsingArrayFinishState, + // Single value state + IterativeParsingValueState, + cIterativeParsingStateCount }; @@ -965,11 +967,11 @@ private: IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number + IterativeParsingValueState, // String + IterativeParsingValueState, // False + IterativeParsingValueState, // True + IterativeParsingValueState, // Null + IterativeParsingValueState // Number }, // Finish(sink state) { @@ -1102,6 +1104,12 @@ private: IterativeParsingElementState // Number }, // 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, @@ -1242,6 +1250,14 @@ private: } } + case IterativeParsingValueState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return IterativeParsingFinishState; + default: RAPIDJSON_ASSERT(false); return IterativeParsingErrorState; @@ -1256,7 +1272,7 @@ private: } 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 IterativeParsingObjectInitialState: case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 9fdfde2..7927a0c 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -321,7 +321,6 @@ protected: level->valueCount++; } else { - RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. hasRoot_ = true; } diff --git a/readme.md b/readme.md index 8141c8b..d4c8f85 100644 --- a/readme.md +++ b/readme.md @@ -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). -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/) -* [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) ## Compatibility diff --git a/test/unittest/jsoncheckertest.cpp b/test/unittest/jsoncheckertest.cpp index d661528..caa1b8a 100644 --- a/test/unittest/jsoncheckertest.cpp +++ b/test/unittest/jsoncheckertest.cpp @@ -46,6 +46,8 @@ TEST(JsonChecker, Reader) { // jsonchecker/failXX.json 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. continue; @@ -57,14 +59,18 @@ TEST(JsonChecker, Reader) { json = ReadFile(filename, length); if (!json) { printf("jsonchecker file %s not found", filename); + ADD_FAILURE(); continue; } } GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) - if (!document.Parse((const char*)json).HasParseError()) - FAIL(); - //printf("%s(%u):%s\n", filename, (unsigned)document.GetErrorOffset(), document.GetParseError()); + document.Parse((const char*)json); + EXPECT_TRUE(document.HasParseError()); + + document.Parse((const char*)json); + EXPECT_TRUE(document.HasParseError()); + free(json); } @@ -84,7 +90,11 @@ TEST(JsonChecker, Reader) { GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) document.Parse((const char*)json); - EXPECT_TRUE(!document.HasParseError()); + EXPECT_FALSE(document.HasParseError()); + + document.Parse((const char*)json); + EXPECT_FALSE(document.HasParseError()); + free(json); } } diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index e403bb8..09560d8 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -20,7 +20,6 @@ #include "unittest.h" -#define private public // For testing private members #include "rapidjson/reader.h" using namespace rapidjson; @@ -31,7 +30,7 @@ RAPIDJSON_DIAG_OFF(effc++) #endif template -struct ParseBoolHandler : BaseReaderHandler<> { +struct ParseBoolHandler : BaseReaderHandler, ParseBoolHandler > { ParseBoolHandler() : step_(0) {} bool Default() { ADD_FAILURE(); return false; } // 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"); ParseBoolHandler h; Reader reader; - reader.ParseTrue<0>(s, h); + reader.Parse(s, h); EXPECT_EQ(1u, h.step_); } @@ -53,11 +52,11 @@ TEST(Reader, ParseFalse) { StringStream s("false"); ParseBoolHandler h; Reader reader; - reader.ParseFalse<0>(s, h); + reader.Parse(s, h); EXPECT_EQ(1u, h.step_); } -struct ParseIntHandler : BaseReaderHandler<> { +struct ParseIntHandler : BaseReaderHandler, ParseIntHandler> { ParseIntHandler() : step_(0), actual_() {} bool Default() { ADD_FAILURE(); return false; } bool Int(int i) { actual_ = i; step_++; return true; } @@ -66,7 +65,7 @@ struct ParseIntHandler : BaseReaderHandler<> { int actual_; }; -struct ParseUintHandler : BaseReaderHandler<> { +struct ParseUintHandler : BaseReaderHandler, ParseUintHandler> { ParseUintHandler() : step_(0), actual_() {} bool Default() { ADD_FAILURE(); return false; } bool Uint(unsigned i) { actual_ = i; step_++; return true; } @@ -75,7 +74,7 @@ struct ParseUintHandler : BaseReaderHandler<> { unsigned actual_; }; -struct ParseInt64Handler : BaseReaderHandler<> { +struct ParseInt64Handler : BaseReaderHandler, ParseInt64Handler> { ParseInt64Handler() : step_(0), actual_() {} bool Default() { ADD_FAILURE(); return false; } bool Int64(int64_t i) { actual_ = i; step_++; return true; } @@ -84,7 +83,7 @@ struct ParseInt64Handler : BaseReaderHandler<> { int64_t actual_; }; -struct ParseUint64Handler : BaseReaderHandler<> { +struct ParseUint64Handler : BaseReaderHandler, ParseUint64Handler> { ParseUint64Handler() : step_(0), actual_() {} bool Default() { ADD_FAILURE(); return false; } bool Uint64(uint64_t i) { actual_ = i; step_++; return true; } @@ -93,7 +92,7 @@ struct ParseUint64Handler : BaseReaderHandler<> { uint64_t actual_; }; -struct ParseDoubleHandler : BaseReaderHandler<> { +struct ParseDoubleHandler : BaseReaderHandler, ParseDoubleHandler> { ParseDoubleHandler() : step_(0), actual_() {} bool Default() { ADD_FAILURE(); return false; } bool Double(double d) { actual_ = d; step_++; return true; } @@ -108,7 +107,7 @@ TEST(Reader, ParseNumberHandler) { StringStream s(str); \ Handler h; \ Reader reader; \ - reader.ParseNumber<0>(s, h); \ + reader.Parse(s, h); \ EXPECT_EQ(1u, h.step_); \ EXPECT_EQ(double(x), h.actual_); \ } @@ -118,7 +117,7 @@ TEST(Reader, ParseNumberHandler) { StringStream s(str); \ ParseDoubleHandler h; \ Reader reader; \ - reader.ParseNumber<0>(s, h); \ + reader.Parse(s, h); \ EXPECT_EQ(1u, h.step_); \ EXPECT_DOUBLE_EQ(x, h.actual_); \ } @@ -178,11 +177,11 @@ TEST(Reader, ParseNumber_Error) { #define TEST_NUMBER_ERROR(errorCode, str) \ { \ char buffer[1001]; \ - sprintf(buffer, "[%s]", str); \ + sprintf(buffer, "%s", str); \ InsituStringStream s(buffer); \ BaseReaderHandler<> h; \ Reader reader; \ - EXPECT_FALSE(reader.Parse<0>(s, h)); \ + EXPECT_FALSE(reader.Parse(s, h)); \ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ } @@ -209,7 +208,7 @@ TEST(Reader, ParseNumber_Error) { } template -struct ParseStringHandler : BaseReaderHandler { +struct ParseStringHandler : BaseReaderHandler > { ParseStringHandler() : str_(0), length_(0), copy_() {} ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast(str_)); } @@ -242,14 +241,14 @@ TEST(Reader, ParseString) { GenericInsituStringStream is(buffer); \ ParseStringHandler h; \ GenericReader reader; \ - reader.ParseString(is, h); \ + reader.Parse(is, h); \ EXPECT_EQ(0, StrCmp(e, h.str_)); \ EXPECT_EQ(StrLen(e), h.length_); \ free(buffer); \ GenericStringStream s(x); \ ParseStringHandler h2; \ GenericReader reader2; \ - reader2.ParseString<0>(s, h2); \ + reader2.Parse(s, h2); \ EXPECT_EQ(0, StrCmp(e, h2.str_)); \ EXPECT_EQ(StrLen(e), h2.length_); \ } @@ -314,7 +313,7 @@ TEST(Reader, ParseString) { const char e[] = "Hello\0World"; ParseStringHandler > h; Reader reader; - reader.ParseString<0>(s, h); + reader.Parse(s, h); EXPECT_EQ(0, memcmp(e, h.str_, h.length_ + 1)); EXPECT_EQ(11u, h.length_); } @@ -326,7 +325,7 @@ TEST(Reader, ParseString_Transcoding) { GenericStringStream > is(x); GenericReader, UTF16<> > reader; ParseStringHandler > h; - reader.ParseString<0>(is, h); + reader.Parse(is, h); EXPECT_EQ(0, StrCmp::Ch>(e, h.str_)); EXPECT_EQ(StrLen(e), h.length_); } @@ -335,7 +334,7 @@ TEST(Reader, ParseString_NonDestructive) { StringStream s("\"Hello\\nWorld\""); ParseStringHandler > h; Reader reader; - reader.ParseString<0>(s, h); + reader.Parse(s, h); EXPECT_EQ(0, StrCmp("Hello\nWorld", h.str_)); EXPECT_EQ(11u, h.length_); } @@ -431,7 +430,7 @@ TEST(Reader, ParseString_Error) { } template -struct ParseArrayHandler : BaseReaderHandler<> { +struct ParseArrayHandler : BaseReaderHandler, ParseArrayHandler > { ParseArrayHandler() : step_(0) {} bool Default() { ADD_FAILURE(); return false; } @@ -447,7 +446,7 @@ TEST(Reader, ParseEmptyArray) { InsituStringStream s(json); ParseArrayHandler<0> h; Reader reader; - reader.ParseArray<0>(s, h); + reader.Parse(s, h); EXPECT_EQ(2u, h.step_); free(json); } @@ -457,7 +456,7 @@ TEST(Reader, ParseArray) { InsituStringStream s(json); ParseArrayHandler<4> h; Reader reader; - reader.ParseArray<0>(s, h); + reader.Parse(s, h); EXPECT_EQ(6u, h.step_); free(json); } @@ -470,7 +469,7 @@ TEST(Reader, ParseArray_Error) { InsituStringStream s(buffer); \ BaseReaderHandler<> h; \ GenericReader, UTF8<>, CrtAllocator> reader; \ - EXPECT_FALSE(reader.Parse<0>(s, h)); \ + EXPECT_FALSE(reader.Parse(s, h)); \ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ } @@ -482,9 +481,10 @@ TEST(Reader, ParseArray_Error) { #undef TEST_ARRAY_ERROR } -struct ParseObjectHandler : BaseReaderHandler<> { +struct ParseObjectHandler : BaseReaderHandler, ParseObjectHandler> { ParseObjectHandler() : step_(0) {} + bool Default() { ADD_FAILURE(); return false; } bool Null() { EXPECT_EQ(8u, step_); step_++; return true; } bool Bool(bool b) { switch(step_) { @@ -534,7 +534,7 @@ TEST(Reader, ParseObject) { InsituStringStream s(json2); ParseObjectHandler h; Reader reader; - reader.ParseObject(s, h); + reader.Parse(s, h); EXPECT_EQ(20u, h.step_); free(json2); } @@ -544,12 +544,12 @@ TEST(Reader, ParseObject) { StringStream s(json); ParseObjectHandler h; Reader reader; - reader.ParseObject<0>(s, h); + reader.Parse(s, h); EXPECT_EQ(20u, h.step_); } } -struct ParseEmptyObjectHandler : BaseReaderHandler<> { +struct ParseEmptyObjectHandler : BaseReaderHandler, ParseEmptyObjectHandler> { ParseEmptyObjectHandler() : step_(0) {} bool Default() { ADD_FAILURE(); return false; } @@ -563,11 +563,11 @@ TEST(Reader, Parse_EmptyObject) { StringStream s("{ } "); ParseEmptyObjectHandler h; Reader reader; - reader.ParseObject<0>(s, h); + reader.Parse(s, h); EXPECT_EQ(2u, h.step_); } -struct ParseMultipleRootHandler : BaseReaderHandler<> { +struct ParseMultipleRootHandler : BaseReaderHandler, ParseMultipleRootHandler> { ParseMultipleRootHandler() : step_(0) {} bool Default() { ADD_FAILURE(); return false; } @@ -630,7 +630,7 @@ TEST(Reader, ParseInsituIterative_MultipleRoot) { InsituStringStream s(buffer); \ BaseReaderHandler<> h; \ Reader reader; \ - EXPECT_FALSE(reader.Parse<0>(s, h)); \ + EXPECT_FALSE(reader.Parse(s, h)); \ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ } @@ -640,25 +640,20 @@ TEST(Reader, ParseDocument_Error) { TEST_ERROR(kParseErrorDocumentEmpty, " "); TEST_ERROR(kParseErrorDocumentEmpty, " \n"); - // The document root must be either object or array. - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "null"); - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "true"); - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "false"); - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "\"s\""); - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "0"); - // The document root must not follow by other values. TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0"); TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0"); + TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []"); + TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}"); } TEST(Reader, ParseValue_Error) { // Invalid value. - TEST_ERROR(kParseErrorValueInvalid, "[nulL]"); - TEST_ERROR(kParseErrorValueInvalid, "[truE]"); - TEST_ERROR(kParseErrorValueInvalid, "[falsE]"); - TEST_ERROR(kParseErrorValueInvalid, "[a]"); - TEST_ERROR(kParseErrorValueInvalid, "[.1]"); + TEST_ERROR(kParseErrorValueInvalid, "nulL"); + TEST_ERROR(kParseErrorValueInvalid, "truE"); + TEST_ERROR(kParseErrorValueInvalid, "falsE"); + TEST_ERROR(kParseErrorValueInvalid, "a]"); + TEST_ERROR(kParseErrorValueInvalid, ".1"); } TEST(Reader, ParseObject_Error) { @@ -737,7 +732,7 @@ TEST(Reader, CustomStringStream) { CustomStringStream > s(json); ParseObjectHandler h; Reader reader; - reader.ParseObject<0>(s, h); + reader.Parse(s, h); EXPECT_EQ(20u, h.step_); } @@ -781,7 +776,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) { Reader reader; ParseArrayHandler<4> h; - reader.ParseArray<0>(is, h); + reader.Parse(is, h); EXPECT_FALSE(reader.HasParseError()); } @@ -792,7 +787,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) { StringStream json(text); \ BaseReaderHandler<> handler; \ Reader reader; \ - reader.IterativeParse(json, handler); \ + reader.Parse(json, handler); \ EXPECT_TRUE(reader.HasParseError()); \ EXPECT_EQ(errorCode, reader.GetParseErrorCode()); \ EXPECT_EQ(offset, reader.GetErrorOffset()); \ @@ -802,7 +797,6 @@ TEST(Reader, IterativeParsing_ErrorHandling) { TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid, 6u); TESTERRORHANDLING("", kParseErrorDocumentEmpty, 0u); - TESTERRORHANDLING("1", kParseErrorDocumentRootNotObjectOrArray, 0u); TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular, 2u); TESTERRORHANDLING("{1}", kParseErrorObjectMissName, 1u); @@ -877,7 +871,7 @@ TEST(Reader, IterativeParsing_General) { Reader reader; IterativeParsingReaderHandler<> handler; - ParseResult r = reader.IterativeParse(is, handler); + ParseResult r = reader.Parse(is, handler); EXPECT_FALSE(r.IsError()); EXPECT_FALSE(reader.HasParseError()); @@ -914,7 +908,7 @@ TEST(Reader, IterativeParsing_Count) { Reader reader; IterativeParsingReaderHandler<> handler; - ParseResult r = reader.IterativeParse(is, handler); + ParseResult r = reader.Parse(is, handler); EXPECT_FALSE(r.IsError()); EXPECT_FALSE(reader.HasParseError()); diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 2d83418..e313c8b 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -50,6 +50,16 @@ TEST(Writer, Compact) { 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_ROUNDTRIP("[-1]"); 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()); } -TEST(Writer, AssertRootMustBeArrayOrObject) { +TEST(Writer, AssertRootMayBeAnyValue) { #define T(x)\ {\ StringBuffer buffer;\ Writer writer(buffer);\ - ASSERT_THROW(x, AssertException);\ + EXPECT_TRUE(x);\ } T(writer.Bool(false)); T(writer.Bool(true)); @@ -228,9 +238,23 @@ TEST(Writer, AssertObjectKeyNotString) { TEST(Writer, AssertMultipleRoot) { StringBuffer buffer; Writer writer(buffer); + writer.StartObject(); writer.EndObject(); 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) { @@ -260,3 +284,24 @@ TEST(Writer, RootArrayIsComplete) { writer.EndArray(); EXPECT_TRUE(writer.IsComplete()); } + +TEST(Writer, RootValueIsComplete) { +#define T(x)\ + {\ + StringBuffer buffer;\ + Writer 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 +}