code & tests for openapi 2.0 & 3.0 suppprt
This commit is contained in:
parent
80b6d1c834
commit
55eca66f39
@ -1,5 +1,5 @@
|
|||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
@ -7,9 +7,9 @@
|
|||||||
//
|
//
|
||||||
// http://opensource.org/licenses/MIT
|
// http://opensource.org/licenses/MIT
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
#ifndef RAPIDJSON_ERROR_EN_H_
|
#ifndef RAPIDJSON_ERROR_EN_H_
|
||||||
@ -109,6 +109,9 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode val
|
|||||||
case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
|
case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
|
||||||
case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
|
case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
|
||||||
|
|
||||||
|
case kValidateErrorReadOnly: return RAPIDJSON_ERROR_STRING("Property is read-only but has been provided when validation is for writing.");
|
||||||
|
case kValidateErrorWriteOnly: return RAPIDJSON_ERROR_STRING("Property is write-only but has been provided when validation is for reading.");
|
||||||
|
|
||||||
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,6 +137,10 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode val
|
|||||||
case kSchemaErrorRefNoRemoteProvider: return RAPIDJSON_ERROR_STRING("$ref is remote but there is no remote provider.");
|
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 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 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.");
|
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
@ -7,9 +7,9 @@
|
|||||||
//
|
//
|
||||||
// http://opensource.org/licenses/MIT
|
// http://opensource.org/licenses/MIT
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
#ifndef RAPIDJSON_ERROR_ERROR_H_
|
#ifndef RAPIDJSON_ERROR_ERROR_H_
|
||||||
@ -192,7 +192,10 @@ enum ValidateErrorCode {
|
|||||||
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().
|
||||||
@ -225,7 +228,11 @@ enum SchemaErrorCode {
|
|||||||
kSchemaErrorRefCyclical, //!< $ref is cyclical
|
kSchemaErrorRefCyclical, //!< $ref is cyclical
|
||||||
kSchemaErrorRefNoRemoteProvider, //!< $ref is remote but there is no remote provider
|
kSchemaErrorRefNoRemoteProvider, //!< $ref is remote but there is no remote provider
|
||||||
kSchemaErrorRefNoRemoteSchema, //!< $ref is remote but the remote provider did not return a schema
|
kSchemaErrorRefNoRemoteSchema, //!< $ref is remote but the remote provider did not return a schema
|
||||||
kSchemaErrorRegexInvalid //!< Invalid regular expression in 'pattern' or 'patternProperties'
|
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().
|
//! Function pointer type of GetSchemaError().
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Tencent is pleased to support the open source community by making RapidJSON available->
|
// Tencent is pleased to support the open source community by making RapidJSON available->
|
||||||
//
|
//
|
||||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
|
||||||
//
|
//
|
||||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
@ -7,9 +7,9 @@
|
|||||||
//
|
//
|
||||||
// http://opensource->org/licenses/MIT
|
// http://opensource->org/licenses/MIT
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software distributed
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
|
||||||
// specific language governing permissions and limitations under the License->
|
// specific language governing permissions and limitations under the License->
|
||||||
|
|
||||||
#ifndef RAPIDJSON_SCHEMA_H_
|
#ifndef RAPIDJSON_SCHEMA_H_
|
||||||
@ -74,48 +74,94 @@ RAPIDJSON_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
inline void PrintInvalidKeyword(const char* keyword) {
|
inline void PrintInvalidKeywordData(const char* keyword) {
|
||||||
printf("Fail keyword: %s\n", keyword);
|
printf(" Fail keyword: '%s'\n", keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PrintInvalidKeyword(const wchar_t* keyword) {
|
inline void PrintInvalidKeywordData(const wchar_t* keyword) {
|
||||||
wprintf(L"Fail keyword: %ls\n", keyword);
|
wprintf(L" Fail keyword: '%ls'\n", keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PrintInvalidDocument(const char* document) {
|
inline void PrintInvalidDocumentData(const char* document) {
|
||||||
printf("Fail document: %s\n\n", document);
|
printf(" Fail document: '%s'\n", document);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PrintInvalidDocument(const wchar_t* document) {
|
inline void PrintInvalidDocumentData(const wchar_t* document) {
|
||||||
wprintf(L"Fail document: %ls\n\n", document);
|
wprintf(L" Fail document: '%ls'\n", document);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
|
inline void PrintValidatorPointersData(const char* s, const char* d, unsigned depth) {
|
||||||
printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
|
printf(" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4, " ", s, depth * 4, " ", d);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
|
inline void PrintValidatorPointersData(const wchar_t* s, const wchar_t* d, unsigned depth) {
|
||||||
wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
|
wprintf(L" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L" ", s, depth * 4, L" ", d);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintSchemaIdsData(const char* base, const char* local, const char* resolved) {
|
||||||
|
printf(" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintSchemaIdsData(const wchar_t* base, const wchar_t* local, const wchar_t* resolved) {
|
||||||
|
wprintf(L" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintMethodData(const char* method) {
|
||||||
|
printf("%s\n", method);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintMethodData(const char* method, bool b) {
|
||||||
|
printf("%s, Data: '%s'\n", method, b ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintMethodData(const char* method, int64_t i) {
|
||||||
|
printf("%s, Data: '%" PRId64 "'\n", method, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintMethodData(const char* method, uint64_t u) {
|
||||||
|
printf("%s, Data: '%" PRIu64 "'\n", method, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintMethodData(const char* method, double d) {
|
||||||
|
printf("%s, Data: '%lf'\n", method, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintMethodData(const char* method, const char* s) {
|
||||||
|
printf("%s, Data: '%s'\n", method, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintMethodData(const char* method, const wchar_t* s) {
|
||||||
|
wprintf(L"%hs, Data: '%ls'\n", method, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintMethodData(const char* method, const char* s1, const char* s2) {
|
||||||
|
printf("%s, Data: '%s', '%s'\n", method, s1, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintMethodData(const char* method, const wchar_t* s1, const wchar_t* s2) {
|
||||||
|
wprintf(L"%hs, Data: '%ls', '%ls'\n", method, s1, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
#endif // RAPIDJSON_SCHEMA_VERBOSE
|
#endif // RAPIDJSON_SCHEMA_VERBOSE
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_SCHEMA_PRINT
|
||||||
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
||||||
|
#define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_SCHEMA_PRINT(name, ...)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// RAPIDJSON_INVALID_KEYWORD_RETURN
|
// RAPIDJSON_INVALID_KEYWORD_RETURN
|
||||||
|
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
|
||||||
#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
|
|
||||||
#else
|
|
||||||
#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
|
#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
|
||||||
RAPIDJSON_MULTILINEMACRO_BEGIN\
|
RAPIDJSON_MULTILINEMACRO_BEGIN\
|
||||||
context.invalidCode = code;\
|
context.invalidCode = code;\
|
||||||
context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
|
context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
|
||||||
RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\
|
RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword);\
|
||||||
return false;\
|
return false;\
|
||||||
RAPIDJSON_MULTILINEMACRO_END
|
RAPIDJSON_MULTILINEMACRO_END
|
||||||
|
|
||||||
@ -138,9 +184,53 @@ RAPIDJSON_MULTILINEMACRO_END
|
|||||||
enum ValidateFlag {
|
enum ValidateFlag {
|
||||||
kValidateNoFlags = 0, //!< No flags are set.
|
kValidateNoFlags = 0, //!< No flags are set.
|
||||||
kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error.
|
kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error.
|
||||||
|
kValidateReadFlag = 2, //!< Validation is for a read semantic.
|
||||||
|
kValidateWriteFlag = 4, //!< Validation is for a write semantic.
|
||||||
kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS
|
kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Specification
|
||||||
|
enum SchemaDraft {
|
||||||
|
kDraftUnknown = -1,
|
||||||
|
kDraftNone = 0,
|
||||||
|
kDraft03 = 3,
|
||||||
|
kDraftMin = 4, //!< Current minimum supported draft
|
||||||
|
kDraft04 = 4,
|
||||||
|
kDraft05 = 5,
|
||||||
|
kDraftMax = 5, //!< Current maximum supported draft
|
||||||
|
kDraft06 = 6,
|
||||||
|
kDraft07 = 7,
|
||||||
|
kDraft2019_09 = 8,
|
||||||
|
kDraft2020_12 = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
enum OpenApiVersion {
|
||||||
|
kVersionUnknown = -1,
|
||||||
|
kVersionNone = 0,
|
||||||
|
kVersionMin = 2, //!< Current minimum supported version
|
||||||
|
kVersion20 = 2,
|
||||||
|
kVersion30 = 3,
|
||||||
|
kVersionMax = 3, //!< Current maximum supported version
|
||||||
|
kVersion31 = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Specification {
|
||||||
|
Specification(SchemaDraft d) : draft(d), oapi(kVersionNone) {}
|
||||||
|
Specification(OpenApiVersion o) : oapi(o) {
|
||||||
|
if (oapi == kVersion20) draft = kDraft04;
|
||||||
|
else if (oapi == kVersion30) draft = kDraft05;
|
||||||
|
else if (oapi == kVersion31) draft = kDraft2020_12;
|
||||||
|
else draft = kDraft04;
|
||||||
|
}
|
||||||
|
~Specification() {}
|
||||||
|
bool IsSupported() const {
|
||||||
|
return ((draft >= kDraftMin && draft <= kDraftMax) && ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax)));
|
||||||
|
}
|
||||||
|
SchemaDraft draft;
|
||||||
|
OpenApiVersion oapi;
|
||||||
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
|
|
||||||
@ -233,6 +323,8 @@ public:
|
|||||||
virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
|
||||||
virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0;
|
virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0;
|
||||||
virtual void Disallowed() = 0;
|
virtual void Disallowed() = 0;
|
||||||
|
virtual void DisallowedWhenWriting() = 0;
|
||||||
|
virtual void DisallowedWhenReading() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -253,10 +345,10 @@ public:
|
|||||||
bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
|
bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
|
||||||
bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
|
bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
|
||||||
bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
|
bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
|
||||||
bool Double(double d) {
|
bool Double(double d) {
|
||||||
Number n;
|
Number n;
|
||||||
if (d < 0) n.u.i = static_cast<int64_t>(d);
|
if (d < 0) n.u.i = static_cast<int64_t>(d);
|
||||||
else n.u.u = static_cast<uint64_t>(d);
|
else n.u.u = static_cast<uint64_t>(d);
|
||||||
n.d = d;
|
n.d = d;
|
||||||
return WriteNumber(n);
|
return WriteNumber(n);
|
||||||
}
|
}
|
||||||
@ -350,10 +442,11 @@ struct SchemaValidationContext {
|
|||||||
kPatternValidatorWithAdditionalProperty
|
kPatternValidatorWithAdditionalProperty
|
||||||
};
|
};
|
||||||
|
|
||||||
SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) :
|
SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s, unsigned fl = 0) :
|
||||||
factory(f),
|
factory(f),
|
||||||
error_handler(eh),
|
error_handler(eh),
|
||||||
schema(s),
|
schema(s),
|
||||||
|
flags(fl),
|
||||||
valueSchema(),
|
valueSchema(),
|
||||||
invalidKeyword(),
|
invalidKeyword(),
|
||||||
invalidCode(),
|
invalidCode(),
|
||||||
@ -401,6 +494,7 @@ struct SchemaValidationContext {
|
|||||||
SchemaValidatorFactoryType& factory;
|
SchemaValidatorFactoryType& factory;
|
||||||
ErrorHandlerType& error_handler;
|
ErrorHandlerType& error_handler;
|
||||||
const SchemaType* schema;
|
const SchemaType* schema;
|
||||||
|
unsigned flags;
|
||||||
const SchemaType* valueSchema;
|
const SchemaType* valueSchema;
|
||||||
const Ch* invalidKeyword;
|
const Ch* invalidKeyword;
|
||||||
ValidateErrorCode invalidCode;
|
ValidateErrorCode invalidCode;
|
||||||
@ -443,6 +537,7 @@ public:
|
|||||||
allocator_(allocator),
|
allocator_(allocator),
|
||||||
uri_(schemaDocument->GetURI(), *allocator),
|
uri_(schemaDocument->GetURI(), *allocator),
|
||||||
id_(id, allocator),
|
id_(id, allocator),
|
||||||
|
spec_(schemaDocument->GetSpecification()),
|
||||||
pointer_(p, allocator),
|
pointer_(p, allocator),
|
||||||
typeless_(schemaDocument->GetTypeless()),
|
typeless_(schemaDocument->GetTypeless()),
|
||||||
enum_(),
|
enum_(),
|
||||||
@ -475,8 +570,15 @@ public:
|
|||||||
maxLength_(~SizeType(0)),
|
maxLength_(~SizeType(0)),
|
||||||
exclusiveMinimum_(false),
|
exclusiveMinimum_(false),
|
||||||
exclusiveMaximum_(false),
|
exclusiveMaximum_(false),
|
||||||
defaultValueLength_(0)
|
defaultValueLength_(0),
|
||||||
|
readOnly_(false),
|
||||||
|
writeOnly_(false),
|
||||||
|
nullable_(false)
|
||||||
{
|
{
|
||||||
|
GenericStringBuffer<EncodingType> sb;
|
||||||
|
p.StringifyUriFragment(sb);
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Schema", sb.GetString(), id.GetString());
|
||||||
|
|
||||||
typedef typename ValueType::ConstValueIterator ConstValueIterator;
|
typedef typename ValueType::ConstValueIterator ConstValueIterator;
|
||||||
typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
|
typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
|
||||||
|
|
||||||
@ -495,10 +597,13 @@ public:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// If we have an id property, resolve it with the in-scope id
|
// If we have an id property, resolve it with the in-scope id
|
||||||
|
// Not supported for open api 2.0 or 3.0
|
||||||
|
if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
|
||||||
if (const ValueType* v = GetMember(value, GetIdString())) {
|
if (const ValueType* v = GetMember(value, GetIdString())) {
|
||||||
if (v->IsString()) {
|
if (v->IsString()) {
|
||||||
UriType local(*v, allocator);
|
UriType local(*v, allocator);
|
||||||
id_ = local.Resolve(id_, allocator);
|
id_ = local.Resolve(id_, allocator);
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), v->GetString(), id_.GetString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,8 +630,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schemaDocument) {
|
if (schemaDocument)
|
||||||
AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
|
AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
|
||||||
|
|
||||||
|
// AnyOf, OneOf, Not not supported for open api 2.0
|
||||||
|
if (schemaDocument && spec_.oapi != kVersion20) {
|
||||||
AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
|
AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
|
||||||
AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
|
AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
|
||||||
|
|
||||||
@ -555,6 +663,8 @@ public:
|
|||||||
if (itr->IsString())
|
if (itr->IsString())
|
||||||
AddUniqueElement(allProperties, *itr);
|
AddUniqueElement(allProperties, *itr);
|
||||||
|
|
||||||
|
// Dependencies not supported for open api 2.0 and 3.0
|
||||||
|
if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
|
||||||
if (dependencies && dependencies->IsObject())
|
if (dependencies && dependencies->IsObject())
|
||||||
for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
|
for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
|
||||||
AddUniqueElement(allProperties, itr->name);
|
AddUniqueElement(allProperties, itr->name);
|
||||||
@ -584,6 +694,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PatternProperties not supported for open api 2.0 and 3.0
|
||||||
|
if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
|
||||||
if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
|
if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
|
||||||
PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
|
PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
|
||||||
patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
|
patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
|
||||||
@ -608,6 +720,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dependencies not supported for open api 2.0 and 3.0
|
||||||
|
if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
|
||||||
if (dependencies && dependencies->IsObject()) {
|
if (dependencies && dependencies->IsObject()) {
|
||||||
PointerType q = p.Append(GetDependenciesString(), allocator_);
|
PointerType q = p.Append(GetDependenciesString(), allocator_);
|
||||||
hasDependencies_ = true;
|
hasDependencies_ = true;
|
||||||
@ -659,6 +773,8 @@ public:
|
|||||||
AssignIfExist(minItems_, value, GetMinItemsString());
|
AssignIfExist(minItems_, value, GetMinItemsString());
|
||||||
AssignIfExist(maxItems_, value, GetMaxItemsString());
|
AssignIfExist(maxItems_, value, GetMaxItemsString());
|
||||||
|
|
||||||
|
// AdditionalItems not supported for openapi 2.0 and 3.0
|
||||||
|
if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
|
||||||
if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
|
if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
|
||||||
if (v->IsBool())
|
if (v->IsBool())
|
||||||
additionalItems_ = v->GetBool();
|
additionalItems_ = v->GetBool();
|
||||||
@ -696,6 +812,23 @@ public:
|
|||||||
if (v->IsString())
|
if (v->IsString())
|
||||||
defaultValueLength_ = v->GetStringLength();
|
defaultValueLength_ = v->GetStringLength();
|
||||||
|
|
||||||
|
// ReadOnly - open api only (until draft 7 supported)
|
||||||
|
// WriteOnly - open api 3 only (until draft 7 supported)
|
||||||
|
// Both can't be true
|
||||||
|
if (spec_.oapi != kVersionNone)
|
||||||
|
AssignIfExist(readOnly_, value, GetReadOnlyString());
|
||||||
|
if (spec_.oapi >= kVersion30)
|
||||||
|
AssignIfExist(writeOnly_, value, GetWriteOnlyString());
|
||||||
|
if (readOnly_ && writeOnly_)
|
||||||
|
schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p);
|
||||||
|
|
||||||
|
// Nullable - open api 3 only
|
||||||
|
// If true add 'null' as allowable type
|
||||||
|
if (spec_.oapi >= kVersion30) {
|
||||||
|
AssignIfExist(nullable_, value, GetNullableString());
|
||||||
|
if (nullable_)
|
||||||
|
AddType(GetNullString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~Schema() {
|
~Schema() {
|
||||||
@ -727,11 +860,16 @@ public:
|
|||||||
return id_;
|
return id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Specification& GetSpecification() const {
|
||||||
|
return spec_;
|
||||||
|
}
|
||||||
|
|
||||||
const PointerType& GetPointer() const {
|
const PointerType& GetPointer() const {
|
||||||
return pointer_;
|
return pointer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BeginValue(Context& context) const {
|
bool BeginValue(Context& context) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::BeginValue");
|
||||||
if (context.inArray) {
|
if (context.inArray) {
|
||||||
if (uniqueItems_)
|
if (uniqueItems_)
|
||||||
context.valueUniqueness = true;
|
context.valueUniqueness = true;
|
||||||
@ -763,6 +901,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
|
RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndValue");
|
||||||
// Only check pattern properties if we have validators
|
// Only check pattern properties if we have validators
|
||||||
if (context.patternPropertiesValidatorCount > 0) {
|
if (context.patternPropertiesValidatorCount > 0) {
|
||||||
bool otherValid = false;
|
bool otherValid = false;
|
||||||
@ -853,6 +992,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Null(Context& context) const {
|
bool Null(Context& context) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Null");
|
||||||
if (!(type_ & (1 << kNullSchemaType))) {
|
if (!(type_ & (1 << kNullSchemaType))) {
|
||||||
DisallowedType(context, GetNullString());
|
DisallowedType(context, GetNullString());
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
||||||
@ -860,39 +1000,43 @@ public:
|
|||||||
return CreateParallelValidator(context);
|
return CreateParallelValidator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bool(Context& context, bool) const {
|
bool Bool(Context& context, bool b) const {
|
||||||
if (!(type_ & (1 << kBooleanSchemaType))) {
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Bool", b);
|
||||||
DisallowedType(context, GetBooleanString());
|
if (!CheckBool(context, b))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
return false;
|
||||||
}
|
|
||||||
return CreateParallelValidator(context);
|
return CreateParallelValidator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Int(Context& context, int i) const {
|
bool Int(Context& context, int i) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int", (int64_t)i);
|
||||||
if (!CheckInt(context, i))
|
if (!CheckInt(context, i))
|
||||||
return false;
|
return false;
|
||||||
return CreateParallelValidator(context);
|
return CreateParallelValidator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Uint(Context& context, unsigned u) const {
|
bool Uint(Context& context, unsigned u) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint", (uint64_t)u);
|
||||||
if (!CheckUint(context, u))
|
if (!CheckUint(context, u))
|
||||||
return false;
|
return false;
|
||||||
return CreateParallelValidator(context);
|
return CreateParallelValidator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Int64(Context& context, int64_t i) const {
|
bool Int64(Context& context, int64_t i) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int64", i);
|
||||||
if (!CheckInt(context, i))
|
if (!CheckInt(context, i))
|
||||||
return false;
|
return false;
|
||||||
return CreateParallelValidator(context);
|
return CreateParallelValidator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Uint64(Context& context, uint64_t u) const {
|
bool Uint64(Context& context, uint64_t u) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint64", u);
|
||||||
if (!CheckUint(context, u))
|
if (!CheckUint(context, u))
|
||||||
return false;
|
return false;
|
||||||
return CreateParallelValidator(context);
|
return CreateParallelValidator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Double(Context& context, double d) const {
|
bool Double(Context& context, double d) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Double", d);
|
||||||
if (!(type_ & (1 << kNumberSchemaType))) {
|
if (!(type_ & (1 << kNumberSchemaType))) {
|
||||||
DisallowedType(context, GetNumberString());
|
DisallowedType(context, GetNumberString());
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
||||||
@ -911,6 +1055,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool String(Context& context, const Ch* str, SizeType length, bool) const {
|
bool String(Context& context, const Ch* str, SizeType length, bool) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::String", str);
|
||||||
if (!(type_ & (1 << kStringSchemaType))) {
|
if (!(type_ & (1 << kStringSchemaType))) {
|
||||||
DisallowedType(context, GetStringString());
|
DisallowedType(context, GetStringString());
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
||||||
@ -939,6 +1084,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool StartObject(Context& context) const {
|
bool StartObject(Context& context) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartObject");
|
||||||
if (!(type_ & (1 << kObjectSchemaType))) {
|
if (!(type_ & (1 << kObjectSchemaType))) {
|
||||||
DisallowedType(context, GetObjectString());
|
DisallowedType(context, GetObjectString());
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
||||||
@ -960,6 +1106,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Key(Context& context, const Ch* str, SizeType len, bool) const {
|
bool Key(Context& context, const Ch* str, SizeType len, bool) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Key", str);
|
||||||
|
|
||||||
if (patternProperties_) {
|
if (patternProperties_) {
|
||||||
context.patternPropertiesSchemaCount = 0;
|
context.patternPropertiesSchemaCount = 0;
|
||||||
for (SizeType i = 0; i < patternPropertyCount_; i++)
|
for (SizeType i = 0; i < patternPropertyCount_; i++)
|
||||||
@ -1011,6 +1159,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EndObject(Context& context, SizeType memberCount) const {
|
bool EndObject(Context& context, SizeType memberCount) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndObject");
|
||||||
if (hasRequired_) {
|
if (hasRequired_) {
|
||||||
context.error_handler.StartMissingProperties();
|
context.error_handler.StartMissingProperties();
|
||||||
for (SizeType index = 0; index < propertyCount_; index++)
|
for (SizeType index = 0; index < propertyCount_; index++)
|
||||||
@ -1058,6 +1207,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool StartArray(Context& context) const {
|
bool StartArray(Context& context) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartArray");
|
||||||
context.arrayElementIndex = 0;
|
context.arrayElementIndex = 0;
|
||||||
context.inArray = true; // Ensure we note that we are in an array
|
context.inArray = true; // Ensure we note that we are in an array
|
||||||
|
|
||||||
@ -1070,6 +1220,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EndArray(Context& context, SizeType elementCount) const {
|
bool EndArray(Context& context, SizeType elementCount) const {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndArray");
|
||||||
context.inArray = false;
|
context.inArray = false;
|
||||||
|
|
||||||
if (elementCount < minItems_) {
|
if (elementCount < minItems_) {
|
||||||
@ -1118,6 +1269,9 @@ public:
|
|||||||
case kValidateErrorAnyOf: return GetAnyOfString();
|
case kValidateErrorAnyOf: return GetAnyOfString();
|
||||||
case kValidateErrorNot: return GetNotString();
|
case kValidateErrorNot: return GetNotString();
|
||||||
|
|
||||||
|
case kValidateErrorReadOnly: return GetReadOnlyString();
|
||||||
|
case kValidateErrorWriteOnly: return GetWriteOnlyString();
|
||||||
|
|
||||||
default: return GetNullString();
|
default: return GetNullString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1165,15 +1319,14 @@ public:
|
|||||||
RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
|
RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
|
||||||
RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
|
RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
|
||||||
RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
|
RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
|
||||||
|
RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a')
|
||||||
RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f')
|
RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f')
|
||||||
RAPIDJSON_STRING_(Id, 'i', 'd')
|
RAPIDJSON_STRING_(Id, 'i', 'd')
|
||||||
|
RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r')
|
||||||
RAPIDJSON_STRING_(SchemeEnd, ':')
|
RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i')
|
||||||
RAPIDJSON_STRING_(AuthStart, '/', '/')
|
RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y')
|
||||||
RAPIDJSON_STRING_(QueryStart, '?')
|
RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
|
||||||
RAPIDJSON_STRING_(FragStart, '#')
|
RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e')
|
||||||
RAPIDJSON_STRING_(Slash, '/')
|
|
||||||
RAPIDJSON_STRING_(Dot, '.')
|
|
||||||
|
|
||||||
#undef RAPIDJSON_STRING_
|
#undef RAPIDJSON_STRING_
|
||||||
|
|
||||||
@ -1307,6 +1460,7 @@ private:
|
|||||||
|
|
||||||
// Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if required.
|
// Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if required.
|
||||||
// Also creates a hasher for enums and array uniqueness, if required.
|
// Also creates a hasher for enums and array uniqueness, if required.
|
||||||
|
// Also a useful place to add type-independent error checks.
|
||||||
bool CreateParallelValidator(Context& context) const {
|
bool CreateParallelValidator(Context& context) const {
|
||||||
if (enum_ || context.arrayUniqueness)
|
if (enum_ || context.arrayUniqueness)
|
||||||
context.hasher = context.factory.CreateHasher();
|
context.hasher = context.factory.CreateHasher();
|
||||||
@ -1337,6 +1491,16 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add any other type-independent checks here
|
||||||
|
if (readOnly_ && (context.flags & kValidateWriteFlag)) {
|
||||||
|
context.error_handler.DisallowedWhenWriting();
|
||||||
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorReadOnly);
|
||||||
|
}
|
||||||
|
if (writeOnly_ && (context.flags & kValidateReadFlag)) {
|
||||||
|
context.error_handler.DisallowedWhenReading();
|
||||||
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorWriteOnly);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1359,6 +1523,14 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckBool(Context& context, bool) const {
|
||||||
|
if (!(type_ & (1 << kBooleanSchemaType))) {
|
||||||
|
DisallowedType(context, GetBooleanString());
|
||||||
|
RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CheckInt(Context& context, int64_t i) const {
|
bool CheckInt(Context& context, int64_t i) const {
|
||||||
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
|
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
|
||||||
DisallowedType(context, GetIntegerString());
|
DisallowedType(context, GetIntegerString());
|
||||||
@ -1524,6 +1696,7 @@ private:
|
|||||||
AllocatorType* allocator_;
|
AllocatorType* allocator_;
|
||||||
SValue uri_;
|
SValue uri_;
|
||||||
UriType id_;
|
UriType id_;
|
||||||
|
Specification spec_;
|
||||||
PointerType pointer_;
|
PointerType pointer_;
|
||||||
const SchemaType* typeless_;
|
const SchemaType* typeless_;
|
||||||
uint64_t* enum_;
|
uint64_t* enum_;
|
||||||
@ -1568,6 +1741,10 @@ private:
|
|||||||
bool exclusiveMaximum_;
|
bool exclusiveMaximum_;
|
||||||
|
|
||||||
SizeType defaultValueLength_;
|
SizeType defaultValueLength_;
|
||||||
|
|
||||||
|
bool readOnly_;
|
||||||
|
bool writeOnly_;
|
||||||
|
bool nullable_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Stack, typename Ch>
|
template<typename Stack, typename Ch>
|
||||||
@ -1614,7 +1791,12 @@ public:
|
|||||||
|
|
||||||
virtual ~IGenericRemoteSchemaDocumentProvider() {}
|
virtual ~IGenericRemoteSchemaDocumentProvider() {}
|
||||||
virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
|
virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
|
||||||
virtual const SchemaDocumentType* GetRemoteDocument(const GenericUri<ValueType, AllocatorType> uri) { return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength()); }
|
virtual const SchemaDocumentType* GetRemoteDocument(const GenericUri<ValueType, AllocatorType> uri, Specification& spec) {
|
||||||
|
// Default implementation just calls through for compatibility
|
||||||
|
// Following line suppresses unused parameter warning
|
||||||
|
if (false) printf("GetRemoteDocument: %d %d\n", spec.draft, spec.oapi);
|
||||||
|
return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -1656,10 +1838,12 @@ public:
|
|||||||
\param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
|
\param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
|
||||||
\param allocator An optional allocator instance for allocating memory. Can be null.
|
\param allocator An optional allocator instance for allocating memory. Can be null.
|
||||||
\param pointer An optional JSON pointer to the start of the schema document
|
\param pointer An optional JSON pointer to the start of the schema document
|
||||||
|
\param spec Optional schema draft or OpenAPI version. Used if no specification in document. Defaults to draft-04.
|
||||||
*/
|
*/
|
||||||
explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
|
explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
|
||||||
IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0,
|
IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0,
|
||||||
const PointerType& pointer = PointerType()) : // PR #1393
|
const PointerType& pointer = PointerType(), // PR #1393
|
||||||
|
const Specification& spec = Specification(kDraft04)) :
|
||||||
remoteProvider_(remoteProvider),
|
remoteProvider_(remoteProvider),
|
||||||
allocator_(allocator),
|
allocator_(allocator),
|
||||||
ownAllocator_(),
|
ownAllocator_(),
|
||||||
@ -1667,9 +1851,11 @@ public:
|
|||||||
typeless_(),
|
typeless_(),
|
||||||
schemaMap_(allocator, kInitialSchemaMapSize),
|
schemaMap_(allocator, kInitialSchemaMapSize),
|
||||||
schemaRef_(allocator, kInitialSchemaRefSize),
|
schemaRef_(allocator, kInitialSchemaRefSize),
|
||||||
|
spec_(spec),
|
||||||
error_(kObjectType),
|
error_(kObjectType),
|
||||||
currentError_()
|
currentError_()
|
||||||
{
|
{
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::GenericSchemaDocument");
|
||||||
if (!allocator_)
|
if (!allocator_)
|
||||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
|
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
|
||||||
|
|
||||||
@ -1680,6 +1866,10 @@ public:
|
|||||||
typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
|
typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
|
||||||
new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_);
|
new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_);
|
||||||
|
|
||||||
|
// Establish the schema draft or open api version.
|
||||||
|
// We only ever look for '$schema' or 'swagger' or 'openapi' at the root of the document.
|
||||||
|
SetSchemaSpecification(document);
|
||||||
|
|
||||||
// Generate root schema, it will call CreateSchema() to create sub-schemas,
|
// Generate root schema, it will call CreateSchema() to create sub-schemas,
|
||||||
// And call HandleRefSchema() if there are $ref.
|
// And call HandleRefSchema() if there are $ref.
|
||||||
// PR #1393 use input pointer if supplied
|
// PR #1393 use input pointer if supplied
|
||||||
@ -1713,6 +1903,7 @@ public:
|
|||||||
schemaRef_(std::move(rhs.schemaRef_)),
|
schemaRef_(std::move(rhs.schemaRef_)),
|
||||||
uri_(std::move(rhs.uri_)),
|
uri_(std::move(rhs.uri_)),
|
||||||
docId_(std::move(rhs.docId_)),
|
docId_(std::move(rhs.docId_)),
|
||||||
|
spec_(rhs.spec_),
|
||||||
error_(std::move(rhs.error_)),
|
error_(std::move(rhs.error_)),
|
||||||
currentError_(std::move(rhs.currentError_))
|
currentError_(std::move(rhs.currentError_))
|
||||||
{
|
{
|
||||||
@ -1743,6 +1934,23 @@ public:
|
|||||||
|
|
||||||
const GValue& GetURI() const { return uri_; }
|
const GValue& GetURI() const { return uri_; }
|
||||||
|
|
||||||
|
const Specification& GetSpecification() const { return spec_; }
|
||||||
|
bool IsSupportedSpecification() const { return spec_.IsSupported(); }
|
||||||
|
|
||||||
|
//! Static method to get the specification of any schema document
|
||||||
|
// Returns kDraftNone if document is silent
|
||||||
|
static const Specification GetSpecification(const ValueType& document) {
|
||||||
|
SchemaDraft draft = GetSchemaDraft(document);
|
||||||
|
if (draft != kDraftNone)
|
||||||
|
return Specification(draft);
|
||||||
|
else {
|
||||||
|
OpenApiVersion oapi = GetOpenApiVersion(document);
|
||||||
|
if (oapi != kVersionNone)
|
||||||
|
return Specification(oapi);
|
||||||
|
}
|
||||||
|
return Specification(kDraftNone);
|
||||||
|
}
|
||||||
|
|
||||||
//! Get the root schema.
|
//! Get the root schema.
|
||||||
const SchemaType& GetRoot() const { return *root_; }
|
const SchemaType& GetRoot() const { return *root_; }
|
||||||
|
|
||||||
@ -1761,6 +1969,10 @@ public:
|
|||||||
case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString();
|
case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString();
|
||||||
case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString();
|
case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString();
|
||||||
case kSchemaErrorRegexInvalid: return GetRegexInvalidString();
|
case kSchemaErrorRegexInvalid: return GetRegexInvalidString();
|
||||||
|
case kSchemaErrorSpecUnknown: return GetSpecUnknownString();
|
||||||
|
case kSchemaErrorSpecUnsupported: return GetSpecUnsupportedString();
|
||||||
|
case kSchemaErrorSpecIllegal: return GetSpecIllegalString();
|
||||||
|
case kSchemaErrorReadOnlyAndWriteOnly: return GetReadOnlyAndWriteOnlyString();
|
||||||
default: return GetNullString();
|
default: return GetNullString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1829,6 +2041,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AddCurrentError(const SchemaErrorCode code, const PointerType& location) {
|
void AddCurrentError(const SchemaErrorCode code, const PointerType& location) {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code));
|
||||||
currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
|
currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
|
||||||
AddErrorInstanceLocation(currentError_, location);
|
AddErrorInstanceLocation(currentError_, location);
|
||||||
AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
|
AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
|
||||||
@ -1847,6 +2060,9 @@ public:
|
|||||||
RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't')
|
RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't')
|
||||||
|
|
||||||
RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
|
RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
|
||||||
|
RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
|
||||||
|
RAPIDJSON_STRING_(SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd')
|
||||||
|
RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l')
|
||||||
RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
|
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_(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_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
|
||||||
@ -1855,10 +2071,94 @@ public:
|
|||||||
RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l')
|
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_(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_(RefNoRemoteSchema, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'S', 'c', 'h', 'e', 'm', 'a')
|
||||||
|
RAPIDJSON_STRING_(ReadOnlyAndWriteOnly, 'R', 'e', 'a', 'd', 'O', 'n', 'l', 'y', 'A', 'n', 'd', 'W', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
|
||||||
RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
|
RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
|
||||||
|
|
||||||
#undef RAPIDJSON_STRING_
|
#undef RAPIDJSON_STRING_
|
||||||
|
|
||||||
|
// Static method to get schema draft of any schema document
|
||||||
|
static SchemaDraft GetSchemaDraft(const ValueType& document) {
|
||||||
|
static const Ch kDraft03String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '3', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
|
||||||
|
static const Ch kDraft04String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '4', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
|
||||||
|
static const Ch kDraft05String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '5', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
|
||||||
|
static const Ch kDraft06String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '6', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
|
||||||
|
static const Ch kDraft07String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '7', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
|
||||||
|
static const Ch kDraft2019_09String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '1', '9', '-', '0', '9', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' };
|
||||||
|
static const Ch kDraft2020_12String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '2', '0', '-', '1', '2', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' };
|
||||||
|
|
||||||
|
if (!document.IsObject()) {
|
||||||
|
return kDraftNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the schema draft from the $schema keyword at the supplied location
|
||||||
|
typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString());
|
||||||
|
if (itr != document.MemberEnd()) {
|
||||||
|
if (!itr->value.IsString()) return kDraftUnknown;
|
||||||
|
const UriType draftUri(itr->value);
|
||||||
|
// Check base uri for match
|
||||||
|
if (draftUri.Match(UriType(kDraft04String), false)) return kDraft04;
|
||||||
|
if (draftUri.Match(UriType(kDraft05String), false)) return kDraft05;
|
||||||
|
if (draftUri.Match(UriType(kDraft06String), false)) return kDraft06;
|
||||||
|
if (draftUri.Match(UriType(kDraft07String), false)) return kDraft07;
|
||||||
|
if (draftUri.Match(UriType(kDraft03String), false)) return kDraft03;
|
||||||
|
if (draftUri.Match(UriType(kDraft2019_09String), false)) return kDraft2019_09;
|
||||||
|
if (draftUri.Match(UriType(kDraft2020_12String), false)) return kDraft2020_12;
|
||||||
|
return kDraftUnknown;
|
||||||
|
}
|
||||||
|
// $schema not found
|
||||||
|
return kDraftNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get open api version of any schema document
|
||||||
|
static OpenApiVersion GetOpenApiVersion(const ValueType& document) {
|
||||||
|
static const Ch kVersion20String[] = { '2', '.', '0', '\0' };
|
||||||
|
static const Ch kVersion30String[] = { '3', '.', '0', '.', '\0' }; // ignore patch level
|
||||||
|
static const Ch kVersion31String[] = { '3', '.', '1', '.', '\0' }; // ignore patch level
|
||||||
|
static SizeType len = internal::StrLen<Ch>(kVersion30String);
|
||||||
|
|
||||||
|
if (!document.IsObject()) {
|
||||||
|
return kVersionNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the open api version from the swagger / openapi keyword at the supplied location
|
||||||
|
typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString());
|
||||||
|
if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString());
|
||||||
|
if (itr != document.MemberEnd()) {
|
||||||
|
if (!itr->value.IsString()) return kVersionUnknown;
|
||||||
|
const ValueType kVersion20Value(kVersion20String);
|
||||||
|
if (kVersion20Value == itr->value) return kVersion20; // must match 2.0 exactly
|
||||||
|
const ValueType kVersion30Value(kVersion30String);
|
||||||
|
if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len)) return kVersion30; // must match 3.0.x
|
||||||
|
const ValueType kVersion31Value(kVersion31String);
|
||||||
|
if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len)) return kVersion31; // must match 3.1.x
|
||||||
|
return kVersionUnknown;
|
||||||
|
}
|
||||||
|
// swagger or openapi not found
|
||||||
|
return kVersionNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the draft of the schema or the open api version (which implies the draft).
|
||||||
|
// Report an error if schema draft or open api version not supported or not recognized, or both in document, and carry on.
|
||||||
|
void SetSchemaSpecification(const ValueType& document) {
|
||||||
|
// Look for '$schema', 'swagger' or 'openapi' keyword at document root
|
||||||
|
SchemaDraft docDraft = GetSchemaDraft(document);
|
||||||
|
OpenApiVersion docOapi = GetOpenApiVersion(document);
|
||||||
|
// Error if both in document
|
||||||
|
if (docDraft != kDraftNone && docOapi != kVersionNone)
|
||||||
|
SchemaError(kSchemaErrorSpecIllegal, PointerType());
|
||||||
|
// Use document draft or open api version if present or use spec from constructor
|
||||||
|
if (docDraft != kDraftNone)
|
||||||
|
spec_ = Specification(docDraft);
|
||||||
|
else if (docOapi != kVersionNone)
|
||||||
|
spec_ = Specification(docOapi);
|
||||||
|
// Error if draft or version unknown
|
||||||
|
if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
|
||||||
|
SchemaError(kSchemaErrorSpecUnknown, PointerType());
|
||||||
|
else if (!spec_.IsSupported())
|
||||||
|
SchemaError(kSchemaErrorSpecUnsupported, PointerType());
|
||||||
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
@ -1875,6 +2175,9 @@ public:
|
|||||||
// Changed by PR #1393
|
// Changed by PR #1393
|
||||||
const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
|
const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
|
||||||
RAPIDJSON_ASSERT(pointer.IsValid());
|
RAPIDJSON_ASSERT(pointer.IsValid());
|
||||||
|
GenericStringBuffer<EncodingType> sb;
|
||||||
|
pointer.StringifyUriFragment(sb);
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::CreateSchema", sb.GetString(), id.GetString());
|
||||||
if (v.IsObject()) {
|
if (v.IsObject()) {
|
||||||
if (const SchemaType* sc = GetSchema(pointer)) {
|
if (const SchemaType* sc = GetSchema(pointer)) {
|
||||||
if (schema)
|
if (schema)
|
||||||
@ -1904,6 +2207,9 @@ public:
|
|||||||
if (itr == v.MemberEnd())
|
if (itr == v.MemberEnd())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
GenericStringBuffer<EncodingType> sb;
|
||||||
|
source.StringifyUriFragment(sb);
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::HandleRefSchema", sb.GetString(), id.GetString());
|
||||||
// Resolve the source pointer to the $ref'ed schema (finally)
|
// Resolve the source pointer to the $ref'ed schema (finally)
|
||||||
new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
|
new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
|
||||||
|
|
||||||
@ -1915,6 +2221,7 @@ public:
|
|||||||
// 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_);
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), itr->value.GetString(), ref.GetString());
|
||||||
// See if the resolved $ref minus the fragment matches a resolved id in this document
|
// See if the resolved $ref minus the fragment matches a resolved id in this document
|
||||||
// Search from the root. Returns the subschema in the document and its absolute JSON pointer.
|
// Search from the root. Returns the subschema in the document and its absolute JSON pointer.
|
||||||
PointerType basePointer = PointerType();
|
PointerType basePointer = PointerType();
|
||||||
@ -1924,7 +2231,7 @@ public:
|
|||||||
if (!remoteProvider_)
|
if (!remoteProvider_)
|
||||||
SchemaError(kSchemaErrorRefNoRemoteProvider, source);
|
SchemaError(kSchemaErrorRefNoRemoteProvider, source);
|
||||||
else {
|
else {
|
||||||
if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref)) {
|
if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref, spec_)) {
|
||||||
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] == '/') {
|
||||||
@ -1979,10 +2286,13 @@ public:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Plain name fragment, relative to the resolved URI
|
// Plain name fragment, relative to the resolved URI
|
||||||
|
// Not supported in open api 2.0 and 3.0
|
||||||
PointerType pointer(allocator_);
|
PointerType pointer(allocator_);
|
||||||
|
if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
|
||||||
|
SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
|
||||||
// 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.
|
||||||
if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) {
|
else if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) {
|
||||||
if (IsCyclicRef(pointer))
|
if (IsCyclicRef(pointer))
|
||||||
SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
|
SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
|
||||||
else {
|
else {
|
||||||
@ -2024,6 +2334,7 @@ public:
|
|||||||
}
|
}
|
||||||
// See if it matches
|
// See if it matches
|
||||||
if (localuri.Match(finduri, full)) {
|
if (localuri.Match(finduri, full)) {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString());
|
||||||
resval = const_cast<ValueType *>(&doc);
|
resval = const_cast<ValueType *>(&doc);
|
||||||
resptr = here;
|
resptr = here;
|
||||||
return resval;
|
return resval;
|
||||||
@ -2050,6 +2361,7 @@ public:
|
|||||||
|
|
||||||
// Added by PR #1393
|
// Added by PR #1393
|
||||||
void AddSchemaRefs(SchemaType* schema) {
|
void AddSchemaRefs(SchemaType* schema) {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::AddSchemaRefs");
|
||||||
while (!schemaRef_.Empty()) {
|
while (!schemaRef_.Empty()) {
|
||||||
SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
|
SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
|
||||||
SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
|
SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
|
||||||
@ -2093,6 +2405,7 @@ public:
|
|||||||
internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
|
internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
|
||||||
GValue uri_; // Schema document URI
|
GValue uri_; // Schema document URI
|
||||||
UriType docId_;
|
UriType docId_;
|
||||||
|
Specification spec_;
|
||||||
GValue error_;
|
GValue error_;
|
||||||
GValue currentError_;
|
GValue currentError_;
|
||||||
};
|
};
|
||||||
@ -2158,11 +2471,10 @@ public:
|
|||||||
currentError_(),
|
currentError_(),
|
||||||
missingDependents_(),
|
missingDependents_(),
|
||||||
valid_(true),
|
valid_(true),
|
||||||
flags_(kValidateDefaultFlags)
|
flags_(kValidateDefaultFlags),
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
depth_(0)
|
||||||
, depth_(0)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator");
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Constructor with output handler.
|
//! Constructor with output handler.
|
||||||
@ -2190,11 +2502,10 @@ public:
|
|||||||
currentError_(),
|
currentError_(),
|
||||||
missingDependents_(),
|
missingDependents_(),
|
||||||
valid_(true),
|
valid_(true),
|
||||||
flags_(kValidateDefaultFlags)
|
flags_(kValidateDefaultFlags),
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
depth_(0)
|
||||||
, depth_(0)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (output handler)");
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Destructor.
|
//! Destructor.
|
||||||
@ -2455,6 +2766,14 @@ public:
|
|||||||
currentError_.SetObject();
|
currentError_.SetObject();
|
||||||
AddCurrentError(kValidateErrorNot);
|
AddCurrentError(kValidateErrorNot);
|
||||||
}
|
}
|
||||||
|
void DisallowedWhenWriting() {
|
||||||
|
currentError_.SetObject();
|
||||||
|
AddCurrentError(kValidateErrorReadOnly);
|
||||||
|
}
|
||||||
|
void DisallowedWhenReading() {
|
||||||
|
currentError_.SetObject();
|
||||||
|
AddCurrentError(kValidateErrorWriteOnly);
|
||||||
|
}
|
||||||
|
|
||||||
#define RAPIDJSON_STRING_(name, ...) \
|
#define RAPIDJSON_STRING_(name, ...) \
|
||||||
static const StringRefType& Get##name##String() {\
|
static const StringRefType& Get##name##String() {\
|
||||||
@ -2477,21 +2796,12 @@ public:
|
|||||||
|
|
||||||
#undef RAPIDJSON_STRING_
|
#undef RAPIDJSON_STRING_
|
||||||
|
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
|
||||||
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
|
|
||||||
RAPIDJSON_MULTILINEMACRO_BEGIN\
|
|
||||||
*documentStack_.template Push<Ch>() = '\0';\
|
|
||||||
documentStack_.template Pop<Ch>(1);\
|
|
||||||
internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
|
|
||||||
RAPIDJSON_MULTILINEMACRO_END
|
|
||||||
#else
|
|
||||||
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
|
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
|
||||||
if (!valid_) return false; \
|
if (!valid_) return false; \
|
||||||
if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
|
if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
|
||||||
RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
|
*documentStack_.template Push<Ch>() = '\0';\
|
||||||
|
documentStack_.template Pop<Ch>(1);\
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom<Ch>());\
|
||||||
valid_ = false;\
|
valid_ = false;\
|
||||||
return valid_;\
|
return valid_;\
|
||||||
}
|
}
|
||||||
@ -2530,6 +2840,7 @@ RAPIDJSON_MULTILINEMACRO_END
|
|||||||
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
|
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
|
||||||
|
|
||||||
bool StartObject() {
|
bool StartObject() {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartObject");
|
||||||
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
|
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
|
||||||
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
|
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
|
||||||
valid_ = !outputHandler_ || outputHandler_->StartObject();
|
valid_ = !outputHandler_ || outputHandler_->StartObject();
|
||||||
@ -2537,6 +2848,7 @@ RAPIDJSON_MULTILINEMACRO_END
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Key(const Ch* str, SizeType len, bool copy) {
|
bool Key(const Ch* str, SizeType len, bool copy) {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::Key", str);
|
||||||
if (!valid_) return false;
|
if (!valid_) return false;
|
||||||
AppendToken(str, len);
|
AppendToken(str, len);
|
||||||
if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) {
|
if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) {
|
||||||
@ -2549,6 +2861,7 @@ RAPIDJSON_MULTILINEMACRO_END
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EndObject(SizeType memberCount) {
|
bool EndObject(SizeType memberCount) {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndObject");
|
||||||
if (!valid_) return false;
|
if (!valid_) return false;
|
||||||
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
|
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
|
||||||
if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) {
|
if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) {
|
||||||
@ -2559,6 +2872,7 @@ RAPIDJSON_MULTILINEMACRO_END
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool StartArray() {
|
bool StartArray() {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartArray");
|
||||||
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
|
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
|
||||||
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
|
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
|
||||||
valid_ = !outputHandler_ || outputHandler_->StartArray();
|
valid_ = !outputHandler_ || outputHandler_->StartArray();
|
||||||
@ -2566,6 +2880,7 @@ RAPIDJSON_MULTILINEMACRO_END
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EndArray(SizeType elementCount) {
|
bool EndArray(SizeType elementCount) {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndArray");
|
||||||
if (!valid_) return false;
|
if (!valid_) return false;
|
||||||
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
|
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
|
||||||
if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) {
|
if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) {
|
||||||
@ -2575,17 +2890,16 @@ RAPIDJSON_MULTILINEMACRO_END
|
|||||||
RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
|
RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
|
|
||||||
#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
|
#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
|
||||||
#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
|
#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
|
||||||
#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
|
#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
|
||||||
|
|
||||||
// Implementation of ISchemaStateFactory<SchemaType>
|
// Implementation of ISchemaStateFactory<SchemaType>
|
||||||
virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) {
|
virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) {
|
||||||
|
*documentStack_.template Push<Ch>() = '\0';
|
||||||
|
documentStack_.template Pop<Ch>(1);
|
||||||
ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
|
ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
|
||||||
depth_ + 1,
|
depth_ + 1,
|
||||||
#endif
|
|
||||||
&GetStateAllocator());
|
&GetStateAllocator());
|
||||||
sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag);
|
sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag);
|
||||||
return sv;
|
return sv;
|
||||||
@ -2629,9 +2943,7 @@ private:
|
|||||||
const SchemaDocumentType& schemaDocument,
|
const SchemaDocumentType& schemaDocument,
|
||||||
const SchemaType& root,
|
const SchemaType& root,
|
||||||
const char* basePath, size_t basePathSize,
|
const char* basePath, size_t basePathSize,
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
|
||||||
unsigned depth,
|
unsigned depth,
|
||||||
#endif
|
|
||||||
StateAllocator* allocator = 0,
|
StateAllocator* allocator = 0,
|
||||||
size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
|
size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
|
||||||
size_t documentStackCapacity = kDefaultDocumentStackCapacity)
|
size_t documentStackCapacity = kDefaultDocumentStackCapacity)
|
||||||
@ -2647,11 +2959,10 @@ private:
|
|||||||
currentError_(),
|
currentError_(),
|
||||||
missingDependents_(),
|
missingDependents_(),
|
||||||
valid_(true),
|
valid_(true),
|
||||||
flags_(kValidateDefaultFlags)
|
flags_(kValidateDefaultFlags),
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
depth_(depth)
|
||||||
, depth_(depth)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath : "");
|
||||||
if (basePath && basePathSize)
|
if (basePath && basePathSize)
|
||||||
memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
|
memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
|
||||||
}
|
}
|
||||||
@ -2667,6 +2978,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool BeginValue() {
|
bool BeginValue() {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::BeginValue");
|
||||||
if (schemaStack_.Empty())
|
if (schemaStack_.Empty())
|
||||||
PushSchema(root_);
|
PushSchema(root_);
|
||||||
else {
|
else {
|
||||||
@ -2699,17 +3011,15 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool EndValue() {
|
bool EndValue() {
|
||||||
|
RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndValue");
|
||||||
if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
|
if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
|
||||||
GenericStringBuffer<EncodingType> sb;
|
GenericStringBuffer<EncodingType> sb;
|
||||||
schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
|
schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb);
|
||||||
|
|
||||||
*documentStack_.template Push<Ch>() = '\0';
|
*documentStack_.template Push<Ch>() = '\0';
|
||||||
documentStack_.template Pop<Ch>(1);
|
documentStack_.template Pop<Ch>(1);
|
||||||
internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
|
RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(), documentStack_.template Bottom<Ch>(), depth_);
|
||||||
#endif
|
|
||||||
void* hasher = CurrentContext().hasher;
|
void* hasher = CurrentContext().hasher;
|
||||||
uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
|
uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
|
||||||
|
|
||||||
@ -2760,7 +3070,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema); }
|
RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema, flags_); }
|
||||||
|
|
||||||
RAPIDJSON_FORCEINLINE void PopSchema() {
|
RAPIDJSON_FORCEINLINE void PopSchema() {
|
||||||
Context* c = schemaStack_.template Pop<Context>(1);
|
Context* c = schemaStack_.template Pop<Context>(1);
|
||||||
@ -2862,9 +3172,7 @@ private:
|
|||||||
ValueType missingDependents_;
|
ValueType missingDependents_;
|
||||||
bool valid_;
|
bool valid_;
|
||||||
unsigned flags_;
|
unsigned flags_;
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
|
||||||
unsigned depth_;
|
unsigned depth_;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
|
typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
|
||||||
|
@ -118,12 +118,7 @@ TEST(SchemaValidator, Hasher) {
|
|||||||
#define VALIDATE_(schema, json, expected, expected2) \
|
#define VALIDATE_(schema, json, expected, expected2) \
|
||||||
{\
|
{\
|
||||||
EXPECT_TRUE(expected2 == schema.GetError().ObjectEmpty());\
|
EXPECT_TRUE(expected2 == schema.GetError().ObjectEmpty());\
|
||||||
if (expected2 && !schema.GetError().ObjectEmpty()) {\
|
EXPECT_TRUE(schema.IsSupportedSpecification());\
|
||||||
StringBuffer ssb;\
|
|
||||||
Writer<StringBuffer> ws(ssb);\
|
|
||||||
schema.GetError().Accept(ws);\
|
|
||||||
printf("Schema error: %s\n", ssb.GetString());\
|
|
||||||
}\
|
|
||||||
SchemaValidator validator(schema);\
|
SchemaValidator validator(schema);\
|
||||||
Document d;\
|
Document d;\
|
||||||
/*printf("\n%s\n", json);*/\
|
/*printf("\n%s\n", json);*/\
|
||||||
@ -162,12 +157,7 @@ TEST(SchemaValidator, Hasher) {
|
|||||||
flags, SchemaValidatorType, PointerType) \
|
flags, SchemaValidatorType, PointerType) \
|
||||||
{\
|
{\
|
||||||
EXPECT_TRUE(schema.GetError().ObjectEmpty());\
|
EXPECT_TRUE(schema.GetError().ObjectEmpty());\
|
||||||
if (!schema.GetError().ObjectEmpty()) {\
|
EXPECT_TRUE(schema.IsSupportedSpecification());\
|
||||||
StringBuffer ssb;\
|
|
||||||
Writer<StringBuffer> ws(ssb);\
|
|
||||||
schema.GetError().Accept(ws);\
|
|
||||||
printf("Schema error: %s\n", ssb.GetString());\
|
|
||||||
}\
|
|
||||||
SchemaValidatorType validator(schema);\
|
SchemaValidatorType validator(schema);\
|
||||||
validator.SetValidateFlags(flags);\
|
validator.SetValidateFlags(flags);\
|
||||||
Document d;\
|
Document d;\
|
||||||
@ -2163,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::GValue(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2999,6 +2993,334 @@ TEST(SchemaValidator, DuplicateKeyword) {
|
|||||||
|
|
||||||
// SchemaDocument tests
|
// 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) {
|
TEST(SchemaValidator, Schema_StartUnknown) {
|
||||||
Document sd;
|
Document sd;
|
||||||
sd.Parse("{\"type\": \"integer\"}");
|
sd.Parse("{\"type\": \"integer\"}");
|
||||||
@ -3007,6 +3329,25 @@ TEST(SchemaValidator, Schema_StartUnknown) {
|
|||||||
SCHEMAERROR(s, "{\"StartUnknown\":{\"errorCode\":1,\"instanceRef\":\"#\", \"value\":\"#/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
|
// $ref is a non-JSON pointer fragment - not allowed when remote document
|
||||||
TEST(SchemaValidator, Schema_RefPlainNameRemote) {
|
TEST(SchemaValidator, Schema_RefPlainNameRemote) {
|
||||||
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
|
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
|
||||||
@ -3019,9 +3360,10 @@ TEST(SchemaValidator, Schema_RefPlainNameRemote) {
|
|||||||
|
|
||||||
// $ref is an empty string
|
// $ref is an empty string
|
||||||
TEST(SchemaValidator, Schema_RefEmptyString) {
|
TEST(SchemaValidator, Schema_RefEmptyString) {
|
||||||
|
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
|
||||||
Document sd;
|
Document sd;
|
||||||
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"\"}}}");
|
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"\"}}}");
|
||||||
SchemaDocument s(sd);
|
SchemaDocumentType s(sd);
|
||||||
SCHEMAERROR(s, "{\"RefInvalid\":{\"errorCode\":3,\"instanceRef\":\"#/properties/myInt1\"}}");
|
SCHEMAERROR(s, "{\"RefInvalid\":{\"errorCode\":3,\"instanceRef\":\"#/properties/myInt1\"}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3046,9 +3388,10 @@ TEST(SchemaValidator, Schema_RefNoRemoteSchema) {
|
|||||||
|
|
||||||
// $ref pointer is invalid
|
// $ref pointer is invalid
|
||||||
TEST(SchemaValidator, Schema_RefPointerInvalid) {
|
TEST(SchemaValidator, Schema_RefPointerInvalid) {
|
||||||
|
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
|
||||||
Document sd;
|
Document sd;
|
||||||
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/&&&&&\"}}}");
|
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/&&&&&\"}}}");
|
||||||
SchemaDocument s(sd);
|
SchemaDocumentType s(sd);
|
||||||
SCHEMAERROR(s, "{\"RefPointerInvalid\":{\"errorCode\":4,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/&&&&&\",\"offset\":2}}");
|
SCHEMAERROR(s, "{\"RefPointerInvalid\":{\"errorCode\":4,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/&&&&&\",\"offset\":2}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3064,17 +3407,19 @@ TEST(SchemaValidator, Schema_RefPointerInvalidRemote) {
|
|||||||
|
|
||||||
// $ref is unknown non-pointer
|
// $ref is unknown non-pointer
|
||||||
TEST(SchemaValidator, Schema_RefUnknownPlainName) {
|
TEST(SchemaValidator, Schema_RefUnknownPlainName) {
|
||||||
|
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
|
||||||
Document sd;
|
Document sd;
|
||||||
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#plainname\"}}}");
|
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#plainname\"}}}");
|
||||||
SchemaDocument s(sd);
|
SchemaDocumentType s(sd);
|
||||||
SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#plainname\"}}");
|
SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#plainname\"}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// $ref is unknown pointer
|
/// $ref is unknown pointer
|
||||||
TEST(SchemaValidator, Schema_RefUnknownPointer) {
|
TEST(SchemaValidator, Schema_RefUnknownPointer) {
|
||||||
|
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
|
||||||
Document sd;
|
Document sd;
|
||||||
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/a/b\"}}}");
|
sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/a/b\"}}}");
|
||||||
SchemaDocument s(sd);
|
SchemaDocumentType s(sd);
|
||||||
SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/a/b\"}}");
|
SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/a/b\"}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3090,6 +3435,7 @@ TEST(SchemaValidator, Schema_RefUnknownPointerRemote) {
|
|||||||
|
|
||||||
// $ref is cyclical
|
// $ref is cyclical
|
||||||
TEST(SchemaValidator, Schema_RefCyclical) {
|
TEST(SchemaValidator, Schema_RefCyclical) {
|
||||||
|
typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
|
||||||
Document sd;
|
Document sd;
|
||||||
sd.Parse("{\"type\": \"object\", \"properties\": {"
|
sd.Parse("{\"type\": \"object\", \"properties\": {"
|
||||||
" \"cyclic_source\": {"
|
" \"cyclic_source\": {"
|
||||||
@ -3099,10 +3445,130 @@ TEST(SchemaValidator, Schema_RefCyclical) {
|
|||||||
" \"$ref\": \"#/properties/cyclic_source\""
|
" \"$ref\": \"#/properties/cyclic_source\""
|
||||||
" }"
|
" }"
|
||||||
"}}");
|
"}}");
|
||||||
SchemaDocument s(sd);
|
SchemaDocumentType s(sd);
|
||||||
SCHEMAERROR(s, "{\"RefCyclical\":{\"errorCode\":6,\"instanceRef\":\"#/properties/cyclic_target\",\"value\":\"#/properties/cyclic_source\"}}");
|
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user