Merge commit '11e98042f40ee7c48a06c9f8e348df92c858209a' into library-updates

This commit is contained in:
Leon Styhre 2023-08-05 11:13:29 +02:00
commit 941377e26a
28 changed files with 1612 additions and 339 deletions

View file

@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8) CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)
if(POLICY CMP0025) if(POLICY CMP0025)
# detect Apple's Clang # detect Apple's Clang
cmake_policy(SET CMP0025 NEW) cmake_policy(SET CMP0025 NEW)
@ -68,7 +68,7 @@ endif(CCACHE_FOUND)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT AND NOT CMAKE_CROSSCOMPILING) if(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT AND NOT CMAKE_CROSSCOMPILING)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le") if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
else() else()
#FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER.
@ -102,7 +102,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
endif() endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if(NOT CMAKE_CROSSCOMPILING) if(NOT CMAKE_CROSSCOMPILING)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le") if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
else() else()
#FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER.
@ -128,6 +128,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
endif() endif()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
add_definitions(-DNOMINMAX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
# CMake >= 3.10 should handle the above CMAKE_CXX_STANDARD fine, otherwise use /std:c++XX with MSVC >= 19.10 # CMake >= 3.10 should handle the above CMAKE_CXX_STANDARD fine, otherwise use /std:c++XX with MSVC >= 19.10
if (RAPIDJSON_BUILD_CXX11 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.10") if (RAPIDJSON_BUILD_CXX11 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.10")
@ -241,8 +242,10 @@ INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAM
DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) DESTINATION ${CMAKECONFIG_INSTALL_DIR} )
# Install files # Install files
INSTALL(FILES IF(CMAKE_INSTALL_DIR)
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake INSTALL(FILES
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
DESTINATION "${CMAKE_INSTALL_DIR}" ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
COMPONENT dev) DESTINATION "${CMAKE_INSTALL_DIR}"
COMPONENT dev)
ENDIF()

View file

@ -2,30 +2,30 @@
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- rapidjson::GenericValue - basic support --> <!-- rapidjson::GenericValue - basic support -->
<Type Name="rapidjson::GenericValue&lt;*,*&gt;"> <Type Name="rapidjson::GenericValue&lt;*,*&gt;">
<DisplayString Condition="(data_.f.flags &amp; kTypeMask) == kNullType">null</DisplayString> <DisplayString Condition="(data_.f.flags &amp; kTypeMask) == rapidjson::kNullType">null</DisplayString>
<DisplayString Condition="data_.f.flags == kTrueFlag">true</DisplayString> <DisplayString Condition="data_.f.flags == kTrueFlag">true</DisplayString>
<DisplayString Condition="data_.f.flags == kFalseFlag">false</DisplayString> <DisplayString Condition="data_.f.flags == kFalseFlag">false</DisplayString>
<DisplayString Condition="data_.f.flags == kShortStringFlag">{(const Ch*)data_.ss.str,na}</DisplayString> <DisplayString Condition="data_.f.flags == kShortStringFlag">{(const Ch*)data_.ss.str,na}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kTypeMask) == kStringType">{(const Ch*)((size_t)data_.s.str &amp; 0x0000FFFFFFFFFFFF),na}</DisplayString> <DisplayString Condition="(data_.f.flags &amp; kTypeMask) == rapidjson::kStringType">{(const Ch*)((size_t)data_.s.str &amp; 0x0000FFFFFFFFFFFF),[data_.s.length]na}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kNumberIntFlag) == kNumberIntFlag">{data_.n.i.i}</DisplayString> <DisplayString Condition="(data_.f.flags &amp; kNumberIntFlag) == kNumberIntFlag">{data_.n.i.i}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kNumberUintFlag) == kNumberUintFlag">{data_.n.u.u}</DisplayString> <DisplayString Condition="(data_.f.flags &amp; kNumberUintFlag) == kNumberUintFlag">{data_.n.u.u}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kNumberInt64Flag) == kNumberInt64Flag">{data_.n.i64}</DisplayString> <DisplayString Condition="(data_.f.flags &amp; kNumberInt64Flag) == kNumberInt64Flag">{data_.n.i64}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kNumberUint64Flag) == kNumberUint64Flag">{data_.n.u64}</DisplayString> <DisplayString Condition="(data_.f.flags &amp; kNumberUint64Flag) == kNumberUint64Flag">{data_.n.u64}</DisplayString>
<DisplayString Condition="(data_.f.flags &amp; kNumberDoubleFlag) == kNumberDoubleFlag">{data_.n.d}</DisplayString> <DisplayString Condition="(data_.f.flags &amp; kNumberDoubleFlag) == kNumberDoubleFlag">{data_.n.d}</DisplayString>
<DisplayString Condition="data_.f.flags == kObjectType">Object members={data_.o.size}</DisplayString> <DisplayString Condition="data_.f.flags == rapidjson::kObjectType">Object members={data_.o.size}</DisplayString>
<DisplayString Condition="data_.f.flags == kArrayType">Array members={data_.a.size}</DisplayString> <DisplayString Condition="data_.f.flags == rapidjson::kArrayType">Array members={data_.a.size}</DisplayString>
<Expand> <Expand>
<Item Condition="data_.f.flags == kObjectType" Name="[size]">data_.o.size</Item> <Item Condition="data_.f.flags == rapidjson::kObjectType" Name="[size]">data_.o.size</Item>
<Item Condition="data_.f.flags == kObjectType" Name="[capacity]">data_.o.capacity</Item> <Item Condition="data_.f.flags == rapidjson::kObjectType" Name="[capacity]">data_.o.capacity</Item>
<ArrayItems Condition="data_.f.flags == kObjectType"> <ArrayItems Condition="data_.f.flags == rapidjson::kObjectType">
<Size>data_.o.size</Size> <Size>data_.o.size</Size>
<!-- NOTE: Rapidjson stores some extra data in the high bits of pointers, which is why the mask --> <!-- NOTE: Rapidjson stores some extra data in the high bits of pointers, which is why the mask -->
<ValuePointer>(rapidjson::GenericMember&lt;$T1,$T2&gt;*)(((size_t)data_.o.members) &amp; 0x0000FFFFFFFFFFFF)</ValuePointer> <ValuePointer>(rapidjson::GenericMember&lt;$T1,$T2&gt;*)(((size_t)data_.o.members) &amp; 0x0000FFFFFFFFFFFF)</ValuePointer>
</ArrayItems> </ArrayItems>
<Item Condition="data_.f.flags == kArrayType" Name="[size]">data_.a.size</Item> <Item Condition="data_.f.flags == rapidjson::kArrayType" Name="[size]">data_.a.size</Item>
<Item Condition="data_.f.flags == kArrayType" Name="[capacity]">data_.a.capacity</Item> <Item Condition="data_.f.flags == rapidjson::kArrayType" Name="[capacity]">data_.a.capacity</Item>
<ArrayItems Condition="data_.f.flags == kArrayType"> <ArrayItems Condition="data_.f.flags == rapidjson::kArrayType">
<Size>data_.a.size</Size> <Size>data_.a.size</Size>
<!-- NOTE: Rapidjson stores some extra data in the high bits of pointers, which is why the mask --> <!-- NOTE: Rapidjson stores some extra data in the high bits of pointers, which is why the mask -->
<ValuePointer>(rapidjson::GenericValue&lt;$T1,$T2&gt;*)(((size_t)data_.a.elements) &amp; 0x0000FFFFFFFFFFFF)</ValuePointer> <ValuePointer>(rapidjson::GenericValue&lt;$T1,$T2&gt;*)(((size_t)data_.a.elements) &amp; 0x0000FFFFFFFFFFFF)</ValuePointer>

View file

@ -22,13 +22,15 @@
* RapidJSON should be fully RFC4627/ECMA-404 compliance. * RapidJSON should be fully RFC4627/ECMA-404 compliance.
* Support JSON Pointer (RFC6901). * Support JSON Pointer (RFC6901).
* Support JSON Schema Draft v4. * Support JSON Schema Draft v4.
* Support Swagger v2 schema.
* Support OpenAPI v3.0.x schema.
* Support Unicode surrogate. * Support Unicode surrogate.
* Support null character (`"\u0000"`) * Support null character (`"\u0000"`)
* For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string. * For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string.
* Support optional relaxed syntax. * Support optional relaxed syntax.
* Single line (`// ...`) and multiple line (`/* ... */`) comments (`kParseCommentsFlag`). * Single line (`// ...`) and multiple line (`/* ... */`) comments (`kParseCommentsFlag`).
* Trailing commas at the end of objects and arrays (`kParseTrailingCommasFlag`). * Trailing commas at the end of objects and arrays (`kParseTrailingCommasFlag`).
* `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (`kParseNanAndInfFlag`) * `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (`kParseNanAndInfFlag`)
* [NPM compliant](http://github.com/Tencent/rapidjson/blob/master/doc/npm.md). * [NPM compliant](http://github.com/Tencent/rapidjson/blob/master/doc/npm.md).
## Unicode ## Unicode

View file

@ -24,7 +24,15 @@ if (sd.Parse(schemaJson).HasParseError()) {
// the schema is not a valid JSON. // the schema is not a valid JSON.
// ... // ...
} }
SchemaDocument schema(sd); // Compile a Document to SchemaDocument SchemaDocument schema(sd); // Compile a Document to SchemaDocument
if (!schema.GetError().ObjectEmpty()) {
// there was a problem compiling the schema
StringBuffer sb;
Writer<StringBuffer> w(sb);
schema.GetError().Accept(w);
printf("Invalid schema: %s\n", sb.GetString());
}
// sd is no longer needed here. // sd is no longer needed here.
Document d; Document d;

View file

@ -41,7 +41,8 @@ static std::string GetString(const ValueType& val) {
s << "false"; s << "false";
else if (val.IsFloat()) else if (val.IsFloat())
s << val.GetFloat(); s << val.GetFloat();
return s.str();} return s.str();
}
// Create the error message for a named error // Create the error message for a named error
// The error object can either be empty or contain at least member properties: // The error object can either be empty or contain at least member properties:

View file

@ -19,6 +19,7 @@
#include "internal/meta.h" #include "internal/meta.h"
#include <memory> #include <memory>
#include <limits>
#if RAPIDJSON_HAS_CXX11 #if RAPIDJSON_HAS_CXX11
#include <type_traits> #include <type_traits>
@ -433,7 +434,7 @@ namespace internal {
template<typename T, typename A> template<typename T, typename A>
inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n) inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
{ {
RAPIDJSON_NOEXCEPT_ASSERT(old_n <= SIZE_MAX / sizeof(T) && new_n <= SIZE_MAX / sizeof(T)); RAPIDJSON_NOEXCEPT_ASSERT(old_n <= (std::numeric_limits<size_t>::max)() / sizeof(T) && new_n <= (std::numeric_limits<size_t>::max)() / sizeof(T));
return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T))); return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
} }

View file

@ -75,7 +75,7 @@ class GenericDocument;
User can define this to use CrtAllocator or MemoryPoolAllocator. User can define this to use CrtAllocator or MemoryPoolAllocator.
*/ */
#ifndef RAPIDJSON_DEFAULT_ALLOCATOR #ifndef RAPIDJSON_DEFAULT_ALLOCATOR
#define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator<CrtAllocator> #define RAPIDJSON_DEFAULT_ALLOCATOR ::RAPIDJSON_NAMESPACE::MemoryPoolAllocator<::RAPIDJSON_NAMESPACE::CrtAllocator>
#endif #endif
/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR /*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR
@ -85,7 +85,7 @@ class GenericDocument;
User can define this to use CrtAllocator or MemoryPoolAllocator. User can define this to use CrtAllocator or MemoryPoolAllocator.
*/ */
#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR #ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR
#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator #define RAPIDJSON_DEFAULT_STACK_ALLOCATOR ::RAPIDJSON_NAMESPACE::CrtAllocator
#endif #endif
/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY /*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
@ -1078,6 +1078,7 @@ public:
*/ */
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
#ifndef __cpp_impl_three_way_comparison
//! Not-equal-to operator //! Not-equal-to operator
/*! \return !(*this == rhs) /*! \return !(*this == rhs)
*/ */
@ -1092,7 +1093,6 @@ public:
*/ */
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
#ifndef __cpp_lib_three_way_comparison
//! Equal-to operator with arbitrary types (symmetric version) //! Equal-to operator with arbitrary types (symmetric version)
/*! \return (rhs == lhs) /*! \return (rhs == lhs)
*/ */
@ -1230,13 +1230,28 @@ public:
else { else {
RAPIDJSON_ASSERT(false); // see above note RAPIDJSON_ASSERT(false); // see above note
// This will generate -Wexit-time-destructors in clang #if RAPIDJSON_HAS_CXX11
// static GenericValue NullValue; // Use thread-local storage to prevent races between threads.
// return NullValue; // Use static buffer and placement-new to prevent destruction, with
// alignas() to ensure proper alignment.
// Use static buffer and placement-new to prevent destruction alignas(GenericValue) thread_local static char buffer[sizeof(GenericValue)];
static char buffer[sizeof(GenericValue)];
return *new (buffer) GenericValue(); return *new (buffer) GenericValue();
#elif defined(_MSC_VER) && _MSC_VER < 1900
// There's no way to solve both thread locality and proper alignment
// simultaneously.
__declspec(thread) static char buffer[sizeof(GenericValue)];
return *new (buffer) GenericValue();
#elif defined(__GNUC__) || defined(__clang__)
// This will generate -Wexit-time-destructors in clang, but that's
// better than having under-alignment.
__thread static GenericValue buffer;
return buffer;
#else
// Don't know what compiler this is, so don't know how to ensure
// thread-locality.
static GenericValue buffer;
return buffer;
#endif
} }
} }
template <typename SourceAllocator> template <typename SourceAllocator>
@ -2486,6 +2501,7 @@ public:
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document. typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter.
typedef StackAllocator StackAllocatorType; //!< StackAllocator type from template parameter.
//! Constructor //! Constructor
/*! Creates an empty document of specified type. /*! Creates an empty document of specified type.

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_EN_H_ #ifndef RAPIDJSON_ERROR_EN_H_
@ -39,13 +39,13 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
@ -104,15 +104,69 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode val
case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'."); case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors."); case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'."); case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf', indices '%matches'.");
case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors."); case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors."); case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'."); case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
case kValidateErrorReadOnly: return RAPIDJSON_ERROR_STRING("Property is read-only but has been provided when validation is for writing.");
case kValidateErrorWriteOnly: return RAPIDJSON_ERROR_STRING("Property is write-only but has been provided when validation is for reading.");
default: return RAPIDJSON_ERROR_STRING("Unknown error."); default: return RAPIDJSON_ERROR_STRING("Unknown error.");
} }
} }
//! Maps error code of schema document compilation into error message.
/*!
\ingroup RAPIDJSON_ERRORS
\param schemaErrorCode Error code obtained from compiling the schema document.
\return the error message.
\note User can make a copy of this function for localization.
Using switch-case is safer for future modification of error codes.
*/
inline const RAPIDJSON_ERROR_CHARTYPE* GetSchemaError_En(SchemaErrorCode schemaErrorCode) {
switch (schemaErrorCode) {
case kSchemaErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kSchemaErrorStartUnknown: return RAPIDJSON_ERROR_STRING("Pointer '%value' to start of schema does not resolve to a location in the document.");
case kSchemaErrorRefPlainName: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' must be a JSON pointer.");
case kSchemaErrorRefInvalid: return RAPIDJSON_ERROR_STRING("$ref must not be an empty string.");
case kSchemaErrorRefPointerInvalid: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' is not a valid JSON pointer at offset '%offset'.");
case kSchemaErrorRefUnknown: return RAPIDJSON_ERROR_STRING("$ref '%value' does not resolve to a location in the target document.");
case kSchemaErrorRefCyclical: return RAPIDJSON_ERROR_STRING("$ref '%value' is cyclical.");
case kSchemaErrorRefNoRemoteProvider: return RAPIDJSON_ERROR_STRING("$ref is remote but there is no remote provider.");
case kSchemaErrorRefNoRemoteSchema: return RAPIDJSON_ERROR_STRING("$ref '%value' is remote but the remote provider did not return a schema.");
case kSchemaErrorRegexInvalid: return RAPIDJSON_ERROR_STRING("Invalid regular expression '%value' in 'pattern' or 'patternProperties'.");
case kSchemaErrorSpecUnknown: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not recognized.");
case kSchemaErrorSpecUnsupported: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not supported.");
case kSchemaErrorSpecIllegal: return RAPIDJSON_ERROR_STRING("Both JSON schema draft and OpenAPI version found in document.");
case kSchemaErrorReadOnlyAndWriteOnly: return RAPIDJSON_ERROR_STRING("Property must not be both 'readOnly' and 'writeOnly'.");
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
}
}
//! Maps error code of pointer parse into error message.
/*!
\ingroup RAPIDJSON_ERRORS
\param pointerParseErrorCode Error code obtained from pointer parse.
\return the error message.
\note User can make a copy of this function for localization.
Using switch-case is safer for future modification of error codes.
*/
inline const RAPIDJSON_ERROR_CHARTYPE* GetPointerParseError_En(PointerParseErrorCode pointerParseErrorCode) {
switch (pointerParseErrorCode) {
case kPointerParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kPointerParseErrorTokenMustBeginWithSolidus: return RAPIDJSON_ERROR_STRING("A token must begin with a '/'.");
case kPointerParseErrorInvalidEscape: return RAPIDJSON_ERROR_STRING("Invalid escape.");
case kPointerParseErrorInvalidPercentEncoding: return RAPIDJSON_ERROR_STRING("Invalid percent encoding in URI fragment.");
case kPointerParseErrorCharacterMustPercentEncode: return RAPIDJSON_ERROR_STRING("A character must be percent encoded in a URI fragment.");
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
}
}
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#ifdef __clang__ #ifdef __clang__

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_ERROR_H_ #ifndef RAPIDJSON_ERROR_ERROR_H_
@ -42,7 +42,7 @@ RAPIDJSON_DIAG_OFF(padded)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ERROR_STRING // RAPIDJSON_ERROR_STRING
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. //! Macro for converting string literal to \ref RAPIDJSON_ERROR_CHARTYPE[].
/*! \ingroup RAPIDJSON_ERRORS /*! \ingroup RAPIDJSON_ERRORS
By default this conversion macro does nothing. By default this conversion macro does nothing.
On Windows, user can define this macro as \c _T(x) for supporting both On Windows, user can define this macro as \c _T(x) for supporting both
@ -185,14 +185,17 @@ enum ValidateErrorCode {
kValidateErrorPatternProperties, //!< See other errors. kValidateErrorPatternProperties, //!< See other errors.
kValidateErrorDependencies, //!< Object has missing property or schema dependencies. kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values.
kValidateErrorType, //!< Property has a type that is not allowed by the schema.. kValidateErrorType, //!< Property has a type that is not allowed by the schema.
kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'. kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'.
kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'. kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'. kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'.
kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'. kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'.
kValidateErrorNot //!< Property matched the sub-schema specified by 'not'. kValidateErrorNot, //!< Property matched the sub-schema specified by 'not'.
kValidateErrorReadOnly, //!< Property is read-only but has been provided when validation is for writing
kValidateErrorWriteOnly //!< Property is write-only but has been provided when validation is for reading
}; };
//! Function pointer type of GetValidateError(). //! Function pointer type of GetValidateError().
@ -207,6 +210,72 @@ enum ValidateErrorCode {
*/ */
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode); typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
///////////////////////////////////////////////////////////////////////////////
// SchemaErrorCode
//! Error codes when validating.
/*! \ingroup RAPIDJSON_ERRORS
\see GenericSchemaValidator
*/
enum SchemaErrorCode {
kSchemaErrorNone = 0, //!< No error.
kSchemaErrorStartUnknown, //!< Pointer to start of schema does not resolve to a location in the document
kSchemaErrorRefPlainName, //!< $ref fragment must be a JSON pointer
kSchemaErrorRefInvalid, //!< $ref must not be an empty string
kSchemaErrorRefPointerInvalid, //!< $ref fragment is not a valid JSON pointer at offset
kSchemaErrorRefUnknown, //!< $ref does not resolve to a location in the target document
kSchemaErrorRefCyclical, //!< $ref is cyclical
kSchemaErrorRefNoRemoteProvider, //!< $ref is remote but there is no remote provider
kSchemaErrorRefNoRemoteSchema, //!< $ref is remote but the remote provider did not return a schema
kSchemaErrorRegexInvalid, //!< Invalid regular expression in 'pattern' or 'patternProperties'
kSchemaErrorSpecUnknown, //!< JSON schema draft or OpenAPI version is not recognized
kSchemaErrorSpecUnsupported, //!< JSON schema draft or OpenAPI version is not supported
kSchemaErrorSpecIllegal, //!< Both JSON schema draft and OpenAPI version found in document
kSchemaErrorReadOnlyAndWriteOnly //!< Property must not be both 'readOnly' and 'writeOnly'
};
//! Function pointer type of GetSchemaError().
/*! \ingroup RAPIDJSON_ERRORS
This is the prototype for \c GetSchemaError_X(), where \c X is a locale.
User can dynamically change locale in runtime, e.g.:
\code
GetSchemaErrorFunc GetSchemaError = GetSchemaError_En; // or whatever
const RAPIDJSON_ERROR_CHARTYPE* s = GetSchemaError(validator.GetInvalidSchemaCode());
\endcode
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetSchemaErrorFunc)(SchemaErrorCode);
///////////////////////////////////////////////////////////////////////////////
// PointerParseErrorCode
//! Error code of JSON pointer parsing.
/*! \ingroup RAPIDJSON_ERRORS
\see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
*/
enum PointerParseErrorCode {
kPointerParseErrorNone = 0, //!< The parse is successful
kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
kPointerParseErrorInvalidEscape, //!< Invalid escape
kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
};
//! Function pointer type of GetPointerParseError().
/*! \ingroup RAPIDJSON_ERRORS
This is the prototype for \c GetPointerParseError_X(), where \c X is a locale.
User can dynamically change locale in runtime, e.g.:
\code
GetPointerParseErrorFunc GetPointerParseError = GetPointerParseError_En; // or whatever
const RAPIDJSON_ERROR_CHARTYPE* s = GetPointerParseError(pointer.GetParseErrorCode());
\endcode
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetPointerParseErrorFunc)(PointerParseErrorCode);
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#ifdef __clang__ #ifdef __clang__

View file

@ -19,7 +19,11 @@
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64)
#include <intrin.h> // for _umul128 #include <intrin.h> // for _umul128
#if !defined(_ARM64EC_)
#pragma intrinsic(_umul128) #pragma intrinsic(_umul128)
#else
#pragma comment(lib,"softintrin")
#endif
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -255,7 +259,7 @@ private:
if (low < k) if (low < k)
(*outHigh)++; (*outHigh)++;
return low; return low;
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128; __extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b); uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
p += k; p += k;

View file

@ -25,7 +25,11 @@
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
#include <intrin.h> #include <intrin.h>
#if !defined(_ARM64EC_)
#pragma intrinsic(_umul128) #pragma intrinsic(_umul128)
#else
#pragma comment(lib,"softintrin")
#endif
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -75,7 +79,7 @@ struct DiyFp {
if (l & (uint64_t(1) << 63)) // rounding if (l & (uint64_t(1) << 63)) // rounding
h++; h++;
return DiyFp(h, e + rhs.e + 64); return DiyFp(h, e + rhs.e + 64);
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128; __extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f); uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
uint64_t h = static_cast<uint64_t>(p >> 64); uint64_t h = static_cast<uint64_t>(p >> 64);

View file

@ -58,11 +58,11 @@ inline int CountDecimalDigit32(uint32_t n) {
} }
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
static const uint64_t kPow10[] = { 1U, 10U, 100U, 1000U, 10000U, 100000U, 1000000U, 10000000U, 100000000U, static const uint64_t kPow10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL,
1000000000U, 10000000000U, 100000000000U, 1000000000000U, 1000000000ULL, 10000000000ULL, 100000000000ULL, 1000000000000ULL,
10000000000000U, 100000000000000U, 1000000000000000U, 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL,
10000000000000000U, 100000000000000000U, 1000000000000000000U, 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL,
10000000000000000000U }; 10000000000000000000ULL };
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp wp_w = Mp - W; const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);

View file

@ -18,6 +18,7 @@
#include "document.h" #include "document.h"
#include "uri.h" #include "uri.h"
#include "internal/itoa.h" #include "internal/itoa.h"
#include "error/error.h" // PointerParseErrorCode
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
@ -31,19 +32,6 @@ RAPIDJSON_NAMESPACE_BEGIN
static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
//! Error code of parsing.
/*! \ingroup RAPIDJSON_ERRORS
\see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
*/
enum PointerParseErrorCode {
kPointerParseErrorNone = 0, //!< The parse is successful
kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
kPointerParseErrorInvalidEscape, //!< Invalid escape
kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// GenericPointer // GenericPointer
@ -69,10 +57,10 @@ enum PointerParseErrorCode {
supplied tokens eliminates these. supplied tokens eliminates these.
GenericPointer depends on GenericDocument and GenericValue. GenericPointer depends on GenericDocument and GenericValue.
\tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> > \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
\tparam Allocator The allocator type for allocating memory for internal representation. \tparam Allocator The allocator type for allocating memory for internal representation.
\note GenericPointer uses same encoding of ValueType. \note GenericPointer uses same encoding of ValueType.
However, Allocator of GenericPointer is independent of Allocator of Value. However, Allocator of GenericPointer is independent of Allocator of Value.
*/ */
@ -84,7 +72,7 @@ public:
typedef GenericUri<ValueType, Allocator> UriType; typedef GenericUri<ValueType, Allocator> UriType;
//! A token is the basic units of internal representation. //! A token is the basic units of internal representation.
/*! /*!
A JSON pointer string representation "/foo/123" is parsed to two tokens: A JSON pointer string representation "/foo/123" is parsed to two tokens:
"foo" and 123. 123 will be represented in both numeric form and string form. "foo" and 123. 123 will be represented in both numeric form and string form.
@ -701,7 +689,7 @@ public:
ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const { ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
return GetWithDefault(document, defaultValue, document.GetAllocator()); return GetWithDefault(document, defaultValue, document.GetAllocator());
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
//! Query a value in a document with default std::basic_string. //! Query a value in a document with default std::basic_string.
template <typename stackAllocator> template <typename stackAllocator>
@ -902,10 +890,16 @@ private:
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
} }
// Adjust pointers to name buffer // The names of each token point to a string in the nameBuffer_. The
std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; // previous memcpy copied over string pointers into the rhs.nameBuffer_,
for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) // but they should point to the strings in the new nameBuffer_.
t->name += diff; for (size_t i = 0; i < rhs.tokenCount_; ++i) {
// The offset between the string address and the name buffer should
// still be constant, so we can just get this offset and set each new
// token name according the new buffer start + the known offset.
std::ptrdiff_t name_offset = rhs.tokens_[i].name - rhs.nameBuffer_;
tokens_[i].name = nameBuffer_ + name_offset;
}
return nameBuffer_ + nameBufferSize; return nameBuffer_ + nameBufferSize;
} }
@ -995,7 +989,7 @@ private:
} }
i++; i++;
// Escaping "~0" -> '~', "~1" -> '/' // Escaping "~0" -> '~', "~1" -> '/'
if (c == '~') { if (c == '~') {
if (i < length) { if (i < length) {

View file

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_RAPIDJSON_H_ #ifndef RAPIDJSON_RAPIDJSON_H_
@ -17,7 +17,7 @@
/*!\file rapidjson.h /*!\file rapidjson.h
\brief common definitions and configuration \brief common definitions and configuration
\see RAPIDJSON_CONFIG \see RAPIDJSON_CONFIG
*/ */
@ -195,7 +195,7 @@
*/ */
#ifndef RAPIDJSON_NO_INT64DEFINE #ifndef RAPIDJSON_NO_INT64DEFINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 #if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
#include "msinttypes/stdint.h" #include "msinttypes/stdint.h"
#include "msinttypes/inttypes.h" #include "msinttypes/inttypes.h"
#else #else
@ -277,7 +277,7 @@
# elif defined(RAPIDJSON_DOXYGEN_RUNNING) # elif defined(RAPIDJSON_DOXYGEN_RUNNING)
# define RAPIDJSON_ENDIAN # define RAPIDJSON_ENDIAN
# else # else
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif # endif
#endif // RAPIDJSON_ENDIAN #endif // RAPIDJSON_ENDIAN
@ -513,7 +513,7 @@ RAPIDJSON_NAMESPACE_END
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_BEGIN do {
#define RAPIDJSON_MULTILINEMACRO_END \ #define RAPIDJSON_MULTILINEMACRO_END \
} while((void)0, 0) } while((void)0, 0)
@ -731,7 +731,7 @@ enum Type {
kFalseType = 1, //!< false kFalseType = 1, //!< false
kTrueType = 2, //!< true kTrueType = 2, //!< true
kObjectType = 3, //!< object kObjectType = 3, //!< object
kArrayType = 4, //!< array kArrayType = 4, //!< array
kStringType = 5, //!< string kStringType = 5, //!< string
kNumberType = 6 //!< number kNumberType = 6 //!< number
}; };

View file

@ -1433,7 +1433,7 @@ private:
class NumberStream<InputStream, StackCharacter, true, false> : public NumberStream<InputStream, StackCharacter, false, false> { class NumberStream<InputStream, StackCharacter, true, false> : public NumberStream<InputStream, StackCharacter, false, false> {
typedef NumberStream<InputStream, StackCharacter, false, false> Base; typedef NumberStream<InputStream, StackCharacter, false, false> Base;
public: public:
NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s), stackStream(reader.stack_) {}
RAPIDJSON_FORCEINLINE Ch TakePush() { RAPIDJSON_FORCEINLINE Ch TakePush() {
stackStream.Put(static_cast<StackCharacter>(Base::is.Peek())); stackStream.Put(static_cast<StackCharacter>(Base::is.Peek()));
@ -1459,7 +1459,7 @@ private:
class NumberStream<InputStream, StackCharacter, true, true> : public NumberStream<InputStream, StackCharacter, true, false> { class NumberStream<InputStream, StackCharacter, true, true> : public NumberStream<InputStream, StackCharacter, true, false> {
typedef NumberStream<InputStream, StackCharacter, true, false> Base; typedef NumberStream<InputStream, StackCharacter, true, false> Base;
public: public:
NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s) {}
RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
}; };
@ -1694,7 +1694,7 @@ private:
} }
else { else {
SizeType numCharsToCopy = static_cast<SizeType>(s.Length()); SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
GenericStringStream<UTF8<NumberCharacter>> srcStream(s.Pop()); GenericStringStream<UTF8<NumberCharacter> > srcStream(s.Pop());
StackStream<typename TargetEncoding::Ch> dstStream(stack_); StackStream<typename TargetEncoding::Ch> dstStream(stack_);
while (numCharsToCopy--) { while (numCharsToCopy--) {
Transcoder<UTF8<typename TargetEncoding::Ch>, TargetEncoding>::Transcode(srcStream, dstStream); Transcoder<UTF8<typename TargetEncoding::Ch>, TargetEncoding>::Transcode(srcStream, dstStream);

File diff suppressed because it is too large Load diff

View file

@ -67,6 +67,7 @@ enum WriteFlag {
kWriteNoFlags = 0, //!< No flags are set. kWriteNoFlags = 0, //!< No flags are set.
kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
kWriteNanAndInfNullFlag = 4, //!< Allow writing of Infinity, -Infinity and NaN as null.
kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
}; };
@ -350,6 +351,11 @@ protected:
if (internal::Double(d).IsNanOrInf()) { if (internal::Double(d).IsNanOrInf()) {
if (!(writeFlags & kWriteNanAndInfFlag)) if (!(writeFlags & kWriteNanAndInfFlag))
return false; return false;
if (writeFlags & kWriteNanAndInfNullFlag) {
PutReserve(*os_, 4);
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l');
return true;
}
if (internal::Double(d).IsNan()) { if (internal::Double(d).IsNan()) {
PutReserve(*os_, 3); PutReserve(*os_, 3);
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
@ -548,6 +554,11 @@ inline bool Writer<StringBuffer>::WriteDouble(double d) {
// Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
return false; return false;
if (kWriteDefaultFlags & kWriteNanAndInfNullFlag) {
PutReserve(*os_, 4);
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l');
return true;
}
if (internal::Double(d).IsNan()) { if (internal::Double(d).IsNan()) {
PutReserve(*os_, 3); PutReserve(*os_, 3);
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');

View file

@ -20,7 +20,7 @@ using namespace rapidjson;
// static const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; // static const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
bool testJson(const char *json, size_t &line, size_t &col) { static bool testJson(const char *json, size_t &line, size_t &col) {
StringStream ss(json); StringStream ss(json);
CursorStreamWrapper<StringStream> csw(ss); CursorStreamWrapper<StringStream> csw(ss);
Document document; Document document;

View file

@ -113,8 +113,8 @@ protected:
EXPECT_EQ(expected, actual); EXPECT_EQ(expected, actual);
} }
EXPECT_EQ('\0', s.Peek()); EXPECT_EQ('\0', s.Peek());
free(data);
EXPECT_EQ(size, eis.Tell()); EXPECT_EQ(size, eis.Tell());
free(data);
} }
} }

View file

@ -77,7 +77,7 @@ static void TestFileStream() {
} }
fp = fopen(filename, "r"); fp = fopen(filename, "r");
ASSERT_TRUE( fp != NULL ); ASSERT_TRUE( fp != NULL );
for (const char* p = s; *p; p++) for (const char* p = s; *p; p++)
EXPECT_EQ(*p, static_cast<char>(fgetc(fp))); EXPECT_EQ(*p, static_cast<char>(fgetc(fp)));
fclose(fp); fclose(fp);

View file

@ -303,7 +303,7 @@ TEST(Pointer, Parse_URIFragment) {
} }
{ {
// Decode UTF-8 perecent encoding to UTF-8 // Decode UTF-8 percent encoding to UTF-8
Pointer p("#/%C2%A2"); Pointer p("#/%C2%A2");
EXPECT_TRUE(p.IsValid()); EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount()); EXPECT_EQ(1u, p.GetTokenCount());
@ -311,7 +311,7 @@ TEST(Pointer, Parse_URIFragment) {
} }
{ {
// Decode UTF-8 perecent encoding to UTF-16 // Decode UTF-8 percent encoding to UTF-16
GenericPointer<GenericValue<UTF16<> > > p(L"#/%C2%A2"); GenericPointer<GenericValue<UTF16<> > > p(L"#/%C2%A2");
EXPECT_TRUE(p.IsValid()); EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount()); EXPECT_EQ(1u, p.GetTokenCount());
@ -320,7 +320,7 @@ TEST(Pointer, Parse_URIFragment) {
} }
{ {
// Decode UTF-8 perecent encoding to UTF-16 // Decode UTF-8 percent encoding to UTF-16
GenericPointer<GenericValue<UTF16<> > > p(L"#/%E2%82%AC"); GenericPointer<GenericValue<UTF16<> > > p(L"#/%E2%82%AC");
EXPECT_TRUE(p.IsValid()); EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount()); EXPECT_EQ(1u, p.GetTokenCount());
@ -475,7 +475,7 @@ TEST(Pointer, CopyConstructor) {
EXPECT_EQ(1u, q.GetTokens()[1].length); EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name); EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index); EXPECT_EQ(0u, q.GetTokens()[1].index);
// Copied pointer needs to have its own allocator // Copied pointer needs to have its own allocator
EXPECT_NE(&p.GetAllocator(), &q.GetAllocator()); EXPECT_NE(&p.GetAllocator(), &q.GetAllocator());
} }
@ -1727,4 +1727,4 @@ TEST(Pointer, Issue1899) {
EXPECT_TRUE(PointerType("/foo/1234") == q); EXPECT_TRUE(PointerType("/foo/1234") == q);
q = q.Append(""); q = q.Append("");
EXPECT_TRUE(PointerType("/foo/1234/") == q); EXPECT_TRUE(PointerType("/foo/1234/") == q);
} }

View file

@ -2054,61 +2054,61 @@ struct NumbersAsStringsHandlerWChar_t {
TEST(Reader, NumbersAsStringsWChar_t) { TEST(Reader, NumbersAsStringsWChar_t) {
{ {
const wchar_t* json = L"{ \"pi\": 3.1416 } "; const wchar_t* json = L"{ \"pi\": 3.1416 } ";
GenericStringStream<UTF16<>> s(json); GenericStringStream<UTF16<> > s(json);
NumbersAsStringsHandlerWChar_t h(L"3.1416"); NumbersAsStringsHandlerWChar_t h(L"3.1416");
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
} }
{ {
wchar_t* json = StrDup(L"{ \"pi\": 3.1416 } "); wchar_t* json = StrDup(L"{ \"pi\": 3.1416 } ");
GenericInsituStringStream<UTF16<>> s(json); GenericInsituStringStream<UTF16<> > s(json);
NumbersAsStringsHandlerWChar_t h(L"3.1416"); NumbersAsStringsHandlerWChar_t h(L"3.1416");
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h));
free(json); free(json);
} }
{ {
const wchar_t* json = L"{ \"gigabyte\": 1.0e9 } "; const wchar_t* json = L"{ \"gigabyte\": 1.0e9 } ";
GenericStringStream<UTF16<>> s(json); GenericStringStream<UTF16<> > s(json);
NumbersAsStringsHandlerWChar_t h(L"1.0e9"); NumbersAsStringsHandlerWChar_t h(L"1.0e9");
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
} }
{ {
wchar_t* json = StrDup(L"{ \"gigabyte\": 1.0e9 } "); wchar_t* json = StrDup(L"{ \"gigabyte\": 1.0e9 } ");
GenericInsituStringStream<UTF16<>> s(json); GenericInsituStringStream<UTF16<> > s(json);
NumbersAsStringsHandlerWChar_t h(L"1.0e9"); NumbersAsStringsHandlerWChar_t h(L"1.0e9");
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h));
free(json); free(json);
} }
{ {
const wchar_t* json = L"{ \"pi\": 314.159e-2 } "; const wchar_t* json = L"{ \"pi\": 314.159e-2 } ";
GenericStringStream<UTF16<>> s(json); GenericStringStream<UTF16<> > s(json);
NumbersAsStringsHandlerWChar_t h(L"314.159e-2"); NumbersAsStringsHandlerWChar_t h(L"314.159e-2");
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
} }
{ {
wchar_t* json = StrDup(L"{ \"gigabyte\": 314.159e-2 } "); wchar_t* json = StrDup(L"{ \"gigabyte\": 314.159e-2 } ");
GenericInsituStringStream<UTF16<>> s(json); GenericInsituStringStream<UTF16<> > s(json);
NumbersAsStringsHandlerWChar_t h(L"314.159e-2"); NumbersAsStringsHandlerWChar_t h(L"314.159e-2");
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h));
free(json); free(json);
} }
{ {
const wchar_t* json = L"{ \"negative\": -1.54321 } "; const wchar_t* json = L"{ \"negative\": -1.54321 } ";
GenericStringStream<UTF16<>> s(json); GenericStringStream<UTF16<> > s(json);
NumbersAsStringsHandlerWChar_t h(L"-1.54321"); NumbersAsStringsHandlerWChar_t h(L"-1.54321");
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
} }
{ {
wchar_t* json = StrDup(L"{ \"negative\": -1.54321 } "); wchar_t* json = StrDup(L"{ \"negative\": -1.54321 } ");
GenericInsituStringStream<UTF16<>> s(json); GenericInsituStringStream<UTF16<> > s(json);
NumbersAsStringsHandlerWChar_t h(L"-1.54321"); NumbersAsStringsHandlerWChar_t h(L"-1.54321");
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h));
free(json); free(json);
} }
@ -2117,7 +2117,7 @@ TEST(Reader, NumbersAsStringsWChar_t) {
std::wstringstream ss(json); std::wstringstream ss(json);
WIStreamWrapper s(ss); WIStreamWrapper s(ss);
NumbersAsStringsHandlerWChar_t h(L"314.159e-2"); NumbersAsStringsHandlerWChar_t h(L"314.159e-2");
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
} }
{ {
@ -2126,9 +2126,9 @@ TEST(Reader, NumbersAsStringsWChar_t) {
for(int i = 1; i < 320; i++) for(int i = 1; i < 320; i++)
n1e319[i] = L'0'; n1e319[i] = L'0';
n1e319[320] = L'\0'; n1e319[320] = L'\0';
GenericStringStream<UTF16<>> s(n1e319); GenericStringStream<UTF16<> > s(n1e319);
NumbersAsStringsHandlerWChar_t h(n1e319); NumbersAsStringsHandlerWChar_t h(n1e319);
GenericReader<UTF16<>, UTF16<>> reader; GenericReader<UTF16<>, UTF16<> > reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h)); EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
} }
} }

View file

@ -112,6 +112,13 @@ TEST(SchemaValidator, Hasher) {
#define VALIDATE(schema, json, expected) \ #define VALIDATE(schema, json, expected) \
{\ {\
VALIDATE_(schema, json, expected, true) \
}
#define VALIDATE_(schema, json, expected, expected2) \
{\
EXPECT_TRUE(expected2 == schema.GetError().ObjectEmpty());\
EXPECT_TRUE(schema.IsSupportedSpecification());\
SchemaValidator validator(schema);\ SchemaValidator validator(schema);\
Document d;\ Document d;\
/*printf("\n%s\n", json);*/\ /*printf("\n%s\n", json);*/\
@ -149,6 +156,8 @@ TEST(SchemaValidator, Hasher) {
#define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, \ #define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, \
flags, SchemaValidatorType, PointerType) \ flags, SchemaValidatorType, PointerType) \
{\ {\
EXPECT_TRUE(schema.GetError().ObjectEmpty());\
EXPECT_TRUE(schema.IsSupportedSpecification());\
SchemaValidatorType validator(schema);\ SchemaValidatorType validator(schema);\
validator.SetValidateFlags(flags);\ validator.SetValidateFlags(flags);\
Document d;\ Document d;\
@ -188,6 +197,20 @@ TEST(SchemaValidator, Hasher) {
}\ }\
} }
// Use for checking whether a compiled schema document contains errors
#define SCHEMAERROR(schema, error) \
{\
Document e;\
e.Parse(error);\
if (schema.GetError() != e) {\
StringBuffer sb;\
Writer<StringBuffer> w(sb);\
schema.GetError().Accept(w);\
printf("GetError() Expected: %s Actual: %s\n", error, sb.GetString());\
ADD_FAILURE();\
}\
}
TEST(SchemaValidator, Typeless) { TEST(SchemaValidator, Typeless) {
Document sd; Document sd;
sd.Parse("{}"); sd.Parse("{}");
@ -223,7 +246,7 @@ TEST(SchemaValidator, Enum_Typed) {
"{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}"); "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
} }
TEST(SchemaValidator, Enum_Typless) { TEST(SchemaValidator, Enum_Typeless) {
Document sd; Document sd;
sd.Parse("{ \"enum\": [\"red\", \"amber\", \"green\", null, 42] }"); sd.Parse("{ \"enum\": [\"red\", \"amber\", \"green\", null, 42] }");
SchemaDocument s(sd); SchemaDocument s(sd);
@ -333,7 +356,7 @@ TEST(SchemaValidator, OneOf) {
" ]" " ]"
"}}"); "}}");
INVALIDATE(s, "15", "", "oneOf", "", INVALIDATE(s, "15", "", "oneOf", "",
"{ \"oneOf\": { \"errorCode\": 22, \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"errors\": [{}, {}]}}"); "{ \"oneOf\": { \"errorCode\": 22, \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"matches\": [0,1]}}");
} }
TEST(SchemaValidator, Not) { TEST(SchemaValidator, Not) {
@ -502,12 +525,13 @@ TEST(SchemaValidator, String_Pattern) {
TEST(SchemaValidator, String_Pattern_Invalid) { TEST(SchemaValidator, String_Pattern_Invalid) {
Document sd; Document sd;
sd.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}"); // TODO: report regex is invalid somehow sd.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}");
SchemaDocument s(sd); SchemaDocument s(sd);
SCHEMAERROR(s, "{\"RegexInvalid\":{\"errorCode\":9,\"instanceRef\":\"#/pattern\",\"value\":\"a{0}\"}}");
VALIDATE(s, "\"\"", true); VALIDATE_(s, "\"\"", true, false);
VALIDATE(s, "\"a\"", true); VALIDATE_(s, "\"a\"", true, false);
VALIDATE(s, "\"aa\"", true); VALIDATE_(s, "\"aa\"", true, false);
} }
#endif #endif
@ -1886,12 +1910,6 @@ TEST(SchemaValidator, SchemaPointer) {
" }," " },"
" \"f\": {" " \"f\": {"
" \"type\": \"boolean\"" " \"type\": \"boolean\""
" },"
" \"cyclic_source\": {"
" \"$ref\": \"#/definitions/Resp_200/properties/cyclic_target\""
" },"
" \"cyclic_target\": {"
" \"$ref\": \"#/definitions/Resp_200/properties/cyclic_source\""
" }" " }"
" }," " },"
" \"type\": \"object\"" " \"type\": \"object\""
@ -2135,9 +2153,13 @@ public:
} }
virtual const SchemaDocumentType* GetRemoteDocument(const char* uri, SizeType length) { virtual const SchemaDocumentType* GetRemoteDocument(const char* uri, SizeType length) {
//printf("GetRemoteDocument : %s\n", uri);
for (size_t i = 0; i < kCount; i++) for (size_t i = 0; i < kCount; i++)
if (typename SchemaDocumentType::SValue(uri, length) == sd_[i]->GetURI()) if (typename SchemaDocumentType::GValue(uri, length) == sd_[i]->GetURI()) {
//printf("Matched document");
return sd_[i]; return sd_[i];
}
//printf("No matched document");
return 0; return 0;
} }
@ -2390,7 +2412,9 @@ TEST(SchemaValidator, Issue728_AllOfRef) {
Document sd; Document sd;
sd.Parse("{\"allOf\": [{\"$ref\": \"#/abc\"}]}"); sd.Parse("{\"allOf\": [{\"$ref\": \"#/abc\"}]}");
SchemaDocument s(sd); SchemaDocument s(sd);
VALIDATE(s, "{\"key1\": \"abc\", \"key2\": \"def\"}", true); SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/allOf/0\",\"value\":\"#/abc\"}}");
VALIDATE_(s, "{\"key1\": \"abc\", \"key2\": \"def\"}", true, false);
} }
TEST(SchemaValidator, Issue1017_allOfHandler) { TEST(SchemaValidator, Issue1017_allOfHandler) {
@ -2625,7 +2649,7 @@ TEST(SchemaValidator, Ref_remote_issue1210) {
SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { } SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { }
virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) { virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
int i = 0; int i = 0;
while (collection[i] && SchemaDocument::SValue(uri, length) != collection[i]->GetURI()) ++i; while (collection[i] && SchemaDocument::GValue(uri, length) != collection[i]->GetURI()) ++i;
return collection[i]; return collection[i];
} }
}; };
@ -2656,7 +2680,7 @@ TEST(SchemaValidator, ContinueOnErrors) {
ASSERT_FALSE(sd.HasParseError()); ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd); SchemaDocument s(sd);
VALIDATE(s, "{\"version\": 1.0, \"address\": {\"number\": 24, \"street1\": \"The Woodlands\", \"street3\": \"Ham\", \"city\": \"Romsey\", \"area\": \"Kent\", \"country\": \"UK\", \"postcode\": \"SO51 0GP\"}, \"phones\": [\"0111-222333\", \"0777-666888\"], \"names\": [\"Fred\", \"Bloggs\"]}", true); VALIDATE(s, "{\"version\": 1.0, \"address\": {\"number\": 24, \"street1\": \"The Woodlands\", \"street3\": \"Ham\", \"city\": \"Romsey\", \"area\": \"Kent\", \"country\": \"UK\", \"postcode\": \"SO51 0GP\"}, \"phones\": [\"0111-222333\", \"0777-666888\"], \"names\": [\"Fred\", \"Bloggs\"]}", true);
INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#", INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"Narnia\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
"{ \"multipleOf\": {" "{ \"multipleOf\": {"
" \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01" " \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
" }," " },"
@ -2691,6 +2715,9 @@ TEST(SchemaValidator, ContinueOnErrors) {
" }," " },"
" \"required\": {" " \"required\": {"
" \"missing\": [\"street1\"], \"errorCode\": 15, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\"" " \"missing\": [\"street1\"], \"errorCode\": 15, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\""
" },"
" \"oneOf\": {"
" \"matches\": [0, 1], \"errorCode\": 22, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/address_type/properties/area\""
" }" " }"
"}", "}",
kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer); kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
@ -2917,7 +2944,7 @@ TEST(SchemaValidator, ContinueOnErrors_RogueString) {
// Test that when kValidateContinueOnErrorFlag is set, an incorrect simple type with a sub-schema is handled correctly. // Test that when kValidateContinueOnErrorFlag is set, an incorrect simple type with a sub-schema is handled correctly.
// This tests that we don't blow up when there is a type mismatch but there is a sub-schema present // This tests that we don't blow up when there is a type mismatch but there is a sub-schema present
TEST(SchemaValidator, ContinueOnErrors_Issue2) { TEST(SchemaValidator, ContinueOnErrors_BadSimpleType) {
Document sd; Document sd;
sd.Parse("{\"type\":\"string\", \"anyOf\":[{\"maxLength\":2}]}"); sd.Parse("{\"type\":\"string\", \"anyOf\":[{\"maxLength\":2}]}");
ASSERT_FALSE(sd.HasParseError()); ASSERT_FALSE(sd.HasParseError());
@ -2943,10 +2970,606 @@ TEST(SchemaValidator, ContinueOnErrors_Issue2) {
kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer); kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
} }
TEST(SchemaValidator, Schema_UnknownError) {
TEST(SchemaValidator, UnknownValidationError) {
ASSERT_TRUE(SchemaValidator::SchemaType::GetValidateErrorKeyword(kValidateErrors).GetString() == std::string("null")); ASSERT_TRUE(SchemaValidator::SchemaType::GetValidateErrorKeyword(kValidateErrors).GetString() == std::string("null"));
} }
// The first occurrence of a duplicate keyword is taken
TEST(SchemaValidator, DuplicateKeyword) {
Document sd;
sd.Parse("{ \"title\": \"test\",\"type\": \"number\", \"type\": \"string\" }");
EXPECT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
VALIDATE(s, "42", true);
INVALIDATE(s, "\"Life, the universe, and everything\"", "", "type", "",
"{ \"type\": {"
" \"errorCode\": 20,"
" \"instanceRef\": \"#\", \"schemaRef\": \"#\","
" \"expected\": [\"number\"], \"actual\": \"string\""
"}}");
}
// SchemaDocument tests
// Specification (schema draft, open api version)
TEST(SchemaValidator, Schema_SupportedNotObject) {
Document sd;
sd.Parse("true");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_SupportedNoSpec) {
Document sd;
sd.Parse("{\"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_SupportedNoSpecStatic) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
Specification spec = SchemaDocumentType::GetSpecification(sd);
ASSERT_FALSE(spec.IsSupported());
ASSERT_TRUE(spec.draft == kDraftNone);
ASSERT_TRUE(spec.oapi == kVersionNone);
}
TEST(SchemaValidator, Schema_SupportedDraft5Static) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"$schema\":\"http://json-schema.org/draft-05/schema#\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
Specification spec = SchemaDocumentType::GetSpecification(sd);
ASSERT_TRUE(spec.IsSupported());
ASSERT_TRUE(spec.draft == kDraft05);
ASSERT_TRUE(spec.oapi == kVersionNone);
}
TEST(SchemaValidator, Schema_SupportedDraft4) {
Document sd;
sd.Parse("{\"$schema\":\"http://json-schema.org/draft-04/schema#\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_SupportedDraft4NoFrag) {
Document sd;
sd.Parse("{\"$schema\":\"http://json-schema.org/draft-04/schema\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_SupportedDraft5) {
Document sd;
sd.Parse("{\"$schema\":\"http://json-schema.org/draft-05/schema#\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft05);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_SupportedDraft5NoFrag) {
Document sd;
sd.Parse("{\"$schema\":\"http://json-schema.org/draft-05/schema\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft05);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_IgnoreDraftEmbedded) {
Document sd;
sd.Parse("{\"root\": {\"$schema\":\"http://json-schema.org/draft-05/schema#\", \"type\": \"integer\"}}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd, 0, 0, 0, 0, SchemaDocument::PointerType("/root"));
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_SupportedDraftOverride) {
Document sd;
sd.Parse("{\"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kDraft04));
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_UnknownDraftOverride) {
Document sd;
sd.Parse("{\"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kDraftUnknown));
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraftUnknown);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnsupportedDraftOverride) {
Document sd;
sd.Parse("{\"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kDraft03));
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft03);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnknownDraft) {
Document sd;
sd.Parse("{\"$schema\":\"http://json-schema.org/draft-xxx/schema#\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraftUnknown);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnknownDraftNotString) {
Document sd;
sd.Parse("{\"$schema\": 4, \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraftUnknown);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnsupportedDraft3) {
Document sd;
sd.Parse("{\"$schema\":\"http://json-schema.org/draft-03/schema#\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft03);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnsupportedDraft6) {
Document sd;
sd.Parse("{\"$schema\":\"http://json-schema.org/draft-06/schema#\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft06);
SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnsupportedDraft7) {
Document sd;
sd.Parse("{\"$schema\":\"http://json-schema.org/draft-07/schema#\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft07);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnsupportedDraft2019_09) {
Document sd;
sd.Parse("{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft2019_09);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnsupportedDraft2020_12) {
Document sd;
sd.Parse("{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\", \"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().draft == kDraft2020_12);
ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_SupportedVersion20Static) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"swagger\":\"2.0\"}");
ASSERT_FALSE(sd.HasParseError());
Specification spec = SchemaDocumentType::GetSpecification(sd);
ASSERT_TRUE(spec.IsSupported());
ASSERT_TRUE(spec.draft == kDraft04);
ASSERT_TRUE(spec.oapi == kVersion20);
}
TEST(SchemaValidator, Schema_SupportedVersion20) {
Document sd;
sd.Parse("{\"swagger\":\"2.0\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().oapi == kVersion20);
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_SupportedVersion30x) {
Document sd;
sd.Parse("{\"openapi\":\"3.0.0\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().oapi == kVersion30);
ASSERT_TRUE(s.GetSpecification().draft == kDraft05);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_SupportedVersionOverride) {
Document sd;
sd.Parse("{\"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion20));
ASSERT_TRUE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().oapi == kVersion20);
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
EXPECT_TRUE(s.GetError().ObjectEmpty());
}
TEST(SchemaValidator, Schema_UnknownVersionOverride) {
Document sd;
sd.Parse("{\"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersionUnknown));
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnsupportedVersionOverride) {
Document sd;
sd.Parse("{\"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion31));
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().oapi == kVersion31);
ASSERT_TRUE(s.GetSpecification().draft == kDraft2020_12);
SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnknownVersion) {
Document sd;
sd.Parse("{\"openapi\":\"1.0\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnknownVersionShort) {
Document sd;
sd.Parse("{\"openapi\":\"3.0.\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnknownVersionNotString) {
Document sd;
sd.Parse("{\"swagger\": 2}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_UnsupportedVersion31) {
Document sd;
sd.Parse("{\"openapi\":\"3.1.0\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_FALSE(s.IsSupportedSpecification());
ASSERT_TRUE(s.GetSpecification().oapi == kVersion31);
ASSERT_TRUE(s.GetSpecification().draft == kDraft2020_12);
SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_DraftAndVersion) {
Document sd;
sd.Parse("{\"swagger\": \"2.0\", \"$schema\": \"http://json-schema.org/draft-04/schema#\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
ASSERT_TRUE(s.IsSupportedSpecification());
SCHEMAERROR(s, "{\"SpecIllegal\":{\"errorCode\":12,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, Schema_StartUnknown) {
Document sd;
sd.Parse("{\"type\": \"integer\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd, 0, 0, 0, 0, SchemaDocument::PointerType("/nowhere"));
SCHEMAERROR(s, "{\"StartUnknown\":{\"errorCode\":1,\"instanceRef\":\"#\", \"value\":\"#/nowhere\"}}");
}
TEST(SchemaValidator, Schema_MultipleErrors) {
Document sd;
sd.Parse("{\"swagger\": \"foo\", \"$schema\": \"bar\"}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s(sd);
SCHEMAERROR(s, "{ \"SpecUnknown\": {\"errorCode\":10,\"instanceRef\":\"#\"},"
" \"SpecIllegal\": {\"errorCode\":12,\"instanceRef\":\"#\"}"
"}");
}
// $ref is a non-JSON pointer fragment - not allowed when OpenAPI
TEST(SchemaValidator, Schema_RefPlainNameOpenApi) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"swagger\": \"2.0\", \"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myStr\": {\"type\": \"string\", \"id\": \"#myStrId\"}, \"myInt2\": {\"type\": \"integer\", \"id\": \"#myId\"}}}");
SchemaDocumentType s(sd);
SCHEMAERROR(s, "{\"RefPlainName\":{\"errorCode\":2,\"instanceRef\":\"#/properties/myInt1\",\"value\":\"#myId\"}}");
}
// $ref is a non-JSON pointer fragment - not allowed when remote document
TEST(SchemaValidator, Schema_RefPlainNameRemote) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#plainname\"}}}");
SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
SCHEMAERROR(s, "{\"RefPlainName\":{\"errorCode\":2,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#plainname\"}}");
}
// $ref is an empty string
TEST(SchemaValidator, Schema_RefEmptyString) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"\"}}}");
SchemaDocumentType s(sd);
SCHEMAERROR(s, "{\"RefInvalid\":{\"errorCode\":3,\"instanceRef\":\"#/properties/myInt1\"}}");
}
// $ref is remote but no provider
TEST(SchemaValidator, Schema_RefNoRemoteProvider) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#plainname\"}}}");
SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, 0);
SCHEMAERROR(s, "{\"RefNoRemoteProvider\":{\"errorCode\":7,\"instanceRef\":\"#/properties/myInt\"}}");
}
// $ref is remote but no schema returned
TEST(SchemaValidator, Schema_RefNoRemoteSchema) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/will-not-resolve.json\"}}}");
SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
SCHEMAERROR(s, "{\"RefNoRemoteSchema\":{\"errorCode\":8,\"instanceRef\":\"#/properties/myInt\",\"value\":\"http://localhost:1234/will-not-resolve.json\"}}");
}
// $ref pointer is invalid
TEST(SchemaValidator, Schema_RefPointerInvalid) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/&&&&&\"}}}");
SchemaDocumentType s(sd);
SCHEMAERROR(s, "{\"RefPointerInvalid\":{\"errorCode\":4,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/&&&&&\",\"offset\":2}}");
}
// $ref is remote and pointer is invalid
TEST(SchemaValidator, Schema_RefPointerInvalidRemote) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/abc&&&&&\"}}}");
SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
SCHEMAERROR(s, "{\"RefPointerInvalid\":{\"errorCode\":4,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/abc&&&&&\",\"offset\":5}}");
}
// $ref is unknown non-pointer
TEST(SchemaValidator, Schema_RefUnknownPlainName) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#plainname\"}}}");
SchemaDocumentType s(sd);
SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#plainname\"}}");
}
/// $ref is unknown pointer
TEST(SchemaValidator, Schema_RefUnknownPointer) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/a/b\"}}}");
SchemaDocumentType s(sd);
SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/a/b\"}}");
}
// $ref is remote and unknown pointer
TEST(SchemaValidator, Schema_RefUnknownPointerRemote) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/a/b\"}}}");
SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"http://localhost:1234/subSchemas.json#/a/b\"}}");
}
// $ref is cyclical
TEST(SchemaValidator, Schema_RefCyclical) {
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
Document sd;
sd.Parse("{\"type\": \"object\", \"properties\": {"
" \"cyclic_source\": {"
" \"$ref\": \"#/properties/cyclic_target\""
" },"
" \"cyclic_target\": {"
" \"$ref\": \"#/properties/cyclic_source\""
" }"
"}}");
SchemaDocumentType s(sd);
SCHEMAERROR(s, "{\"RefCyclical\":{\"errorCode\":6,\"instanceRef\":\"#/properties/cyclic_target\",\"value\":\"#/properties/cyclic_source\"}}");
}
TEST(SchemaValidator, Schema_ReadOnlyAndWriteOnly) {
Document sd;
sd.Parse("{\"type\": \"integer\", \"readOnly\": true, \"writeOnly\": true}");
ASSERT_FALSE(sd.HasParseError());
SchemaDocument s1(sd, 0, 0, 0, 0, 0, Specification(kDraft04));
EXPECT_TRUE(s1.GetError().ObjectEmpty());
SchemaDocument s2(sd, 0, 0, 0, 0, 0, Specification(kVersion30));
SCHEMAERROR(s2, "{\"ReadOnlyAndWriteOnly\":{\"errorCode\":13,\"instanceRef\":\"#\"}}");
}
TEST(SchemaValidator, ReadOnlyWhenWriting) {
Document sd;
sd.Parse(
"{"
" \"type\":\"object\","
" \"properties\": {"
" \"rprop\" : {"
" \"type\": \"string\","
" \"readOnly\": true"
" }"
" }"
"}");
SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion20));
VALIDATE(s, "{ \"rprop\": \"hello\" }", true);
INVALIDATE_(s, "{ \"rprop\": \"hello\" }", "/properties/rprop", "readOnly", "/rprop",
"{ \"readOnly\": {"
" \"errorCode\": 26, \"instanceRef\": \"#/rprop\", \"schemaRef\": \"#/properties/rprop\""
" }"
"}",
kValidateDefaultFlags | kValidateWriteFlag, SchemaValidator, Pointer);
}
TEST(SchemaValidator, WriteOnlyWhenReading) {
Document sd;
sd.Parse(
"{"
" \"type\":\"object\","
" \"properties\": {"
" \"wprop\" : {"
" \"type\": \"boolean\","
" \"writeOnly\": true"
" }"
" }"
"}");
SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion30));
VALIDATE(s, "{ \"wprop\": true }", true);
INVALIDATE_(s, "{ \"wprop\": true }", "/properties/wprop", "writeOnly", "/wprop",
"{ \"writeOnly\": {"
" \"errorCode\": 27, \"instanceRef\": \"#/wprop\", \"schemaRef\": \"#/properties/wprop\""
" }"
"}",
kValidateDefaultFlags | kValidateReadFlag, SchemaValidator, Pointer);
}
TEST(SchemaValidator, NullableTrue) {
Document sd;
sd.Parse("{\"type\": \"string\", \"nullable\": true}");
SchemaDocument s(sd, 0, 0, 0, 0, 0, kVersion20);
VALIDATE(s, "\"hello\"", true);
INVALIDATE(s, "null", "", "type", "",
"{ \"type\": {"
" \"errorCode\": 20,"
" \"instanceRef\": \"#\", \"schemaRef\": \"#\","
" \"expected\": [\"string\"], \"actual\": \"null\""
"}}");
INVALIDATE(s, "false", "", "type", "",
"{ \"type\": {"
" \"errorCode\": 20,"
" \"instanceRef\": \"#\", \"schemaRef\": \"#\","
" \"expected\": [\"string\"], \"actual\": \"boolean\""
"}}");
SchemaDocument s30(sd, 0, 0, 0, 0, 0, kVersion30);
VALIDATE(s30, "\"hello\"", true);
VALIDATE(s30, "null", true);
INVALIDATE(s30, "false", "", "type", "",
"{ \"type\": {"
" \"errorCode\": 20,"
" \"instanceRef\": \"#\", \"schemaRef\": \"#\","
" \"expected\": [\"null\", \"string\"], \"actual\": \"boolean\""
"}}");
}
TEST(SchemaValidator, NullableFalse) {
Document sd;
sd.Parse("{\"type\": \"string\", \"nullable\": false}");
SchemaDocument s(sd, 0, 0, 0, 0, 0, kVersion20);
VALIDATE(s, "\"hello\"", true);
INVALIDATE(s, "null", "", "type", "",
"{ \"type\": {"
" \"errorCode\": 20,"
" \"instanceRef\": \"#\", \"schemaRef\": \"#\","
" \"expected\": [\"string\"], \"actual\": \"null\""
"}}");
INVALIDATE(s, "false", "", "type", "",
"{ \"type\": {"
" \"errorCode\": 20,"
" \"instanceRef\": \"#\", \"schemaRef\": \"#\","
" \"expected\": [\"string\"], \"actual\": \"boolean\""
"}}");
SchemaDocument s30(sd, 0, 0, 0, 0, 0, kVersion30);
VALIDATE(s30, "\"hello\"", true);
INVALIDATE(s, "null", "", "type", "",
"{ \"type\": {"
" \"errorCode\": 20,"
" \"instanceRef\": \"#\", \"schemaRef\": \"#\","
" \"expected\": [\"string\"], \"actual\": \"null\""
"}}");
INVALIDATE(s30, "false", "", "type", "",
"{ \"type\": {"
" \"errorCode\": 20,"
" \"instanceRef\": \"#\", \"schemaRef\": \"#\","
" \"expected\": [\"string\"], \"actual\": \"boolean\""
"}}");
}
#if defined(_MSC_VER) || defined(__clang__) #if defined(_MSC_VER) || defined(__clang__)
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif

View file

@ -49,10 +49,12 @@ using namespace rapidjson_simd;
#define SIMD_SUFFIX(name) name #define SIMD_SUFFIX(name) name
#endif #endif
#define SIMD_SIZE_ALIGN(n) ((size_t(n) + 15) & ~size_t(15))
template <typename StreamType> template <typename StreamType>
void TestSkipWhitespace() { void TestSkipWhitespace() {
for (size_t step = 1; step < 32; step++) { for (size_t step = 1; step < 32; step++) {
char buffer[1025]; char buffer[SIMD_SIZE_ALIGN(1025)];
for (size_t i = 0; i < 1024; i++) for (size_t i = 0; i < 1024; i++)
buffer[i] = " \t\r\n"[i % 4]; buffer[i] = " \t\r\n"[i % 4];
for (size_t i = 0; i < 1024; i += step) for (size_t i = 0; i < 1024; i += step)
@ -79,7 +81,7 @@ TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) { TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) {
for (size_t step = 1; step < 32; step++) { for (size_t step = 1; step < 32; step++) {
char buffer[1024]; char buffer[SIMD_SIZE_ALIGN(1024)];
for (size_t i = 0; i < 1024; i++) for (size_t i = 0; i < 1024; i++)
buffer[i] = " \t\r\n"[i % 4]; buffer[i] = " \t\r\n"[i % 4];
for (size_t i = 0; i < 1024; i += step) for (size_t i = 0; i < 1024; i += step)
@ -87,14 +89,12 @@ TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) {
MemoryStream ms(buffer, 1024); MemoryStream ms(buffer, 1024);
EncodedInputStream<UTF8<>, MemoryStream> s(ms); EncodedInputStream<UTF8<>, MemoryStream> s(ms);
size_t i = 0;
for (;;) { for (;;) {
SkipWhitespace(s); SkipWhitespace(s);
if (s.Peek() == '\0') if (s.Peek() == '\0')
break; break;
//EXPECT_EQ(i, s.Tell()); //EXPECT_EQ(i, s.Tell());
EXPECT_EQ('X', s.Take()); EXPECT_EQ('X', s.Take());
i += step;
} }
} }
} }
@ -109,8 +109,8 @@ struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnesca
template <unsigned parseFlags, typename StreamType> template <unsigned parseFlags, typename StreamType>
void TestScanCopyUnescapedString() { void TestScanCopyUnescapedString() {
char buffer[1024u + 5 + 32]; char buffer[SIMD_SIZE_ALIGN(1024u + 5 + 32)];
char backup[1024u + 5 + 32]; char backup[SIMD_SIZE_ALIGN(1024u + 5 + 32)];
// Test "ABCDABCD...\\" // Test "ABCDABCD...\\"
for (size_t offset = 0; offset < 32; offset++) { for (size_t offset = 0; offset < 32; offset++) {
@ -167,7 +167,7 @@ TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) {
} }
TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) { TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) {
char buffer[2048 + 1 + 32]; char buffer[SIMD_SIZE_ALIGN(2048 + 1 + 32)];
for (size_t offset = 0; offset < 32; offset++) { for (size_t offset = 0; offset < 32; offset++) {
for (size_t step = 0; step < 1024; step++) { for (size_t step = 0; step < 1024; step++) {
char* s = buffer + offset; char* s = buffer + offset;

View file

@ -48,7 +48,6 @@ TEST(Uri, DefaultConstructor) {
EXPECT_TRUE(u.GetStringLength() == 0); EXPECT_TRUE(u.GetStringLength() == 0);
} }
TEST(Uri, Parse) { TEST(Uri, Parse) {
typedef GenericUri<Value, MemoryPoolAllocator<> > UriType; typedef GenericUri<Value, MemoryPoolAllocator<> > UriType;
MemoryPoolAllocator<CrtAllocator> allocator; MemoryPoolAllocator<CrtAllocator> allocator;
@ -66,21 +65,8 @@ TEST(Uri, Parse) {
u.Get(w, allocator); u.Get(w, allocator);
EXPECT_TRUE(*w.GetString() == *v.GetString()); EXPECT_TRUE(*w.GetString() == *v.GetString());
#if RAPIDJSON_HAS_STDSTRING
typedef std::basic_string<Value::Ch> String;
String str = "http://auth/path/xxx?query#frag";
const UriType uri = UriType(str);
EXPECT_TRUE(UriType::GetScheme(uri) == "http:");
EXPECT_TRUE(UriType::GetAuth(uri) == "//auth");
EXPECT_TRUE(UriType::GetPath(uri) == "/path/xxx");
EXPECT_TRUE(UriType::GetBase(uri) == "http://auth/path/xxx?query");
EXPECT_TRUE(UriType::GetQuery(uri) == "?query");
EXPECT_TRUE(UriType::GetFrag(uri) == "#frag");
EXPECT_TRUE(UriType::Get(uri) == str);
#endif
v.SetString("urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f", allocator); v.SetString("urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f", allocator);
u = UriType(v); u = UriType(v, &allocator);
EXPECT_TRUE(StrCmp(u.GetSchemeString(), "urn:") == 0); EXPECT_TRUE(StrCmp(u.GetSchemeString(), "urn:") == 0);
EXPECT_TRUE(u.GetAuthStringLength() == 0); EXPECT_TRUE(u.GetAuthStringLength() == 0);
EXPECT_TRUE(StrCmp(u.GetPathString(), "uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0); EXPECT_TRUE(StrCmp(u.GetPathString(), "uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0);
@ -91,7 +77,7 @@ TEST(Uri, Parse) {
EXPECT_TRUE(*w.GetString() == *v.GetString()); EXPECT_TRUE(*w.GetString() == *v.GetString());
v.SetString("", allocator); v.SetString("", allocator);
u = UriType(v); u = UriType(v, &allocator);
EXPECT_TRUE(u.GetSchemeStringLength() == 0); EXPECT_TRUE(u.GetSchemeStringLength() == 0);
EXPECT_TRUE(u.GetAuthStringLength() == 0); EXPECT_TRUE(u.GetAuthStringLength() == 0);
EXPECT_TRUE(u.GetPathStringLength() == 0); EXPECT_TRUE(u.GetPathStringLength() == 0);
@ -100,7 +86,7 @@ TEST(Uri, Parse) {
EXPECT_TRUE(u.GetFragStringLength() == 0); EXPECT_TRUE(u.GetFragStringLength() == 0);
v.SetString("http://auth/", allocator); v.SetString("http://auth/", allocator);
u = UriType(v); u = UriType(v, &allocator);
EXPECT_TRUE(StrCmp(u.GetSchemeString(), "http:") == 0); EXPECT_TRUE(StrCmp(u.GetSchemeString(), "http:") == 0);
EXPECT_TRUE(StrCmp(u.GetAuthString(), "//auth") == 0); EXPECT_TRUE(StrCmp(u.GetAuthString(), "//auth") == 0);
EXPECT_TRUE(StrCmp(u.GetPathString(), "/") == 0); EXPECT_TRUE(StrCmp(u.GetPathString(), "/") == 0);
@ -162,12 +148,11 @@ TEST(Uri, Parse) {
EXPECT_TRUE(u.GetFragStringLength() == len); EXPECT_TRUE(u.GetFragStringLength() == len);
// Incomplete auth treated as path // Incomplete auth treated as path
str = "http:/"; u = UriType("http:/");
const UriType u2 = UriType(str); EXPECT_TRUE(StrCmp(u.GetSchemeString(), "http:") == 0);
EXPECT_TRUE(StrCmp(u2.GetSchemeString(), "http:") == 0); EXPECT_TRUE(u.GetAuthStringLength() == 0);
EXPECT_TRUE(u2.GetAuthStringLength() == 0); EXPECT_TRUE(StrCmp(u.GetPathString(), "/") == 0);
EXPECT_TRUE(StrCmp(u2.GetPathString(), "/") == 0); EXPECT_TRUE(StrCmp(u.GetBaseString(), "http:/") == 0);
EXPECT_TRUE(StrCmp(u2.GetBaseString(), "http:/") == 0);
} }
TEST(Uri, Parse_UTF16) { TEST(Uri, Parse_UTF16) {
@ -188,21 +173,8 @@ TEST(Uri, Parse_UTF16) {
u.Get(w, allocator); u.Get(w, allocator);
EXPECT_TRUE(*w.GetString() == *v.GetString()); EXPECT_TRUE(*w.GetString() == *v.GetString());
#if RAPIDJSON_HAS_STDSTRING
typedef std::basic_string<Value16::Ch> String;
String str = L"http://auth/path/xxx?query#frag";
const UriType uri = UriType(str);
EXPECT_TRUE(UriType::GetScheme(uri) == L"http:");
EXPECT_TRUE(UriType::GetAuth(uri) == L"//auth");
EXPECT_TRUE(UriType::GetPath(uri) == L"/path/xxx");
EXPECT_TRUE(UriType::GetBase(uri) == L"http://auth/path/xxx?query");
EXPECT_TRUE(UriType::GetQuery(uri) == L"?query");
EXPECT_TRUE(UriType::GetFrag(uri) == L"#frag");
EXPECT_TRUE(UriType::Get(uri) == str);
#endif
v.SetString(L"urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f", allocator); v.SetString(L"urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f", allocator);
u = UriType(v); u = UriType(v, &allocator);
EXPECT_TRUE(StrCmp(u.GetSchemeString(), L"urn:") == 0); EXPECT_TRUE(StrCmp(u.GetSchemeString(), L"urn:") == 0);
EXPECT_TRUE(u.GetAuthStringLength() == 0); EXPECT_TRUE(u.GetAuthStringLength() == 0);
EXPECT_TRUE(StrCmp(u.GetPathString(), L"uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0); EXPECT_TRUE(StrCmp(u.GetPathString(), L"uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0);
@ -213,7 +185,7 @@ TEST(Uri, Parse_UTF16) {
EXPECT_TRUE(*w.GetString() == *v.GetString()); EXPECT_TRUE(*w.GetString() == *v.GetString());
v.SetString(L"", allocator); v.SetString(L"", allocator);
u = UriType(v); u = UriType(v, &allocator);
EXPECT_TRUE(u.GetSchemeStringLength() == 0); EXPECT_TRUE(u.GetSchemeStringLength() == 0);
EXPECT_TRUE(u.GetAuthStringLength() == 0); EXPECT_TRUE(u.GetAuthStringLength() == 0);
EXPECT_TRUE(u.GetPathStringLength() == 0); EXPECT_TRUE(u.GetPathStringLength() == 0);
@ -222,7 +194,7 @@ TEST(Uri, Parse_UTF16) {
EXPECT_TRUE(u.GetFragStringLength() == 0); EXPECT_TRUE(u.GetFragStringLength() == 0);
v.SetString(L"http://auth/", allocator); v.SetString(L"http://auth/", allocator);
u = UriType(v); u = UriType(v, &allocator);
EXPECT_TRUE(StrCmp(u.GetSchemeString(), L"http:") == 0); EXPECT_TRUE(StrCmp(u.GetSchemeString(), L"http:") == 0);
EXPECT_TRUE(StrCmp(u.GetAuthString(), L"//auth") == 0); EXPECT_TRUE(StrCmp(u.GetAuthString(), L"//auth") == 0);
EXPECT_TRUE(StrCmp(u.GetPathString(), L"/") == 0); EXPECT_TRUE(StrCmp(u.GetPathString(), L"/") == 0);
@ -291,6 +263,41 @@ TEST(Uri, Parse_UTF16) {
EXPECT_TRUE(StrCmp(u.GetBaseString(), L"http:/") == 0); EXPECT_TRUE(StrCmp(u.GetBaseString(), L"http:/") == 0);
} }
#if RAPIDJSON_HAS_STDSTRING
TEST(Uri, Parse_Std) {
typedef GenericUri<Value, MemoryPoolAllocator<> > UriType;
MemoryPoolAllocator<CrtAllocator> allocator;
typedef std::basic_string<Value::Ch> String;
String str = "http://auth/path/xxx?query#frag";
const UriType uri = UriType(str, &allocator);
EXPECT_TRUE(UriType::GetScheme(uri) == "http:");
EXPECT_TRUE(UriType::GetAuth(uri) == "//auth");
EXPECT_TRUE(UriType::GetPath(uri) == "/path/xxx");
EXPECT_TRUE(UriType::GetBase(uri) == "http://auth/path/xxx?query");
EXPECT_TRUE(UriType::GetQuery(uri) == "?query");
EXPECT_TRUE(UriType::GetFrag(uri) == "#frag");
EXPECT_TRUE(UriType::Get(uri) == str);
}
TEST(Uri, Parse_UTF16_Std) {
typedef GenericValue<UTF16<> > Value16;
typedef GenericUri<Value16, MemoryPoolAllocator<> > UriType;
MemoryPoolAllocator<CrtAllocator> allocator;
typedef std::basic_string<Value16::Ch> String;
String str = L"http://auth/path/xxx?query#frag";
const UriType uri = UriType(str, &allocator);
EXPECT_TRUE(UriType::GetScheme(uri) == L"http:");
EXPECT_TRUE(UriType::GetAuth(uri) == L"//auth");
EXPECT_TRUE(UriType::GetPath(uri) == L"/path/xxx");
EXPECT_TRUE(UriType::GetBase(uri) == L"http://auth/path/xxx?query");
EXPECT_TRUE(UriType::GetQuery(uri) == L"?query");
EXPECT_TRUE(UriType::GetFrag(uri) == L"#frag");
EXPECT_TRUE(UriType::Get(uri) == str);
}
#endif
TEST(Uri, CopyConstructor) { TEST(Uri, CopyConstructor) {
typedef GenericUri<Value> UriType; typedef GenericUri<Value> UriType;
CrtAllocator allocator; CrtAllocator allocator;

View file

@ -1060,7 +1060,7 @@ static void TestArray(T& x, Allocator& allocator) {
x.Clear(); x.Clear();
for (unsigned i = 0; i < n; i++) for (unsigned i = 0; i < n; i++)
x.PushBack(Value(kArrayType).PushBack(i, allocator).Move(), allocator); x.PushBack(Value(kArrayType).PushBack(i, allocator).Move(), allocator);
itr = x.Erase(x.Begin() + first, x.Begin() + last); itr = x.Erase(x.Begin() + first, x.Begin() + last);
if (last == n) if (last == n)
EXPECT_EQ(x.End(), itr); EXPECT_EQ(x.End(), itr);
@ -1556,7 +1556,7 @@ TEST(Value, ObjectHelper) {
EXPECT_STREQ("apple", y["a"].GetString()); EXPECT_STREQ("apple", y["a"].GetString());
EXPECT_TRUE(x.IsObject()); // Invariant EXPECT_TRUE(x.IsObject()); // Invariant
} }
{ {
Value x(kObjectType); Value x(kObjectType);
x.AddMember("a", "apple", allocator); x.AddMember("a", "apple", allocator);
@ -1581,7 +1581,7 @@ TEST(Value, ObjectHelperRangeFor) {
{ {
int i = 0; int i = 0;
for (auto& m : x.GetObject()) { for (auto& m : x.GetObject()) {
char name[10]; char name[11];
sprintf(name, "%d", i); sprintf(name, "%d", i);
EXPECT_STREQ(name, m.name.GetString()); EXPECT_STREQ(name, m.name.GetString());
EXPECT_EQ(i, m.value.GetInt()); EXPECT_EQ(i, m.value.GetInt());
@ -1592,7 +1592,7 @@ TEST(Value, ObjectHelperRangeFor) {
{ {
int i = 0; int i = 0;
for (const auto& m : const_cast<const Value&>(x).GetObject()) { for (const auto& m : const_cast<const Value&>(x).GetObject()) {
char name[10]; char name[11];
sprintf(name, "%d", i); sprintf(name, "%d", i);
EXPECT_STREQ(name, m.name.GetString()); EXPECT_STREQ(name, m.name.GetString());
EXPECT_EQ(i, m.value.GetInt()); EXPECT_EQ(i, m.value.GetInt());
@ -1674,7 +1674,7 @@ TEST(Value, BigNestedObject) {
for (SizeType i = 0; i < n; i++) { for (SizeType i = 0; i < n; i++) {
char name1[10]; char name1[10];
sprintf(name1, "%d", i); sprintf(name1, "%d", i);
for (SizeType j = 0; j < n; j++) { for (SizeType j = 0; j < n; j++) {
char name2[10]; char name2[10];
sprintf(name2, "%d", j); sprintf(name2, "%d", j);
@ -1689,8 +1689,8 @@ TEST(Value, BigNestedObject) {
TEST(Value, RemoveLastElement) { TEST(Value, RemoveLastElement) {
rapidjson::Document doc; rapidjson::Document doc;
rapidjson::Document::AllocatorType& allocator = doc.GetAllocator(); rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
rapidjson::Value objVal(rapidjson::kObjectType); rapidjson::Value objVal(rapidjson::kObjectType);
objVal.AddMember("var1", 123, allocator); objVal.AddMember("var1", 123, allocator);
objVal.AddMember("var2", "444", allocator); objVal.AddMember("var2", "444", allocator);
objVal.AddMember("var3", 555, allocator); objVal.AddMember("var3", 555, allocator);
EXPECT_TRUE(objVal.HasMember("var3")); EXPECT_TRUE(objVal.HasMember("var3"));
@ -1712,22 +1712,22 @@ TEST(Document, CrtAllocator) {
static void TestShortStringOptimization(const char* str) { static void TestShortStringOptimization(const char* str) {
const rapidjson::SizeType len = static_cast<rapidjson::SizeType>(strlen(str)); const rapidjson::SizeType len = static_cast<rapidjson::SizeType>(strlen(str));
rapidjson::Document doc; rapidjson::Document doc;
rapidjson::Value val; rapidjson::Value val;
val.SetString(str, len, doc.GetAllocator()); val.SetString(str, len, doc.GetAllocator());
EXPECT_EQ(val.GetStringLength(), len); EXPECT_EQ(val.GetStringLength(), len);
EXPECT_STREQ(val.GetString(), str); EXPECT_STREQ(val.GetString(), str);
} }
TEST(Value, AllocateShortString) { TEST(Value, AllocateShortString) {
TestShortStringOptimization(""); // edge case: empty string TestShortStringOptimization(""); // edge case: empty string
TestShortStringOptimization("12345678"); // regular case for short strings: 8 chars TestShortStringOptimization("12345678"); // regular case for short strings: 8 chars
TestShortStringOptimization("12345678901"); // edge case: 11 chars in 32-bit mode (=> short string) TestShortStringOptimization("12345678901"); // edge case: 11 chars in 32-bit mode (=> short string)
TestShortStringOptimization("123456789012"); // edge case: 12 chars in 32-bit mode (=> regular string) TestShortStringOptimization("123456789012"); // edge case: 12 chars in 32-bit mode (=> regular string)
TestShortStringOptimization("123456789012345"); // edge case: 15 chars in 64-bit mode (=> short string) TestShortStringOptimization("123456789012345"); // edge case: 15 chars in 64-bit mode (=> short string)
TestShortStringOptimization("1234567890123456"); // edge case: 16 chars in 64-bit mode (=> regular string) TestShortStringOptimization("1234567890123456"); // edge case: 16 chars in 64-bit mode (=> regular string)
} }
template <int e> template <int e>
@ -1802,7 +1802,7 @@ static void MergeDuplicateKey(Value& v, Value::AllocatorType& a) {
// Convert all key:value into key:[value] // Convert all key:value into key:[value]
for (Value::MemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) for (Value::MemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
itr->value = Value(kArrayType).Move().PushBack(itr->value, a); itr->value = Value(kArrayType).Move().PushBack(itr->value, a);
// Merge arrays if key is duplicated // Merge arrays if key is duplicated
for (Value::MemberIterator itr = v.MemberBegin(); itr != v.MemberEnd();) { for (Value::MemberIterator itr = v.MemberBegin(); itr != v.MemberEnd();) {
Value::MemberIterator itr2 = v.FindMember(itr->name); Value::MemberIterator itr2 = v.FindMember(itr->name);

View file

@ -15,3 +15,12 @@
Memcheck:Value8 Memcheck:Value8
fun:__wcslen_sse2 fun:__wcslen_sse2
} }
{
Suppress wmemcmp valgrind report 4
Memcheck:Addr32
fun:__wmemcmp_avx2_movbe
...
fun:*Uri*Parse_UTF16_Std*
}