summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Rousskikh <ext-alexei.rousskikh@nokia.com>2012-03-05 10:46:52 -0500
committerChris Craig <ext-chris.craig@nokia.com>2012-03-05 21:46:26 +0100
commitc84ef3980f2d0f7e214c002f03db4be3e03f73b8 (patch)
tree99151de305d4052a28001a2d200f0bb80b887da6
parent5c55284cceea22fcd4768f4b41fcfb7e0f893d0c (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.h78
-rw-r--r--src/qtjsonschema/jsonobjecttypes_p.h4
-rw-r--r--src/qtjsonschema/schemamanager_impl_p.h2
-rw-r--r--src/qtjsonschema/schemaobject_p.h16
-rw-r--r--tests/auto/jsonschema/tst_jsonschema.cpp4
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)