initial
This commit is contained in:
parent
06d58b9e84
commit
338d8defdb
@ -104,7 +104,7 @@ 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'.");
|
||||||
@ -113,6 +113,57 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! 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 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 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 kSchemaErrorReadOnlyAndWriteOnly: return RAPIDJSON_ERROR_STRING("Property must not be both 'readOnly' and 'writeOnly'.");
|
||||||
|
case kSchemaErrorRegexInvalid: return RAPIDJSON_ERROR_STRING("Invalid regular expression '%value' in 'pattern' or 'patternProperties'.");
|
||||||
|
|
||||||
|
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__
|
||||||
|
@ -185,8 +185,8 @@ 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'.
|
||||||
@ -207,6 +207,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.
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
kSchemaErrorReadOnlyAndWriteOnly, //!< Property must not be both 'readOnly' and 'writeOnly'
|
||||||
|
kSchemaErrorRegexInvalid //!< Invalid regular expression in 'pattern' or 'patternProperties'
|
||||||
|
};
|
||||||
|
|
||||||
|
//! 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__
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -234,7 +234,8 @@ public:
|
|||||||
virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
|
virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
|
||||||
virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
||||||
virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
||||||
virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched) = 0;
|
virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
||||||
|
virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0;
|
||||||
virtual void Disallowed() = 0;
|
virtual void Disallowed() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -594,8 +595,9 @@ public:
|
|||||||
|
|
||||||
for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
|
for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
|
||||||
new (&patternProperties_[patternPropertyCount_]) PatternProperty();
|
new (&patternProperties_[patternPropertyCount_]) PatternProperty();
|
||||||
patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
|
PointerType r = q.Append(itr->name, allocator_);
|
||||||
schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document, id_);
|
patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r);
|
||||||
|
schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_);
|
||||||
patternPropertyCount_++;
|
patternPropertyCount_++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -675,7 +677,7 @@ public:
|
|||||||
AssignIfExist(maxLength_, value, GetMaxLengthString());
|
AssignIfExist(maxLength_, value, GetMaxLengthString());
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, GetPatternString()))
|
if (const ValueType* v = GetMember(value, GetPatternString()))
|
||||||
pattern_ = CreatePattern(*v);
|
pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_));
|
||||||
|
|
||||||
// Number
|
// Number
|
||||||
if (const ValueType* v = GetMember(value, GetMinimumString()))
|
if (const ValueType* v = GetMember(value, GetMinimumString()))
|
||||||
@ -828,16 +830,19 @@ public:
|
|||||||
|
|
||||||
if (oneOf_.schemas) {
|
if (oneOf_.schemas) {
|
||||||
bool oneValid = false;
|
bool oneValid = false;
|
||||||
|
SizeType firstMatch = 0;
|
||||||
for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
|
for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
|
||||||
if (context.validators[i]->IsValid()) {
|
if (context.validators[i]->IsValid()) {
|
||||||
if (oneValid) {
|
if (oneValid) {
|
||||||
context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true);
|
context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin);
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch);
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch);
|
||||||
} else
|
} else {
|
||||||
oneValid = true;
|
oneValid = true;
|
||||||
|
firstMatch = i - oneOf_.begin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!oneValid) {
|
if (!oneValid) {
|
||||||
context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false);
|
context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf);
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1247,10 +1252,11 @@ private:
|
|||||||
|
|
||||||
#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
|
#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
RegexType* CreatePattern(const ValueType& value) {
|
RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) {
|
||||||
if (value.IsString()) {
|
if (value.IsString()) {
|
||||||
RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
|
RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
|
||||||
if (!r->IsValid()) {
|
if (!r->IsValid()) {
|
||||||
|
sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
|
||||||
r->~RegexType();
|
r->~RegexType();
|
||||||
AllocatorType::Free(r);
|
AllocatorType::Free(r);
|
||||||
r = 0;
|
r = 0;
|
||||||
@ -1266,13 +1272,14 @@ private:
|
|||||||
}
|
}
|
||||||
#elif RAPIDJSON_SCHEMA_USE_STDREGEX
|
#elif RAPIDJSON_SCHEMA_USE_STDREGEX
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
RegexType* CreatePattern(const ValueType& value) {
|
RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) {
|
||||||
if (value.IsString()) {
|
if (value.IsString()) {
|
||||||
RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
|
RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
|
||||||
try {
|
try {
|
||||||
return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
|
return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
|
||||||
}
|
}
|
||||||
catch (const std::regex_error&) {
|
catch (const std::regex_error& e) {
|
||||||
|
sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
|
||||||
AllocatorType::Free(r);
|
AllocatorType::Free(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1285,7 +1292,9 @@ private:
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
RegexType* CreatePattern(const ValueType&) { return 0; }
|
RegexType* CreatePattern(const ValueType&) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
|
static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
|
||||||
#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
|
#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
|
||||||
@ -1632,8 +1641,9 @@ public:
|
|||||||
typedef typename EncodingType::Ch Ch;
|
typedef typename EncodingType::Ch Ch;
|
||||||
typedef internal::Schema<GenericSchemaDocument> SchemaType;
|
typedef internal::Schema<GenericSchemaDocument> SchemaType;
|
||||||
typedef GenericPointer<ValueType, Allocator> PointerType;
|
typedef GenericPointer<ValueType, Allocator> PointerType;
|
||||||
typedef GenericValue<EncodingType, AllocatorType> SValue;
|
typedef GenericValue<EncodingType, AllocatorType> GValue;
|
||||||
typedef GenericUri<ValueType, Allocator> UriType;
|
typedef GenericUri<ValueType, Allocator> UriType;
|
||||||
|
typedef GenericStringRef<Ch> StringRefType;
|
||||||
friend class internal::Schema<GenericSchemaDocument>;
|
friend class internal::Schema<GenericSchemaDocument>;
|
||||||
template <typename, typename, typename>
|
template <typename, typename, typename>
|
||||||
friend class GenericSchemaValidator;
|
friend class GenericSchemaValidator;
|
||||||
@ -1658,7 +1668,9 @@ public:
|
|||||||
root_(),
|
root_(),
|
||||||
typeless_(),
|
typeless_(),
|
||||||
schemaMap_(allocator, kInitialSchemaMapSize),
|
schemaMap_(allocator, kInitialSchemaMapSize),
|
||||||
schemaRef_(allocator, kInitialSchemaRefSize)
|
schemaRef_(allocator, kInitialSchemaRefSize),
|
||||||
|
error_(kObjectType),
|
||||||
|
currentError_()
|
||||||
{
|
{
|
||||||
if (!allocator_)
|
if (!allocator_)
|
||||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
|
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
|
||||||
@ -1680,6 +1692,11 @@ public:
|
|||||||
else if (const ValueType* v = pointer.Get(document)) {
|
else if (const ValueType* v = pointer.Get(document)) {
|
||||||
CreateSchema(&root_, pointer, *v, document, docId_);
|
CreateSchema(&root_, pointer, *v, document, docId_);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
GenericStringBuffer<EncodingType> sb;
|
||||||
|
pointer.StringifyUriFragment(sb);
|
||||||
|
SchemaErrorValue(kSchemaErrorStartUnknown, PointerType(), sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)));
|
||||||
|
}
|
||||||
|
|
||||||
RAPIDJSON_ASSERT(root_ != 0);
|
RAPIDJSON_ASSERT(root_ != 0);
|
||||||
|
|
||||||
@ -1697,7 +1714,9 @@ public:
|
|||||||
schemaMap_(std::move(rhs.schemaMap_)),
|
schemaMap_(std::move(rhs.schemaMap_)),
|
||||||
schemaRef_(std::move(rhs.schemaRef_)),
|
schemaRef_(std::move(rhs.schemaRef_)),
|
||||||
uri_(std::move(rhs.uri_)),
|
uri_(std::move(rhs.uri_)),
|
||||||
docId_(rhs.docId_)
|
docId_(rhs.docId_),
|
||||||
|
error_(std::move(rhs.error_)),
|
||||||
|
currentError_(std::move(rhs.currentError_))
|
||||||
{
|
{
|
||||||
rhs.remoteProvider_ = 0;
|
rhs.remoteProvider_ = 0;
|
||||||
rhs.allocator_ = 0;
|
rhs.allocator_ = 0;
|
||||||
@ -1719,11 +1738,51 @@ public:
|
|||||||
RAPIDJSON_DELETE(ownAllocator_);
|
RAPIDJSON_DELETE(ownAllocator_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SValue& GetURI() const { return uri_; }
|
const GValue& GetURI() const { return uri_; }
|
||||||
|
|
||||||
//! Get the root schema.
|
//! Get the root schema.
|
||||||
const SchemaType& GetRoot() const { return *root_; }
|
const SchemaType& GetRoot() const { return *root_; }
|
||||||
|
|
||||||
|
//! Gets the error object.
|
||||||
|
GValue& GetError() { return error_; }
|
||||||
|
const GValue& GetError() const { return error_; }
|
||||||
|
|
||||||
|
static const StringRefType& GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode) {
|
||||||
|
switch (schemaErrorCode) {
|
||||||
|
case kSchemaErrorStartUnknown: return GetStartUnknownString();
|
||||||
|
case kSchemaErrorRefPlainName: return GetRefPlainNameString();
|
||||||
|
case kSchemaErrorRefInvalid: return GetRefInvalidString();
|
||||||
|
case kSchemaErrorRefPointerInvalid: return GetRefPointerInvalidString();
|
||||||
|
case kSchemaErrorRefUnknown: return GetRefUnknownString();
|
||||||
|
case kSchemaErrorRefCyclical: return GetRefCyclicalString();
|
||||||
|
case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString();
|
||||||
|
case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString();
|
||||||
|
case kSchemaErrorRegexInvalid: return GetRegexInvalidString();
|
||||||
|
default: return GetNullString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Default error method
|
||||||
|
void SchemaError(const SchemaErrorCode code, const PointerType& location) {
|
||||||
|
currentError_ = GValue(kObjectType);
|
||||||
|
AddCurrentError(code, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Method for error with single string value insert
|
||||||
|
void SchemaErrorValue(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length) {
|
||||||
|
currentError_ = GValue(kObjectType);
|
||||||
|
currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
|
||||||
|
AddCurrentError(code, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Method for error with invalid pointer
|
||||||
|
void SchemaErrorPointer(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length, const PointerType& pointer) {
|
||||||
|
currentError_ = GValue(kObjectType);
|
||||||
|
currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
|
||||||
|
currentError_.AddMember(GetOffsetString(), static_cast<SizeType>(pointer.GetParseErrorOffset() / sizeof(Ch)), *allocator_);
|
||||||
|
AddCurrentError(code, location);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Prohibit copying
|
//! Prohibit copying
|
||||||
GenericSchemaDocument(const GenericSchemaDocument&);
|
GenericSchemaDocument(const GenericSchemaDocument&);
|
||||||
@ -1745,6 +1804,58 @@ private:
|
|||||||
bool owned;
|
bool owned;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void AddErrorInstanceLocation(GValue& result, const PointerType& location) {
|
||||||
|
GenericStringBuffer<EncodingType> sb;
|
||||||
|
location.StringifyUriFragment(sb);
|
||||||
|
GValue instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), *allocator_);
|
||||||
|
result.AddMember(GetInstanceRefString(), instanceRef, *allocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddError(GValue& keyword, GValue& error) {
|
||||||
|
typename GValue::MemberIterator member = error_.FindMember(keyword);
|
||||||
|
if (member == error_.MemberEnd())
|
||||||
|
error_.AddMember(keyword, error, *allocator_);
|
||||||
|
else {
|
||||||
|
if (member->value.IsObject()) {
|
||||||
|
GValue errors(kArrayType);
|
||||||
|
errors.PushBack(member->value, *allocator_);
|
||||||
|
member->value = errors;
|
||||||
|
}
|
||||||
|
member->value.PushBack(error, *allocator_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddCurrentError(const SchemaErrorCode code, const PointerType& location) {
|
||||||
|
currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
|
||||||
|
AddErrorInstanceLocation(currentError_, location);
|
||||||
|
AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RAPIDJSON_STRING_(name, ...) \
|
||||||
|
static const StringRefType& Get##name##String() {\
|
||||||
|
static const Ch s[] = { __VA_ARGS__, '\0' };\
|
||||||
|
static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
|
||||||
|
return v;\
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
|
||||||
|
RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
|
||||||
|
RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e')
|
||||||
|
RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't')
|
||||||
|
|
||||||
|
RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
|
||||||
|
RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
|
||||||
|
RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e')
|
||||||
|
RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
|
||||||
|
RAPIDJSON_STRING_(RefPointerInvalid, 'R', 'e', 'f', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
|
||||||
|
RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
|
||||||
|
RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l')
|
||||||
|
RAPIDJSON_STRING_(RefNoRemoteProvider, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r')
|
||||||
|
RAPIDJSON_STRING_(RefNoRemoteSchema, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'S', 'c', 'h', 'e', 'm', 'a')
|
||||||
|
RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
|
||||||
|
|
||||||
|
#undef RAPIDJSON_STRING_
|
||||||
|
|
||||||
// Changed by PR #1393
|
// Changed by PR #1393
|
||||||
void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
|
void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
|
||||||
if (v.GetType() == kObjectType) {
|
if (v.GetType() == kObjectType) {
|
||||||
@ -1795,7 +1906,9 @@ private:
|
|||||||
|
|
||||||
if (itr->value.IsString()) {
|
if (itr->value.IsString()) {
|
||||||
SizeType len = itr->value.GetStringLength();
|
SizeType len = itr->value.GetStringLength();
|
||||||
if (len > 0) {
|
if (len == 0)
|
||||||
|
SchemaError(kSchemaErrorRefInvalid, source);
|
||||||
|
else {
|
||||||
// First resolve $ref against the in-scope id
|
// First resolve $ref against the in-scope id
|
||||||
UriType scopeId = UriType(id, allocator_);
|
UriType scopeId = UriType(id, allocator_);
|
||||||
UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
|
UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
|
||||||
@ -1805,26 +1918,32 @@ private:
|
|||||||
const ValueType *base = FindId(document, ref, basePointer, docId_, false);
|
const ValueType *base = FindId(document, ref, basePointer, docId_, false);
|
||||||
if (!base) {
|
if (!base) {
|
||||||
// Remote reference - call the remote document provider
|
// Remote reference - call the remote document provider
|
||||||
if (remoteProvider_) {
|
if (!remoteProvider_)
|
||||||
|
SchemaError(kSchemaErrorRefNoRemoteProvider, source);
|
||||||
|
else {
|
||||||
if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref)) {
|
if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref)) {
|
||||||
const Ch* s = ref.GetFragString();
|
const Ch* s = ref.GetFragString();
|
||||||
len = ref.GetFragStringLength();
|
len = ref.GetFragStringLength();
|
||||||
if (len <= 1 || s[1] == '/') {
|
if (len <= 1 || s[1] == '/') {
|
||||||
// JSON pointer fragment, absolute in the remote schema
|
// JSON pointer fragment, absolute in the remote schema
|
||||||
const PointerType pointer(s, len, allocator_);
|
const PointerType pointer(s, len, allocator_);
|
||||||
if (pointer.IsValid()) {
|
if (!pointer.IsValid())
|
||||||
|
SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, pointer);
|
||||||
|
else {
|
||||||
// Get the subschema
|
// Get the subschema
|
||||||
if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) {
|
if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) {
|
||||||
if (schema)
|
if (schema)
|
||||||
*schema = sc;
|
*schema = sc;
|
||||||
AddSchemaRefs(const_cast<SchemaType *>(sc));
|
AddSchemaRefs(const_cast<SchemaType *>(sc));
|
||||||
return true;
|
return true;
|
||||||
|
} else
|
||||||
|
SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
} else {
|
// Plain name fragment, not allowed in remote schema
|
||||||
// Plain name fragment, not allowed
|
SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
|
||||||
}
|
} else
|
||||||
}
|
SchemaErrorValue(kSchemaErrorRefNoRemoteSchema, source, ref.GetString(), ref.GetStringLength());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // Local reference
|
else { // Local reference
|
||||||
@ -1833,16 +1952,18 @@ private:
|
|||||||
if (len <= 1 || s[1] == '/') {
|
if (len <= 1 || s[1] == '/') {
|
||||||
// JSON pointer fragment, relative to the resolved URI
|
// JSON pointer fragment, relative to the resolved URI
|
||||||
const PointerType relPointer(s, len, allocator_);
|
const PointerType relPointer(s, len, allocator_);
|
||||||
if (relPointer.IsValid()) {
|
if (!relPointer.IsValid())
|
||||||
|
SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, relPointer);
|
||||||
|
else {
|
||||||
// Get the subschema
|
// Get the subschema
|
||||||
if (const ValueType *pv = relPointer.Get(*base)) {
|
if (const ValueType *pv = relPointer.Get(*base)) {
|
||||||
// Now get the absolute JSON pointer by adding relative to base
|
// Now get the absolute JSON pointer by adding relative to base
|
||||||
PointerType pointer(basePointer);
|
PointerType pointer(basePointer);
|
||||||
for (SizeType i = 0; i < relPointer.GetTokenCount(); i++)
|
for (SizeType i = 0; i < relPointer.GetTokenCount(); i++)
|
||||||
pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
|
pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
|
||||||
//GenericStringBuffer<EncodingType> sb;
|
if (IsCyclicRef(pointer))
|
||||||
//pointer.StringifyUriFragment(sb);
|
SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
|
||||||
if (pointer.IsValid() && !IsCyclicRef(pointer)) {
|
else {
|
||||||
// Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
|
// Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
|
||||||
// TODO: cache pointer <-> id mapping
|
// TODO: cache pointer <-> id mapping
|
||||||
size_t unresolvedTokenIndex;
|
size_t unresolvedTokenIndex;
|
||||||
@ -1850,17 +1971,18 @@ private:
|
|||||||
CreateSchema(schema, pointer, *pv, document, scopeId);
|
CreateSchema(schema, pointer, *pv, document, scopeId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Plain name fragment, relative to the resolved URI
|
// Plain name fragment, relative to the resolved URI
|
||||||
|
PointerType pointer = PointerType();
|
||||||
// See if the fragment matches an id in this document.
|
// See if the fragment matches an id in this document.
|
||||||
// Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer.
|
// Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer.
|
||||||
PointerType pointer = PointerType();
|
|
||||||
if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) {
|
if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) {
|
||||||
if (!IsCyclicRef(pointer)) {
|
if (IsCyclicRef(pointer))
|
||||||
//GenericStringBuffer<EncodingType> sb;
|
SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
|
||||||
//pointer.StringifyUriFragment(sb);
|
else {
|
||||||
// Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
|
// Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
|
||||||
// TODO: cache pointer <-> id mapping
|
// TODO: cache pointer <-> id mapping
|
||||||
size_t unresolvedTokenIndex;
|
size_t unresolvedTokenIndex;
|
||||||
@ -1868,7 +1990,8 @@ private:
|
|||||||
CreateSchema(schema, pointer, *pv, document, scopeId);
|
CreateSchema(schema, pointer, *pv, document, scopeId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1965,8 +2088,10 @@ private:
|
|||||||
SchemaType* typeless_;
|
SchemaType* typeless_;
|
||||||
internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
|
internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
|
||||||
internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
|
internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
|
||||||
SValue uri_; // Schema document URI
|
GValue uri_; // Schema document URI
|
||||||
UriType docId_;
|
UriType docId_;
|
||||||
|
GValue error_;
|
||||||
|
GValue currentError_;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! GenericSchemaDocument using Value type.
|
//! GenericSchemaDocument using Value type.
|
||||||
@ -2099,13 +2224,12 @@ public:
|
|||||||
return flags_;
|
return flags_;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Checks whether the current state is valid.
|
|
||||||
// Implementation of ISchemaValidator
|
|
||||||
virtual bool IsValid() const {
|
virtual bool IsValid() const {
|
||||||
if (!valid_) return false;
|
if (!valid_) return false;
|
||||||
if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false;
|
if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
//! End of Implementation of ISchemaValidator
|
||||||
|
|
||||||
//! Gets the error object.
|
//! Gets the error object.
|
||||||
ValueType& GetError() { return error_; }
|
ValueType& GetError() { return error_; }
|
||||||
@ -2313,8 +2437,16 @@ public:
|
|||||||
void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
|
void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
|
||||||
AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
|
AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
|
||||||
}
|
}
|
||||||
void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched = false) {
|
void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
|
||||||
AddErrorArray(matched ? kValidateErrorOneOfMatch : kValidateErrorOneOf, subvalidators, count);
|
AddErrorArray(kValidateErrorOneOf, subvalidators, count);
|
||||||
|
}
|
||||||
|
void MultipleOneOf(SizeType index1, SizeType index2) {
|
||||||
|
ValueType matches(kArrayType);
|
||||||
|
matches.PushBack(index1, GetStateAllocator());
|
||||||
|
matches.PushBack(index2, GetStateAllocator());
|
||||||
|
currentError_.SetObject();
|
||||||
|
currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator());
|
||||||
|
AddCurrentError(kValidateErrorOneOfMatch);
|
||||||
}
|
}
|
||||||
void Disallowed() {
|
void Disallowed() {
|
||||||
currentError_.SetObject();
|
currentError_.SetObject();
|
||||||
@ -2338,6 +2470,7 @@ public:
|
|||||||
RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
|
RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
|
||||||
RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
|
RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
|
||||||
RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
|
RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
|
||||||
|
RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's')
|
||||||
|
|
||||||
#undef RAPIDJSON_STRING_
|
#undef RAPIDJSON_STRING_
|
||||||
|
|
||||||
@ -2482,6 +2615,7 @@ RAPIDJSON_MULTILINEMACRO_END
|
|||||||
virtual void FreeState(void* p) {
|
virtual void FreeState(void* p) {
|
||||||
StateAllocator::Free(p);
|
StateAllocator::Free(p);
|
||||||
}
|
}
|
||||||
|
// End of implementation of ISchemaStateFactory<SchemaType>
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef typename SchemaType::Context Context;
|
typedef typename SchemaType::Context Context;
|
||||||
|
@ -112,6 +112,12 @@ 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());\
|
||||||
SchemaValidator validator(schema);\
|
SchemaValidator validator(schema);\
|
||||||
Document d;\
|
Document d;\
|
||||||
/*printf("\n%s\n", json);*/\
|
/*printf("\n%s\n", json);*/\
|
||||||
@ -149,6 +155,7 @@ 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());\
|
||||||
SchemaValidatorType validator(schema);\
|
SchemaValidatorType validator(schema);\
|
||||||
validator.SetValidateFlags(flags);\
|
validator.SetValidateFlags(flags);\
|
||||||
Document d;\
|
Document d;\
|
||||||
@ -188,6 +195,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 +244,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 +354,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 +523,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 +1908,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\""
|
||||||
@ -2390,7 +2406,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 +2643,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 +2674,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 +2709,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 +2938,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 +2964,148 @@ 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
|
||||||
|
|
||||||
|
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\"}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// $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\"}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__clang__)
|
#if defined(_MSC_VER) || defined(__clang__)
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user