Merge pull request #304 from miloyip/issue298_coverage
100% line of code coverage
This commit is contained in:
commit
75ee552f49
@ -21,7 +21,7 @@ before_install:
|
||||
- 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
|
||||
- if [ "$CC" = "gcc" ] && [ "CONF" = "debug" ]; then sudo pip install cpp-coveralls; export GCOV_FLAGS='--coverage'; fi
|
||||
|
||||
install: true
|
||||
|
||||
@ -48,4 +48,4 @@ script:
|
||||
- make travis_doc
|
||||
|
||||
after_success:
|
||||
- coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes
|
||||
- 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
|
||||
|
@ -1459,17 +1459,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:
|
||||
@ -1753,7 +1750,7 @@ public:
|
||||
*/
|
||||
template <unsigned parseFlags, typename InputStream>
|
||||
GenericDocument& ParseStream(InputStream& is) {
|
||||
return ParseStream<parseFlags,Encoding,InputStream>(is);
|
||||
return ParseStream<parseFlags, Encoding, InputStream>(is);
|
||||
}
|
||||
|
||||
//! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
|
||||
|
@ -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_];
|
||||
|
@ -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;
|
||||
|
@ -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<uint64_t>(exponent + kDpExponentBias);
|
||||
u.u64 = (significand & kDpSignificandMask) | (be << kDpSignificandSize);
|
||||
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
|
||||
static_cast<uint64_t>(e + kDpExponentBias);
|
||||
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
|
||||
return u.d;
|
||||
}
|
||||
|
||||
|
@ -50,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) {
|
||||
@ -60,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<uint32_t>(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;
|
||||
@ -76,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<char>('0' + static_cast<char>(d));
|
||||
|
@ -34,14 +34,6 @@ public:
|
||||
return Double(u + 1).Value();
|
||||
}
|
||||
|
||||
double PreviousPositiveDouble() const {
|
||||
RAPIDJSON_ASSERT(!Sign());
|
||||
if (IsZero())
|
||||
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; }
|
||||
|
@ -15,6 +15,8 @@
|
||||
#ifndef RAPIDJSON_ITOA_
|
||||
#define RAPIDJSON_ITOA_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ public:
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool String(const std::basic_string<Ch>& 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;
|
||||
|
@ -122,9 +122,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
|
||||
|
@ -1227,14 +1227,9 @@ private:
|
||||
// May return a new state on state pop.
|
||||
template <unsigned parseFlags, typename InputStream, typename Handler>
|
||||
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;
|
||||
|
||||
@ -1273,12 +1268,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.
|
||||
@ -1353,17 +1345,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<parseFlags>(is, handler);
|
||||
if (HasParseError()) {
|
||||
return IterativeParsingErrorState;
|
||||
}
|
||||
return IterativeParsingFinishState;
|
||||
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false);
|
||||
return IterativeParsingErrorState;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ public:
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
bool String(const std::basic_string<Ch>& 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<SourceEncoding, TargetEncoding>::Transcode(is, *os_);
|
||||
if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))
|
||||
return false;
|
||||
}
|
||||
os_->Put('\"');
|
||||
return true;
|
||||
|
@ -1,12 +1,16 @@
|
||||
set(UNITTEST_SOURCES
|
||||
allocatorstest.cpp
|
||||
bigintegertest.cpp
|
||||
documenttest.cpp
|
||||
encodedstreamtest.cpp
|
||||
encodingstest.cpp
|
||||
filestreamtest.cpp
|
||||
itoatest.cpp
|
||||
jsoncheckertest.cpp
|
||||
namespacetest.cpp
|
||||
prettywritertest.cpp
|
||||
readertest.cpp
|
||||
simdtest.cpp
|
||||
stringbuffertest.cpp
|
||||
strtodtest.cpp
|
||||
unittest.cpp
|
||||
@ -33,8 +37,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")
|
||||
|
64
test/unittest/allocatorstest.cpp
Normal file
64
test/unittest/allocatorstest.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
#include "rapidjson/allocators.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
template <typename Allocator>
|
||||
void TestAllocator(Allocator& a) {
|
||||
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 = 0; i < 1000; i++) {
|
||||
EXPECT_TRUE(a.Malloc(i) != 0);
|
||||
EXPECT_LE(a.Size(), a.Capacity());
|
||||
}
|
||||
}
|
@ -28,13 +28,11 @@
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
template <typename Allocator, typename StackAllocator>
|
||||
void ParseTest() {
|
||||
typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType;
|
||||
template <typename DocumentType>
|
||||
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());
|
||||
|
||||
@ -73,6 +71,28 @@ void ParseTest() {
|
||||
EXPECT_EQ(i + 1, a[i].GetUint());
|
||||
}
|
||||
|
||||
template <typename Allocator, typename StackAllocator>
|
||||
void ParseTest() {
|
||||
typedef GenericDocument<UTF8<>, 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<MemoryPoolAllocator<>, CrtAllocator>();
|
||||
ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >();
|
||||
@ -81,14 +101,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 +250,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
|
||||
|
@ -47,14 +47,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 +119,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 +131,7 @@ protected:
|
||||
ASSERT_TRUE(fp != 0);
|
||||
FileReadStream fs(fp, buffer, sizeof(buffer));
|
||||
AutoUTFInputStream<unsigned, FileReadStream> eis(fs);
|
||||
EXPECT_EQ(expectHasBOM, eis.HasBOM());
|
||||
StringStream s(json_);
|
||||
while (eis.Peek() != '\0') {
|
||||
unsigned expected, actual;
|
||||
@ -140,6 +149,7 @@ protected:
|
||||
char* data = ReadFile(filename, true, &size);
|
||||
MemoryStream ms(data, size);
|
||||
AutoUTFInputStream<unsigned, MemoryStream> eis(ms);
|
||||
EXPECT_EQ(expectHasBOM, eis.HasBOM());
|
||||
StringStream s(json_);
|
||||
|
||||
while (eis.Peek() != '\0') {
|
||||
@ -150,6 +160,7 @@ protected:
|
||||
}
|
||||
EXPECT_EQ('\0', s.Peek());
|
||||
free(data);
|
||||
EXPECT_EQ(size, eis.Tell());
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,16 +268,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<unsigned, MemoryStream> eis(ms, kUTF8);
|
||||
EXPECT_FALSE(eis.HasBOM());
|
||||
EXPECT_EQ(kUTF8, eis.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EncodedStreamTest, EncodedOutputStream) {
|
||||
|
@ -30,9 +30,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);
|
||||
|
164
test/unittest/itoatest.cpp
Normal file
164
test/unittest/itoatest.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/internal/itoa.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(type-limits)
|
||||
#endif
|
||||
|
||||
using namespace rapidjson::internal;
|
||||
|
||||
template <typename T>
|
||||
struct Traits {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Traits<uint32_t> {
|
||||
enum { kBufferSize = 11 };
|
||||
enum { kMaxDigit = 10 };
|
||||
static uint32_t Negate(uint32_t x) { return x; };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Traits<int32_t> {
|
||||
enum { kBufferSize = 12 };
|
||||
enum { kMaxDigit = 10 };
|
||||
static int32_t Negate(int32_t x) { return -x; };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Traits<uint64_t> {
|
||||
enum { kBufferSize = 21 };
|
||||
enum { kMaxDigit = 20 };
|
||||
static uint64_t Negate(uint64_t x) { return x; };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Traits<int64_t> {
|
||||
enum { kBufferSize = 22 };
|
||||
enum { kMaxDigit = 20 };
|
||||
static int64_t Negate(int64_t x) { return -x; };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static void VerifyValue(T value, void(*f)(T, char*), char* (*g)(T, char*)) {
|
||||
char buffer1[Traits<T>::kBufferSize];
|
||||
char buffer2[Traits<T>::kBufferSize];
|
||||
|
||||
f(value, buffer1);
|
||||
*g(value, buffer2) = '\0';
|
||||
|
||||
|
||||
EXPECT_STREQ(buffer1, buffer2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void Verify(void(*f)(T, char*), char* (*g)(T, char*)) {
|
||||
// Boundary cases
|
||||
VerifyValue<T>(0, f, g);
|
||||
VerifyValue<T>(std::numeric_limits<T>::min(), f, g);
|
||||
VerifyValue<T>(std::numeric_limits<T>::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<T>(i - 1, f, g);
|
||||
VerifyValue<T>(i, f, g);
|
||||
if (std::numeric_limits<T>::min() < 0) {
|
||||
VerifyValue<T>(Traits<T>::Negate(i), f, g);
|
||||
VerifyValue<T>(Traits<T>::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<uint32_t>(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<uint64_t>(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
|
@ -25,9 +25,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 +64,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<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||
@ -76,16 +85,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<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||
|
167
test/unittest/prettywritertest.cpp
Normal file
167
test/unittest/prettywritertest.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#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<StringBuffer> writer(buffer);
|
||||
Reader reader;
|
||||
StringStream s(kJson);
|
||||
reader.Parse(s, writer);
|
||||
EXPECT_STREQ(kPrettyJson, buffer.GetString());
|
||||
}
|
||||
|
||||
TEST(PrettyWriter, SetIndent) {
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> 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<StringBuffer> 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<StringBuffer> 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 <sstream>
|
||||
|
||||
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<OStreamWrapper> 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<FileWriteStream> 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);
|
||||
}
|
@ -254,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';
|
||||
@ -263,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<fullPrecision ? kParseFullPrecisionFlag : 0>(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
|
||||
}
|
||||
|
||||
@ -487,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<UTF8<> > is(x);
|
||||
GenericReader<UTF8<>, UTF16<> > reader;
|
||||
ParseStringHandler<UTF16<> > h;
|
||||
reader.Parse<kParseValidateEncodingFlag>(is, h);
|
||||
EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_));
|
||||
EXPECT_EQ(StrLen(e), h.length_);
|
||||
}
|
||||
|
||||
TEST(Reader, ParseString_NonDestructive) {
|
||||
StringStream s("\"Hello\\nWorld\"");
|
||||
ParseStringHandler<UTF8<> > h;
|
||||
@ -496,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<kParseValidateEncodingFlag>(s, h);
|
||||
template <typename Encoding>
|
||||
ParseErrorCode TestString(const typename Encoding::Ch* str) {
|
||||
GenericStringStream<Encoding> s(str);
|
||||
BaseReaderHandler<Encoding> h;
|
||||
GenericReader<Encoding, Encoding> reader;
|
||||
reader.template Parse<kParseValidateEncodingFlag>(s, h);
|
||||
return reader.GetParseErrorCode();
|
||||
}
|
||||
|
||||
TEST(Reader, ParseString_Error) {
|
||||
#define TEST_STRING_ERROR(errorCode, str)\
|
||||
EXPECT_EQ(errorCode, TestString(str))
|
||||
EXPECT_EQ(errorCode, TestString<UTF8<> >(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<const Encoding::Ch *>(&ue[0]); \
|
||||
EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString(e));\
|
||||
EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString<Encoding>(e));\
|
||||
/* decode error */\
|
||||
GenericStringStream<Encoding> s(e);\
|
||||
BaseReaderHandler<TargetEncoding> h;\
|
||||
GenericReader<Encoding, TargetEncoding> reader;\
|
||||
reader.Parse(s, h);\
|
||||
EXPECT_EQ(kParseErrorStringInvalidEncoding, reader.GetParseErrorCode());\
|
||||
}
|
||||
|
||||
// Invalid escape character in string.
|
||||
@ -542,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<UTF8<> >(e);
|
||||
EXPECT_EQ(kParseErrorStringInvalidEncoding, error);
|
||||
if (error != kParseErrorStringInvalidEncoding)
|
||||
std::cout << (unsigned)(unsigned char)c << std::endl;
|
||||
@ -561,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
|
||||
@ -974,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<typename Encoding = UTF8<> >
|
||||
@ -1177,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 <int e>
|
||||
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<e> 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
|
||||
|
74
test/unittest/simdtest.cpp
Normal file
74
test/unittest/simdtest.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// 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 <typename StreamType>
|
||||
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<StringStream>();
|
||||
TestSkipWhitespace<InsituStringStream>();
|
||||
}
|
@ -54,6 +54,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) {
|
||||
|
@ -203,12 +203,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 +245,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());
|
||||
@ -462,10 +485,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<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 00000000)));
|
||||
EXPECT_DOUBLE_EQ(-9223372036854775808.0, z.GetDouble());
|
||||
}
|
||||
|
||||
TEST(Value, Uint64) {
|
||||
@ -508,9 +540,8 @@ 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) {
|
||||
@ -977,6 +1008,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 +1073,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 +1271,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 <int e>
|
||||
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<e> 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\":[]}");
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ TEST(Writer, Compact) {
|
||||
StringBuffer buffer; \
|
||||
Writer<StringBuffer> writer(buffer); \
|
||||
Reader reader; \
|
||||
reader.Parse<0>(s, writer); \
|
||||
reader.Parse<kParseFullPrecisionFlag>(s, writer); \
|
||||
EXPECT_STREQ(json, buffer.GetString()); \
|
||||
EXPECT_TRUE(writer.IsComplete()); \
|
||||
}
|
||||
@ -89,11 +89,28 @@ TEST(Writer, String) {
|
||||
TEST_ROUNDTRIP("[\"Hello\"]");
|
||||
TEST_ROUNDTRIP("[\"Hello\\u0000World\"]");
|
||||
TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> 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]"); // Issue #289
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
TEST(Writer, Transcode) {
|
||||
@ -152,7 +169,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 +180,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 +323,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<UTF16<> > buffer;
|
||||
Writer<GenericStringBuffer<UTF16<> >, 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<StringBuffer, UTF32<> > 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<StringBuffer, UTF32<>, 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<StringBuffer> writer(buffer);
|
||||
writer.StartObject();
|
||||
EXPECT_THROW(writer.EndArray(), AssertException);
|
||||
EXPECT_FALSE(writer.IsComplete());
|
||||
}
|
||||
|
||||
// [}
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartArray();
|
||||
EXPECT_THROW(writer.EndObject(), AssertException);
|
||||
EXPECT_FALSE(writer.IsComplete());
|
||||
}
|
||||
|
||||
// { 1:
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartObject();
|
||||
EXPECT_THROW(writer.Int(1), AssertException);
|
||||
EXPECT_FALSE(writer.IsComplete());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user