Commit 8f4e99b2 authored by Milo Yip's avatar Milo Yip

Merge pull request #604 from miloyip/coverage

Improve coverage to 100%
parents 105c92ee d7ee0862
...@@ -51,7 +51,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ...@@ -51,7 +51,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Fix Document::Parse(const Ch*) for transcoding (#478) * Fix Document::Parse(const Ch*) for transcoding (#478)
* encodings.h: fix typo in preprocessor condition (#495) * encodings.h: fix typo in preprocessor condition (#495)
* Custom Microsoft headers are necessary only for Visual Studio 2012 and lower (#559) * Custom Microsoft headers are necessary only for Visual Studio 2012 and lower (#559)
* * Fix memory leak for invalid regex (26e69ffde95ba4773ab06db6457b78f308716f4b)
* Fix a bug in schema minimum/maximum keywords for 64-bit integer (e7149d665941068ccf8c565e77495521331cf390)
### Changed ### Changed
* Clarify problematic JSON license (#392) * Clarify problematic JSON license (#392)
......
...@@ -375,14 +375,14 @@ private: ...@@ -375,14 +375,14 @@ private:
bool Eval(Stack<Allocator>& operandStack, Operator op) { bool Eval(Stack<Allocator>& operandStack, Operator op) {
switch (op) { switch (op) {
case kConcatenation: case kConcatenation:
if (operandStack.GetSize() >= sizeof(Frag) * 2) { RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
{
Frag e2 = *operandStack.template Pop<Frag>(1); Frag e2 = *operandStack.template Pop<Frag>(1);
Frag e1 = *operandStack.template Pop<Frag>(1); Frag e1 = *operandStack.template Pop<Frag>(1);
Patch(e1.out, e2.start); Patch(e1.out, e2.start);
*operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
return true;
} }
return false; return true;
case kAlternation: case kAlternation:
if (operandStack.GetSize() >= sizeof(Frag) * 2) { if (operandStack.GetSize() >= sizeof(Frag) * 2) {
...@@ -413,7 +413,8 @@ private: ...@@ -413,7 +413,8 @@ private:
} }
return false; return false;
case kOneOrMore: default:
RAPIDJSON_ASSERT(op == kOneOrMore);
if (operandStack.GetSize() >= sizeof(Frag)) { if (operandStack.GetSize() >= sizeof(Frag)) {
Frag e = *operandStack.template Pop<Frag>(1); Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0); SizeType s = NewState(kRegexInvalidState, e.start, 0);
...@@ -422,16 +423,12 @@ private: ...@@ -422,16 +423,12 @@ private:
return true; return true;
} }
return false; return false;
default:
return false;
} }
} }
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) { bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
RAPIDJSON_ASSERT(n <= m); RAPIDJSON_ASSERT(n <= m);
if (operandStack.GetSize() < sizeof(Frag)) RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
return false;
if (n == 0) { if (n == 0) {
if (m == 0) // a{0} not support if (m == 0) // a{0} not support
...@@ -647,8 +644,7 @@ private: ...@@ -647,8 +644,7 @@ private:
// Return whether the added states is a match state // Return whether the added states is a match state
bool AddState(Stack<Allocator>& l, SizeType index) const { bool AddState(Stack<Allocator>& l, SizeType index) const {
if (index == kRegexInvalidState) RAPIDJSON_ASSERT(index != kRegexInvalidState);
return true;
const State& s = GetState(index); const State& s = GetState(index);
if (s.out1 != kRegexInvalidState) { // Split if (s.out1 != kRegexInvalidState) { // Split
......
...@@ -635,8 +635,7 @@ private: ...@@ -635,8 +635,7 @@ private:
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
return; return;
default: default:
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy
break;
} }
if (parseFlags & kParseTrailingCommasFlag) { if (parseFlags & kParseTrailingCommasFlag) {
...@@ -1793,8 +1792,7 @@ private: ...@@ -1793,8 +1792,7 @@ private:
case IterativeParsingKeyValueDelimiterState: case IterativeParsingKeyValueDelimiterState:
case IterativeParsingArrayInitialState: case IterativeParsingArrayInitialState:
case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return;
} }
} }
......
...@@ -159,7 +159,6 @@ public: ...@@ -159,7 +159,6 @@ public:
virtual uint64_t GetHashCode(void* hasher) = 0; virtual uint64_t GetHashCode(void* hasher) = 0;
virtual void DestroryHasher(void* hasher) = 0; virtual void DestroryHasher(void* hasher) = 0;
virtual void* MallocState(size_t size) = 0; virtual void* MallocState(size_t size) = 0;
virtual void* ReallocState(void* originalPtr, size_t originalSize, size_t newSize) = 0;
virtual void FreeState(void* p) = 0; virtual void FreeState(void* p) = 0;
}; };
...@@ -1006,6 +1005,7 @@ private: ...@@ -1006,6 +1005,7 @@ private:
RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
if (!r->IsValid()) { if (!r->IsValid()) {
r->~RegexType(); r->~RegexType();
AllocatorType::Free(r);
r = 0; r = 0;
} }
return r; return r;
...@@ -1108,6 +1108,9 @@ private: ...@@ -1108,6 +1108,9 @@ private:
if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
} }
else if (minimum_.IsUint64()) {
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
}
else if (!CheckDoubleMinimum(context, static_cast<double>(i))) else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
return false; return false;
} }
...@@ -1117,6 +1120,8 @@ private: ...@@ -1117,6 +1120,8 @@ private:
if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
} }
else if (maximum_.IsUint64())
/* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
else if (!CheckDoubleMaximum(context, static_cast<double>(i))) else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
return false; return false;
} }
...@@ -1142,6 +1147,8 @@ private: ...@@ -1142,6 +1147,8 @@ private:
if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
} }
else if (minimum_.IsInt64())
/* do nothing */; // i >= 0 > minimum.Getint64()
else if (!CheckDoubleMinimum(context, static_cast<double>(i))) else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
return false; return false;
} }
...@@ -1151,6 +1158,8 @@ private: ...@@ -1151,6 +1158,8 @@ private:
if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
} }
else if (maximum_.IsInt64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
else if (!CheckDoubleMaximum(context, static_cast<double>(i))) else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
return false; return false;
} }
...@@ -1428,8 +1437,6 @@ private: ...@@ -1428,8 +1437,6 @@ private:
const SchemaType* s = GetSchema(pointer); const SchemaType* s = GetSchema(pointer);
if (!s) if (!s)
CreateSchema(schema, pointer, v, document); CreateSchema(schema, pointer, v, document);
else if (schema)
*schema = s;
for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
...@@ -1766,10 +1773,6 @@ RAPIDJSON_MULTILINEMACRO_END ...@@ -1766,10 +1773,6 @@ RAPIDJSON_MULTILINEMACRO_END
return GetStateAllocator().Malloc(size); return GetStateAllocator().Malloc(size);
} }
virtual void* ReallocState(void* originalPtr, size_t originalSize, size_t newSize) {
return GetStateAllocator().Realloc(originalPtr, originalSize, newSize);
}
virtual void FreeState(void* p) { virtual void FreeState(void* p) {
return StateAllocator::Free(p); return StateAllocator::Free(p);
} }
......
...@@ -423,3 +423,28 @@ TEST(EncodingsTest, UTF32) { ...@@ -423,3 +423,28 @@ TEST(EncodingsTest, UTF32) {
} }
} }
} }
TEST(EncodingsTest, ASCII) {
StringBuffer os, os2;
for (unsigned codepoint = 0; codepoint < 128; codepoint++) {
os.Clear();
ASCII<>::Encode(os, codepoint);
const ASCII<>::Ch* encodedStr = os.GetString();
{
StringStream is(encodedStr);
unsigned decodedCodepoint;
bool result = ASCII<>::Decode(is, &decodedCodepoint);
if (!result || codepoint != decodedCodepoint)
std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl;
}
// Validate
{
StringStream is(encodedStr);
os2.Clear();
bool result = ASCII<>::Validate(is, os2);
EXPECT_TRUE(result);
EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString()));
}
}
}
...@@ -17,6 +17,14 @@ ...@@ -17,6 +17,14 @@
using namespace rapidjson::internal; using namespace rapidjson::internal;
TEST(Regex, Single) {
Regex re("a");
ASSERT_TRUE(re.IsValid());
EXPECT_TRUE(re.Match("a"));
EXPECT_FALSE(re.Match(""));
EXPECT_FALSE(re.Match("b"));
}
TEST(Regex, Concatenation) { TEST(Regex, Concatenation) {
Regex re("abc"); Regex re("abc");
ASSERT_TRUE(re.IsValid()); ASSERT_TRUE(re.IsValid());
...@@ -560,6 +568,9 @@ TEST(Regex, Invalid) { ...@@ -560,6 +568,9 @@ TEST(Regex, Invalid) {
TEST_INVALID("a{1,0}"); TEST_INVALID("a{1,0}");
TEST_INVALID("a{-1,0}"); TEST_INVALID("a{-1,0}");
TEST_INVALID("a{-1,1}"); TEST_INVALID("a{-1,1}");
TEST_INVALID("a{4294967296}"); // overflow of unsigned
TEST_INVALID("a{1a}");
TEST_INVALID("[");
TEST_INVALID("[]"); TEST_INVALID("[]");
TEST_INVALID("[^]"); TEST_INVALID("[^]");
TEST_INVALID("[\\a]"); TEST_INVALID("[\\a]");
......
...@@ -51,6 +51,11 @@ TEST(SchemaValidator, Hasher) { ...@@ -51,6 +51,11 @@ TEST(SchemaValidator, Hasher) {
TEST_HASHER("false", "null", false); TEST_HASHER("false", "null", false);
TEST_HASHER("1", "1", true); TEST_HASHER("1", "1", true);
TEST_HASHER("2147483648", "2147483648", true); // 2^31 can only be fit in unsigned
TEST_HASHER("-2147483649", "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
TEST_HASHER("2147483648", "2147483648", true); // 2^31 can only be fit in unsigned
TEST_HASHER("4294967296", "4294967296", true); // 2^32 can only be fit in int64_t
TEST_HASHER("9223372036854775808", "9223372036854775808", true); // 2^63 can only be fit in uint64_t
TEST_HASHER("1.5", "1.5", true); TEST_HASHER("1.5", "1.5", true);
TEST_HASHER("1", "1.0", true); TEST_HASHER("1", "1.0", true);
TEST_HASHER("1", "-1", false); TEST_HASHER("1", "-1", false);
...@@ -316,6 +321,10 @@ TEST(SchemaValidator, String) { ...@@ -316,6 +321,10 @@ TEST(SchemaValidator, String) {
VALIDATE(s, "\"I'm a string\"", true); VALIDATE(s, "\"I'm a string\"", true);
INVALIDATE(s, "42", "", "type", ""); INVALIDATE(s, "42", "", "type", "");
INVALIDATE(s, "2147483648", "", "type", ""); // 2^31 can only be fit in unsigned
INVALIDATE(s, "-2147483649", "", "type", ""); // -2^31 - 1 can only be fit in int64_t
INVALIDATE(s, "4294967296", "", "type", ""); // 2^32 can only be fit in int64_t
INVALIDATE(s, "3.1415926", "", "type", "");
} }
TEST(SchemaValidator, String_LengthRange) { TEST(SchemaValidator, String_LengthRange) {
...@@ -340,6 +349,16 @@ TEST(SchemaValidator, String_Pattern) { ...@@ -340,6 +349,16 @@ TEST(SchemaValidator, String_Pattern) {
INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", ""); INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "");
INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", ""); INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "");
} }
TEST(SchemaValidator, String_Pattern_Invalid) {
Document sd;
sd.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}"); // TODO: report regex is invalid somehow
SchemaDocument s(sd);
VALIDATE(s, "\"\"", true);
VALIDATE(s, "\"a\"", true);
VALIDATE(s, "\"aa\"", true);
}
#endif #endif
TEST(SchemaValidator, Integer) { TEST(SchemaValidator, Integer) {
...@@ -349,6 +368,10 @@ TEST(SchemaValidator, Integer) { ...@@ -349,6 +368,10 @@ TEST(SchemaValidator, Integer) {
VALIDATE(s, "42", true); VALIDATE(s, "42", true);
VALIDATE(s, "-1", true); VALIDATE(s, "-1", true);
VALIDATE(s, "2147483648", true); // 2^31 can only be fit in unsigned
VALIDATE(s, "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
VALIDATE(s, "2147483648", true); // 2^31 can only be fit in unsigned
VALIDATE(s, "4294967296", true); // 2^32 can only be fit in int64_t
INVALIDATE(s, "3.1415926", "", "type", ""); INVALIDATE(s, "3.1415926", "", "type", "");
INVALIDATE(s, "\"42\"", "", "type", ""); INVALIDATE(s, "\"42\"", "", "type", "");
} }
...@@ -368,11 +391,34 @@ TEST(SchemaValidator, Integer_Range) { ...@@ -368,11 +391,34 @@ TEST(SchemaValidator, Integer_Range) {
TEST(SchemaValidator, Integer_Range64Boundary) { TEST(SchemaValidator, Integer_Range64Boundary) {
Document sd; Document sd;
sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":18446744073709551614}"); sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":9223372036854775806}");
SchemaDocument s(sd); SchemaDocument s(sd);
INVALIDATE(s, "-9223372036854775808", "", "minimum", ""); INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
VALIDATE(s, "-9223372036854775807", true); VALIDATE(s, "-9223372036854775807", true);
VALIDATE(s, "-2147483648", true); // int min
VALIDATE(s, "0", true);
VALIDATE(s, "2147483647", true); // int max
VALIDATE(s, "2147483648", true); // unsigned first
VALIDATE(s, "4294967295", true); // unsigned max
VALIDATE(s, "9223372036854775806", true);
INVALIDATE(s, "9223372036854775807", "", "maximum", "");
INVALIDATE(s, "18446744073709551615", "", "maximum", ""); // uint64_t max
}
TEST(SchemaValidator, Integer_RangeU64Boundary) {
Document sd;
sd.Parse("{\"type\":\"integer\",\"minimum\":9223372036854775808,\"maximum\":18446744073709551614}");
SchemaDocument s(sd);
INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
INVALIDATE(s, "9223372036854775807", "", "minimum", "");
INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min
INVALIDATE(s, "0", "", "minimum", "");
INVALIDATE(s, "2147483647", "", "minimum", ""); // int max
INVALIDATE(s, "2147483648", "", "minimum", ""); // unsigned first
INVALIDATE(s, "4294967295", "", "minimum", ""); // unsigned max
VALIDATE(s, "9223372036854775808", true);
VALIDATE(s, "18446744073709551614", true); VALIDATE(s, "18446744073709551614", true);
INVALIDATE(s, "18446744073709551615", "", "maximum", ""); INVALIDATE(s, "18446744073709551615", "", "maximum", "");
} }
...@@ -418,10 +464,73 @@ TEST(SchemaValidator, Number_Range) { ...@@ -418,10 +464,73 @@ TEST(SchemaValidator, Number_Range) {
INVALIDATE(s, "-1", "", "minimum", ""); INVALIDATE(s, "-1", "", "minimum", "");
VALIDATE(s, "0", true); VALIDATE(s, "0", true);
VALIDATE(s, "0.1", true);
VALIDATE(s, "10", true); VALIDATE(s, "10", true);
VALIDATE(s, "99", true); VALIDATE(s, "99", true);
VALIDATE(s, "99.9", true);
INVALIDATE(s, "100", "", "maximum", ""); INVALIDATE(s, "100", "", "maximum", "");
INVALIDATE(s, "100.0", "", "maximum", "");
INVALIDATE(s, "101.5", "", "maximum", "");
}
TEST(SchemaValidator, Number_RangeInt) {
Document sd;
sd.Parse("{\"type\":\"number\",\"minimum\":-100,\"maximum\":-1,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
INVALIDATE(s, "-101", "", "minimum", "");
INVALIDATE(s, "-100.1", "", "minimum", "");
VALIDATE(s, "-100", true);
VALIDATE(s, "-2", true);
INVALIDATE(s, "-1", "", "maximum", "");
INVALIDATE(s, "-0.9", "", "maximum", "");
INVALIDATE(s, "0", "", "maximum", "");
INVALIDATE(s, "2147483647", "", "maximum", ""); // int max
INVALIDATE(s, "2147483648", "", "maximum", ""); // unsigned first
INVALIDATE(s, "4294967295", "", "maximum", ""); // unsigned max
INVALIDATE(s, "9223372036854775808", "", "maximum", "");
INVALIDATE(s, "18446744073709551614", "", "maximum", "");
INVALIDATE(s, "18446744073709551615", "", "maximum", "");
}
TEST(SchemaValidator, Number_RangeDouble) {
Document sd;
sd.Parse("{\"type\":\"number\",\"minimum\":0.1,\"maximum\":100.1,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min
INVALIDATE(s, "-1", "", "minimum", "");
VALIDATE(s, "0.1", true);
VALIDATE(s, "10", true);
VALIDATE(s, "99", true);
VALIDATE(s, "100", true);
INVALIDATE(s, "101", "", "maximum", ""); INVALIDATE(s, "101", "", "maximum", "");
INVALIDATE(s, "101.5", "", "maximum", "");
INVALIDATE(s, "18446744073709551614", "", "maximum", "");
INVALIDATE(s, "18446744073709551615", "", "maximum", "");
INVALIDATE(s, "2147483647", "", "maximum", ""); // int max
INVALIDATE(s, "2147483648", "", "maximum", ""); // unsigned first
INVALIDATE(s, "4294967295", "", "maximum", ""); // unsigned max
INVALIDATE(s, "9223372036854775808", "", "maximum", "");
INVALIDATE(s, "18446744073709551614", "", "maximum", "");
INVALIDATE(s, "18446744073709551615", "", "maximum", "");
}
TEST(SchemaValidator, Number_RangeDoubleU64Boundary) {
Document sd;
sd.Parse("{\"type\":\"number\",\"minimum\":9223372036854775808.0,\"maximum\":18446744073709550000.0}");
SchemaDocument s(sd);
INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min
INVALIDATE(s, "0", "", "minimum", "");
INVALIDATE(s, "2147483647", "", "minimum", ""); // int max
INVALIDATE(s, "2147483648", "", "minimum", ""); // unsigned first
INVALIDATE(s, "4294967295", "", "minimum", ""); // unsigned max
VALIDATE(s, "9223372036854775808", true);
VALIDATE(s, "18446744073709540000", true);
INVALIDATE(s, "18446744073709551615", "", "maximum", "");
} }
TEST(SchemaValidator, Number_MultipleOf) { TEST(SchemaValidator, Number_MultipleOf) {
...@@ -434,6 +543,13 @@ TEST(SchemaValidator, Number_MultipleOf) { ...@@ -434,6 +543,13 @@ TEST(SchemaValidator, Number_MultipleOf) {
VALIDATE(s, "-10", true); VALIDATE(s, "-10", true);
VALIDATE(s, "20", true); VALIDATE(s, "20", true);
INVALIDATE(s, "23", "", "multipleOf", ""); INVALIDATE(s, "23", "", "multipleOf", "");
INVALIDATE(s, "-2147483648", "", "multipleOf", ""); // int min
VALIDATE(s, "-2147483640", true);
INVALIDATE(s, "2147483647", "", "multipleOf", ""); // int max
INVALIDATE(s, "2147483648", "", "multipleOf", ""); // unsigned first
VALIDATE(s, "2147483650", true);
INVALIDATE(s, "4294967295", "", "multipleOf", ""); // unsigned max
VALIDATE(s, "4294967300", true);
} }
TEST(SchemaValidator, Number_MultipleOfOne) { TEST(SchemaValidator, Number_MultipleOfOne) {
...@@ -844,6 +960,19 @@ TEST(SchemaValidator, AllOf_Nested) { ...@@ -844,6 +960,19 @@ TEST(SchemaValidator, AllOf_Nested) {
INVALIDATE(s, "123", "", "allOf", ""); INVALIDATE(s, "123", "", "allOf", "");
} }
TEST(SchemaValidator, EscapedPointer) {
Document sd;
sd.Parse(
"{"
" \"type\": \"object\","
" \"properties\": {"
" \"~/\": { \"type\": \"number\" }"
" }"
"}");
SchemaDocument s(sd);
INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1");
}
template <typename Allocator> template <typename Allocator>
static char* ReadFile(const char* filename, Allocator& allocator) { static char* ReadFile(const char* filename, Allocator& allocator) {
const char *paths[] = { const char *paths[] = {
......
...@@ -100,29 +100,60 @@ struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnesca ...@@ -100,29 +100,60 @@ struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnesca
memcpy(buffer, str, length + 1); memcpy(buffer, str, length + 1);
return true; return true;
} }
char buffer[1024 + 5]; char buffer[1024 + 5 + 32];
}; };
template <unsigned parseFlags, typename StreamType> template <unsigned parseFlags, typename StreamType>
void TestScanCopyUnescapedString() { void TestScanCopyUnescapedString() {
for (size_t step = 0; step < 1024; step++) { char buffer[1024 + 5 + 32];
char json[1024 + 5]; char backup[1024 + 5 + 32];
char *p = json;
*p ++= '\"'; // Test "ABCDABCD...\\"
for (size_t i = 0; i < step; i++) for (size_t offset = 0; offset < 32; offset++) {
*p++= "ABCD"[i % 4]; for (size_t step = 0; step < 1024; step++) {
*p++ = '\\'; char* json = buffer + offset;
*p++ = '\\'; char *p = json;
*p++ = '\"'; *p++ = '\"';
*p++ = '\0'; for (size_t i = 0; i < step; i++)
*p++ = "ABCD"[i % 4];
StreamType s(json); *p++ = '\\';
Reader reader; *p++ = '\\';
ScanCopyUnescapedStringHandler h; *p++ = '\"';
reader.Parse<parseFlags>(s, h); *p++ = '\0';
EXPECT_TRUE(memcmp(h.buffer, json + 1, step) == 0); strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
EXPECT_EQ('\\', h.buffer[step]); // escaped
EXPECT_EQ('\0', h.buffer[step + 1]); StreamType s(json);
Reader reader;
ScanCopyUnescapedStringHandler h;
reader.Parse<parseFlags>(s, h);
EXPECT_TRUE(memcmp(h.buffer, backup + 1, step) == 0);
EXPECT_EQ('\\', h.buffer[step]); // escaped
EXPECT_EQ('\0', h.buffer[step + 1]);
}
}
// Test "\\ABCDABCD..."
for (size_t offset = 0; offset < 32; offset++) {
for (size_t step = 0; step < 1024; step++) {
char* json = buffer + offset;
char *p = json;
*p++ = '\"';
*p++ = '\\';
*p++ = '\\';
for (size_t i = 0; i < step; i++)
*p++ = "ABCD"[i % 4];
*p++ = '\"';
*p++ = '\0';
strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
StreamType s(json);
Reader reader;
ScanCopyUnescapedStringHandler h;
reader.Parse<parseFlags>(s, h);
EXPECT_TRUE(memcmp(h.buffer + 1, backup + 3, step) == 0);
EXPECT_EQ('\\', h.buffer[0]); // escaped
EXPECT_EQ('\0', h.buffer[step + 1]);
}
} }
} }
...@@ -132,47 +163,50 @@ TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) { ...@@ -132,47 +163,50 @@ TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) {
} }
TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) { TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) {
for (size_t step = 0; step < 1024; step++) { char buffer[2048 + 1 + 32];
char s[2048 + 1]; for (size_t offset = 0; offset < 32; offset++) {
char *p = s; for (size_t step = 0; step < 1024; step++) {
for (size_t i = 0; i < step; i++) char* s = buffer + offset;
*p++= "ABCD"[i % 4]; char* p = s;
char escape = "\0\n\\\""[step % 4]; for (size_t i = 0; i < step; i++)
*p++ = escape; *p++ = "ABCD"[i % 4];
for (size_t i = 0; i < step; i++) char escape = "\0\n\\\""[step % 4];
*p++= "ABCD"[i % 4]; *p++ = escape;
for (size_t i = 0; i < step; i++)
StringBuffer sb; *p++ = "ABCD"[i % 4];
Writer<StringBuffer> writer(sb);
writer.String(s, SizeType(step * 2 + 1)); StringBuffer sb;
const char* q = sb.GetString(); Writer<StringBuffer> writer(sb);
EXPECT_EQ('\"', *q++); writer.String(s, SizeType(step * 2 + 1));
for (size_t i = 0; i < step; i++) const char* q = sb.GetString();
EXPECT_EQ("ABCD"[i % 4], *q++); EXPECT_EQ('\"', *q++);
if (escape == '\0') { for (size_t i = 0; i < step; i++)
EXPECT_EQ('\\', *q++); EXPECT_EQ("ABCD"[i % 4], *q++);
EXPECT_EQ('u', *q++); if (escape == '\0') {
EXPECT_EQ('0', *q++); EXPECT_EQ('\\', *q++);
EXPECT_EQ('0', *q++); EXPECT_EQ('u', *q++);
EXPECT_EQ('0', *q++); EXPECT_EQ('0', *q++);
EXPECT_EQ('0', *q++); EXPECT_EQ('0', *q++);
} EXPECT_EQ('0', *q++);
else if (escape == '\n') { EXPECT_EQ('0', *q++);
EXPECT_EQ('\\', *q++); }
EXPECT_EQ('n', *q++); else if (escape == '\n') {
} EXPECT_EQ('\\', *q++);
else if (escape == '\\') { EXPECT_EQ('n', *q++);
EXPECT_EQ('\\', *q++); }
EXPECT_EQ('\\', *q++); else if (escape == '\\') {
} EXPECT_EQ('\\', *q++);
else if (escape == '\"') { EXPECT_EQ('\\', *q++);
EXPECT_EQ('\\', *q++); }
else if (escape == '\"') {
EXPECT_EQ('\\', *q++);
EXPECT_EQ('\"', *q++);
}
for (size_t i = 0; i < step; i++)
EXPECT_EQ("ABCD"[i % 4], *q++);
EXPECT_EQ('\"', *q++); EXPECT_EQ('\"', *q++);
EXPECT_EQ('\0', *q++);
} }
for (size_t i = 0; i < step; i++)
EXPECT_EQ("ABCD"[i % 4], *q++);
EXPECT_EQ('\"', *q++);
EXPECT_EQ('\0', *q++);
} }
} }
......
...@@ -402,6 +402,7 @@ TEST(Value, Int) { ...@@ -402,6 +402,7 @@ TEST(Value, Int) {
EXPECT_TRUE(x.IsUint64()); EXPECT_TRUE(x.IsUint64());
EXPECT_FALSE(x.IsDouble()); EXPECT_FALSE(x.IsDouble());
EXPECT_FALSE(x.IsFloat());
EXPECT_FALSE(x.IsNull()); EXPECT_FALSE(x.IsNull());
EXPECT_FALSE(x.IsBool()); EXPECT_FALSE(x.IsBool());
EXPECT_FALSE(x.IsFalse()); EXPECT_FALSE(x.IsFalse());
...@@ -456,6 +457,7 @@ TEST(Value, Uint) { ...@@ -456,6 +457,7 @@ TEST(Value, Uint) {
EXPECT_NEAR(1234.0, x.GetDouble(), 0.0); // 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.IsDouble());
EXPECT_FALSE(x.IsFloat());
EXPECT_FALSE(x.IsNull()); EXPECT_FALSE(x.IsNull());
EXPECT_FALSE(x.IsBool()); EXPECT_FALSE(x.IsBool());
EXPECT_FALSE(x.IsFalse()); EXPECT_FALSE(x.IsFalse());
...@@ -500,6 +502,7 @@ TEST(Value, Int64) { ...@@ -500,6 +502,7 @@ TEST(Value, Int64) {
EXPECT_TRUE(x.IsUint64()); EXPECT_TRUE(x.IsUint64());
EXPECT_FALSE(x.IsDouble()); EXPECT_FALSE(x.IsDouble());
EXPECT_FALSE(x.IsFloat());
EXPECT_FALSE(x.IsNull()); EXPECT_FALSE(x.IsNull());
EXPECT_FALSE(x.IsBool()); EXPECT_FALSE(x.IsBool());
EXPECT_FALSE(x.IsFalse()); EXPECT_FALSE(x.IsFalse());
...@@ -561,6 +564,7 @@ TEST(Value, Uint64) { ...@@ -561,6 +564,7 @@ TEST(Value, Uint64) {
EXPECT_TRUE(x.IsUint64()); EXPECT_TRUE(x.IsUint64());
EXPECT_FALSE(x.IsDouble()); EXPECT_FALSE(x.IsDouble());
EXPECT_FALSE(x.IsFloat());
EXPECT_FALSE(x.IsNull()); EXPECT_FALSE(x.IsNull());
EXPECT_FALSE(x.IsBool()); EXPECT_FALSE(x.IsBool());
EXPECT_FALSE(x.IsFalse()); EXPECT_FALSE(x.IsFalse());
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "rapidjson/reader.h" #include "rapidjson/reader.h"
#include "rapidjson/writer.h" #include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h" #include "rapidjson/stringbuffer.h"
#include "rapidjson/memorybuffer.h"
using namespace rapidjson; using namespace rapidjson;
...@@ -94,6 +95,19 @@ TEST(Writer, String) { ...@@ -94,6 +95,19 @@ TEST(Writer, String) {
#endif #endif
} }
TEST(Writer, ScanWriteUnescapedString) {
const char json[] = "[\" \\\"0123456789ABCDEF\"]";
// ^ scanning stops here.
char buffer2[sizeof(json) + 32];
// Use different offset to test different alignments
for (int i = 0; i < 32; i++) {
char* p = buffer2 + i;
memcpy(p, json, sizeof(json));
TEST_ROUNDTRIP(p);
}
}
TEST(Writer, Double) { TEST(Writer, Double) {
TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]"); TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]");
TEST_ROUNDTRIP("0.0"); TEST_ROUNDTRIP("0.0");
...@@ -107,35 +121,59 @@ TEST(Writer, Double) { ...@@ -107,35 +121,59 @@ TEST(Writer, Double) {
} }
// UTF8 -> TargetEncoding -> UTF8
template <typename TargetEncoding>
void TestTranscode(const char* json) {
StringStream s(json);
GenericStringBuffer<TargetEncoding> buffer;
Writer<GenericStringBuffer<TargetEncoding>, UTF8<>, TargetEncoding> writer(buffer);
Reader reader;
reader.Parse(s, writer);
StringBuffer buffer2;
Writer<StringBuffer> writer2(buffer2);
GenericReader<TargetEncoding, UTF8<> > reader2;
GenericStringStream<TargetEncoding> s2(buffer.GetString());
reader2.Parse(s2, writer2);
EXPECT_STREQ(json, buffer2.GetString());
}
TEST(Writer, Transcode) { TEST(Writer, Transcode) {
const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"dollar\":\"\x24\",\"cents\":\"\xC2\xA2\",\"euro\":\"\xE2\x82\xAC\",\"gclef\":\"\xF0\x9D\x84\x9E\"}"; const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"dollar\":\"\x24\",\"cents\":\"\xC2\xA2\",\"euro\":\"\xE2\x82\xAC\",\"gclef\":\"\xF0\x9D\x84\x9E\"}";
// UTF8 -> UTF16 -> UTF8 // UTF8 -> UTF16 -> UTF8
{ TestTranscode<UTF8<> >(json);
StringStream s(json);
StringBuffer buffer;
Writer<StringBuffer, UTF16<>, UTF8<> > writer(buffer);
GenericReader<UTF8<>, UTF16<> > reader;
reader.Parse(s, writer);
EXPECT_STREQ(json, buffer.GetString());
}
// UTF8 -> UTF8 -> ASCII -> UTF8 -> UTF8 // UTF8 -> ASCII -> UTF8
{ TestTranscode<ASCII<> >(json);
// UTF8 -> UTF16 -> UTF8
TestTranscode<UTF16<> >(json);
// UTF8 -> UTF32 -> UTF8
TestTranscode<UTF32<> >(json);
// UTF8 -> AutoUTF -> UTF8
UTFType types[] = { kUTF8, kUTF16LE , kUTF16BE, kUTF32LE , kUTF32BE };
for (size_t i = 0; i < 5; i++) {
StringStream s(json); StringStream s(json);
StringBuffer buffer; MemoryBuffer buffer;
Writer<StringBuffer, UTF8<>, ASCII<> > writer(buffer); AutoUTFOutputStream<unsigned, MemoryBuffer> os(buffer, types[i], true);
Writer<AutoUTFOutputStream<unsigned, MemoryBuffer>, UTF8<>, AutoUTF<unsigned> > writer(os);
Reader reader; Reader reader;
reader.Parse(s, writer); reader.Parse(s, writer);
StringBuffer buffer2; StringBuffer buffer2;
Writer<StringBuffer> writer2(buffer2); Writer<StringBuffer> writer2(buffer2);
GenericReader<ASCII<>, UTF8<> > reader2; GenericReader<AutoUTF<unsigned>, UTF8<> > reader2;
StringStream s2(buffer.GetString()); MemoryStream s2(buffer.GetBuffer(), buffer.GetSize());
reader2.Parse(s2, writer2); AutoUTFInputStream<unsigned, MemoryStream> is(s2);
reader2.Parse(is, writer2);
EXPECT_STREQ(json, buffer2.GetString()); EXPECT_STREQ(json, buffer2.GetString());
} }
} }
#include <sstream> #include <sstream>
...@@ -410,6 +448,10 @@ TEST(Writer, NaN) { ...@@ -410,6 +448,10 @@ TEST(Writer, NaN) {
StringBuffer buffer; StringBuffer buffer;
Writer<StringBuffer> writer(buffer); Writer<StringBuffer> writer(buffer);
EXPECT_FALSE(writer.Double(nan)); EXPECT_FALSE(writer.Double(nan));
GenericStringBuffer<UTF16<> > buffer2;
Writer<GenericStringBuffer<UTF16<> > > writer2(buffer2);
EXPECT_FALSE(writer2.Double(nan));
} }
TEST(Writer, Inf) { TEST(Writer, Inf) {
...@@ -418,7 +460,7 @@ TEST(Writer, Inf) { ...@@ -418,7 +460,7 @@ TEST(Writer, Inf) {
StringBuffer buffer; StringBuffer buffer;
{ {
Writer<StringBuffer> writer(buffer); Writer<StringBuffer> writer(buffer);
EXPECT_FALSE(writer.Double(inf)); EXPECT_FALSE(writer.Double(inf));
} }
{ {
Writer<StringBuffer> writer(buffer); Writer<StringBuffer> writer(buffer);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment