diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 30251fa..6f45571 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_READER_H_ @@ -127,7 +127,7 @@ RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseFlag -/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS +/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kParseDefaultFlags definition. @@ -158,7 +158,7 @@ enum ParseFlag { /*! \class rapidjson::Handler \brief Concept for receiving events from GenericReader upon parsing. - The functions return true if no error occurs. If they return false, + The functions return true if no error occurs. If they return false, the event publisher should terminate the process. \code concept Handler { @@ -425,7 +425,7 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream -template<> inline void SkipWhitespace(InsituStringStream& is) { +template<> inline void SkipWhitespace(InsituStringStream& is) { is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); } @@ -443,17 +443,17 @@ template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& // GenericReader //! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. -/*! GenericReader parses JSON text from a stream, and send events synchronously to an +/*! GenericReader parses JSON text from a stream, and send events synchronously to an object implementing Handler concept. - It needs to allocate a stack for storing a single decoded string during + It needs to allocate a stack for storing a single decoded string during non-destructive parsing. - For in-situ parsing, the decoded string is directly written to the source + For in-situ parsing, the decoded string is directly written to the source text string, no temporary buffer is required. A GenericReader object can be reused for parsing multiple JSON text. - + \tparam SourceEncoding Encoding of the input stream. \tparam TargetEncoding Encoding of the parse output. \tparam StackAllocator Allocator type for stack. @@ -525,7 +525,7 @@ public: //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } - + //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } @@ -585,7 +585,7 @@ private: void ParseObject(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '{'); is.Take(); // Skip '{' - + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); @@ -628,12 +628,12 @@ private: SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; break; - case '}': + case '}': is.Take(); if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; - default: + default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; } @@ -654,10 +654,10 @@ private: void ParseArray(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '['); is.Take(); // Skip '[' - + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - + SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; @@ -780,7 +780,7 @@ private: *stack_.template Push() = c; ++length_; } - + RAPIDJSON_FORCEINLINE void* Push(SizeType count) { length_ += count; return stack_.template Push(count); @@ -838,10 +838,10 @@ private: //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const char escape[256] = { - Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', - Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, - 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, - 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 }; #undef Z16 @@ -893,8 +893,8 @@ private: } else { size_t offset = is.Tell(); - if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? - !Transcoder::Validate(is, os) : + if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? + !Transcoder::Validate(is, os) : !Transcoder::Transcode(is, os)))) RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); } @@ -954,7 +954,7 @@ private: } _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); } - + is.src_ = p; } @@ -977,7 +977,7 @@ private: if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; is.dst_ = q; - return; + return; } else *q++ = *p++; @@ -1063,11 +1063,11 @@ private: } #endif - template + template class NumberStream; template - class NumberStream { + class NumberStream { public: typedef typename InputStream::Ch Ch; @@ -1090,10 +1090,10 @@ private: }; template - class NumberStream : public NumberStream { - typedef NumberStream Base; + class NumberStream : public NumberStream { + typedef NumberStream Base; public: - NumberStream(GenericReader& reader, InputStream& is) : NumberStream(reader, is), stackStream(reader.stack_) {} + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch TakePush() { @@ -1101,9 +1101,9 @@ private: return Base::is.Take(); } - RAPIDJSON_FORCEINLINE void Push(char c) { - stackStream.Put(c); - } + RAPIDJSON_FORCEINLINE void Push(char c) { + stackStream.Put(c); + } size_t Length() { return stackStream.Length(); } @@ -1116,13 +1116,25 @@ private: StackStream stackStream; }; + template + class NumberStream : public NumberStream { + typedef NumberStream Base; + public: + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} + ~NumberStream() {} + + RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } + }; + template void ParseNumber(InputStream& is, Handler& handler) { internal::StreamLocalCopy copy(is); NumberStream s(*this, copy.s); + ((parseFlags & kParseFullPrecisionFlag) != 0), + (parseFlags & kParseNumbersAsStringsFlag) != 0 && + (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s); size_t startOffset = s.Tell(); @@ -1173,7 +1185,7 @@ private: bool useDouble = false; double d = 0.0; if (use64bit) { - if (minus) + if (minus) while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { @@ -1210,9 +1222,6 @@ private: int expFrac = 0; size_t decimalPosition; if (Consume(s, '.')) { - if (((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0)) { - s.Push('.'); - } decimalPosition = s.Length(); if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) @@ -1223,7 +1232,7 @@ private: // Use i64 to store significand in 64-bit architecture if (!use64bit) i64 = i; - + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path break; @@ -1260,11 +1269,7 @@ private: // Parse exp = e [ minus / plus ] 1*DIGIT int exp = 0; if (Consume(s, 'e') || Consume(s, 'E')) { - if ( ((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0) ) { - s.Push( 'e' ); - } - - if (!useDouble) { + if (!useDouble) { d = static_cast(use64bit ? i64 : i); useDouble = true; } @@ -1316,14 +1321,15 @@ private: cont = handler.RawNumber(str, SizeType(length), false); } else { - StackStream stackStream(stack_); SizeType numCharsToCopy = static_cast(s.Length()); + StringStream srcStream(s.Pop()); + StackStream dstStream(stack_); while (numCharsToCopy--) { - Transcoder::Transcode(is, stackStream); + Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); } - stackStream.Put('\0'); - const typename TargetEncoding::Ch* str = stackStream.Pop(); - const SizeType length = static_cast(stackStream.Length()) - 1; + dstStream.Put('\0'); + const typename TargetEncoding::Ch* str = dstStream.Pop(); + const SizeType length = static_cast(dstStream.Length()) - 1; cont = handler.RawNumber(str, SizeType(length), true); } } @@ -1369,10 +1375,10 @@ private: case '"': ParseString(is, handler); break; case '{': ParseObject(is, handler); break; case '[': ParseArray (is, handler); break; - default : + default : ParseNumber(is, handler); break; - + } } @@ -1444,7 +1450,7 @@ private: #undef N #undef N16 //!@endcond - + if (sizeof(Ch) == 1 || static_cast(c) < 256) return static_cast(tokenMap[static_cast(c)]); else @@ -1775,7 +1781,7 @@ private: // Error flag has been set. return; } - + switch (src) { case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; @@ -1788,7 +1794,7 @@ private: case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; - } + } } template diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index 02c1532..3f76a4f 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -38,6 +38,11 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything") + # If the user is running a newer version of Clang that includes the + # -Wdouble-promotion, we will ignore that warning. + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.7) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-double-promotion") + endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif() diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 83c1802..3f11fec 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "unittest.h" @@ -241,13 +241,13 @@ static void TestParseDouble() { TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form // Since - // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... ¡Á 10^-324 - // abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... ¡Á 10 ^ -324 + // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... �� 10^-324 + // abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... �� 10 ^ -324 // So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308 TEST_DOUBLE(fullPrecision, "2.2250738585072012e-308", 2.2250738585072014e-308); // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ // More closer to normal/subnormal boundary - // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... ¡Á 10^-308 + // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... �� 10^-308 TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164564e-308", 2.2250738585072009e-308); TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164565e-308", 2.2250738585072014e-308); @@ -297,7 +297,7 @@ static void TestParseDouble() { } // Cover trimming - TEST_DOUBLE(fullPrecision, + TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508" "7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012" "9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306" @@ -306,7 +306,7 @@ static void TestParseDouble() { "5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844" "2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042" "7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901" -"e-308", +"e-308", 2.2250738585072014e-308); { @@ -457,12 +457,12 @@ template struct ParseStringHandler : BaseReaderHandler > { ParseStringHandler() : str_(0), length_(0), copy_() {} ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast(str_)); } - + ParseStringHandler(const ParseStringHandler&); ParseStringHandler& operator=(const ParseStringHandler&); bool Default() { ADD_FAILURE(); return false; } - bool String(const typename Encoding::Ch* str, size_t length, bool copy) { + bool String(const typename Encoding::Ch* str, size_t length, bool copy) { EXPECT_EQ(0, str_); if (copy) { str_ = static_cast(malloc((length + 1) * sizeof(typename Encoding::Ch))); @@ -470,7 +470,7 @@ struct ParseStringHandler : BaseReaderHandler= 128 are assigned to signed integer types. // Therefore, utype is added for declaring unsigned array, and then cast it to Encoding::Ch. @@ -650,7 +650,7 @@ TEST(Reader, ParseString_Error) { // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt - // 3 Malformed sequences + // 3 Malformed sequences // 3.1 Unexpected continuation bytes { @@ -684,19 +684,19 @@ TEST(Reader, ParseString_Error) { } } - // 4 Overlong sequences + // 4 Overlong sequences // 4.1 Examples of an overlong ASCII character TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0')); - // 4.2 Maximum overlong sequences + // 4.2 Maximum overlong sequences TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0')); - // 4.3 Overlong representation of the NUL character + // 4.3 Overlong representation of the NUL character TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0')); TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0')); @@ -790,14 +790,14 @@ struct ParseObjectHandler : BaseReaderHandler, ParseObjectHandler> { bool Default() { ADD_FAILURE(); return false; } bool Null() { EXPECT_EQ(8u, step_); step_++; return true; } - bool Bool(bool b) { + bool Bool(bool b) { switch(step_) { case 4: EXPECT_TRUE(b); step_++; return true; case 6: EXPECT_FALSE(b); step_++; return true; default: ADD_FAILURE(); return false; } } - bool Int(int i) { + bool Int(int i) { switch(step_) { case 10: EXPECT_EQ(123, i); step_++; return true; case 15: EXPECT_EQ(1, i); step_++; return true; @@ -808,7 +808,7 @@ struct ParseObjectHandler : BaseReaderHandler, ParseObjectHandler> { } bool Uint(unsigned i) { return Int(static_cast(i)); } bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; } - bool String(const char* str, size_t, bool) { + bool String(const char* str, size_t, bool) { switch(step_) { case 1: EXPECT_STREQ("hello", str); step_++; return true; case 2: EXPECT_STREQ("world", str); step_++; return true; @@ -1045,7 +1045,7 @@ struct StreamTraits > { }; } // namespace rapidjson -#endif +#endif TEST(Reader, CustomStringStream) { const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; @@ -1069,7 +1069,7 @@ public: return c == std::char_traits::eof() ? '\0' : static_cast(c); } - Ch Take() { + Ch Take() { int c = is_.get(); return c == std::char_traits::eof() ? '\0' : static_cast(c); } @@ -1097,7 +1097,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) { Reader reader; ParseArrayHandler<4> h; reader.Parse(is, h); - EXPECT_FALSE(reader.HasParseError()); + EXPECT_FALSE(reader.HasParseError()); } // Test iterative parsing. @@ -1195,7 +1195,7 @@ struct IterativeParsingReaderHandler { bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; } bool Key (const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_KEY; return true; } - + bool EndObject(SizeType c) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_ENDOBJECT; @@ -1446,7 +1446,7 @@ TEST(Reader, ParseEmptyOnelineComment) { } TEST(Reader, ParseMultipleCommentsInARow) { - const char* json = + const char* json = "{/* first comment *//* second */\n" "/* third */ /*fourth*/// last one\n" "\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }"; @@ -1541,7 +1541,8 @@ struct NumbersAsStringsHandler { // 'str' is not null-terminated bool RawNumber(const char* str, SizeType length, bool) { EXPECT_TRUE(str != 0); - EXPECT_TRUE(strncmp(str, "3.1416", length) == 0); + EXPECT_TRUE(expected_len_ == length); + EXPECT_TRUE(strncmp(str, expected_, length) == 0); return true; } bool String(const char*, SizeType, bool) { return true; } @@ -1550,24 +1551,84 @@ struct NumbersAsStringsHandler { bool EndObject(SizeType) { return true; } bool StartArray() { return true; } bool EndArray(SizeType) { return true; } + + NumbersAsStringsHandler(const char* expected) + : expected_(expected) + , expected_len_(strlen(expected)) {} + + const char* expected_; + size_t expected_len_; }; TEST(Reader, NumbersAsStrings) { - { - const char* json = "{ \"pi\": 3.1416 } "; - StringStream s(json); - NumbersAsStringsHandler h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - } - { - char* json = StrDup("{ \"pi\": 3.1416 } "); - InsituStringStream s(json); - NumbersAsStringsHandler h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - free(json); - } + { + const char* json = "{ \"pi\": 3.1416 } "; + StringStream s(json); + NumbersAsStringsHandler h("3.1416"); + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } + { + char* json = StrDup("{ \"pi\": 3.1416 } "); + InsituStringStream s(json); + NumbersAsStringsHandler h("3.1416"); + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + free(json); + } + { + const char* json = "{ \"gigabyte\": 1.0e9 } "; + StringStream s(json); + NumbersAsStringsHandler h("1.0e9"); + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } + { + char* json = StrDup("{ \"gigabyte\": 1.0e9 } "); + InsituStringStream s(json); + NumbersAsStringsHandler h("1.0e9"); + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + free(json); + } + { + const char* json = "{ \"pi\": 314.159e-2 } "; + StringStream s(json); + NumbersAsStringsHandler h("314.159e-2"); + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } + { + char* json = StrDup("{ \"gigabyte\": 314.159e-2 } "); + InsituStringStream s(json); + NumbersAsStringsHandler h("314.159e-2"); + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + free(json); + } + { + const char* json = "{ \"negative\": -1.54321 } "; + StringStream s(json); + NumbersAsStringsHandler h("-1.54321"); + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } + { + char* json = StrDup("{ \"negative\": -1.54321 } "); + InsituStringStream s(json); + NumbersAsStringsHandler h("-1.54321"); + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + free(json); + } + { + const char* json = "{ \"pi\": 314.159e-2 } "; + std::stringstream ss(json); + IStreamWrapper s(ss); + NumbersAsStringsHandler h("314.159e-2"); + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } } template