Commit a5d700e9 authored by miloyip's avatar miloyip

Implemented property dependencies of schema

parent c629d37a
...@@ -44,15 +44,18 @@ class BaseSchema; ...@@ -44,15 +44,18 @@ class BaseSchema;
template <typename Encoding> template <typename Encoding>
struct SchemaValidationContext { struct SchemaValidationContext {
SchemaValidationContext(const BaseSchema<Encoding>* s) : schema(s), valueSchema(), multiTypeSchema() {} SchemaValidationContext(const BaseSchema<Encoding>* s) : schema(s), valueSchema(), multiTypeSchema(), objectDependencies() {}
~SchemaValidationContext() {} ~SchemaValidationContext() {
delete[] objectDependencies;
}
const BaseSchema<Encoding>* schema; const BaseSchema<Encoding>* schema;
const BaseSchema<Encoding>* valueSchema; const BaseSchema<Encoding>* valueSchema;
const BaseSchema<Encoding>* multiTypeSchema; const BaseSchema<Encoding>* multiTypeSchema;
SizeType objectRequiredCount; SizeType objectRequiredCount;
SizeType arrayElementIndex; SizeType arrayElementIndex;
bool* objectDependencies;
}; };
template <typename Encoding> template <typename Encoding>
...@@ -246,7 +249,8 @@ public: ...@@ -246,7 +249,8 @@ public:
requiredCount_(), requiredCount_(),
minProperties_(), minProperties_(),
maxProperties_(SizeType(~0)), maxProperties_(SizeType(~0)),
additionalProperty_(true) additionalProperty_(true),
hasDependencies_()
{ {
typename ValueType::ConstMemberIterator propretiesItr = value.FindMember("properties"); typename ValueType::ConstMemberIterator propretiesItr = value.FindMember("properties");
if (propretiesItr != value.MemberEnd()) { if (propretiesItr != value.MemberEnd()) {
...@@ -272,13 +276,53 @@ public: ...@@ -272,13 +276,53 @@ public:
properties_[index].required = true; properties_[index].required = true;
requiredCount_++; requiredCount_++;
} }
else {
// Error
}
}
else {
// Error
} }
} }
}
else {
// Error
}
}
if (requiredCount_ != requiredItr->value.Size()) { // Establish dependencies after properties
// Error typename ValueType::ConstMemberIterator dependenciesItr = value.FindMember("dependencies");
if (dependenciesItr != value.MemberEnd()) {
if (dependenciesItr->value.IsObject()) {
hasDependencies_ = true;
for (typename ValueType::ConstMemberIterator itr = dependenciesItr->value.MemberBegin(); itr != dependenciesItr->value.MemberEnd(); ++itr) {
SizeType sourceIndex;
if (FindPropertyIndex(itr->name, &sourceIndex)) {
properties_[sourceIndex].dependencies = new bool[propertyCount_];
std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool) * propertyCount_);
if (itr->value.IsArray()) {
for (typename ValueType::ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
SizeType targetIndex;
if (FindPropertyIndex(*targetItr, &targetIndex)) {
properties_[sourceIndex].dependencies[targetIndex] = true;
}
else {
// Error
}
}
}
else {
// Error
}
}
else {
// Error
}
} }
} }
else {
// Error
}
} }
typename ValueType::ConstMemberIterator additionalPropretiesItr = value.FindMember("additionalProperties"); typename ValueType::ConstMemberIterator additionalPropretiesItr = value.FindMember("additionalProperties");
...@@ -329,6 +373,10 @@ public: ...@@ -329,6 +373,10 @@ public:
virtual bool StartObject(Context& context) const { virtual bool StartObject(Context& context) const {
context.objectRequiredCount = 0; context.objectRequiredCount = 0;
if (hasDependencies_) {
context.objectDependencies = new bool[propertyCount_];
std::memset(context.objectDependencies, 0, sizeof(bool) * propertyCount_);
}
return true; return true;
} }
...@@ -340,6 +388,9 @@ public: ...@@ -340,6 +388,9 @@ public:
if (properties_[index].required) if (properties_[index].required)
context.objectRequiredCount++; context.objectRequiredCount++;
if (hasDependencies_)
context.objectDependencies[index] = true;
return true; return true;
} }
...@@ -356,9 +407,18 @@ public: ...@@ -356,9 +407,18 @@ public:
} }
virtual bool EndObject(Context& context, SizeType memberCount) const { virtual bool EndObject(Context& context, SizeType memberCount) const {
return context.objectRequiredCount == requiredCount_ && if (context.objectRequiredCount != requiredCount_ || memberCount < minProperties_ || memberCount > maxProperties_)
memberCount >= minProperties_ && return false;
memberCount <= maxProperties_;
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])
return false;
}
return true;
} }
virtual bool StartArray(Context&) const { return false; } virtual bool StartArray(Context&) const { return false; }
...@@ -391,13 +451,15 @@ private: ...@@ -391,13 +451,15 @@ private:
} }
struct Property { struct Property {
Property() : schema(), required(false) {} Property() : schema(), dependencies(), required(false) {}
~Property() { ~Property() {
delete schema; delete schema;
delete[] dependencies;
} }
GenericValue<Encoding> name; GenericValue<Encoding> name;
BaseSchema<Encoding>* schema; BaseSchema<Encoding>* schema;
bool* dependencies;
bool required; bool required;
}; };
...@@ -409,6 +471,7 @@ private: ...@@ -409,6 +471,7 @@ private:
SizeType minProperties_; SizeType minProperties_;
SizeType maxProperties_; SizeType maxProperties_;
bool additionalProperty_; bool additionalProperty_;
bool hasDependencies_;
}; };
template <typename Encoding> template <typename Encoding>
...@@ -894,7 +957,6 @@ public: ...@@ -894,7 +957,6 @@ public:
schemaStack_(allocator, schemaStackCapacity), schemaStack_(allocator, schemaStackCapacity),
documentStack_(allocator, documentStackCapacity) documentStack_(allocator, documentStackCapacity)
{ {
Reset();
} }
GenericSchemaValidator( GenericSchemaValidator(
...@@ -909,11 +971,15 @@ public: ...@@ -909,11 +971,15 @@ public:
schemaStack_(allocator, schemaStackCapacity), schemaStack_(allocator, schemaStackCapacity),
documentStack_(allocator, documentStackCapacity) documentStack_(allocator, documentStackCapacity)
{ {
}
~GenericSchemaValidator() {
Reset(); Reset();
} }
void Reset() { void Reset() {
schemaStack_.Clear(); while (!schemaStack_.Empty())
PopSchema();
documentStack_.Clear(); documentStack_.Clear();
}; };
...@@ -965,7 +1031,7 @@ private: ...@@ -965,7 +1031,7 @@ private:
} }
void PushSchema(const BaseSchemaType& schema) { *schemaStack_.template Push<Context>() = Context(&schema); } void PushSchema(const BaseSchemaType& schema) { *schemaStack_.template Push<Context>() = Context(&schema); }
const BaseSchemaType& PopSchema() { return *schemaStack_.template Pop<Context>(1)->schema; } void PopSchema() { schemaStack_.template Pop<Context>(1)->~Context(); }
const BaseSchemaType& CurrentSchema() { return *schemaStack_.template Top<Context>()->schema; } const BaseSchemaType& CurrentSchema() { return *schemaStack_.template Top<Context>()->schema; }
Context& CurrentContext() { return *schemaStack_.template Top<Context>(); } Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
......
...@@ -278,8 +278,6 @@ TEST(SchemaValidator, Object_PropertiesRange) { ...@@ -278,8 +278,6 @@ TEST(SchemaValidator, Object_PropertiesRange) {
VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", false); VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", false);
} }
#if 0
// TODO
TEST(SchemaValidator, Object_PropertyDependencies) { TEST(SchemaValidator, Object_PropertyDependencies) {
Document sd; Document sd;
sd.Parse( sd.Parse(
...@@ -302,7 +300,6 @@ TEST(SchemaValidator, Object_PropertyDependencies) { ...@@ -302,7 +300,6 @@ TEST(SchemaValidator, Object_PropertyDependencies) {
VALIDATE(s, "{ \"name\": \"John Doe\"}", true); VALIDATE(s, "{ \"name\": \"John Doe\"}", true);
VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true); VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true);
} }
#endif
TEST(SchemaValidator, Array) { TEST(SchemaValidator, Array) {
Document sd; Document sd;
......
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