Commit e9dd5fff authored by miloyip's avatar miloyip

Add schema dependencies (not handling missing property)

[ci skip]
parent 9e907ea2
......@@ -60,11 +60,9 @@ template <typename Encoding>
struct SchemaValidatorArray {
SchemaValidatorArray() : validators(), count() {}
~SchemaValidatorArray() {
if (validators) {
for (SizeType i = 0; i < count; i++)
delete validators[i];
delete[] validators;
}
for (SizeType i = 0; i < count; i++)
delete validators[i];
delete[] validators;
}
GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>** validators;
......@@ -75,11 +73,9 @@ template <typename Encoding>
struct BaseSchemaArray {
BaseSchemaArray() : schemas(), count() {}
~BaseSchemaArray() {
if (schemas) {
for (SizeType i = 0; i < count; i++)
delete schemas[i];
delete[] schemas;
}
for (SizeType i = 0; i < count; i++)
delete schemas[i];
delete[] schemas;
}
BaseSchema<Encoding>** schemas;
......@@ -103,6 +99,7 @@ struct SchemaValidationContext {
SchemaValidatorArray<Encoding> allOfValidators;
SchemaValidatorArray<Encoding> anyOfValidators;
SchemaValidatorArray<Encoding> oneOfValidators;
SchemaValidatorArray<Encoding> dependencyValidators;
GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>* notValidator;
SizeType objectRequiredCount;
SizeType arrayElementIndex;
......@@ -132,6 +129,7 @@ public:
maxProperties_(SizeType(~0)),
additionalProperties_(true),
hasDependencies_(),
hasSchemaDependencies_(),
additionalItemsSchema_(),
itemsList_(),
itemsTuple_(),
......@@ -196,7 +194,7 @@ public:
for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
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_++;
}
}
......@@ -229,7 +227,8 @@ public:
}
}
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_)
return false;
if (hasDependencies_)
if (hasDependencies_) {
for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
if (context.objectDependencies[sourceIndex] && properties_[sourceIndex].dependencies)
for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
if (properties_[sourceIndex].dependencies[targetIndex] && !context.objectDependencies[targetIndex])
if (context.objectDependencies[sourceIndex]) {
if (properties_[sourceIndex].dependencies) {
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 true;
}
......@@ -533,6 +539,7 @@ public:
}
private:
typedef GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator> SchemaValidatorType;
static const BaseSchema<Encoding>* GetTypeless() {
static BaseSchema<Encoding> typeless(Value(kObjectType).Move());
return &typeless;
......@@ -610,15 +617,22 @@ private:
if (anyOf_.schemas) CreateSchemaValidators(context.anyOfValidators, anyOf_);
if (oneOf_.schemas) CreateSchemaValidators(context.oneOfValidators, oneOf_);
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 {
if (!validators.validators) {
validators.validators = new GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>*[schemas.count];
validators.validators = new SchemaValidatorType*[schemas.count];
validators.count = schemas.count;
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 {
Property() : schema(), dependencies(), required(false) {}
Property() : schema(), dependenciesSchema(), dependencies(), required(false) {}
~Property() {
delete schema;
delete dependenciesSchema;
delete[] dependencies;
}
GenericValue<Encoding> name;
BaseSchema<Encoding>* schema;
BaseSchema<Encoding>* dependenciesSchema;
bool* dependencies;
bool required;
};
......@@ -704,6 +720,7 @@ private:
SizeType maxProperties_;
bool additionalProperties_;
bool hasDependencies_;
bool hasSchemaDependencies_;
BaseSchema<Encoding>* additionalItemsSchema_;
BaseSchema<Encoding>* itemsList_;
......@@ -814,6 +831,10 @@ public:
context->oneOfValidators.validators[i_]->method arg2;\
if (context->notValidator)\
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)\
......@@ -849,8 +870,8 @@ public:
bool EndObject(SizeType memberCount) {
if (!valid_) return false;
if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(EndObject, (memberCount));
if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
RAPIDJSON_SCHEMA_HANDLE_END_ (EndObject, (memberCount));
}
......@@ -862,8 +883,8 @@ public:
bool EndArray(SizeType elementCount) {
if (!valid_) return false;
if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
RAPIDJSON_SCHEMA_HANDLE_LOGIC_(EndArray, (elementCount));
if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
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);
}
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
TEST(SchemaValidator, Object_PatternProperties) {
......@@ -645,7 +671,7 @@ TEST(SchemaValidator, TestSuite) {
"allOf.json",
"anyOf.json",
//"definitions.json",
//"dependencies.json",
"dependencies.json",
"enum.json",
"items.json",
"maximum.json",
......@@ -696,17 +722,18 @@ TEST(SchemaValidator, TestSuite) {
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
Schema schema((*schemaItr)["schema"]);
SchemaValidator validator(schema);
const char* description1 = (*schemaItr)["description"].GetString();
const Value& tests = (*schemaItr)["tests"];
for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
const char* description = (*testItr)["description"].GetString();
if (!onlyRunDescription || strcmp(description, onlyRunDescription) == 0) {
const char* description2 = (*testItr)["description"].GetString();
if (!onlyRunDescription || strcmp(description2, onlyRunDescription) == 0) {
const Value& data = (*testItr)["data"];
bool expected = (*testItr)["valid"].GetBool();
testCount++;
validator.Reset();
bool actual = data.Accept(validator);
if (expected != actual)
printf("Fail: %30s \"%s\"\n", filename, description);
printf("Fail: %30s \"%s, %s\"\n", filename, description1, description2);
else
passCount++;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment