Add schema dependencies (not handling missing property)
[ci skip]
This commit is contained in:
parent
9e907ea219
commit
e9dd5fffa6
@ -60,11 +60,9 @@ template <typename Encoding>
|
|||||||
struct SchemaValidatorArray {
|
struct SchemaValidatorArray {
|
||||||
SchemaValidatorArray() : validators(), count() {}
|
SchemaValidatorArray() : validators(), count() {}
|
||||||
~SchemaValidatorArray() {
|
~SchemaValidatorArray() {
|
||||||
if (validators) {
|
for (SizeType i = 0; i < count; i++)
|
||||||
for (SizeType i = 0; i < count; i++)
|
delete validators[i];
|
||||||
delete validators[i];
|
delete[] validators;
|
||||||
delete[] validators;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>** validators;
|
GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>** validators;
|
||||||
@ -75,11 +73,9 @@ template <typename Encoding>
|
|||||||
struct BaseSchemaArray {
|
struct BaseSchemaArray {
|
||||||
BaseSchemaArray() : schemas(), count() {}
|
BaseSchemaArray() : schemas(), count() {}
|
||||||
~BaseSchemaArray() {
|
~BaseSchemaArray() {
|
||||||
if (schemas) {
|
for (SizeType i = 0; i < count; i++)
|
||||||
for (SizeType i = 0; i < count; i++)
|
delete schemas[i];
|
||||||
delete schemas[i];
|
delete[] schemas;
|
||||||
delete[] schemas;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseSchema<Encoding>** schemas;
|
BaseSchema<Encoding>** schemas;
|
||||||
@ -103,6 +99,7 @@ struct SchemaValidationContext {
|
|||||||
SchemaValidatorArray<Encoding> allOfValidators;
|
SchemaValidatorArray<Encoding> allOfValidators;
|
||||||
SchemaValidatorArray<Encoding> anyOfValidators;
|
SchemaValidatorArray<Encoding> anyOfValidators;
|
||||||
SchemaValidatorArray<Encoding> oneOfValidators;
|
SchemaValidatorArray<Encoding> oneOfValidators;
|
||||||
|
SchemaValidatorArray<Encoding> dependencyValidators;
|
||||||
GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>* notValidator;
|
GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>* notValidator;
|
||||||
SizeType objectRequiredCount;
|
SizeType objectRequiredCount;
|
||||||
SizeType arrayElementIndex;
|
SizeType arrayElementIndex;
|
||||||
@ -132,6 +129,7 @@ public:
|
|||||||
maxProperties_(SizeType(~0)),
|
maxProperties_(SizeType(~0)),
|
||||||
additionalProperties_(true),
|
additionalProperties_(true),
|
||||||
hasDependencies_(),
|
hasDependencies_(),
|
||||||
|
hasSchemaDependencies_(),
|
||||||
additionalItemsSchema_(),
|
additionalItemsSchema_(),
|
||||||
itemsList_(),
|
itemsList_(),
|
||||||
itemsTuple_(),
|
itemsTuple_(),
|
||||||
@ -196,7 +194,7 @@ public:
|
|||||||
|
|
||||||
for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
|
for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
|
||||||
patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
|
patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
|
||||||
patternProperties_[patternPropertyCount_].schema = new BaseSchema<Encoding>(itr->value); // TODO: Check error
|
patternProperties_[patternPropertyCount_].schema = new BaseSchema<Encoding>(itr->value);
|
||||||
patternPropertyCount_++;
|
patternPropertyCount_++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,7 +227,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (itr->value.IsObject()) {
|
else if (itr->value.IsObject()) {
|
||||||
// TODO
|
hasSchemaDependencies_ = true;
|
||||||
|
properties_[sourceIndex].dependenciesSchema = new BaseSchema<Encoding>(itr->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,12 +502,19 @@ public:
|
|||||||
if (context.objectRequiredCount != requiredCount_ || memberCount < minProperties_ || memberCount > maxProperties_)
|
if (context.objectRequiredCount != requiredCount_ || memberCount < minProperties_ || memberCount > maxProperties_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (hasDependencies_)
|
if (hasDependencies_) {
|
||||||
for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
|
for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
|
||||||
if (context.objectDependencies[sourceIndex] && properties_[sourceIndex].dependencies)
|
if (context.objectDependencies[sourceIndex]) {
|
||||||
for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
|
if (properties_[sourceIndex].dependencies) {
|
||||||
if (properties_[sourceIndex].dependencies[targetIndex] && !context.objectDependencies[targetIndex])
|
for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
|
||||||
|
if (properties_[sourceIndex].dependencies[targetIndex] && !context.objectDependencies[targetIndex])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (properties_[sourceIndex].dependenciesSchema)
|
||||||
|
if (!context.dependencyValidators.validators[sourceIndex]->IsValid())
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -533,6 +539,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator> SchemaValidatorType;
|
||||||
static const BaseSchema<Encoding>* GetTypeless() {
|
static const BaseSchema<Encoding>* GetTypeless() {
|
||||||
static BaseSchema<Encoding> typeless(Value(kObjectType).Move());
|
static BaseSchema<Encoding> typeless(Value(kObjectType).Move());
|
||||||
return &typeless;
|
return &typeless;
|
||||||
@ -610,15 +617,22 @@ private:
|
|||||||
if (anyOf_.schemas) CreateSchemaValidators(context.anyOfValidators, anyOf_);
|
if (anyOf_.schemas) CreateSchemaValidators(context.anyOfValidators, anyOf_);
|
||||||
if (oneOf_.schemas) CreateSchemaValidators(context.oneOfValidators, oneOf_);
|
if (oneOf_.schemas) CreateSchemaValidators(context.oneOfValidators, oneOf_);
|
||||||
if (not_ && !context.notValidator)
|
if (not_ && !context.notValidator)
|
||||||
context.notValidator = new GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>(*not_);
|
context.notValidator = new SchemaValidatorType(*not_);
|
||||||
|
|
||||||
|
if (hasSchemaDependencies_ && !context.dependencyValidators.validators) {
|
||||||
|
context.dependencyValidators.validators = new SchemaValidatorType*[propertyCount_];
|
||||||
|
context.dependencyValidators.count = propertyCount_;
|
||||||
|
for (SizeType i = 0; i < propertyCount_; i++)
|
||||||
|
context.dependencyValidators.validators[i] = properties_[i].dependenciesSchema ? new SchemaValidatorType(*properties_[i].dependenciesSchema) : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateSchemaValidators(SchemaValidatorArray<Encoding>& validators, const BaseSchemaArray<Encoding>& schemas) const {
|
void CreateSchemaValidators(SchemaValidatorArray<Encoding>& validators, const BaseSchemaArray<Encoding>& schemas) const {
|
||||||
if (!validators.validators) {
|
if (!validators.validators) {
|
||||||
validators.validators = new GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>*[schemas.count];
|
validators.validators = new SchemaValidatorType*[schemas.count];
|
||||||
validators.count = schemas.count;
|
validators.count = schemas.count;
|
||||||
for (SizeType i = 0; i < schemas.count; i++)
|
for (SizeType i = 0; i < schemas.count; i++)
|
||||||
validators.validators[i] = new GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>(*schemas.schemas[i]);
|
validators.validators[i] = new SchemaValidatorType(*schemas.schemas[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -657,14 +671,16 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Property {
|
struct Property {
|
||||||
Property() : schema(), dependencies(), required(false) {}
|
Property() : schema(), dependenciesSchema(), dependencies(), required(false) {}
|
||||||
~Property() {
|
~Property() {
|
||||||
delete schema;
|
delete schema;
|
||||||
|
delete dependenciesSchema;
|
||||||
delete[] dependencies;
|
delete[] dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericValue<Encoding> name;
|
GenericValue<Encoding> name;
|
||||||
BaseSchema<Encoding>* schema;
|
BaseSchema<Encoding>* schema;
|
||||||
|
BaseSchema<Encoding>* dependenciesSchema;
|
||||||
bool* dependencies;
|
bool* dependencies;
|
||||||
bool required;
|
bool required;
|
||||||
};
|
};
|
||||||
@ -704,6 +720,7 @@ private:
|
|||||||
SizeType maxProperties_;
|
SizeType maxProperties_;
|
||||||
bool additionalProperties_;
|
bool additionalProperties_;
|
||||||
bool hasDependencies_;
|
bool hasDependencies_;
|
||||||
|
bool hasSchemaDependencies_;
|
||||||
|
|
||||||
BaseSchema<Encoding>* additionalItemsSchema_;
|
BaseSchema<Encoding>* additionalItemsSchema_;
|
||||||
BaseSchema<Encoding>* itemsList_;
|
BaseSchema<Encoding>* itemsList_;
|
||||||
@ -814,6 +831,10 @@ public:
|
|||||||
context->oneOfValidators.validators[i_]->method arg2;\
|
context->oneOfValidators.validators[i_]->method arg2;\
|
||||||
if (context->notValidator)\
|
if (context->notValidator)\
|
||||||
context->notValidator->method arg2;\
|
context->notValidator->method arg2;\
|
||||||
|
if (context->dependencyValidators.validators)\
|
||||||
|
for (SizeType i_ = 0; i_ < context->dependencyValidators.count; i_++)\
|
||||||
|
if (context->dependencyValidators.validators[i_])\
|
||||||
|
context->dependencyValidators.validators[i_]->method arg2;\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
|
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
|
||||||
@ -849,8 +870,8 @@ public:
|
|||||||
|
|
||||||
bool EndObject(SizeType memberCount) {
|
bool EndObject(SizeType memberCount) {
|
||||||
if (!valid_) return false;
|
if (!valid_) return false;
|
||||||
if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
|
|
||||||
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(EndObject, (memberCount));
|
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(EndObject, (memberCount));
|
||||||
|
if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
|
||||||
RAPIDJSON_SCHEMA_HANDLE_END_ (EndObject, (memberCount));
|
RAPIDJSON_SCHEMA_HANDLE_END_ (EndObject, (memberCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,8 +883,8 @@ public:
|
|||||||
|
|
||||||
bool EndArray(SizeType elementCount) {
|
bool EndArray(SizeType elementCount) {
|
||||||
if (!valid_) return false;
|
if (!valid_) return false;
|
||||||
if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
|
|
||||||
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(EndArray, (elementCount));
|
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(EndArray, (elementCount));
|
||||||
|
if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
|
||||||
RAPIDJSON_SCHEMA_HANDLE_END_ (EndArray, (elementCount));
|
RAPIDJSON_SCHEMA_HANDLE_END_ (EndArray, (elementCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,6 +361,32 @@ TEST(SchemaValidator, Object_PropertyDependencies) {
|
|||||||
VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true);
|
VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SchemaValidator, Object_SchemaDependencies) {
|
||||||
|
Document sd;
|
||||||
|
sd.Parse(
|
||||||
|
"{"
|
||||||
|
" \"type\": \"object\","
|
||||||
|
" \"properties\" : {"
|
||||||
|
" \"name\": { \"type\": \"string\" },"
|
||||||
|
" \"credit_card\" : { \"type\": \"number\" }"
|
||||||
|
" },"
|
||||||
|
" \"required\" : [\"name\"],"
|
||||||
|
" \"dependencies\" : {"
|
||||||
|
" \"credit_card\": {"
|
||||||
|
" \"properties\": {"
|
||||||
|
" \"billing_address\": { \"type\": \"string\" }"
|
||||||
|
" },"
|
||||||
|
" \"required\" : [\"billing_address\"]"
|
||||||
|
" }"
|
||||||
|
" }"
|
||||||
|
"}");
|
||||||
|
Schema s(sd);
|
||||||
|
|
||||||
|
//VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true);
|
||||||
|
VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", false);
|
||||||
|
VALIDATE(s, "{\"name\": \"John Doe\", \"billing_address\" : \"555 Debtor's Lane\"}", true);
|
||||||
|
}
|
||||||
|
|
||||||
#if RAPIDJSON_SCHEMA_HAS_REGEX
|
#if RAPIDJSON_SCHEMA_HAS_REGEX
|
||||||
|
|
||||||
TEST(SchemaValidator, Object_PatternProperties) {
|
TEST(SchemaValidator, Object_PatternProperties) {
|
||||||
@ -645,7 +671,7 @@ TEST(SchemaValidator, TestSuite) {
|
|||||||
"allOf.json",
|
"allOf.json",
|
||||||
"anyOf.json",
|
"anyOf.json",
|
||||||
//"definitions.json",
|
//"definitions.json",
|
||||||
//"dependencies.json",
|
"dependencies.json",
|
||||||
"enum.json",
|
"enum.json",
|
||||||
"items.json",
|
"items.json",
|
||||||
"maximum.json",
|
"maximum.json",
|
||||||
@ -696,17 +722,18 @@ TEST(SchemaValidator, TestSuite) {
|
|||||||
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
|
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
|
||||||
Schema schema((*schemaItr)["schema"]);
|
Schema schema((*schemaItr)["schema"]);
|
||||||
SchemaValidator validator(schema);
|
SchemaValidator validator(schema);
|
||||||
|
const char* description1 = (*schemaItr)["description"].GetString();
|
||||||
const Value& tests = (*schemaItr)["tests"];
|
const Value& tests = (*schemaItr)["tests"];
|
||||||
for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
|
for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
|
||||||
const char* description = (*testItr)["description"].GetString();
|
const char* description2 = (*testItr)["description"].GetString();
|
||||||
if (!onlyRunDescription || strcmp(description, onlyRunDescription) == 0) {
|
if (!onlyRunDescription || strcmp(description2, onlyRunDescription) == 0) {
|
||||||
const Value& data = (*testItr)["data"];
|
const Value& data = (*testItr)["data"];
|
||||||
bool expected = (*testItr)["valid"].GetBool();
|
bool expected = (*testItr)["valid"].GetBool();
|
||||||
testCount++;
|
testCount++;
|
||||||
validator.Reset();
|
validator.Reset();
|
||||||
bool actual = data.Accept(validator);
|
bool actual = data.Accept(validator);
|
||||||
if (expected != actual)
|
if (expected != actual)
|
||||||
printf("Fail: %30s \"%s\"\n", filename, description);
|
printf("Fail: %30s \"%s, %s\"\n", filename, description1, description2);
|
||||||
else
|
else
|
||||||
passCount++;
|
passCount++;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user