diff options
author | Alexei Rousskikh <ext-alexei.rousskikh@nokia.com> | 2012-03-05 10:46:52 -0500 |
---|---|---|
committer | Chris Craig <ext-chris.craig@nokia.com> | 2012-03-05 21:46:26 +0100 |
commit | c84ef3980f2d0f7e214c002f03db4be3e03f73b8 (patch) | |
tree | 99151de305d4052a28001a2d200f0bb80b887da6 | |
parent | 5c55284cceea22fcd4768f4b41fcfb7e0f893d0c (diff) |
implemented self reference ({"$ref" : "#"}) (required for a self validation)
Change-Id: I0ebb0c3c1a26e7f734ccd9784cfbe11fcc5b5e30
Reviewed-by: Chris Craig <ext-chris.craig@nokia.com>
-rw-r--r-- | src/qtjsonschema/checkpoints_p.h | 78 | ||||
-rw-r--r-- | src/qtjsonschema/jsonobjecttypes_p.h | 4 | ||||
-rw-r--r-- | src/qtjsonschema/schemamanager_impl_p.h | 2 | ||||
-rw-r--r-- | src/qtjsonschema/schemaobject_p.h | 16 | ||||
-rw-r--r-- | tests/auto/jsonschema/tst_jsonschema.cpp | 4 |
5 files changed, 90 insertions, 14 deletions
diff --git a/src/qtjsonschema/checkpoints_p.h b/src/qtjsonschema/checkpoints_p.h index 081f895..67357bc 100644 --- a/src/qtjsonschema/checkpoints_p.h +++ b/src/qtjsonschema/checkpoints_p.h @@ -118,6 +118,7 @@ class SchemaPrivate<T>::CheckType : public Check { ArrayType = 0x0020, NullType = 0x0040, AnyType = 0x0080, + SelfRefType = 0x0100, // self reference UnknownType = 0}; public: CheckType(SchemaPrivate *schema, QSharedPointer<CheckSharedData> &data, const Value& type) @@ -137,6 +138,15 @@ public: if (ok) { typesName << typeName; } + else { + // is a self reference ? + const Object obj = (*i).toObject(&ok); + const QLatin1String ref("$ref"); + if (ok && obj.propertyNames().contains(ref) && obj.property(ref).toString(&ok) == QStringLiteral("#") && ok) { + m_type |= ObjectType; + m_type |= SelfRefType; + } + } } } else { typesName << typeName; @@ -292,6 +302,7 @@ public: } m_checks.insert(propertyName, checks); } + Check::m_data->m_flags |= CheckSharedData::HasProperties; } ~CheckProperties() @@ -424,9 +435,35 @@ public: Q_ASSERT(ok); } - virtual bool doCheck(const Value &) + virtual bool doCheck(const Value &value) { - // actual check is done in CheckAdditionalProperties::doCheck + // most time a check is done in CheckProperties::doCheck + QFlags<enum CheckSharedData::Flag> flags(Check::m_data->m_flags); + if (!flags.testFlag(CheckSharedData::HasProperties) && !flags.testFlag(CheckSharedData::HasItems)) { + bool ok; + ValueList array(value.toList(&ok)); + if (ok) { + // arrays are still allowed + return true; + } + if (flags.testFlag(CheckSharedData::NoAdditionalProperties)) { + // items attribute is absent, but additionalItems is set to false + return false; + } + else if (Check::m_data->m_additionalSchema) { + Object object = value.toObject(&ok); + if (!ok) + return false; + + foreach (const Key &key, object.propertyNames()) { + Value property = object.property(key); + if (!Check::m_data->m_additionalSchema->check(property, Check::m_schema->m_callbacks)) { + return false; + } + } + + } + } return true; } }; @@ -469,7 +506,14 @@ public: bool ok; ValueList array = value.toList(&ok); if (!ok) + { + Object object = value.toObject(&ok); + if (ok && m_schema.size() >= 1) { + bool bRet = m_schema[0].check(value, Check::m_schema->m_callbacks); + return bRet; + } return false; + } bool bNoAdditional; if ((bNoAdditional = Check::m_data->m_flags.testFlag(CheckSharedData::NoAdditionalItems))) { @@ -1102,13 +1146,19 @@ public: QString schemaName = value.toString(&ok); Q_ASSERT(ok); - m_newSchema = schema->m_callbacks->loadSchema(schemaName); - if (!m_newSchema.isValid()) { - // FIXME should we have current schema name? - const QString msg = QString::fromLatin1("Schema extends %1 but it is unknown.") - .arg(schemaName); - qWarning() << msg; - schema->m_callbacks->setValidationError(msg); + if (schemaName == QStringLiteral("#")) { // self reference + // assign a root schema + m_newSchema = Check::m_schema->m_callbacks->rootSchema(); + } + else { + m_newSchema = schema->m_callbacks->loadSchema(schemaName); + if (!m_newSchema.isValid()) { + // FIXME should we have current schema name? + const QString msg = QString::fromLatin1("Schema extends %1 but it is unknown.") + .arg(schemaName); + qWarning() << msg; + schema->m_callbacks->setValidationError(msg); + } } } virtual bool doCheck(const Value &value) @@ -1121,7 +1171,6 @@ public: void checkDefault(Value& value, Object &_object) const { m_newSchema.checkDefault(value, _object); - } private: @@ -1269,11 +1318,16 @@ bool SchemaPrivate<T>::check(const Value &value, Service *callbackToUseForCheck) { //qDebug() << Q_FUNC_INFO << m_checks.count() << this; Q_ASSERT(callbackToUseForCheck); - Q_ASSERT(!m_callbacks); + + // allow recursive calls - save mutable variables + Service *savedCallback = m_callbacks; + qint32 savedRequiredCount = m_requiredCount; m_callbacks = callbackToUseForCheck; bool result = check(value); - m_callbacks = 0; + // restore saved variables + m_callbacks = savedCallback; + m_requiredCount = savedRequiredCount; return result; } diff --git a/src/qtjsonschema/jsonobjecttypes_p.h b/src/qtjsonschema/jsonobjecttypes_p.h index 11f0fbe..6ee0097 100644 --- a/src/qtjsonschema/jsonobjecttypes_p.h +++ b/src/qtjsonschema/jsonobjecttypes_p.h @@ -164,6 +164,9 @@ public: inline Service(SchemaManagerBase *schemas); inline QJsonObject error() const; + void setRootSchema(const SchemaValidation::Schema<JsonObjectTypes> & _schema) { m_rootSchema = _schema; } + const SchemaValidation::Schema<JsonObjectTypes> &rootSchema() const { return m_rootSchema; } + // interface inline void setValidationError(const QString &message); inline void setLoadError(const QString &message); @@ -173,6 +176,7 @@ public: private: SchemaManagerBase *m_schemas; QJsonObject m_errorMap; + SchemaValidation::Schema<JsonObjectTypes> m_rootSchema; }; }; diff --git a/src/qtjsonschema/schemamanager_impl_p.h b/src/qtjsonschema/schemamanager_impl_p.h index 951b31a..d779f35 100644 --- a/src/qtjsonschema/schemamanager_impl_p.h +++ b/src/qtjsonschema/schemamanager_impl_p.h @@ -92,7 +92,7 @@ inline T SchemaManager<T,TT>::ensureCompiled(const QString &schemaName, MapSchem else if (!schema.isValid()) { // Try to compile schema typename TT::Object schemaObject(pair->first); - SchemaValidation::Schema<TT> compiledSchema(schemaObject, callbacks); + SchemaValidation::Schema<TT> compiledSchema = SchemaValidation::Schema<TT>::compile(schemaObject, callbacks); pair->second = compiledSchema; m_schemas.insert(schemaName, *pair); return callbacks->error(); diff --git a/src/qtjsonschema/schemaobject_p.h b/src/qtjsonschema/schemaobject_p.h index 548988a..6e89dd8 100644 --- a/src/qtjsonschema/schemaobject_p.h +++ b/src/qtjsonschema/schemaobject_p.h @@ -120,12 +120,25 @@ public: : d_ptr(new SchemaPrivate<T>()) {} +protected: Schema(const Object& schema, Service *callbacksToUseForCompilation) : d_ptr(new SchemaPrivate<T>()) { d_ptr->compile(schema, callbacksToUseForCompilation); } +public: + static Schema compile(const Object& schemaObj, Service *callbacksToUseForCompilation) + { + Schema schema; + if (callbacksToUseForCompilation) { + // need to store a root schema to use for self reference + callbacksToUseForCompilation->setRootSchema(schema); + } + schema.d_ptr->compile(schemaObj, callbacksToUseForCompilation); + return schema; + } + bool isValid() const { return d_ptr->isValid(); @@ -162,7 +175,8 @@ class SchemaPrivate : public QSharedData ExclusiveMaximum = 0x2, NoAdditionalProperties = 0x4, NoAdditionalItems = 0x8, - HasItems = 0x10 + HasItems = 0x10, + HasProperties = 0x20 }; Q_DECLARE_FLAGS(Flags, Flag) Flags m_flags; diff --git a/tests/auto/jsonschema/tst_jsonschema.cpp b/tests/auto/jsonschema/tst_jsonschema.cpp index 379d928..82d1109 100644 --- a/tests/auto/jsonschema/tst_jsonschema.cpp +++ b/tests/auto/jsonschema/tst_jsonschema.cpp @@ -496,6 +496,10 @@ void tst_JsonSchema::testExtendsValidation() // 5.28 void tst_JsonSchema::testRefValidation() { + // + QVERIFY(validate("{ \"a\" : {} }", "{ \"type\" : \"object\", \"additionalProperties\" : { \"$ref\" : \"#\" } }")); + QVERIFY(!validate("{ \"a\" : 1 }", "{ \"type\" : \"object\", \"additionalProperties\" : { \"$ref\" : \"#\" } }")); + QVERIFY(!validate("{ \"a\" : \"1\" }", "{ \"type\" : \"object\", \"additionalProperties\" : { \"$ref\" : \"#\" } }")); } bool tst_JsonSchema::validate(const char *data, const QByteArray & schemaBody) |