Add anyOf, oneOf and not in schema (buggy)
This commit is contained in:
parent
1062f0a46b
commit
eb7d02b51d
@ -89,19 +89,45 @@ public:
|
|||||||
virtual ISchemaValidator<Encoding>* CreateSchemaValidator(const BaseSchema<Encoding>& root) = 0;
|
virtual ISchemaValidator<Encoding>* CreateSchemaValidator(const BaseSchema<Encoding>& root) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct SchemaValidatorArray {
|
||||||
|
SchemaValidatorArray() : validators(), count() {}
|
||||||
|
~SchemaValidatorArray() {
|
||||||
|
if (validators) {
|
||||||
|
for (SizeType i = 0; i < count; i++)
|
||||||
|
delete validators[i];
|
||||||
|
delete[] validators;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ISchemaValidator<Encoding>** validators;
|
||||||
|
SizeType count;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct BaseSchemaArray {
|
||||||
|
BaseSchemaArray() : schemas(), count() {}
|
||||||
|
~BaseSchemaArray() {
|
||||||
|
if (schemas) {
|
||||||
|
for (SizeType i = 0; i < count; i++)
|
||||||
|
delete schemas[i];
|
||||||
|
delete[] schemas;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseSchema<Encoding>** schemas;
|
||||||
|
SizeType count;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Encoding>
|
template <typename Encoding>
|
||||||
struct SchemaValidationContext {
|
struct SchemaValidationContext {
|
||||||
SchemaValidationContext(ISchemaValidatorFactory<Encoding>* factory, const BaseSchema<Encoding>* s) :
|
SchemaValidationContext(ISchemaValidatorFactory<Encoding>* factory, const BaseSchema<Encoding>* s) :
|
||||||
schemaValidatorFactory(factory), schema(s), valueSchema(), multiTypeSchema(), allOfValidators(), objectDependencies()
|
schemaValidatorFactory(factory), schema(s), valueSchema(), multiTypeSchema(), notValidator(), objectDependencies()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
~SchemaValidationContext() {
|
~SchemaValidationContext() {
|
||||||
if (allOfValidators) {
|
delete notValidator;
|
||||||
for (SizeType i = 0; i < allOfValidatorCount; i++)
|
|
||||||
delete allOfValidators[i];
|
|
||||||
delete[] allOfValidators;
|
|
||||||
}
|
|
||||||
delete[] objectDependencies;
|
delete[] objectDependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,8 +135,10 @@ struct SchemaValidationContext {
|
|||||||
const BaseSchema<Encoding>* schema;
|
const BaseSchema<Encoding>* schema;
|
||||||
const BaseSchema<Encoding>* valueSchema;
|
const BaseSchema<Encoding>* valueSchema;
|
||||||
const BaseSchema<Encoding>* multiTypeSchema;
|
const BaseSchema<Encoding>* multiTypeSchema;
|
||||||
ISchemaValidator<Encoding>** allOfValidators;
|
SchemaValidatorArray<Encoding> allOfValidators;
|
||||||
SizeType allOfValidatorCount;
|
SchemaValidatorArray<Encoding> anyOfValidators;
|
||||||
|
SchemaValidatorArray<Encoding> oneOfValidators;
|
||||||
|
ISchemaValidator<Encoding>* notValidator;
|
||||||
SizeType objectRequiredCount;
|
SizeType objectRequiredCount;
|
||||||
SizeType arrayElementIndex;
|
SizeType arrayElementIndex;
|
||||||
bool* objectDependencies;
|
bool* objectDependencies;
|
||||||
@ -122,11 +150,10 @@ public:
|
|||||||
typedef typename Encoding::Ch Ch;
|
typedef typename Encoding::Ch Ch;
|
||||||
typedef SchemaValidationContext<Encoding> Context;
|
typedef SchemaValidationContext<Encoding> Context;
|
||||||
|
|
||||||
BaseSchema() : allOf_(), allOfCount_() {
|
BaseSchema() : not_() {}
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
BaseSchema(const ValueType& value) : allOf_(), allOfCount_() {
|
BaseSchema(const ValueType& value) : not_() {
|
||||||
typename ValueType::ConstMemberIterator enumItr = value.FindMember("enum");
|
typename ValueType::ConstMemberIterator enumItr = value.FindMember("enum");
|
||||||
if (enumItr != value.MemberEnd()) {
|
if (enumItr != value.MemberEnd()) {
|
||||||
if (enumItr->value.IsArray() && enumItr->value.Size() > 0)
|
if (enumItr->value.IsArray() && enumItr->value.Size() > 0)
|
||||||
@ -137,28 +164,26 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
typename ValueType::ConstMemberIterator allOfItr = value.FindMember("allOf");
|
typename ValueType::ConstMemberIterator allOfItr = value.FindMember("allOf");
|
||||||
if (allOfItr != value.MemberEnd()) {
|
if (allOfItr != value.MemberEnd())
|
||||||
const Value& allOf = allOfItr->value;
|
CreateLogicalSchemas(allOfItr->value, allOf_);
|
||||||
if (allOf.IsArray() && allOf.Size() > 0) {
|
|
||||||
allOfCount_ = allOf.Size();
|
|
||||||
allOf_ = new BaseSchema*[allOfCount_];
|
|
||||||
memset(allOf_, 0, sizeof(BaseSchema*) * allOfCount_);
|
|
||||||
for (SizeType i = 0; i < allOfCount_; i++)
|
|
||||||
allOf_[i] = CreateSchema<Encoding>(allOf[i]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
typename ValueType::ConstMemberIterator anyOfItr = value.FindMember("anyOf");
|
||||||
|
if (anyOfItr != value.MemberEnd())
|
||||||
|
CreateLogicalSchemas(anyOfItr->value, anyOf_);
|
||||||
|
|
||||||
|
typename ValueType::ConstMemberIterator oneOfItr = value.FindMember("oneOf");
|
||||||
|
if (oneOfItr != value.MemberEnd())
|
||||||
|
CreateLogicalSchemas(oneOfItr->value, oneOf_);
|
||||||
|
|
||||||
|
typename ValueType::ConstMemberIterator notItr = value.FindMember("not");
|
||||||
|
if (notItr != value.MemberEnd()) {
|
||||||
|
if (notItr->value.IsObject())
|
||||||
|
not_ = CreateSchema<Encoding>(notItr->value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~BaseSchema() {
|
virtual ~BaseSchema() {
|
||||||
if (allOf_) {
|
delete not_;
|
||||||
for (SizeType i = 0; i < allOfCount_; i++)
|
|
||||||
delete allOf_[i];
|
|
||||||
delete [] allOf_;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual SchemaType GetSchemaType() const = 0;
|
virtual SchemaType GetSchemaType() const = 0;
|
||||||
@ -167,13 +192,42 @@ public:
|
|||||||
virtual bool BeginValue(Context&) const { return true; }
|
virtual bool BeginValue(Context&) const { return true; }
|
||||||
|
|
||||||
#define RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, method_call)\
|
#define RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, method_call)\
|
||||||
if (allOf_) {\
|
if (allOf_.schemas) {\
|
||||||
CreateAllOfSchemaValidators(context);\
|
CreateSchemaValidators(context, context.allOfValidators, allOf_);\
|
||||||
for (SizeType i = 0; i < allOfCount_; i++)\
|
for (SizeType i_ = 0; i_ < allOf_.count; i_++)\
|
||||||
if (!context.allOfValidators[i]->method_call)\
|
if (!context.allOfValidators.validators[i_]->method_call)\
|
||||||
|
return false;\
|
||||||
|
}\
|
||||||
|
if (anyOf_.schemas) {\
|
||||||
|
CreateSchemaValidators(context, context.anyOfValidators, anyOf_);\
|
||||||
|
bool anyValid = false;\
|
||||||
|
for (SizeType i_ = 0; i_ < anyOf_.count; i_++)\
|
||||||
|
if (context.anyOfValidators.validators[i_]->method_call)\
|
||||||
|
anyValid = true;\
|
||||||
|
if (!anyValid)\
|
||||||
|
return false;\
|
||||||
|
}\
|
||||||
|
if (oneOf_.schemas) {\
|
||||||
|
CreateSchemaValidators(context, context.oneOfValidators, oneOf_);\
|
||||||
|
bool oneValid = false;\
|
||||||
|
for (SizeType i_ = 0; i_ < oneOf_.count; i_++)\
|
||||||
|
if (context.oneOfValidators.validators[i_]->method_call) {\
|
||||||
|
if (oneValid)\
|
||||||
|
return false;\
|
||||||
|
else\
|
||||||
|
oneValid = true;\
|
||||||
|
}\
|
||||||
|
if (!oneValid)\
|
||||||
|
return false;\
|
||||||
|
}\
|
||||||
|
if (not_) {\
|
||||||
|
if (!context.notValidator)\
|
||||||
|
context.notValidator = context.schemaValidatorFactory->CreateSchemaValidator(*not_);\
|
||||||
|
if (context.notValidator->method_call)\
|
||||||
return false;\
|
return false;\
|
||||||
}\
|
}\
|
||||||
return true
|
return true
|
||||||
|
|
||||||
#define RAPIDJSON_BASESCHEMA_HANDLER_(context, arg, method_call)\
|
#define RAPIDJSON_BASESCHEMA_HANDLER_(context, arg, method_call)\
|
||||||
if (enum_.IsArray() && !CheckEnum(GenericValue<Encoding> arg .Move()))\
|
if (enum_.IsArray() && !CheckEnum(GenericValue<Encoding> arg .Move()))\
|
||||||
return false;\
|
return false;\
|
||||||
@ -184,7 +238,7 @@ public:
|
|||||||
virtual bool Int(Context& context, int i) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (i), Int(i)); }
|
virtual bool Int(Context& context, int i) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (i), Int(i)); }
|
||||||
virtual bool Uint(Context& context, unsigned u) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (u), Uint(u)); }
|
virtual bool Uint(Context& context, unsigned u) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (u), Uint(u)); }
|
||||||
virtual bool Int64(Context& context, int64_t i) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (i), Int64(i)); }
|
virtual bool Int64(Context& context, int64_t i) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (i), Int64(i)); }
|
||||||
virtual bool Uint64(Context& context, uint64_t u) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (u), Int(i)); }
|
virtual bool Uint64(Context& context, uint64_t u) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (u), Int(u)); }
|
||||||
virtual bool Double(Context& context, double d) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (d), Double(d)); }
|
virtual bool Double(Context& context, double d) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (d), Double(d)); }
|
||||||
virtual bool String(Context& context, const Ch* s, SizeType length, bool copy) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (s, length), String(s, length, copy)); }
|
virtual bool String(Context& context, const Ch* s, SizeType length, bool copy) const { RAPIDJSON_BASESCHEMA_HANDLER_(context, (s, length), String(s, length, copy)); }
|
||||||
virtual bool StartObject(Context& context) const { RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, StartObject()); }
|
virtual bool StartObject(Context& context) const { RAPIDJSON_BASESCHEMA_HANDLER_LGOICAL_(context, StartObject()); }
|
||||||
@ -197,6 +251,19 @@ public:
|
|||||||
#undef RAPIDJSON_BASESCHEMA_HANDLER_
|
#undef RAPIDJSON_BASESCHEMA_HANDLER_
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void CreateLogicalSchemas(const Value& logic, BaseSchemaArray<Encoding>& logicSchemas) {
|
||||||
|
if (logic.IsArray() && logic.Size() > 0) {
|
||||||
|
logicSchemas.count = logic.Size();
|
||||||
|
logicSchemas.schemas = new BaseSchema*[logicSchemas.count];
|
||||||
|
memset(logicSchemas.schemas, 0, sizeof(BaseSchema*) * logicSchemas.count);
|
||||||
|
for (SizeType i = 0; i < logicSchemas.count; i++)
|
||||||
|
logicSchemas.schemas[i] = CreateSchema<Encoding>(logic[i]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CheckEnum(const GenericValue<Encoding>& v) const {
|
bool CheckEnum(const GenericValue<Encoding>& v) const {
|
||||||
for (typename GenericValue<Encoding>::ConstValueIterator itr = enum_.Begin(); itr != enum_.End(); ++itr)
|
for (typename GenericValue<Encoding>::ConstValueIterator itr = enum_.Begin(); itr != enum_.End(); ++itr)
|
||||||
if (v == *itr)
|
if (v == *itr)
|
||||||
@ -204,19 +271,21 @@ protected:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateAllOfSchemaValidators(Context& context) const {
|
void CreateSchemaValidators(Context& context, SchemaValidatorArray<Encoding>& validators, const BaseSchemaArray<Encoding>& schemas) const {
|
||||||
if (!context.allOfValidators) {
|
if (!validators.validators) {
|
||||||
context.allOfValidators = new ISchemaValidator<Encoding>*[allOfCount_];
|
validators.validators = new ISchemaValidator<Encoding>*[schemas.count];
|
||||||
context.allOfValidatorCount = allOfCount_;
|
validators.count = schemas.count;
|
||||||
for (SizeType i = 0; i < allOfCount_; i++)
|
for (SizeType i = 0; i < schemas.count; i++)
|
||||||
context.allOfValidators[i] = context.schemaValidatorFactory->CreateSchemaValidator(*allOf_[i]);
|
validators.validators[i] = context.schemaValidatorFactory->CreateSchemaValidator(*schemas.schemas[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPoolAllocator<> allocator_;
|
MemoryPoolAllocator<> allocator_;
|
||||||
GenericValue<Encoding> enum_;
|
GenericValue<Encoding> enum_;
|
||||||
BaseSchema<Encoding>** allOf_;
|
BaseSchemaArray<Encoding> allOf_;
|
||||||
SizeType allOfCount_;
|
BaseSchemaArray<Encoding> anyOf_;
|
||||||
|
BaseSchemaArray<Encoding> oneOf_;
|
||||||
|
BaseSchema<Encoding>* not_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Encoding>
|
template <typename Encoding>
|
||||||
|
@ -82,6 +82,56 @@ TEST(SchemaValidator, Enum_InvalidType) {
|
|||||||
VALIDATE(s, "null", false);
|
VALIDATE(s, "null", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SchemaValidator, AllOf) {
|
||||||
|
{
|
||||||
|
Document sd;
|
||||||
|
sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"string\", \"maxLength\": 5 }]}"); // need "type": "string" now
|
||||||
|
Schema s(sd);
|
||||||
|
|
||||||
|
VALIDATE(s, "\"ok\"", true);
|
||||||
|
VALIDATE(s, "\"too long\"", false);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Document sd;
|
||||||
|
sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
|
||||||
|
Schema s(sd);
|
||||||
|
|
||||||
|
VALIDATE(s, "\"No way\"", false);
|
||||||
|
VALIDATE(s, "-1", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SchemaValidator, AnyOf) {
|
||||||
|
Document sd;
|
||||||
|
sd.Parse("{\"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
|
||||||
|
Schema s(sd);
|
||||||
|
|
||||||
|
VALIDATE(s, "\"Yes\"", true);
|
||||||
|
VALIDATE(s, "42", true);
|
||||||
|
VALIDATE(s, "{ \"Not a\": \"string or number\" }", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SchemaValidator, OneOf) {
|
||||||
|
Document sd;
|
||||||
|
sd.Parse("{\"oneOf\": [{ \"type\": \"number\", \"multipleOf\": 5 }, { \"type\": \"number\", \"multipleOf\": 3 } ] }");
|
||||||
|
Schema s(sd);
|
||||||
|
|
||||||
|
VALIDATE(s, "10", true);
|
||||||
|
VALIDATE(s, "9", true);
|
||||||
|
VALIDATE(s, "2", false);
|
||||||
|
VALIDATE(s, "15", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SchemaValidator, Not) {
|
||||||
|
Document sd;
|
||||||
|
sd.Parse("{\"not\":{ \"type\": \"string\"}}");
|
||||||
|
Schema s(sd);
|
||||||
|
|
||||||
|
VALIDATE(s, "42", true);
|
||||||
|
// VALIDATE(s, "{ \"key\": \"value\" }", true); // TO FIX
|
||||||
|
VALIDATE(s, "\"I am a string\"", false);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(SchemaValidator, String) {
|
TEST(SchemaValidator, String) {
|
||||||
Document sd;
|
Document sd;
|
||||||
sd.Parse("{\"type\":\"string\"}");
|
sd.Parse("{\"type\":\"string\"}");
|
||||||
@ -539,17 +589,6 @@ TEST(SchemaValidator, MultiTypeWithObject) {
|
|||||||
VALIDATE(s, "{ \"tel\": \"fail\" }", false);
|
VALIDATE(s, "{ \"tel\": \"fail\" }", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SchemaValidator, AllOf) {
|
|
||||||
Document sd;
|
|
||||||
sd.Parse("{\"allOf\": [{ \"type\": \"string\", \"minLength\": 2 }, { \"type\": \"string\", \"maxLength\": 5 }]}");
|
|
||||||
Schema s(sd);
|
|
||||||
|
|
||||||
VALIDATE(s, "\"ok\"", true);
|
|
||||||
VALIDATE(s, "\"n\"", false);
|
|
||||||
VALIDATE(s, "\"too long\"", false);
|
|
||||||
VALIDATE(s, "123", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(SchemaValidator, AllOf_Nested) {
|
TEST(SchemaValidator, AllOf_Nested) {
|
||||||
Document sd;
|
Document sd;
|
||||||
sd.Parse(
|
sd.Parse(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user