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> ...@@ -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> ...@@ -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 { ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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++;
} }
......
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