diff --git a/.travis.yml b/.travis.yml index ac7240d..be06f35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,8 +18,10 @@ env: before_install: - sudo apt-get update -qq - - sudo apt-get install -qq cmake doxygen valgrind + - sudo apt-get install -qq cmake valgrind + - sudo apt-get --no-install-recommends install doxygen # Don't install LaTeX stuffs - if [ "$ARCH" = "x86" ]; then sudo apt-get install -qq g++-multilib libc6-dbg:i386; fi + - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then sudo pip install cpp-coveralls; export GCOV_FLAGS='--coverage'; fi install: true @@ -34,7 +36,9 @@ before_script: -DRAPIDJSON_HAS_STDSTRING=ON -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=$CONF - -DCMAKE_CXX_FLAGS="$ARCH_FLAGS" ..) + -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS" + -DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS + ..) script: - cd build @@ -42,3 +46,6 @@ script: - make examples - ctest -V `[ "$CONF" = "release" ] || echo "-E perftest"` - make travis_doc + +after_success: + - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..92a4054 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,65 @@ +# Change Log +All notable changes to this project will be documented in this file. +This project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +* Include rapidjson.h for all internal/error headers. + +## [1.0.1] - 2015-04-25 + +### Added +* Changelog following [Keep a CHANGELOG](https://github.com/olivierlacan/keep-a-changelog) suggestions. + +### Fixed +* Parsing of some numbers (e.g. "1e-00011111111111") causing assertion (#314). +* Visual C++ 32-bit compilation error in `diyfp.h` (#317). + +## [1.0.0] - 2015-04-22 + +### Added +* 100% [Coverall](https://coveralls.io/r/miloyip/rapidjson?branch=master) coverage. +* Version macros (#311) + +### Fixed +* A bug in trimming long number sequence (4824f12efbf01af72b8cb6fc96fae7b097b73015). +* Double quote in unicode escape (#288). +* Negative zero roundtrip (double only) (#289). +* Standardize behavior of `memcpy()` and `malloc()` (0c5c1538dcfc7f160e5a4aa208ddf092c787be5a, #305, 0e8bbe5e3ef375e7f052f556878be0bd79e9062d). + +### Removed +* Remove an invalid `Document::ParseInsitu()` API (e7f1c6dd08b522cfcf9aed58a333bd9a0c0ccbeb). + +## 1.0-beta - 2015-04-8 + +### Added +* RFC 7159 (#101) +* Optional Iterative Parser (#76) +* Deep-copy values (#20) +* Error code and message (#27) +* ASCII Encoding (#70) +* `kParseStopWhenDoneFlag` (#83) +* `kParseFullPrecisionFlag` (881c91d696f06b7f302af6d04ec14dd08db66ceb) +* Add `Key()` to handler concept (#134) +* C++11 compatibility and support (#128) +* Optimized number-to-string and vice versa conversions (#137, #80) +* Short-String Optimization (#131) +* Local stream optimization by traits (#32) +* Travis & Appveyor Continuous Integration, with Valgrind verification (#24, #242) +* Redo all documentation (English, Simplified Chinese) + +### Changed +* Copyright ownership transfered to THL A29 Limited (a Tencent company). +* Migrating from Premake to CMAKE (#192) +* Resolve all warning reports + +### Removed +* Remove other JSON libraries for performance comparison (#180) + +## 0.11 - 2012-11-16 + +## 0.1 - 2011-11-18 + +[Unreleased]: https://github.com/miloyip/rapidjson/compare/v1.0.1...HEAD +[1.0.1]: https://github.com/miloyip/rapidjson/compare/v1.0.0...v1.0.1 +[1.0.0]: https://github.com/miloyip/rapidjson/compare/v1.0-beta...v1.0.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c823ac..380bdcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,9 +3,9 @@ SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMakeModules) PROJECT(RapidJSON CXX) -set(LIB_MAJOR_VERSION "0") -set(LIB_MINOR_VERSION "12") -set(LIB_PATCH_VERSION "0") +set(LIB_MAJOR_VERSION "1") +set(LIB_MINOR_VERSION "0") +set(LIB_PATCH_VERSION "1") set(LIB_VERSION_STRING "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}") # compile in release with debug info mode by default @@ -17,6 +17,8 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." ON) option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." ON) option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." ON) +option(RAPIDJSON_BUILD_THIRDPARTY_GTEST + "Use gtest installation in `thirdparty/gtest` by default if available" OFF) option(RAPIDJSON_HAS_STDSTRING "" OFF) if(RAPIDJSON_HAS_STDSTRING) diff --git a/CMakeModules/FindGTestSrc.cmake b/CMakeModules/FindGTestSrc.cmake index 89f132e..b5abc19 100644 --- a/CMakeModules/FindGTestSrc.cmake +++ b/CMakeModules/FindGTestSrc.cmake @@ -1,9 +1,14 @@ + SET(GTEST_SEARCH_PATH "${GTEST_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/thirdparty/gtest") IF(UNIX) - LIST(INSERT GTEST_SEARCH_PATH 1 "/usr/src/gtest") + IF(RAPIDJSON_BUILD_THIRDPARTY_GTEST) + LIST(APPEND GTEST_SEARCH_PATH "/usr/src/gtest") + ELSE() + LIST(INSERT GTEST_SEARCH_PATH 1 "/usr/src/gtest") + ENDIF() ENDIF() FIND_PATH(GTEST_SOURCE_DIR @@ -15,8 +20,10 @@ FIND_PATH(GTEST_SOURCE_DIR FIND_PATH(GTEST_INCLUDE_DIR NAMES gtest/gtest.h PATH_SUFFIXES include + HINTS ${GTEST_SOURCE_DIR} PATHS ${GTEST_SEARCH_PATH}) +INCLUDE(FindPackageHandleStandardArgs) find_package_handle_standard_args(GTestSrc DEFAULT_MSG GTEST_SOURCE_DIR GTEST_INCLUDE_DIR) diff --git a/appveyor.yml b/appveyor.yml index d1a9108..add4017 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 0.12.{build} +version: 1.0.1.{build} configuration: - Debug diff --git a/doc/dom.md b/doc/dom.md index c047ede..f3e4208 100644 --- a/doc/dom.md +++ b/doc/dom.md @@ -84,29 +84,25 @@ template GenericDocument& GenericDocument::ParseStream(InputStream& is); // (4) In situ parsing -template -GenericDocument& GenericDocument::ParseInsitu(Ch* str); - -// (5) In situ parsing, using same Encoding of Document template GenericDocument& GenericDocument::ParseInsitu(Ch* str); -// (6) In situ parsing, using default parse flags +// (5) In situ parsing, using default parse flags GenericDocument& GenericDocument::ParseInsitu(Ch* str); -// (7) Normal parsing of a string +// (6) Normal parsing of a string template GenericDocument& GenericDocument::Parse(const Ch* str); -// (8) Normal parsing of a string, using same Encoding of Document +// (7) Normal parsing of a string, using same Encoding of Document template GenericDocument& GenericDocument::Parse(const Ch* str); -// (9) Normal parsing of a string, using default parse flags +// (8) Normal parsing of a string, using default parse flags GenericDocument& GenericDocument::Parse(const Ch* str); ~~~~~~~~~~ -The examples of [tutorial](doc/tutorial.md) uses (9) for normal parsing of string. The examples of [stream](doc/stream.md) uses the first three. *In situ* parsing will be described soon. +The examples of [tutorial](doc/tutorial.md) uses (8) for normal parsing of string. The examples of [stream](doc/stream.md) uses the first three. *In situ* parsing will be described soon. The `parseFlags` are combination of the following bit-flags: diff --git a/doc/dom.zh-cn.md b/doc/dom.zh-cn.md index 8fb3ee4..c7fcfff 100644 --- a/doc/dom.zh-cn.md +++ b/doc/dom.zh-cn.md @@ -84,29 +84,25 @@ template GenericDocument& GenericDocument::ParseStream(InputStream& is); // (4) 原位解析 -template -GenericDocument& GenericDocument::ParseInsitu(Ch* str); - -// (5) 原位解析,使用Document的编码 template GenericDocument& GenericDocument::ParseInsitu(Ch* str); -// (6) 原位解析,使用缺省标志 +// (5) 原位解析,使用缺省标志 GenericDocument& GenericDocument::ParseInsitu(Ch* str); -// (7) 正常解析一个字符串 +// (6) 正常解析一个字符串 template GenericDocument& GenericDocument::Parse(const Ch* str); -// (8) 正常解析一个字符串,使用Document的编码 +// (7) 正常解析一个字符串,使用Document的编码 template GenericDocument& GenericDocument::Parse(const Ch* str); -// (9) 正常解析一个字符串,使用缺省标志 +// (8) 正常解析一个字符串,使用缺省标志 GenericDocument& GenericDocument::Parse(const Ch* str); ~~~~~~~~~~ -[教程](tutorial.md)中的例使用(9)去正常解析字符串。而[流](stream.md)的例子使用前3个函数。我们将稍后介绍原位(*In situ*) 解析。 +[教程](tutorial.md)中的例使用(8)去正常解析字符串。而[流](stream.md)的例子使用前3个函数。我们将稍后介绍原位(*In situ*) 解析。 `parseFlags`是以下位标置的组合: diff --git a/doc/faq.md b/doc/faq.md index bab7f5f..b00b4c6 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -28,7 +28,7 @@ 6. How to install RapidJSON? - Check [Installation section](http://miloyip.github.io/rapidjson/). + Check [Installation section](https://miloyip.github.io/rapidjson/). 7. Can RapidJSON run on my platform? @@ -198,7 +198,7 @@ 3. What is SIMD? How it is applied in RapidJSON? - [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.1 to accelerate whitespace skipping. This improves performance of parsing indent formatted JSON. + [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.2 to accelerate whitespace skipping. This improves performance of parsing indent formatted JSON. Define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` macro to enable this feature. However, running the executable on a machine without such instruction set support will make it crash. 4. Does it consume a lot of memory? diff --git a/doc/faq.zh-cn.md b/doc/faq.zh-cn.md index ce6acf1..c6e7557 100644 --- a/doc/faq.zh-cn.md +++ b/doc/faq.zh-cn.md @@ -198,7 +198,7 @@ 3. 什是是SIMD?它如何用于RapidJSON? - [SIMD](http://en.wikipedia.org/wiki/SIMD)指令可以在现代CPU中执行并行运算。RapidJSON支持了Intel的SSE2/SSE4.1去加速跳过空白字符。在解析含缩进的JSON时,这能提升性能。 + [SIMD](http://en.wikipedia.org/wiki/SIMD)指令可以在现代CPU中执行并行运算。RapidJSON支持了Intel的SSE2/SSE4.2去加速跳过空白字符。在解析含缩进的JSON时,这能提升性能。只要定义名为`RAPIDJSON_SSE2`或`RAPIDJSON_SSE42`的宏,就能启动这个功能。然而,若在不支持这些指令集的机器上执行这些可执行文件,会导致崩溃。 4. 它会消耗许多内存么? diff --git a/doc/features.md b/doc/features.md index 15de259..fc54cd0 100644 --- a/doc/features.md +++ b/doc/features.md @@ -15,7 +15,7 @@ * High performance * Use template and inline functions to reduce function call overheads. * Internal optimized Grisu2 and floating point parsing implementations. - * Optional SSE2/SSE4.1 support. + * Optional SSE2/SSE4.2 support. ## Standard compliance diff --git a/doc/features.zh-cn.md b/doc/features.zh-cn.md index b56c424..3a01a4b 100644 --- a/doc/features.zh-cn.md +++ b/doc/features.zh-cn.md @@ -15,7 +15,7 @@ * 高性能 * 使用模版及内联函数去降低函数调用开销。 * 内部经优化的Grisu2及浮点数解析实现。 - * 可选的SSE2/SSE4.1支持。 + * 可选的SSE2/SSE4.2支持。 ## 符合标准 diff --git a/doc/internals.md b/doc/internals.md index ebfbc8f..de482cb 100644 --- a/doc/internals.md +++ b/doc/internals.md @@ -183,7 +183,21 @@ void SkipWhitespace(InputStream& s) { However, this requires 4 comparisons and a few branching for each character. This was found to be a hot spot. -To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON only supports SSE2 and SSE4.1 instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing. +To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON only supports SSE2 and SSE4.2 instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing. + +To enable this optimization, need to define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` before including `rapidjson.h`. Some compilers can detect the setting, as in `perftest.h`: + +~~~cpp +// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler. +// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported. +#if defined(__SSE4_2__) +# define RAPIDJSON_SSE42 +#elif defined(__SSE2__) +# define RAPIDJSON_SSE2 +#endif +~~~ + +Note that, these are compile-time settings. Running the executable on a machine without such instruction set support will make it crash. ## Local Stream Copy {#LocalStreamCopy} diff --git a/doc/misc/footer.html b/doc/misc/footer.html index edf3e69..843aa11 100644 --- a/doc/misc/footer.html +++ b/doc/misc/footer.html @@ -18,10 +18,10 @@ (document.getElementsByClassName('contents')[0]).appendChild(dt); var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; + dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); })(); - \ No newline at end of file + diff --git a/doc/tutorial.md b/doc/tutorial.md index 811833d..3508918 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -192,7 +192,7 @@ Checking | Obtaining `bool IsNumber()` | N/A `bool IsUint()` | `unsigned GetUint()` `bool IsInt()` | `int GetInt()` -`bool IsUint64()` | `uint64_t GetUint()` +`bool IsUint64()` | `uint64_t GetUint64()` `bool IsInt64()` | `int64_t GetInt64()` `bool IsDouble()` | `double GetDouble()` diff --git a/doc/tutorial.zh-cn.md b/doc/tutorial.zh-cn.md index 24456d5..d1381be 100644 --- a/doc/tutorial.zh-cn.md +++ b/doc/tutorial.zh-cn.md @@ -192,7 +192,7 @@ JSON只提供一种数值类型──Number。数字可以是整数或实数。R `bool IsNumber()` | 不适用 `bool IsUint()` | `unsigned GetUint()` `bool IsInt()` | `int GetInt()` -`bool IsUint64()` | `uint64_t GetUint()` +`bool IsUint64()` | `uint64_t GetUint64()` `bool IsInt64()` | `int64_t GetInt64()` `bool IsDouble()` | `double GetDouble()` diff --git a/example/serialize/serialize.cpp b/example/serialize/serialize.cpp index 4f9278b..7427939 100644 --- a/example/serialize/serialize.cpp +++ b/example/serialize/serialize.cpp @@ -2,7 +2,6 @@ // This example shows writing JSON string with writer directly. #include "rapidjson/prettywriter.h" // for stringify JSON -#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output #include #include #include @@ -144,13 +143,15 @@ int main(int, char*[]) { employees.push_back(Employee("Percy TSE", 30, false)); - FileStream s(stdout); - PrettyWriter writer(s); // Can also use Writer for condensed formatting + StringBuffer sb; + PrettyWriter writer(sb); writer.StartArray(); for (std::vector::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr) employeeItr->Serialize(writer); writer.EndArray(); + puts(sb.GetString()); + return 0; } diff --git a/example/tutorial/tutorial.cpp b/example/tutorial/tutorial.cpp index 49704c1..206fdb9 100644 --- a/example/tutorial/tutorial.cpp +++ b/example/tutorial/tutorial.cpp @@ -3,7 +3,6 @@ #include "rapidjson/document.h" // rapidjson's DOM-style API #include "rapidjson/prettywriter.h" // for stringify JSON -#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output #include using namespace rapidjson; @@ -143,9 +142,10 @@ int main(int, char*[]) { // 4. Stringify JSON printf("\nModified JSON with reformatting:\n"); - FileStream f(stdout); - PrettyWriter writer(f); + StringBuffer sb; + PrettyWriter writer(sb); document.Accept(writer); // Accept() traverses the DOM and generates Handler events. + puts(sb.GetString()); return 0; } diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h index 7b348b6..d68b74c 100644 --- a/include/rapidjson/allocators.h +++ b/include/rapidjson/allocators.h @@ -62,7 +62,12 @@ concept Allocator { class CrtAllocator { public: static const bool kNeedFree = true; - void* Malloc(size_t size) { return std::malloc(size); } + void* Malloc(size_t size) { + if (size) // behavior of malloc(0) is implementation defined. + return std::malloc(size); + else + return NULL; // standardize to returning NULL. + } void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return std::realloc(originalPtr, newSize); } static void Free(void *ptr) { std::free(ptr); } }; @@ -160,6 +165,9 @@ public: //! Allocates a memory block. (concept Allocator) void* Malloc(size_t size) { + if (!size) + return NULL; + size = RAPIDJSON_ALIGN(size); if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); @@ -191,7 +199,9 @@ public: // Realloc process: allocate and copy memory, do not free original buffer. void* newBuffer = Malloc(newSize); RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. - return std::memcpy(newBuffer, originalPtr, originalSize); + if (originalSize) + std::memcpy(newBuffer, originalPtr, originalSize); + return newBuffer; } //! Frees a memory block (concept Allocator) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index e7a707d..b79abf7 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -701,8 +701,11 @@ public: return StringEqual(rhs); case kNumberType: - if (IsDouble() || rhs.IsDouble()) - return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double. + if (IsDouble() || rhs.IsDouble()) { + double a = GetDouble(); // May convert from integer to double. + double b = rhs.GetDouble(); // Ditto + return a >= b && a <= b; // Prevent -Wfloat-equal + } else return data_.n.u64 == rhs.data_.n.u64; @@ -1457,17 +1460,14 @@ public: case kStringType: return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0); - case kNumberType: + default: + RAPIDJSON_ASSERT(GetType() == kNumberType); if (IsInt()) return handler.Int(data_.n.i.i); else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsInt64()) return handler.Int64(data_.n.i64); else if (IsUint64()) return handler.Uint64(data_.n.u64); else return handler.Double(data_.n.d); - - default: - RAPIDJSON_ASSERT(false); } - return false; } private: @@ -1580,16 +1580,24 @@ private: // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { flags_ = kArrayFlag; - data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); - std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); + if (count) { + data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); + std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); + } + else + data_.a.elements = NULL; data_.a.size = data_.a.capacity = count; } //! Initialize this value as object with initial data, without calling destructor. void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { flags_ = kObjectFlag; - data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); - std::memcpy(data_.o.members, members, count * sizeof(Member)); + if (count) { + data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); + std::memcpy(data_.o.members, members, count * sizeof(Member)); + } + else + data_.o.members = NULL; data_.o.size = data_.o.capacity = count; } @@ -1751,7 +1759,7 @@ public: */ template GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); + return ParseStream(is); } //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) @@ -1768,18 +1776,6 @@ public: //!@name Parse in-place from mutable string //!@{ - //! Parse JSON text from a mutable string (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam SourceEncoding Transcoding from input Encoding - \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseInsitu(Ch* str) { - GenericInsituStringStream s(str); - return ParseStream(s); - } - //! Parse JSON text from a mutable string /*! \tparam parseFlags Combination of \ref ParseFlag. \param str Mutable zero-terminated string to be parsed. @@ -1787,7 +1783,8 @@ public: */ template GenericDocument& ParseInsitu(Ch* str) { - return ParseInsitu(str); + GenericInsituStringStream s(str); + return ParseStream(s); } //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) @@ -1795,7 +1792,7 @@ public: \return The document itself for fluent API. */ GenericDocument& ParseInsitu(Ch* str) { - return ParseInsitu(str); + return ParseInsitu(str); } //!@} diff --git a/include/rapidjson/encodedstream.h b/include/rapidjson/encodedstream.h index f2f3ea3..9a93b38 100644 --- a/include/rapidjson/encodedstream.h +++ b/include/rapidjson/encodedstream.h @@ -109,6 +109,7 @@ public: \param type UTF encoding type if it is not detected from the stream. */ AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); DetectType(); static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; takeFunc_ = f[type_]; @@ -177,21 +178,8 @@ private: } // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. - switch (type_) { - case kUTF8: - // Do nothing - break; - case kUTF16LE: - case kUTF16BE: - RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - break; - case kUTF32LE: - case kUTF32BE: - RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - break; - default: - RAPIDJSON_ASSERT(false); // Invalid type - } + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); } typedef Ch (*TakeFunc)(InputByteStream& is); @@ -220,22 +208,11 @@ public: \param putBOM Whether to write BOM at the beginning of the stream. */ AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { - // RUntime check whether the size of character type is sufficient. It only perform checks with assertion. - switch (type_) { - case kUTF16LE: - case kUTF16BE: - RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - break; - case kUTF32LE: - case kUTF32BE: - RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - break; - case kUTF8: - // Do nothing - break; - default: - RAPIDJSON_ASSERT(false); // Invalid UTFType - } + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; putFunc_ = f[type_]; diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index aa5700c..f9094fb 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -15,6 +15,8 @@ #ifndef RAPIDJSON_ERROR_ERROR_H__ #define RAPIDJSON_ERROR_ERROR_H__ +#include "../rapidjson.h" + /*! \file error.h */ /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ diff --git a/include/rapidjson/filestream.h b/include/rapidjson/filestream.h deleted file mode 100644 index 12701e2..0000000 --- a/include/rapidjson/filestream.h +++ /dev/null @@ -1,67 +0,0 @@ -// 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 -// in compliance with the License. You may obtain a copy of the License at -// -// 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 -// specific language governing permissions and limitations under the License. - -#ifndef RAPIDJSON_FILESTREAM_H_ -#define RAPIDJSON_FILESTREAM_H_ - -#include "rapidjson.h" -#include - -RAPIDJSON_NAMESPACE_BEGIN - -//! (Deprecated) Wrapper of C file stream for input or output. -/*! - This simple wrapper does not check the validity of the stream. - \note implements Stream concept - \note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead. -*/ -class FileStream { -public: - typedef char Ch; //!< Character type. Only support char. - - FileStream(std::FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); } - char Peek() const { return current_; } - char Take() { char c = current_; Read(); return c; } - size_t Tell() const { return count_; } - void Put(char c) { fputc(c, fp_); } - void Flush() { fflush(fp_); } - - // Not implemented - char* PutBegin() { return 0; } - size_t PutEnd(char*) { return 0; } - -private: - // Prohibit copy constructor & assignment operator. - FileStream(const FileStream&); - FileStream& operator=(const FileStream&); - - void Read() { - RAPIDJSON_ASSERT(fp_ != 0); - int c = fgetc(fp_); - if (c != EOF) { - current_ = (char)c; - count_++; - } - else if (current_ != '\0') - current_ = '\0'; - } - - std::FILE* fp_; - char current_; - size_t count_; -}; - -RAPIDJSON_NAMESPACE_END - -#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/include/rapidjson/internal/biginteger.h b/include/rapidjson/internal/biginteger.h index e4703d6..5baba9b 100755 --- a/include/rapidjson/internal/biginteger.h +++ b/include/rapidjson/internal/biginteger.h @@ -172,13 +172,10 @@ public: } // Compute absolute difference of this and rhs. - // Return false if this < rhs + // Assume this != rhs bool Difference(const BigInteger& rhs, BigInteger* out) const { int cmp = Compare(rhs); - if (cmp == 0) { - *out = BigInteger(0); - return false; - } + RAPIDJSON_ASSERT(cmp != 0); const BigInteger *a, *b; // Makes a > b bool ret; if (cmp < 0) { a = &rhs; b = this; ret = true; } @@ -269,12 +266,6 @@ private: #endif } - static Type FullAdd(Type a, Type b, bool inCarry, bool* outCarry) { - Type c = a + b + (inCarry ? 1 : 0); - *outCarry = c < a; - return c; - } - static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 static const size_t kCapacity = kBitCount / sizeof(Type); static const size_t kTypeBit = sizeof(Type) * 8; diff --git a/include/rapidjson/internal/diyfp.h b/include/rapidjson/internal/diyfp.h index 320d05d..4ef53d9 100644 --- a/include/rapidjson/internal/diyfp.h +++ b/include/rapidjson/internal/diyfp.h @@ -19,12 +19,12 @@ #ifndef RAPIDJSON_DIYFP_H_ #define RAPIDJSON_DIYFP_H_ -#if defined(_MSC_VER) +#include "../rapidjson.h" + +#if defined(_MSC_VER) && defined(_M_AMD64) #include -#if defined(_M_AMD64) #pragma intrinsic(_BitScanReverse64) #endif -#endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -135,25 +135,9 @@ struct DiyFp { double d; uint64_t u64; }u; - uint64_t significand = f; - int exponent = e; - while (significand > kDpHiddenBit + kDpSignificandMask) { - significand >>= 1; - exponent++; - } - while (exponent > kDpDenormalExponent && (significand & kDpHiddenBit) == 0) { - significand <<= 1; - exponent--; - } - if (exponent >= kDpMaxExponent) { - u.u64 = kDpExponentMask; // Infinity - return u.d; - } - else if (exponent < kDpDenormalExponent) - return 0.0; - const uint64_t be = (exponent == kDpDenormalExponent && (significand & kDpHiddenBit) == 0) ? 0 : - static_cast(exponent + kDpExponentBias); - u.u64 = (significand & kDpSignificandMask) | (be << kDpSignificandSize); + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + static_cast(e + kDpExponentBias); + u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); return u.d; } @@ -238,7 +222,7 @@ inline DiyFp GetCachedPower(int e, int* K) { //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive int k = static_cast(dk); - if (k != dk) + if (dk - k > 0.0) k++; unsigned index = static_cast((k >> 3) + 1); diff --git a/include/rapidjson/internal/dtoa.h b/include/rapidjson/internal/dtoa.h index c888402..2d8d2e4 100644 --- a/include/rapidjson/internal/dtoa.h +++ b/include/rapidjson/internal/dtoa.h @@ -21,6 +21,7 @@ #include "itoa.h" // GetDigitsLut() #include "diyfp.h" +#include "ieee754.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -49,8 +50,10 @@ inline unsigned CountDecimalDigit32(uint32_t n) { if (n < 1000000) return 6; if (n < 10000000) return 7; if (n < 100000000) return 8; - if (n < 1000000000) return 9; - return 10; + // Will not reach 10 digits in DigitGen() + //if (n < 1000000000) return 9; + //return 10; + return 9; } inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { @@ -59,13 +62,12 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff const DiyFp wp_w = Mp - W; uint32_t p1 = static_cast(Mp.f >> -one.e); uint64_t p2 = Mp.f & (one.f - 1); - int kappa = CountDecimalDigit32(p1); + int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] *len = 0; while (kappa > 0) { - uint32_t d; + uint32_t d = 0; switch (kappa) { - case 10: d = p1 / 1000000000; p1 %= 1000000000; break; case 9: d = p1 / 100000000; p1 %= 100000000; break; case 8: d = p1 / 10000000; p1 %= 10000000; break; case 7: d = p1 / 1000000; p1 %= 1000000; break; @@ -75,14 +77,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff case 3: d = p1 / 100; p1 %= 100; break; case 2: d = p1 / 10; p1 %= 10; break; case 1: d = p1; p1 = 0; break; - default: -#if defined(_MSC_VER) - __assume(0); -#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) - __builtin_unreachable(); -#else - d = 0; -#endif + default:; } if (d || *len) buffer[(*len)++] = static_cast('0' + static_cast(d)); @@ -192,7 +187,10 @@ inline char* Prettify(char* buffer, int length, int k) { } inline char* dtoa(double value, char* buffer) { - if (value == 0) { + Double d(value); + if (d.IsZero()) { + if (d.Sign()) + *buffer++ = '-'; // -0.0, Issue #289 buffer[0] = '0'; buffer[1] = '.'; buffer[2] = '0'; diff --git a/include/rapidjson/internal/ieee754.h b/include/rapidjson/internal/ieee754.h index 934cf19..9a82880 100644 --- a/include/rapidjson/internal/ieee754.h +++ b/include/rapidjson/internal/ieee754.h @@ -34,14 +34,6 @@ public: return Double(u + 1).Value(); } - double PreviousPositiveDouble() const { - RAPIDJSON_ASSERT(!Sign()); - if (d == 0.0) - return 0.0; - else - return Double(u - 1).Value(); - } - bool Sign() const { return (u & kSignMask) != 0; } uint64_t Significand() const { return u & kSignificandMask; } int Exponent() const { return ((u & kExponentMask) >> kSignificandSize) - kExponentBias; } @@ -49,6 +41,7 @@ public: bool IsNan() const { return (u & kExponentMask) == kExponentMask && Significand() != 0; } bool IsInf() const { return (u & kExponentMask) == kExponentMask && Significand() == 0; } bool IsNormal() const { return (u & kExponentMask) != 0 || Significand() == 0; } + bool IsZero() const { return (u & (kExponentMask | kSignificandMask)) == 0; } uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } diff --git a/include/rapidjson/internal/itoa.h b/include/rapidjson/internal/itoa.h index a28001f..01a4e7e 100644 --- a/include/rapidjson/internal/itoa.h +++ b/include/rapidjson/internal/itoa.h @@ -15,6 +15,8 @@ #ifndef RAPIDJSON_ITOA_ #define RAPIDJSON_ITOA_ +#include "../rapidjson.h" + RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -109,12 +111,13 @@ inline char* u32toa(uint32_t value, char* buffer) { } inline char* i32toa(int32_t value, char* buffer) { + uint32_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; - value = -value; + u = ~u + 1; } - return u32toa(static_cast(value), buffer); + return u32toa(u, buffer); } inline char* u64toa(uint64_t value, char* buffer) { @@ -286,12 +289,13 @@ inline char* u64toa(uint64_t value, char* buffer) { } inline char* i64toa(int64_t value, char* buffer) { + uint64_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; - value = -value; + u = ~u + 1; } - return u64toa(static_cast(value), buffer); + return u64toa(u, buffer); } } // namespace internal diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h index 594e259..2daad96 100644 --- a/include/rapidjson/internal/meta.h +++ b/include/rapidjson/internal/meta.h @@ -15,9 +15,7 @@ #ifndef RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_ -#ifndef RAPIDJSON_RAPIDJSON_H_ -#error not yet included. Do not include this file directly. -#endif +#include "../rapidjson.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH diff --git a/include/rapidjson/internal/pow10.h b/include/rapidjson/internal/pow10.h index c552d9f..1d2dff0 100644 --- a/include/rapidjson/internal/pow10.h +++ b/include/rapidjson/internal/pow10.h @@ -15,6 +15,8 @@ #ifndef RAPIDJSON_POW10_ #define RAPIDJSON_POW10_ +#include "../rapidjson.h" + RAPIDJSON_NAMESPACE_BEGIN namespace internal { diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 2f2c76a..bb31cc0 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -15,6 +15,8 @@ #ifndef RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ +#include "../rapidjson.h" + RAPIDJSON_NAMESPACE_BEGIN namespace internal { diff --git a/include/rapidjson/internal/strfunc.h b/include/rapidjson/internal/strfunc.h index e6d1c21..f6c99db 100644 --- a/include/rapidjson/internal/strfunc.h +++ b/include/rapidjson/internal/strfunc.h @@ -15,6 +15,8 @@ #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_ +#include "../rapidjson.h" + RAPIDJSON_NAMESPACE_BEGIN namespace internal { diff --git a/include/rapidjson/internal/strtod.h b/include/rapidjson/internal/strtod.h index 805c752..fa85286 100644 --- a/include/rapidjson/internal/strtod.h +++ b/include/rapidjson/internal/strtod.h @@ -52,7 +52,7 @@ inline T Min3(T a, T b, T c) { return m; } -inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp, bool* adjustToNegative) { +inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { const Double db(b); const uint64_t bInt = db.IntegerSignificand(); const int bExp = db.IntegerExponent(); @@ -104,19 +104,9 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp, bool* adj hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2; BigInteger delta(0); - *adjustToNegative = dS.Difference(bS, &delta); + dS.Difference(bS, &delta); - int cmp = delta.Compare(hS); - // If delta is within 1/2 ULP, check for special case when significand is power of two. - // In this case, need to compare with 1/2h in the lower bound. - if (cmp < 0 && *adjustToNegative && // within and dS < bS - db.IsNormal() && (bInt & (bInt - 1)) == 0 && // Power of 2 - db.Uint64Value() != RAPIDJSON_UINT64_C2(0x00100000, 0x00000000)) // minimum normal number must not do this - { - delta <<= 1; - return delta.Compare(hS); - } - return cmp; + return delta.Compare(hS); } inline bool StrtodFast(double d, int p, double* result) { @@ -213,24 +203,18 @@ inline double StrtodBigInteger(double approx, const char* decimals, size_t lengt const BigInteger dInt(decimals, length); const int dExp = (int)decimalPosition - (int)length + exp; Double a(approx); - for (int i = 0; i < 10; i++) { - bool adjustToNegative; - int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp, &adjustToNegative); - if (cmp < 0) - return a.Value(); // within half ULP - else if (cmp == 0) { - // Round towards even - if (a.Significand() & 1) - return adjustToNegative ? a.PreviousPositiveDouble() : a.NextPositiveDouble(); - else - return a.Value(); - } - else // adjustment - a = adjustToNegative ? a.PreviousPositiveDouble() : a.NextPositiveDouble(); + int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); + if (cmp < 0) + return a.Value(); // within half ULP + else if (cmp == 0) { + // Round towards even + if (a.Significand() & 1) + return a.NextPositiveDouble(); + else + return a.Value(); } - - // This should not happen, but in case there is really a bug, break the infinite-loop - return a.Value(); + else // adjustment + return a.NextPositiveDouble(); } inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { @@ -258,7 +242,9 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t // Trim right-most digits const int kMaxDecimalDigit = 780; if ((int)length > kMaxDecimalDigit) { - exp += (int(length) - kMaxDecimalDigit); + int delta = (int(length) - kMaxDecimalDigit); + exp += delta; + decimalPosition -= delta; length = kMaxDecimalDigit; } diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index 90d1983..fff8886 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -78,7 +78,7 @@ public: #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { - return String(str.data(), SizeType(str.size())); + return String(str.data(), SizeType(str.size())); } #endif @@ -100,8 +100,9 @@ public: Base::os_->Put('\n'); WriteIndent(); } - if (!Base::WriteEndObject()) - return false; + bool ret = Base::WriteEndObject(); + (void)ret; + RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::os_->Flush(); return true; @@ -123,8 +124,9 @@ public: Base::os_->Put('\n'); WriteIndent(); } - if (!Base::WriteEndArray()) - return false; + bool ret = Base::WriteEndArray(); + (void)ret; + RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::os_->Flush(); return true; diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index b847ac7..0c41ab6 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -15,12 +15,9 @@ #ifndef RAPIDJSON_RAPIDJSON_H_ #define RAPIDJSON_RAPIDJSON_H_ -// Copyright (c) 2011 Milo Yip (miloyip@gmail.com) -// Version 0.1 - /*!\file rapidjson.h \brief common definitions and configuration - + \see RAPIDJSON_CONFIG */ @@ -42,6 +39,40 @@ #include // malloc(), realloc(), free(), size_t #include // memset(), memcpy(), memmove(), memcmp() +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_VERSION_STRING +// +// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. +// + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +// token stringification +#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) +#define RAPIDJSON_DO_STRINGIFY(x) #x +//!@endcond + +/*! \def RAPIDJSON_MAJOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Major version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_MINOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Minor version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_PATCH_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Patch version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_VERSION_STRING + \ingroup RAPIDJSON_CONFIG + \brief Version of RapidJSON in ".." string format. +*/ +#define RAPIDJSON_MAJOR_VERSION 1 +#define RAPIDJSON_MINOR_VERSION 0 +#define RAPIDJSON_PATCH_VERSION 1 +#define RAPIDJSON_VERSION_STRING \ + RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NAMESPACE_(BEGIN|END) /*! \def RAPIDJSON_NAMESPACE @@ -122,9 +153,9 @@ #ifndef RAPIDJSON_FORCEINLINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __forceinline -#elif defined(__GNUC__) && __GNUC__ >= 4 +#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #else #define RAPIDJSON_FORCEINLINE @@ -356,10 +387,6 @@ RAPIDJSON_NAMESPACE_END #define RAPIDJSON_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) -// token stringification -#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) -#define RAPIDJSON_DO_STRINGIFY(x) #x - /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index a59f26e..be0d9fb 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -255,23 +255,23 @@ void SkipWhitespace(InputStream& is) { #ifdef RAPIDJSON_SSE42 //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; - // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; // The rest of string using SIMD - static const char whitespace[16] = " \n\r\t"; - const __m128i w = _mm_load_si128((const __m128i *)&whitespace[0]); + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_load_si128((const __m128i *)&whitespace[0]); for (;; p += 16) { const __m128i s = _mm_load_si128((const __m128i *)p); @@ -292,31 +292,31 @@ inline const char *SkipWhitespace_SIMD(const char* p) { //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { - // Fast return for single non-whitespace - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); - while (p != nextAligned) - if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') - ++p; - else - return p; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; // The rest of string - static const char whitespaces[4][17] = { - " ", - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; + static const char whitespaces[4][17] = { + " ", + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", + "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; - const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); - const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); - const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); - const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); + const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); + const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); + const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); + const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); for (;; p += 16) { const __m128i s = _mm_load_si128((const __m128i *)p); @@ -689,11 +689,13 @@ private: } else if (e == 'u') { // Unicode unsigned codepoint = ParseHex4(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair if (is.Take() != '\\' || is.Take() != 'u') RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); unsigned codepoint2 = ParseHex4(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; @@ -894,7 +896,7 @@ private: if (significandDigit < 17) { d = d * 10.0 + (s.TakePush() - '0'); --expFrac; - if (d != 0.0) + if (d > 0.0) significandDigit++; } else @@ -923,10 +925,22 @@ private: if (s.Peek() >= '0' && s.Peek() <= '9') { exp = s.Take() - '0'; - while (s.Peek() >= '0' && s.Peek() <= '9') { - exp = exp * 10 + (s.Take() - '0'); - if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first. - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); + if (expMinus) { + while (s.Peek() >= '0' && s.Peek() <= '9') { + exp = exp * 10 + (s.Take() - '0'); + if (exp >= 214748364) { // Issue #313: prevent overflow exponent + while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent + s.Take(); + } + } + } + else { // positive exp + int maxExp = 308 - expFrac; + while (s.Peek() >= '0' && s.Peek() <= '9') { + exp = exp * 10 + (s.Take() - '0'); + if (exp > maxExp) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); + } } } else @@ -1225,14 +1239,9 @@ private: // May return a new state on state pop. template RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { + (void)token; + switch (dst) { - case IterativeParsingStartState: - RAPIDJSON_ASSERT(false); - return IterativeParsingErrorState; - - case IterativeParsingFinishState: - return dst; - case IterativeParsingErrorState: return dst; @@ -1271,12 +1280,9 @@ private: return dst; case IterativeParsingKeyValueDelimiterState: - if (token == ColonToken) { - is.Take(); - return dst; - } - else - return IterativeParsingErrorState; + RAPIDJSON_ASSERT(token == ColonToken); + is.Take(); + return dst; case IterativeParsingMemberValueState: // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. @@ -1351,17 +1357,25 @@ private: } } - case IterativeParsingValueState: + default: + // This branch is for IterativeParsingValueState actually. + // Use `default:` rather than + // `case IterativeParsingValueState:` is for code coverage. + + // The IterativeParsingStartState is not enumerated in this switch-case. + // It is impossible for that case. And it can be caught by following assertion. + + // The IterativeParsingFinishState is not enumerated in this switch-case either. + // It is a "derivative" state which cannot triggered from Predict() directly. + // Therefore it cannot happen here. And it can be caught by following assertion. + RAPIDJSON_ASSERT(dst == 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; } } diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 6030fe0..40cdb35 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -127,7 +127,7 @@ public: #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { - return String(str.data(), SizeType(str.size())); + return String(str.data(), SizeType(str.size())); } #endif @@ -272,7 +272,8 @@ protected: os_->Put(hexDigits[(codepoint >> 4) & 15]); os_->Put(hexDigits[(codepoint ) & 15]); } - else if (codepoint >= 0x010000 && codepoint <= 0x10FFFF) { + else { + RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); // Surrogate pair unsigned s = codepoint - 0x010000; unsigned lead = (s >> 10) + 0xD800; @@ -288,8 +289,6 @@ protected: os_->Put(hexDigits[(trail >> 4) & 15]); os_->Put(hexDigits[(trail ) & 15]); } - else - return false; // invalid code point } else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { is.Take(); @@ -303,7 +302,8 @@ protected: } } else - Transcoder::Transcode(is, *os_); + if (!Transcoder::Transcode(is, *os_)) + return false; } os_->Put('\"'); return true; diff --git a/readme.md b/readme.md index 59fd776..98f81a7 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,7 @@ ![](doc/logo/rapidjson.png) + +![](https://img.shields.io/badge/release-v1.0.1-blue.png) + ## A fast JSON parser/generator for C++ with both SAX/DOM style API Tencent is pleased to support the open source community by making RapidJSON available. @@ -13,14 +16,16 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights ## Build status -| [Linux][lin-link] | [Windows][win-link] | -| :---------------: | :-----------------: | -| ![lin-badge] | ![win-badge] | +| [Linux][lin-link] | [Windows][win-link] | [Coveralls][cov-link] | +| :---------------: | :-----------------: | :-------------------: | +| ![lin-badge] | ![win-badge] | ![cov-badge] | -[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png "Travis build status" +[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status" [lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status" -[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master?svg=true "AppVeyor build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status" [win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status" +[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master +[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master ## Introduction @@ -28,7 +33,7 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml]( * RapidJSON is small but complete. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code. -* RapidJSON is fast. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.1 for acceleration. +* RapidJSON is fast. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration. * RapidJSON is self-contained. It does not depend on external libraries such as BOOST. It even does not depend on STL. diff --git a/readme.zh-cn.md b/readme.zh-cn.md index 569044b..eb6c21d 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -1,5 +1,9 @@ ![](doc/logo/rapidjson.png) +![](https://img.shields.io/badge/release-v1.0.1-blue.png) + +## 高效的C++ JSON解析/生成器,提供SAX及DOM风格API + 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. @@ -10,13 +14,26 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights * [简体中文](http://miloyip.github.io/rapidjson/zh-cn/) * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/)可下载PDF/EPUB/MOBI,但不含API参考手册。 +## Build 状态 + +| [Linux][lin-link] | [Windows][win-link] | [Coveralls][cov-link] | +| :---------------: | :-----------------: | :-------------------: | +| ![lin-badge] | ![win-badge] | ![cov-badge] | + +[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status" +[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status" +[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status" +[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master +[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master + ## 简介 RapidJSON是一个C++的JSON解析器及生成器。它的灵感来自[RapidXml](http://rapidxml.sourceforge.net/)。 * RapidJSON小而全。它同时支持SAX和DOM风格的API。SAX解析器只有约500行代码。 -* RapidJSON快。它的性能可与`strlen()`相比。可支持SSE2/SSE4.1加速。 +* RapidJSON快。它的性能可与`strlen()`相比。可支持SSE2/SSE4.2加速。 * RapidJSON独立。它不依赖于BOOST等外部库。它甚至不依赖于STL。 @@ -45,21 +62,21 @@ RapidJSON是跨平台的。以下是一些曾测试的平台/编译器组合 RapidJSON是只有头文件的C++库。只需把`include/rapidjson`目录复制至系统或项目的include目录中。 +RapidJSON依赖于以下软件: +* [CMake](http://www.cmake.org) 作为通用生成工具 +* (optional)[Doxygen](http://www.doxygen.org)用于生成文档 +* (optional)[googletest](https://code.google.com/p/googletest/)用于单元及性能测试 + 生成测试及例子的步骤: 1. 执行 `git submodule update --init` 去获取 thirdparty submodules (google test)。 -2. 下载 [premake4](http://industriousone.com/premake/download)。 -3. 复制 premake4 可执行文件至 `rapidjson/build` (或系统路径)。 -4. 进入`rapidjson/build/`目录,在Windows下执行`premake.bat`,在Linux或其他平台下执行`premake.sh`。 -5. 在Windows上,生成位于`rapidjson/build/vs2008/`或`/vs2010/`内的项目方案. -6. 在其他平台上,在`rapidjson/build/gmake/`目录执行GNU `make`(如 `make -f test.make config=release32`、`make -f example.make config=debug32`)。 -7. 若成功,可执行文件会生成在`rapidjson/bin`目录。 +2. 在rapidjson目渌下,建立一个`build`目录。 +3. 在`build`目录下执行`cmake ..`命令以设置生成。Windows用户可使用cmake-gui应用程序。 +4. 在Windows下,编译生成在build目录中的solution。在Linux下,于build目录运行`make`。 -生成[Doxygen](http://doxygen.org)文档的步骤: +成功生成后,你会在`bin`的目录下找到编译后的测试及例子可执行文件。而生成的文档将位于build下的`doc/html`目录。要执行测试,请在build下执行`make test`或`ctest`。使用`ctest -V`命令可获取详细的输出。 -1. 下载及安装[Doxygen](http://doxygen.org/download.html)。 -2. 在顶层目录执行`doxygen build/Doxyfile`。 -3. 在`doc/html`浏览文档。 +我们也可以把程序库安装至全系统中,只要在具管理權限下从build目录执行`make install`命令。这样会按系统的偏好设置安装所有文件。当安装RapidJSON后,其他的CMake项目需要使用它时,可以通过在`CMakeLists.txt`加入一句`find_package(RapidJSON)`。 ## 用法一览 diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp index 3edadda..c6b3353 100644 --- a/test/perftest/misctest.cpp +++ b/test/perftest/misctest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 "perftest.h" @@ -768,7 +762,7 @@ template void itoa_Writer_StringBufferVerify() { rapidjson::StringBuffer sb; Writer writer(sb); - for (int j = 0; j < randvalCount; j++) { + for (size_t j = 0; j < randvalCount; j++) { char buffer[32]; sprintf(buffer, "%d", randval[j]); writer.WriteInt(randval[j]); @@ -780,7 +774,7 @@ void itoa_Writer_StringBufferVerify() { template void itoa_Writer_InsituStringStreamVerify() { Writer writer; - for (int j = 0; j < randvalCount; j++) { + for (size_t j = 0; j < randvalCount; j++) { char buffer[32]; sprintf(buffer, "%d", randval[j]); char buffer2[32]; diff --git a/test/perftest/perftest.cpp b/test/perftest/perftest.cpp index 4366e1c..38ba07e 100644 --- a/test/perftest/perftest.cpp +++ b/test/perftest/perftest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 "perftest.h" diff --git a/test/perftest/perftest.h b/test/perftest/perftest.h index 2fca203..2b0984c 100644 --- a/test/perftest/perftest.h +++ b/test/perftest/perftest.h @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 PERFTEST_H_ #define PERFTEST_H_ @@ -71,9 +65,20 @@ public: PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {} virtual void SetUp() { - FILE *fp = fopen(filename_ = "data/sample.json", "rb"); - if (!fp) - fp = fopen(filename_ = "../../bin/data/sample.json", "rb"); + + const char *paths[] = { + "data/sample.json", + "bin/data/sample.json", + "../bin/data/sample.json", + "../../bin/data/sample.json", + "../../../bin/data/sample.json" + }; + FILE *fp = 0; + for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { + fp = fopen(filename_ = paths[i], "rb"); + if (fp) + break; + } ASSERT_TRUE(fp != 0); fseek(fp, 0, SEEK_END); diff --git a/test/perftest/platformtest.cpp b/test/perftest/platformtest.cpp index 30b690c..7ea2a8e 100644 --- a/test/perftest/platformtest.cpp +++ b/test/perftest/platformtest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 "perftest.h" diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 74bdf27..05ecf6e 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 "perftest.h" @@ -26,7 +20,6 @@ #include "rapidjson/document.h" #include "rapidjson/prettywriter.h" #include "rapidjson/stringbuffer.h" -#include "rapidjson/filestream.h" #include "rapidjson/filereadstream.h" #include "rapidjson/encodedstream.h" #include "rapidjson/memorystream.h" @@ -324,17 +317,6 @@ TEST_F(RapidJson, UTF8_Validate) { } } -// Deprecated. -//TEST_F(RapidJson, FileStream_Read) { -// for (size_t i = 0; i < kTrialCount; i++) { -// FILE *fp = fopen(filename_, "rb"); -// FileStream s(fp); -// while (s.Take() != '\0') -// ; -// fclose(fp); -// } -//} - TEST_F(RapidJson, FileReadStream) { for (size_t i = 0; i < kTrialCount; i++) { FILE *fp = fopen(filename_, "rb"); diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index 1ff88b1..4ff95d6 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -1,13 +1,20 @@ set(UNITTEST_SOURCES + allocatorstest.cpp bigintegertest.cpp documenttest.cpp encodedstreamtest.cpp encodingstest.cpp filestreamtest.cpp + itoatest.cpp jsoncheckertest.cpp namespacetest.cpp +<<<<<<< HEAD pointertest.cpp +======= + prettywritertest.cpp +>>>>>>> master readertest.cpp + simdtest.cpp stringbuffertest.cpp strtodtest.cpp unittest.cpp @@ -15,9 +22,9 @@ set(UNITTEST_SOURCES writertest.cpp) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Weffc++ -Wswitch-default") + 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 -Weffc++ -Wswitch-default") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif() @@ -36,8 +43,9 @@ add_test(NAME unittest WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) if(NOT MSVC) + # Not running SIMD.* unit test cases for Valgrind add_test(NAME valgrind_unittest - COMMAND valgrind --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest + COMMAND valgrind --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.* WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin) if(CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/test/unittest/allocatorstest.cpp b/test/unittest/allocatorstest.cpp new file mode 100644 index 0000000..3f33724 --- /dev/null +++ b/test/unittest/allocatorstest.cpp @@ -0,0 +1,60 @@ +// 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 +// in compliance with the License. You may obtain a copy of the License at +// +// 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 +// specific language governing permissions and limitations under the License. + +#include "unittest.h" + +#include "rapidjson/allocators.h" + +using namespace rapidjson; + +template +void TestAllocator(Allocator& a) { + EXPECT_TRUE(a.Malloc(0) == 0); + + uint8_t* p = (uint8_t*)a.Malloc(100); + EXPECT_TRUE(p != 0); + for (size_t i = 0; i < 100; i++) + p[i] = (uint8_t)i; + + // Expand + uint8_t* q = (uint8_t*)a.Realloc(p, 100, 200); + EXPECT_TRUE(q != 0); + for (size_t i = 0; i < 100; i++) + EXPECT_EQ(i, q[i]); + for (size_t i = 100; i < 200; i++) + q[i] = (uint8_t)i; + + // Shrink + uint8_t *r = (uint8_t*)a.Realloc(q, 200, 150); + EXPECT_TRUE(r != 0); + for (size_t i = 0; i < 150; i++) + EXPECT_EQ(i, r[i]); + + Allocator::Free(r); +} + +TEST(Allocator, CrtAllocator) { + CrtAllocator a; + TestAllocator(a); +} + +TEST(Allocator, MemoryPoolAllocator) { + MemoryPoolAllocator<> a; + TestAllocator(a); + + for (int i = 1; i < 1000; i++) { + EXPECT_TRUE(a.Malloc(i) != 0); + EXPECT_LE(a.Size(), a.Capacity()); + } +} diff --git a/test/unittest/bigintegertest.cpp b/test/unittest/bigintegertest.cpp index e7b3b8f..a68e144 100644 --- a/test/unittest/bigintegertest.cpp +++ b/test/unittest/bigintegertest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 6ececf7..71cd777 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" #include "rapidjson/document.h" @@ -28,13 +22,11 @@ using namespace rapidjson; -template -void ParseTest() { - typedef GenericDocument, Allocator, StackAllocator> DocumentType; +template +void ParseCheck(DocumentType& doc) { typedef typename DocumentType::ValueType ValueType; - DocumentType doc; - doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); + EXPECT_FALSE(doc.HasParseError()); EXPECT_TRUE(doc.IsObject()); @@ -63,7 +55,7 @@ void ParseTest() { EXPECT_TRUE(doc.HasMember("pi")); const ValueType& pi = doc["pi"]; EXPECT_TRUE(pi.IsNumber()); - EXPECT_EQ(3.1416, pi.GetDouble()); + EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble()); EXPECT_TRUE(doc.HasMember("a")); const ValueType& a = doc["a"]; @@ -73,6 +65,28 @@ void ParseTest() { EXPECT_EQ(i + 1, a[i].GetUint()); } +template +void ParseTest() { + typedef GenericDocument, Allocator, StackAllocator> DocumentType; + DocumentType doc; + + const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "; + + doc.Parse(json); + ParseCheck(doc); + + doc.SetNull(); + StringStream s(json); + doc.template ParseStream<0>(s); + ParseCheck(doc); + + doc.SetNull(); + char *buffer = strdup(json); + doc.ParseInsitu(buffer); + ParseCheck(doc); + free(buffer); +} + TEST(Document, Parse) { ParseTest, CrtAllocator>(); ParseTest, MemoryPoolAllocator<> >(); @@ -81,14 +95,21 @@ TEST(Document, Parse) { } static FILE* OpenEncodedFile(const char* filename) { + const char *paths[] = { + "encodings/%s", + "bin/encodings/%s", + "../bin/encodings/%s", + "../../bin/encodings/%s", + "../../../bin/encodings/%s" + }; char buffer[1024]; - sprintf(buffer, "encodings/%s", filename); - FILE *fp = fopen(buffer, "rb"); - if (!fp) { - sprintf(buffer, "../../bin/encodings/%s", filename); - fp = fopen(buffer, "rb"); + for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { + sprintf(buffer, paths[i], filename); + FILE *fp = fopen(buffer, "rb"); + if (fp) + return fp; } - return fp; + return 0; } TEST(Document, ParseStream_EncodedInputStream) { @@ -223,6 +244,10 @@ TEST(Document, UserBuffer) { EXPECT_FALSE(doc.HasParseError()); EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer)); EXPECT_LE(parseAllocator.Size(), sizeof(parseBuffer)); + + // Cover MemoryPoolAllocator::Capacity() + EXPECT_LE(valueAllocator.Size(), valueAllocator.Capacity()); + EXPECT_LE(parseAllocator.Size(), parseAllocator.Capacity()); } // Issue 226: Value of string type should not point to NULL diff --git a/test/unittest/encodedstreamtest.cpp b/test/unittest/encodedstreamtest.cpp index 3580608..8cef208 100644 --- a/test/unittest/encodedstreamtest.cpp +++ b/test/unittest/encodedstreamtest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" #include "rapidjson/filereadstream.h" @@ -47,14 +41,21 @@ private: protected: static FILE* Open(const char* filename) { + const char *paths[] = { + "encodings/%s", + "bin/encodings/%s", + "../bin/encodings/%s", + "../../bin/encodings/%s", + "../../../bin/encodings/%s" + }; char buffer[1024]; - sprintf(buffer, "encodings/%s", filename); - FILE *fp = fopen(buffer, "rb"); - if (!fp) { - sprintf(buffer, "../../bin/encodings/%s", filename); - fp = fopen(buffer, "rb"); + for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { + sprintf(buffer, paths[i], filename); + FILE *fp = fopen(buffer, "rb"); + if (fp) + return fp; } - return fp; + return 0; } static char *ReadFile(const char* filename, bool appendPath, size_t* outLength) { @@ -112,10 +113,11 @@ protected: } EXPECT_EQ('\0', s.Peek()); free(data); + EXPECT_EQ(size, eis.Tell()); } } - void TestAutoUTFInputStream(const char *filename) { + void TestAutoUTFInputStream(const char *filename, bool expectHasBOM) { // Test FileReadStream { char buffer[16]; @@ -123,6 +125,7 @@ protected: ASSERT_TRUE(fp != 0); FileReadStream fs(fp, buffer, sizeof(buffer)); AutoUTFInputStream eis(fs); + EXPECT_EQ(expectHasBOM, eis.HasBOM()); StringStream s(json_); while (eis.Peek() != '\0') { unsigned expected, actual; @@ -140,6 +143,7 @@ protected: char* data = ReadFile(filename, true, &size); MemoryStream ms(data, size); AutoUTFInputStream eis(ms); + EXPECT_EQ(expectHasBOM, eis.HasBOM()); StringStream s(json_); while (eis.Peek() != '\0') { @@ -150,6 +154,7 @@ protected: } EXPECT_EQ('\0', s.Peek()); free(data); + EXPECT_EQ(size, eis.Tell()); } } @@ -257,16 +262,25 @@ TEST_F(EncodedStreamTest, EncodedInputStream) { } TEST_F(EncodedStreamTest, AutoUTFInputStream) { - TestAutoUTFInputStream("utf8.json"); - TestAutoUTFInputStream("utf8bom.json"); - TestAutoUTFInputStream("utf16le.json"); - TestAutoUTFInputStream("utf16lebom.json"); - TestAutoUTFInputStream("utf16be.json"); - TestAutoUTFInputStream("utf16bebom.json"); - TestAutoUTFInputStream("utf32le.json"); - TestAutoUTFInputStream("utf32lebom.json"); - TestAutoUTFInputStream("utf32be.json"); - TestAutoUTFInputStream("utf32bebom.json"); + TestAutoUTFInputStream("utf8.json", false); + TestAutoUTFInputStream("utf8bom.json", true); + TestAutoUTFInputStream("utf16le.json", false); + TestAutoUTFInputStream("utf16lebom.json",true); + TestAutoUTFInputStream("utf16be.json", false); + TestAutoUTFInputStream("utf16bebom.json",true); + TestAutoUTFInputStream("utf32le.json", false); + TestAutoUTFInputStream("utf32lebom.json",true); + TestAutoUTFInputStream("utf32be.json", false); + TestAutoUTFInputStream("utf32bebom.json", true); + + { + // Auto detection fail, use user defined UTF type + const char json[] = "{ }"; + MemoryStream ms(json, sizeof(json)); + AutoUTFInputStream eis(ms, kUTF8); + EXPECT_FALSE(eis.HasBOM()); + EXPECT_EQ(kUTF8, eis.GetType()); + } } TEST_F(EncodedStreamTest, EncodedOutputStream) { diff --git a/test/unittest/encodingstest.cpp b/test/unittest/encodingstest.cpp index 3beebe6..b697d91 100644 --- a/test/unittest/encodingstest.cpp +++ b/test/unittest/encodingstest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" #include "rapidjson/filereadstream.h" diff --git a/test/unittest/filestreamtest.cpp b/test/unittest/filestreamtest.cpp index a176332..2850b56 100644 --- a/test/unittest/filestreamtest.cpp +++ b/test/unittest/filestreamtest.cpp @@ -1,25 +1,18 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" -#include "rapidjson/filestream.h" #include "rapidjson/filereadstream.h" #include "rapidjson/filewritestream.h" #include "rapidjson/encodedstream.h" @@ -31,9 +24,21 @@ public: FileStreamTest() : filename_(), json_(), length_() {} virtual void SetUp() { - FILE *fp = fopen(filename_ = "data/sample.json", "rb"); - if (!fp) - fp = fopen(filename_ = "../../bin/data/sample.json", "rb"); + const char *paths[] = { + "data/sample.json", + "bin/data/sample.json", + "../bin/data/sample.json", + "../../bin/data/sample.json", + "../../../bin/data/sample.json" + }; + FILE* fp = 0; + for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { + fp = fopen(paths[i], "rb"); + if (fp) { + filename_ = paths[i]; + break; + } + } ASSERT_TRUE(fp != 0); fseek(fp, 0, SEEK_END); @@ -60,24 +65,6 @@ protected: size_t length_; }; -// Deprecated -//TEST_F(FileStreamTest, FileStream_Read) { -// FILE *fp = fopen(filename_, "rb"); -// ASSERT_TRUE(fp != 0); -// FileStream s(fp); -// -// for (size_t i = 0; i < length_; i++) { -// EXPECT_EQ(json_[i], s.Peek()); -// EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same -// EXPECT_EQ(json_[i], s.Take()); -// } -// -// EXPECT_EQ(length_, s.Tell()); -// EXPECT_EQ('\0', s.Peek()); -// -// fclose(fp); -//} - TEST_F(FileStreamTest, FileReadStream) { FILE *fp = fopen(filename_, "rb"); ASSERT_TRUE(fp != 0); diff --git a/test/unittest/itoatest.cpp b/test/unittest/itoatest.cpp new file mode 100644 index 0000000..5ceb99f --- /dev/null +++ b/test/unittest/itoatest.cpp @@ -0,0 +1,158 @@ +// 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 +// in compliance with the License. You may obtain a copy of the License at +// +// 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 +// specific language governing permissions and limitations under the License. + +#include "unittest.h" +#include "rapidjson/internal/itoa.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(type-limits) +#endif + +using namespace rapidjson::internal; + +template +struct Traits { +}; + +template <> +struct Traits { + enum { kBufferSize = 11 }; + enum { kMaxDigit = 10 }; + static uint32_t Negate(uint32_t x) { return x; }; +}; + +template <> +struct Traits { + enum { kBufferSize = 12 }; + enum { kMaxDigit = 10 }; + static int32_t Negate(int32_t x) { return -x; }; +}; + +template <> +struct Traits { + enum { kBufferSize = 21 }; + enum { kMaxDigit = 20 }; + static uint64_t Negate(uint64_t x) { return x; }; +}; + +template <> +struct Traits { + enum { kBufferSize = 22 }; + enum { kMaxDigit = 20 }; + static int64_t Negate(int64_t x) { return -x; }; +}; + +template +static void VerifyValue(T value, void(*f)(T, char*), char* (*g)(T, char*)) { + char buffer1[Traits::kBufferSize]; + char buffer2[Traits::kBufferSize]; + + f(value, buffer1); + *g(value, buffer2) = '\0'; + + + EXPECT_STREQ(buffer1, buffer2); +} + +template +static void Verify(void(*f)(T, char*), char* (*g)(T, char*)) { + // Boundary cases + VerifyValue(0, f, g); + VerifyValue(std::numeric_limits::min(), f, g); + VerifyValue(std::numeric_limits::max(), f, g); + + // 2^n - 1, 2^n, 10^n - 1, 10^n until overflow + for (uint32_t power = 2; power <= 10; power += 8) { + T i = 1, last; + do { + VerifyValue(i - 1, f, g); + VerifyValue(i, f, g); + if (std::numeric_limits::min() < 0) { + VerifyValue(Traits::Negate(i), f, g); + VerifyValue(Traits::Negate(i + 1), f, g); + } + last = i; + i *= power; + } while (last < i); + } +} + +static void u32toa_naive(uint32_t value, char* buffer) { + char temp[10]; + char *p = temp; + do { + *p++ = char(value % 10) + '0'; + value /= 10; + } while (value > 0); + + do { + *buffer++ = *--p; + } while (p != temp); + + *buffer = '\0'; +} + +static void i32toa_naive(int32_t value, char* buffer) { + uint32_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + u32toa_naive(u, buffer); +} + +static void u64toa_naive(uint64_t value, char* buffer) { + char temp[20]; + char *p = temp; + do { + *p++ = char(value % 10) + '0'; + value /= 10; + } while (value > 0); + + do { + *buffer++ = *--p; + } while (p != temp); + + *buffer = '\0'; +} + +static void i64toa_naive(int64_t value, char* buffer) { + uint64_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + u64toa_naive(u, buffer); +} + +TEST(itoa, u32toa) { + Verify(u32toa_naive, u32toa); +} + +TEST(itoa, i32toa) { + Verify(i32toa_naive, i32toa); +} + +TEST(itoa, u64toa) { + Verify(u64toa_naive, u64toa); +} + +TEST(itoa, i64toa) { + Verify(i64toa_naive, i64toa); +} + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif diff --git a/test/unittest/jsoncheckertest.cpp b/test/unittest/jsoncheckertest.cpp index caa1b8a..34f8569 100644 --- a/test/unittest/jsoncheckertest.cpp +++ b/test/unittest/jsoncheckertest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" @@ -25,9 +19,22 @@ using namespace rapidjson; static char* ReadFile(const char* filename, size_t& length) { - FILE *fp = fopen(filename, "rb"); - if (!fp) - fp = fopen(filename, "rb"); + const char *paths[] = { + "jsonchecker/%s", + "bin/jsonchecker/%s", + "../bin/jsonchecker/%s", + "../../bin/jsonchecker/%s", + "../../../bin/jsonchecker/%s" + }; + char buffer[1024]; + FILE *fp = 0; + for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { + sprintf(buffer, paths[i], filename); + fp = fopen(buffer, "rb"); + if (fp) + break; + } + if (!fp) return 0; @@ -51,17 +58,13 @@ TEST(JsonChecker, Reader) { if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting. continue; - sprintf(filename, "jsonchecker/fail%d.json", i); + sprintf(filename, "fail%d.json", i); size_t length; char* json = ReadFile(filename, length); if (!json) { - sprintf(filename, "../../bin/jsonchecker/fail%d.json", i); - json = ReadFile(filename, length); - if (!json) { - printf("jsonchecker file %s not found", filename); - ADD_FAILURE(); - continue; - } + printf("jsonchecker file %s not found", filename); + ADD_FAILURE(); + continue; } GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) @@ -76,16 +79,12 @@ TEST(JsonChecker, Reader) { // passX.json for (int i = 1; i <= 3; i++) { - sprintf(filename, "jsonchecker/pass%d.json", i); + sprintf(filename, "pass%d.json", i); size_t length; char* json = ReadFile(filename, length); if (!json) { - sprintf(filename, "../../bin/jsonchecker/pass%d.json", i); - json = ReadFile(filename, length); - if (!json) { - printf("jsonchecker file %s not found", filename); - continue; - } + printf("jsonchecker file %s not found", filename); + continue; } GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) diff --git a/test/unittest/namespacetest.cpp b/test/unittest/namespacetest.cpp index ed74ae3..5db83cc 100644 --- a/test/unittest/namespacetest.cpp +++ b/test/unittest/namespacetest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" diff --git a/test/unittest/prettywritertest.cpp b/test/unittest/prettywritertest.cpp new file mode 100644 index 0000000..1a63c82 --- /dev/null +++ b/test/unittest/prettywritertest.cpp @@ -0,0 +1,161 @@ +// 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 +// in compliance with the License. You may obtain a copy of the License at +// +// 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 +// specific language governing permissions and limitations under the License. + +#include "unittest.h" +#include "rapidjson/reader.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/filewritestream.h" + +using namespace rapidjson; + +static const char kJson[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,-1],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}"; +static const char kPrettyJson[] = +"{\n" +" \"hello\": \"world\",\n" +" \"t\": true,\n" +" \"f\": false,\n" +" \"n\": null,\n" +" \"i\": 123,\n" +" \"pi\": 3.1416,\n" +" \"a\": [\n" +" 1,\n" +" 2,\n" +" 3,\n" +" -1\n" +" ],\n" +" \"u64\": 1234567890123456789,\n" +" \"i64\": -1234567890123456789\n" +"}"; + +TEST(PrettyWriter, Basic) { + StringBuffer buffer; + PrettyWriter writer(buffer); + Reader reader; + StringStream s(kJson); + reader.Parse(s, writer); + EXPECT_STREQ(kPrettyJson, buffer.GetString()); +} + +TEST(PrettyWriter, SetIndent) { + StringBuffer buffer; + PrettyWriter writer(buffer); + writer.SetIndent('\t', 1); + Reader reader; + StringStream s(kJson); + reader.Parse(s, writer); + EXPECT_STREQ( + "{\n" + "\t\"hello\": \"world\",\n" + "\t\"t\": true,\n" + "\t\"f\": false,\n" + "\t\"n\": null,\n" + "\t\"i\": 123,\n" + "\t\"pi\": 3.1416,\n" + "\t\"a\": [\n" + "\t\t1,\n" + "\t\t2,\n" + "\t\t3,\n" + "\t\t-1\n" + "\t],\n" + "\t\"u64\": 1234567890123456789,\n" + "\t\"i64\": -1234567890123456789\n" + "}", + buffer.GetString()); +} + +TEST(PrettyWriter, String) { + StringBuffer buffer; + PrettyWriter writer(buffer); + EXPECT_TRUE(writer.StartArray()); + EXPECT_TRUE(writer.String("Hello\n")); + EXPECT_TRUE(writer.EndArray()); + EXPECT_STREQ("[\n \"Hello\\n\"\n]", buffer.GetString()); +} + +#if RAPIDJSON_HAS_STDSTRING +TEST(PrettyWriter, String_STDSTRING) { + StringBuffer buffer; + PrettyWriter writer(buffer); + EXPECT_TRUE(writer.StartArray()); + EXPECT_TRUE(writer.String(std::string("Hello\n"))); + EXPECT_TRUE(writer.EndArray()); + EXPECT_STREQ("[\n \"Hello\\n\"\n]", buffer.GetString()); +} +#endif + +#include + +class OStreamWrapper { +public: + typedef char Ch; + + OStreamWrapper(std::ostream& os) : os_(os) {} + + Ch Peek() const { assert(false); return '\0'; } + Ch Take() { assert(false); return '\0'; } + size_t Tell() const { return 0; } + + Ch* PutBegin() { assert(false); return 0; } + void Put(Ch c) { os_.put(c); } + void Flush() { os_.flush(); } + size_t PutEnd(Ch*) { assert(false); return 0; } + +private: + OStreamWrapper(const OStreamWrapper&); + OStreamWrapper& operator=(const OStreamWrapper&); + + std::ostream& os_; +}; + +// For covering PutN() generic version +TEST(PrettyWriter, OStreamWrapper) { + StringStream s(kJson); + + std::stringstream ss; + OStreamWrapper os(ss); + + PrettyWriter writer(os); + + Reader reader; + reader.Parse(s, writer); + + std::string actual = ss.str(); + EXPECT_STREQ(kPrettyJson, actual.c_str()); +} + +// For covering FileWriteStream::PutN() +TEST(PrettyWriter, FileWriteStream) { + char filename[L_tmpnam]; + FILE* fp = TempFile(filename); + char buffer[16]; + FileWriteStream os(fp, buffer, sizeof(buffer)); + PrettyWriter writer(os); + Reader reader; + StringStream s(kJson); + reader.Parse(s, writer); + fclose(fp); + + fp = fopen(filename, "rb"); + fseek(fp, 0, SEEK_END); + size_t size = (size_t)ftell(fp); + fseek(fp, 0, SEEK_SET); + char* json = (char*)malloc(size + 1); + size_t readLength = fread(json, 1, size, fp); + json[readLength] = '\0'; + fclose(fp); + remove(filename); + EXPECT_STREQ(kPrettyJson, json); + free(json); +} \ No newline at end of file diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 64904b0..bee19a8 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" @@ -30,6 +24,7 @@ using namespace rapidjson; #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(float-equal) #endif template @@ -187,16 +182,20 @@ static void TestParseDouble() { Reader reader; \ ASSERT_EQ(kParseErrorNone, reader.Parse(s, h).Code()); \ EXPECT_EQ(1u, h.step_); \ + internal::Double e(x), a(h.actual_); \ if (fullPrecision) { \ - EXPECT_EQ(x, h.actual_); \ - if (x != h.actual_) \ - printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", str, h.actual_, x); \ + EXPECT_EQ(e.Uint64Value(), a.Uint64Value()); \ + if (e.Uint64Value() != a.Uint64Value()) \ + printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", str, h.actual_, x); \ } \ - else \ + else { \ + EXPECT_EQ(e.Sign(), a.Sign()); /* for 0.0 != -0.0 */ \ EXPECT_DOUBLE_EQ(x, h.actual_); \ + } \ } TEST_DOUBLE(fullPrecision, "0.0", 0.0); + TEST_DOUBLE(fullPrecision, "-0.0", -0.0); // For checking issue #289 TEST_DOUBLE(fullPrecision, "1.0", 1.0); TEST_DOUBLE(fullPrecision, "-1.0", -1.0); TEST_DOUBLE(fullPrecision, "1.5", 1.5); @@ -220,13 +219,19 @@ static void TestParseDouble() { TEST_DOUBLE(fullPrecision, "2.2250738585072009e-308", 2.2250738585072009e-308); // Max subnormal double TEST_DOUBLE(fullPrecision, "2.2250738585072014e-308", 2.2250738585072014e-308); // Min normal positive double TEST_DOUBLE(fullPrecision, "1.7976931348623157e+308", 1.7976931348623157e+308); // Max double - TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow - TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) - TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) - TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120 - TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise + TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow + TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) + TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) + TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120 + TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0); TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + TEST_DOUBLE(fullPrecision, "1e-00011111111111", 0.0); // Issue #313 + TEST_DOUBLE(fullPrecision, "-1e-00011111111111", -0.0); + TEST_DOUBLE(fullPrecision, "1e-214748363", 0.0); // Maximum supported negative exponent + TEST_DOUBLE(fullPrecision, "1e-214748364", 0.0); + TEST_DOUBLE(fullPrecision, "1e-21474836311", 0.0); + 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 @@ -249,6 +254,32 @@ static void TestParseDouble() { TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203124", 1.0); // previous double TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203126", 1.00000000000000022); // next double + // Numbers from https://github.com/floitsch/double-conversion/blob/master/test/cctest/test-strtod.cc + + TEST_DOUBLE(fullPrecision, "72057594037927928.0", 72057594037927928.0); + TEST_DOUBLE(fullPrecision, "72057594037927936.0", 72057594037927936.0); + TEST_DOUBLE(fullPrecision, "72057594037927932.0", 72057594037927936.0); + TEST_DOUBLE(fullPrecision, "7205759403792793199999e-5", 72057594037927928.0); + TEST_DOUBLE(fullPrecision, "7205759403792793200001e-5", 72057594037927936.0); + + TEST_DOUBLE(fullPrecision, "9223372036854774784.0", 9223372036854774784.0); + TEST_DOUBLE(fullPrecision, "9223372036854775808.0", 9223372036854775808.0); + TEST_DOUBLE(fullPrecision, "9223372036854775296.0", 9223372036854775808.0); + TEST_DOUBLE(fullPrecision, "922337203685477529599999e-5", 9223372036854774784.0); + TEST_DOUBLE(fullPrecision, "922337203685477529600001e-5", 9223372036854775808.0); + + TEST_DOUBLE(fullPrecision, "10141204801825834086073718800384", 10141204801825834086073718800384.0); + TEST_DOUBLE(fullPrecision, "10141204801825835211973625643008", 10141204801825835211973625643008.0); + TEST_DOUBLE(fullPrecision, "10141204801825834649023672221696", 10141204801825835211973625643008.0); + TEST_DOUBLE(fullPrecision, "1014120480182583464902367222169599999e-5", 10141204801825834086073718800384.0); + TEST_DOUBLE(fullPrecision, "1014120480182583464902367222169600001e-5", 10141204801825835211973625643008.0); + + TEST_DOUBLE(fullPrecision, "5708990770823838890407843763683279797179383808", 5708990770823838890407843763683279797179383808.0); + TEST_DOUBLE(fullPrecision, "5708990770823839524233143877797980545530986496", 5708990770823839524233143877797980545530986496.0); + TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185152", 5708990770823839524233143877797980545530986496.0); + TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185151999e-3", 5708990770823838890407843763683279797179383808.0); + TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185152001e-3", 5708990770823839524233143877797980545530986496.0); + { char n1e308[310]; // '1' followed by 308 '0' n1e308[0] = '1'; @@ -258,28 +289,53 @@ static void TestParseDouble() { TEST_DOUBLE(fullPrecision, n1e308, 1E308); } -#if 0 // Very slow - static const unsigned count = 10000000; - // Random test for double + // Cover trimming + TEST_DOUBLE(fullPrecision, +"2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508" +"7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012" +"9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306" +"6665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505" +"1080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621" +"5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844" +"2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042" +"7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901" +"e-308", + 2.2250738585072014e-308); + { + static const unsigned count = 100; // Tested with 1000000 locally Random r; + Reader reader; // Reusing reader to prevent heap allocation - for (unsigned i = 0; i < count; i++) { - internal::Double d; - do { + // Exhaustively test different exponents with random significant + for (uint64_t exp = 0; exp < 2047; exp++) { + ; + for (unsigned i = 0; i < count; i++) { // Need to call r() in two statements for cross-platform coherent sequence. - uint64_t u = uint64_t(r()) << 32; + uint64_t u = (exp << 52) | uint64_t(r() & 0x000FFFFF) << 32; u |= uint64_t(r()); - d = internal::Double(u); - } while (d.IsNan() || d.IsInf()/* || !d.IsNormal()*/); // Also work for subnormal now + internal::Double d = internal::Double(u); - char buffer[32]; - *internal::dtoa(d.Value(), buffer) = '\0'; - TEST_DOUBLE(fullPrecision, buffer, d.Value()); + char buffer[32]; + *internal::dtoa(d.Value(), buffer) = '\0'; + + StringStream s(buffer); + ParseDoubleHandler h; + ASSERT_EQ(kParseErrorNone, reader.Parse(s, h).Code()); + EXPECT_EQ(1u, h.step_); + internal::Double a(h.actual_); + if (fullPrecision) { + EXPECT_EQ(d.Uint64Value(), a.Uint64Value()); + if (d.Uint64Value() != a.Uint64Value()) + printf(" String: %sn Actual: %.17gnExpected: %.17gn", buffer, h.actual_, d.Value()); + } + else { + EXPECT_EQ(d.Sign(), a.Sign()); /* for 0.0 != -0.0 */ + EXPECT_DOUBLE_EQ(d.Value(), h.actual_); + } + } } } -#endif - #undef TEST_DOUBLE } @@ -482,6 +538,17 @@ TEST(Reader, ParseString_Transcoding) { EXPECT_EQ(StrLen(e), h.length_); } +TEST(Reader, ParseString_TranscodingWithValidation) { + const char* x = "\"Hello\""; + const wchar_t* e = L"Hello"; + GenericStringStream > is(x); + GenericReader, UTF16<> > reader; + ParseStringHandler > h; + reader.Parse(is, h); + EXPECT_EQ(0, StrCmp::Ch>(e, h.str_)); + EXPECT_EQ(StrLen(e), h.length_); +} + TEST(Reader, ParseString_NonDestructive) { StringStream s("\"Hello\\nWorld\""); ParseStringHandler > h; @@ -491,24 +558,31 @@ TEST(Reader, ParseString_NonDestructive) { EXPECT_EQ(11u, h.length_); } -ParseErrorCode TestString(const char* str) { - StringStream s(str); - BaseReaderHandler<> h; - Reader reader; - reader.Parse(s, h); +template +ParseErrorCode TestString(const typename Encoding::Ch* str) { + GenericStringStream s(str); + BaseReaderHandler h; + GenericReader reader; + reader.template Parse(s, h); return reader.GetParseErrorCode(); } TEST(Reader, ParseString_Error) { #define TEST_STRING_ERROR(errorCode, str)\ - EXPECT_EQ(errorCode, TestString(str)) + EXPECT_EQ(errorCode, TestString >(str)) #define ARRAY(...) { __VA_ARGS__ } -#define TEST_STRINGENCODING_ERROR(Encoding, utype, array) \ +#define TEST_STRINGENCODING_ERROR(Encoding, TargetEncoding, utype, array) \ { \ static const utype ue[] = array; \ static const Encoding::Ch* e = reinterpret_cast(&ue[0]); \ - EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString(e));\ + EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString(e));\ + /* decode error */\ + GenericStringStream s(e);\ + BaseReaderHandler h;\ + GenericReader reader;\ + reader.Parse(s, h);\ + EXPECT_EQ(kParseErrorStringInvalidEncoding, reader.GetParseErrorCode());\ } // Invalid escape character in string. @@ -517,6 +591,10 @@ TEST(Reader, ParseString_Error) { // Incorrect hex digit after \\u escape in string. TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]"); + // Quotation in \\u escape in string (Issue #288) + TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]"); + TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFFF\"]"); + // The surrogate pair in string is invalid. TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]"); TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]"); @@ -533,7 +611,7 @@ TEST(Reader, ParseString_Error) { char e[] = { '[', '\"', 0, '\"', ']', '\0' }; for (unsigned char c = 0x80u; c <= 0xBFu; c++) { e[2] = c; - ParseErrorCode error = TestString(e); + ParseErrorCode error = TestString >(e); EXPECT_EQ(kParseErrorStringInvalidEncoding, error); if (error != kParseErrorStringInvalidEncoding) std::cout << (unsigned)(unsigned char)c << std::endl; @@ -552,30 +630,40 @@ TEST(Reader, ParseString_Error) { // 4 Overlong sequences // 4.1 Examples of an overlong ASCII character - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0')); + 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 - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0')); + 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 - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0')); + 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')); // 5 Illegal code positions // 5.1 Single UTF-16 surrogates - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0')); + + // Malform UTF-16 sequences + TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xDC00, 0xDC00, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xD800, 0xD800, '\"', ']', '\0')); + + // Malform UTF-32 sequence + TEST_STRINGENCODING_ERROR(UTF32<>, UTF8<>, unsigned, ARRAY('[', '\"', 0x110000, '\"', ']', '\0')); + + // Malform ASCII sequence + TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x80), '\"', ']', '\0')); #undef ARRAY #undef TEST_STRINGARRAY_ERROR @@ -655,7 +743,7 @@ struct ParseObjectHandler : BaseReaderHandler, ParseObjectHandler> { } } bool Uint(unsigned i) { return Int(i); } - bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_EQ(3.1416, d); step_++; return true; } + bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; } bool String(const char* str, size_t, bool) { switch(step_) { case 1: EXPECT_STREQ("hello", str); step_++; return true; @@ -965,6 +1053,17 @@ TEST(Reader, IterativeParsing_ErrorHandling) { TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u); TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u); TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u); + TESTERRORHANDLING("{\"a: 1", kParseErrorStringMissQuotationMark, 5u); + + // Any JSON value can be a valid root element in RFC7159. + TESTERRORHANDLING("\"ab", kParseErrorStringMissQuotationMark, 2u); + TESTERRORHANDLING("truE", kParseErrorValueInvalid, 3u); + TESTERRORHANDLING("False", kParseErrorValueInvalid, 0u); + TESTERRORHANDLING("true, false", kParseErrorDocumentRootNotSingular, 4u); + TESTERRORHANDLING("false, false", kParseErrorDocumentRootNotSingular, 5u); + TESTERRORHANDLING("nulL", kParseErrorValueInvalid, 3u); + TESTERRORHANDLING("null , null", kParseErrorDocumentRootNotSingular, 5u); + TESTERRORHANDLING("1a", kParseErrorDocumentRootNotSingular, 1u); } template > @@ -1168,6 +1267,59 @@ TEST(Reader, IterativeParsing_ShortCircuit) { } } +// For covering BaseReaderHandler default functions +TEST(Reader, BaseReaderHandler_Default) { + BaseReaderHandler<> h; + Reader reader; + StringStream is("[null, true, -1, 1, -1234567890123456789, 1234567890123456789, 3.14, \"s\", { \"a\" : 1 }]"); + EXPECT_TRUE(reader.Parse(is, h)); +} + +template +struct TerminateHandler { + bool Null() { return e != 0; } + bool Bool(bool) { return e != 1; } + bool Int(int) { return e != 2; } + bool Uint(unsigned) { return e != 3; } + bool Int64(int64_t) { return e != 4; } + bool Uint64(uint64_t) { return e != 5; } + bool Double(double) { return e != 6; } + bool String(const char*, SizeType, bool) { return e != 7; } + bool StartObject() { return e != 8; } + bool Key(const char*, SizeType, bool) { return e != 9; } + bool EndObject(SizeType) { return e != 10; } + bool StartArray() { return e != 11; } + bool EndArray(SizeType) { return e != 12; } +}; + +#define TEST_TERMINATION(e, json)\ +{\ + Reader reader;\ + TerminateHandler h;\ + StringStream is(json);\ + EXPECT_FALSE(reader.Parse(is, h));\ + EXPECT_EQ(kParseErrorTermination, reader.GetParseErrorCode());\ +} + +TEST(Reader, ParseTerminationByHandler) { + TEST_TERMINATION(0, "[null"); + TEST_TERMINATION(1, "[true"); + TEST_TERMINATION(1, "[false"); + TEST_TERMINATION(2, "[-1"); + TEST_TERMINATION(3, "[1"); + TEST_TERMINATION(4, "[-1234567890123456789"); + TEST_TERMINATION(5, "[1234567890123456789"); + TEST_TERMINATION(6, "[0.5]"); + TEST_TERMINATION(7, "[\"a\""); + TEST_TERMINATION(8, "[{"); + TEST_TERMINATION(9, "[{\"a\""); + TEST_TERMINATION(10, "[{}"); + TEST_TERMINATION(10, "[{\"a\":1}"); // non-empty object + TEST_TERMINATION(11, "{\"a\":["); + TEST_TERMINATION(12, "{\"a\":[]"); + TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array +} + #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif diff --git a/test/unittest/simdtest.cpp b/test/unittest/simdtest.cpp new file mode 100644 index 0000000..c8f4587 --- /dev/null +++ b/test/unittest/simdtest.cpp @@ -0,0 +1,68 @@ +// 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 +// in compliance with the License. You may obtain a copy of the License at +// +// 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 +// specific language governing permissions and limitations under the License. + +// Since Travis CI installs old Valgrind 3.7.0, which fails with some SSE4.2 +// The unit tests prefix with SIMD should be skipped by Valgrind test + +// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler. +// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported. +#if defined(__SSE4_2__) +# define RAPIDJSON_SSE42 +#elif defined(__SSE2__) +# define RAPIDJSON_SSE2 +#endif + +#define RAPIDJSON_NAMESPACE rapidjson_simd + +#include "unittest.h" + +#include "rapidjson/reader.h" + +using namespace rapidjson_simd; + +#ifdef RAPIDJSON_SSE2 +#define SIMD_SUFFIX(name) name##_SSE2 +#elif defined(RAPIDJSON_SSE42) +#define SIMD_SUFFIX(name) name##_SSE42 +#else +#define SIMD_SUFFIX(name) name +#endif + +template +void TestSkipWhitespace() { + for (int step = 1; step < 32; step++) { + char buffer[1025]; + for (size_t i = 0; i < 1024; i++) + buffer[i] = " \t\r\n"[i % 4]; + for (size_t i = 0; i < 1024; i += step) + buffer[i] = 'X'; + buffer[1024] = '\0'; + + StreamType s(buffer); + size_t i = 0; + for (;;) { + SkipWhitespace(s); + if (s.Peek() == '\0') + break; + EXPECT_EQ(i, s.Tell()); + EXPECT_EQ('X', s.Take()); + i += step; + } + } +} + +TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) { + TestSkipWhitespace(); + TestSkipWhitespace(); +} diff --git a/test/unittest/stringbuffertest.cpp b/test/unittest/stringbuffertest.cpp index 71e0caf..fbacf51 100644 --- a/test/unittest/stringbuffertest.cpp +++ b/test/unittest/stringbuffertest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" #include "rapidjson/stringbuffer.h" @@ -54,6 +48,10 @@ TEST(StringBuffer, Push) { buffer.Push(5); EXPECT_EQ(5u, buffer.GetSize()); + + // Causes sudden expansion to make the stack's capacity equal to size + buffer.Push(65536u); + EXPECT_EQ(5u + 65536u, buffer.GetSize()); } TEST(StringBuffer, Pop) { diff --git a/test/unittest/strtodtest.cpp b/test/unittest/strtodtest.cpp index d8849be..dc2378b 100644 --- a/test/unittest/strtodtest.cpp +++ b/test/unittest/strtodtest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" diff --git a/test/unittest/unittest.cpp b/test/unittest/unittest.cpp index 4604d9d..4e3bc11 100644 --- a/test/unittest/unittest.cpp +++ b/test/unittest/unittest.cpp @@ -1,28 +1,25 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" +#include "rapidjson/rapidjson.h" int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); + std::cout << "RapidJSON v" << RAPIDJSON_VERSION_STRING << std::endl; + #if _MSC_VER _CrtMemState memoryState = { 0 }; _CrtMemCheckpoint(&memoryState); diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index 800fbab..dbba754 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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 UNITTEST_H_ #define UNITTEST_H_ diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index b2647c0..1922222 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" #include "rapidjson/document.h" @@ -203,12 +197,28 @@ TEST(Value, EqualtoOperator) { EXPECT_TRUE(z.RemoveMember("t")); TestUnequal(x, z); TestEqual(y, z); - y.AddMember("t", true, crtAllocator); - z.AddMember("t", true, z.GetAllocator()); + y.AddMember("t", false, crtAllocator); + z.AddMember("t", false, z.GetAllocator()); + TestUnequal(x, y); + TestUnequal(z, x); + y["t"] = true; + z["t"] = true; TestEqual(x, y); TestEqual(y, z); TestEqual(z, x); + // Swapping element order is not OK + x["a"][0].Swap(x["a"][1]); + TestUnequal(x, y); + x["a"][0].Swap(x["a"][1]); + TestEqual(x, y); + + // Array of different size + x["a"].PushBack(4, allocator); + TestUnequal(x, y); + x["a"].PopBack(); + TestEqual(x, y); + // Issue #129: compare Uint64 x.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0)); y.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)); @@ -229,6 +239,13 @@ void TestCopyFrom() { EXPECT_STREQ(v1.GetString(), v2.GetString()); EXPECT_EQ(v1.GetString(), v2.GetString()); // string NOT copied + v1.SetString("bar", a); // copy string + v2.CopyFrom(v1, a); + EXPECT_TRUE(v1.GetType() == v2.GetType()); + EXPECT_STREQ(v1.GetString(), v2.GetString()); + EXPECT_NE(v1.GetString(), v2.GetString()); // string copied + + v1.SetArray().PushBack(1234, a); v2.CopyFrom(v1, a); EXPECT_TRUE(v2.IsArray()); @@ -339,7 +356,7 @@ TEST(Value, Int) { EXPECT_EQ(1234u, x.GetUint()); EXPECT_EQ(1234, x.GetInt64()); EXPECT_EQ(1234u, x.GetUint64()); - EXPECT_EQ(1234, x.GetDouble()); + EXPECT_NEAR(1234.0, x.GetDouble(), 0.0); //EXPECT_EQ(1234, (int)x); //EXPECT_EQ(1234, (unsigned)x); //EXPECT_EQ(1234, (int64_t)x); @@ -397,7 +414,7 @@ TEST(Value, Uint) { EXPECT_TRUE(x.IsUint()); EXPECT_TRUE(x.IsInt64()); EXPECT_TRUE(x.IsUint64()); - EXPECT_EQ(1234.0, x.GetDouble()); // Number can always be cast as double but !IsDouble(). + EXPECT_NEAR(1234.0, x.GetDouble(), 0.0); // Number can always be cast as double but !IsDouble(). EXPECT_FALSE(x.IsDouble()); EXPECT_FALSE(x.IsNull()); @@ -462,10 +479,19 @@ TEST(Value, Int64) { z.SetInt64(2147483648LL); // 2^31, cannot cast as int EXPECT_FALSE(z.IsInt()); EXPECT_TRUE(z.IsUint()); + EXPECT_NEAR(2147483648.0, z.GetDouble(), 0.0); z.SetInt64(4294967296LL); // 2^32, cannot cast as uint EXPECT_FALSE(z.IsInt()); EXPECT_FALSE(z.IsUint()); + EXPECT_NEAR(4294967296.0, z.GetDouble(), 0.0); + + z.SetInt64(-2147483649LL); // -2^31-1, cannot cast as int + EXPECT_FALSE(z.IsInt()); + EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0); + + z.SetInt64(static_cast(RAPIDJSON_UINT64_C2(0x80000000, 00000000))); + EXPECT_DOUBLE_EQ(-9223372036854775808.0, z.GetDouble()); } TEST(Value, Uint64) { @@ -508,16 +534,15 @@ TEST(Value, Uint64) { z.SetUint64(9223372036854775808uLL); // 2^63 cannot cast as int64 EXPECT_FALSE(z.IsInt64()); - - // Issue 48 - EXPECT_EQ(9223372036854775808uLL, z.GetUint64()); + EXPECT_EQ(9223372036854775808uLL, z.GetUint64()); // Issue 48 + EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble()); } TEST(Value, Double) { // Constructor with double Value x(12.34); EXPECT_EQ(kNumberType, x.GetType()); - EXPECT_EQ(12.34, x.GetDouble()); + EXPECT_NEAR(12.34, x.GetDouble(), 0.0); EXPECT_TRUE(x.IsNumber()); EXPECT_TRUE(x.IsDouble()); @@ -533,10 +558,10 @@ TEST(Value, Double) { // SetDouble() Value z; z.SetDouble(12.34); - EXPECT_EQ(12.34, z.GetDouble()); + EXPECT_NEAR(12.34, z.GetDouble(), 0.0); z = 56.78; - EXPECT_EQ(56.78, z.GetDouble()); + EXPECT_NEAR(56.78, z.GetDouble(), 0.0); } TEST(Value, String) { @@ -977,6 +1002,7 @@ TEST(Value, Object) { EXPECT_STREQ("Banana", x["B"].GetString()); EXPECT_STREQ("CherryD", x[C0D].GetString()); EXPECT_STREQ("CherryD", x[othername].GetString()); + EXPECT_THROW(x["nonexist"], AssertException); // const operator[] EXPECT_STREQ("Apple", y["A"].GetString()); @@ -1041,13 +1067,15 @@ TEST(Value, Object) { EXPECT_FALSE(citr >= itr); // RemoveMember() - x.RemoveMember("A"); + EXPECT_TRUE(x.RemoveMember("A")); EXPECT_FALSE(x.HasMember("A")); - x.RemoveMember("B"); + EXPECT_TRUE(x.RemoveMember("B")); EXPECT_FALSE(x.HasMember("B")); - x.RemoveMember(othername); + EXPECT_FALSE(x.RemoveMember("nonexist")); + + EXPECT_TRUE(x.RemoveMember(othername)); EXPECT_FALSE(x.HasMember(name)); EXPECT_TRUE(x.MemberBegin() == x.MemberEnd()); @@ -1237,3 +1265,46 @@ TEST(Value, AllocateShortString) { TestShortStringOptimization("123456789012345"); // edge case: 15 chars in 64-bit mode (=> short string) TestShortStringOptimization("1234567890123456"); // edge case: 16 chars in 64-bit mode (=> regular string) } + +template +struct TerminateHandler { + bool Null() { return e != 0; } + bool Bool(bool) { return e != 1; } + bool Int(int) { return e != 2; } + bool Uint(unsigned) { return e != 3; } + bool Int64(int64_t) { return e != 4; } + bool Uint64(uint64_t) { return e != 5; } + bool Double(double) { return e != 6; } + bool String(const char*, SizeType, bool) { return e != 7; } + bool StartObject() { return e != 8; } + bool Key(const char*, SizeType, bool) { return e != 9; } + bool EndObject(SizeType) { return e != 10; } + bool StartArray() { return e != 11; } + bool EndArray(SizeType) { return e != 12; } +}; + +#define TEST_TERMINATION(e, json)\ +{\ + Document d; \ + EXPECT_FALSE(d.Parse(json).HasParseError()); \ + Reader reader; \ + TerminateHandler h;\ + EXPECT_FALSE(d.Accept(h));\ +} + +TEST(Value, AcceptTerminationByHandler) { + TEST_TERMINATION(0, "[null]"); + TEST_TERMINATION(1, "[true]"); + TEST_TERMINATION(1, "[false]"); + TEST_TERMINATION(2, "[-1]"); + TEST_TERMINATION(3, "[2147483648]"); + TEST_TERMINATION(4, "[-1234567890123456789]"); + TEST_TERMINATION(5, "[9223372036854775808]"); + TEST_TERMINATION(6, "[0.5]"); + TEST_TERMINATION(7, "[\"a\"]"); + TEST_TERMINATION(8, "[{}]"); + TEST_TERMINATION(9, "[{\"a\":1}]"); + TEST_TERMINATION(10, "[{}]"); + TEST_TERMINATION(11, "{\"a\":[]}"); + TEST_TERMINATION(12, "{\"a\":[]}"); +} diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 0ef1423..2adb551 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -1,22 +1,16 @@ -// Copyright (C) 2011 Milo Yip +// 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. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// http://opensource.org/licenses/MIT // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// 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" @@ -46,7 +40,7 @@ TEST(Writer, Compact) { StringBuffer buffer; \ Writer writer(buffer); \ Reader reader; \ - reader.Parse<0>(s, writer); \ + reader.Parse(s, writer); \ EXPECT_STREQ(json, buffer.GetString()); \ EXPECT_TRUE(writer.IsComplete()); \ } @@ -89,10 +83,27 @@ TEST(Writer, String) { TEST_ROUNDTRIP("[\"Hello\"]"); TEST_ROUNDTRIP("[\"Hello\\u0000World\"]"); TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]"); + +#if RAPIDJSON_HAS_STDSTRING + { + StringBuffer buffer; + Writer writer(buffer); + writer.String(std::string("Hello\n")); + EXPECT_STREQ("\"Hello\\n\"", buffer.GetString()); + } +#endif } TEST(Writer, Double) { TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]"); + TEST_ROUNDTRIP("0.0"); + TEST_ROUNDTRIP("-0.0"); // Issue #289 + TEST_ROUNDTRIP("1e30"); + TEST_ROUNDTRIP("1.0"); + TEST_ROUNDTRIP("5e-324"); // Min subnormal positive double + TEST_ROUNDTRIP("2.225073858507201e-308"); // Max subnormal positive double + TEST_ROUNDTRIP("2.2250738585072014e-308"); // Min normal positive double + TEST_ROUNDTRIP("1.7976931348623157e308"); // Max double } @@ -152,7 +163,7 @@ private: }; TEST(Writer, OStreamWrapper) { - StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "); + StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3], \"u64\": 1234567890123456789, \"i64\":-1234567890123456789 } "); std::stringstream ss; OStreamWrapper os(ss); @@ -163,7 +174,7 @@ TEST(Writer, OStreamWrapper) { reader.Parse<0>(s, writer); std::string actual = ss.str(); - 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],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}", actual.c_str()); } TEST(Writer, AssertRootMayBeAnyValue) { @@ -306,3 +317,61 @@ TEST(Writer, RootValueIsComplete) { T(writer.String("")); #undef T } + +TEST(Writer, InvalidEncoding) { + // Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt + { + GenericStringBuffer > buffer; + Writer >, UTF8<>, UTF16<> > writer(buffer); + writer.StartArray(); + EXPECT_FALSE(writer.String("\xfe")); + EXPECT_FALSE(writer.String("\xff")); + EXPECT_FALSE(writer.String("\xfe\xfe\xff\xff")); + writer.EndArray(); + } + + // Fail in encoding + { + StringBuffer buffer; + Writer > writer(buffer); + static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF + EXPECT_FALSE(writer.String(s)); + } + + // Fail in unicode escaping in ASCII output + { + StringBuffer buffer; + Writer, ASCII<> > writer(buffer); + static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF + EXPECT_FALSE(writer.String(s)); + } +} + +TEST(Writer, InvalidEventSequence) { + // {] + { + StringBuffer buffer; + Writer writer(buffer); + writer.StartObject(); + EXPECT_THROW(writer.EndArray(), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } + + // [} + { + StringBuffer buffer; + Writer writer(buffer); + writer.StartArray(); + EXPECT_THROW(writer.EndObject(), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } + + // { 1: + { + StringBuffer buffer; + Writer writer(buffer); + writer.StartObject(); + EXPECT_THROW(writer.Int(1), AssertException); + EXPECT_FALSE(writer.IsComplete()); + } +}