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
IF(CMAKE_INSTALL_DIR)
INSTALL(FILES INSTALL(FILES
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
DESTINATION "${CMAKE_INSTALL_DIR}" DESTINATION "${CMAKE_INSTALL_DIR}"
COMPONENT dev) 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,6 +22,8 @@
* 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.

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

@ -104,11 +104,65 @@ 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.");
}
}
//! 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."); default: return RAPIDJSON_ERROR_STRING("Unknown error.");
} }
} }

View file

@ -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
@ -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;
} }

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(); }
}; };

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

@ -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());

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

@ -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());

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*
}