summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Rousskikh <ext-alexei.rousskikh@nokia.com>2012-02-27 17:02:10 -0500
committerAndrew Christian <andrew.christian@nokia.com>2012-02-28 11:54:52 +0100
commit5d54f9ea2bcf97be6990cae0245b046ffe3bcb0f (patch)
treec26582206d3b8f83329a59d4d96fb762716b41fe
parent77263148f5dc5460329577aac1a9aa26f2521ed3 (diff)
implemented array in 'items' attribute; 'additionalItems' attribute
Change-Id: Id6e040041253907f1e19f4bfa6c6b4d75dd4d3a4 Reviewed-by: Andrew Christian <andrew.christian@nokia.com>
-rw-r--r--src/qtjsonschema/checkpoints_p.h103
-rw-r--r--src/qtjsonschema/schemaobject_p.h8
-rw-r--r--tests/auto/jsonschema/tst_jsonschema.cpp42
3 files changed, 137 insertions, 16 deletions
diff --git a/src/qtjsonschema/checkpoints_p.h b/src/qtjsonschema/checkpoints_p.h
index 045cf0e..e30b009 100644
--- a/src/qtjsonschema/checkpoints_p.h
+++ b/src/qtjsonschema/checkpoints_p.h
@@ -343,9 +343,9 @@ public:
}
}
- if (Check::m_data->m_additionalPropertySchema && 0 == checks.count() && !m_checks.keys().contains(key)) {
+ if (Check::m_data->m_additionalSchema && 0 == checks.count() && !m_checks.keys().contains(key)) {
// do an extra property check if a property does not exist in the schema
- if (!Check::m_data->m_additionalPropertySchema->check(property, Check::m_schema->m_callbacks)) {
+ if (!Check::m_data->m_additionalSchema->check(property, Check::m_schema->m_callbacks)) {
return false;
}
}
@@ -427,7 +427,7 @@ public:
Object obj = _value.toObject(&ok);
if (ok) {
// create extra check for additional properties - create new schema
- Check::m_data->m_additionalPropertySchema = QSharedPointer< Schema<T> >(new Schema<T>(obj, schema->m_callbacks));
+ Check::m_data->m_additionalSchema = QSharedPointer< Schema<T> >(new Schema<T>(obj, schema->m_callbacks));
}
}
Q_ASSERT(ok);
@@ -445,20 +445,30 @@ template<class T>
class SchemaPrivate<T>::CheckItems : public Check {
public:
CheckItems(SchemaPrivate *schemap, QSharedPointer<CheckSharedData> &data, const Value &schema)
- : Check(schemap, data, "Items check failed for %1")
+ : Check(schemap, data, "Items check failed for %1"), m_bList(false)
{
// qDebug() << Q_FUNC_INFO << this;
bool ok;
Object obj = schema.toObject(&ok);
if (ok) {
- m_schema = Schema<T>(obj, schemap->m_callbacks);
+ m_schema.append(Schema<T>(obj, schemap->m_callbacks));
}
else {
ValueList list = schema.toList(&ok);
if (ok) {
- Q_ASSERT(false); // TODO
+ m_bList = true;
+ if (list.count() > 1)
+ m_schema.reserve(list.count());
+ typename ValueList::const_iterator it;
+ for (it = list.constBegin(); it != list.constEnd(); ++it) {
+ Object obj = (*it).toObject(&ok);
+ if (ok) {
+ m_schema.append(Schema<T>(obj, schemap->m_callbacks));
+ }
+ }
}
}
+ Check::m_data->m_flags |= CheckSharedData::HasItems;
Q_ASSERT(ok);
}
@@ -470,16 +480,87 @@ public:
if (!ok)
return false;
+ bool bNoAdditional;
+ if ((bNoAdditional = Check::m_data->m_flags.testFlag(CheckSharedData::NoAdditionalItems))) {
+ if (m_bList && array.count() > m_schema.size())
+ return false; // AdditionalItems is set to false
+ }
+
+ int nCnt(0), nIndex(0);
+ Schema<T> & schema = m_schema[0];
typename ValueList::const_iterator i;
- for (i = array.constBegin(); i != array.constEnd(); ++i) {
- if (!m_schema.check(*i, Check::m_schema->m_callbacks)) {
+ for (i = array.constBegin(); i != array.constEnd(); ++i, nCnt++) {
+ if (m_bList) {
+ // for a list each item should have a matching schema
+ if (m_schema.size() > nCnt) {
+ nIndex = nCnt;
+ schema = m_schema[nIndex];
+ }
+ else if (Check::m_data->m_additionalSchema) {
+ schema = *Check::m_data->m_additionalSchema;
+ }
+ else {
+ return true; // nothing to validate with
+ }
+ }
+
+ if (!schema.check(*i, Check::m_schema->m_callbacks)) {
return false;
}
}
return true;
}
private:
- Schema<T> m_schema;
+ QVarLengthArray<Schema<T>, 1> m_schema;
+ bool m_bList;
+};
+
+// 5.6
+template<class T>
+class SchemaPrivate<T>::CheckAdditionalItems : public Check {
+public:
+ CheckAdditionalItems(SchemaPrivate *schema, QSharedPointer<CheckSharedData> &data, const Value &_value)
+ : Check(schema, data, "Additional items check failed for %1")
+ {
+ bool ok, bAdditional = _value.toBoolean(&ok);
+ if (ok && !bAdditional) {
+ Check::m_data->m_flags |= CheckSharedData::NoAdditionalItems;
+ }
+ else if (!ok) {
+ // object if not bool
+ Object obj = _value.toObject(&ok);
+ if (ok) {
+ // create extra check for additional properties - create new schema
+ Check::m_data->m_additionalSchema = QSharedPointer< Schema<T> >(new Schema<T>(obj, schema->m_callbacks));
+ }
+ }
+ Q_ASSERT(ok);
+ }
+
+ virtual bool doCheck(const Value &value)
+ {
+ // most of the time a check is done inside CheckItems::doCheck
+ if (!Check::m_data->m_flags.testFlag(CheckSharedData::HasItems)) { // items attribute is absent so do a check here
+ if (Check::m_data->m_flags.testFlag(CheckSharedData::NoAdditionalItems)) {
+ // items attribute is absent, but additionalItems is set to false
+ return false;
+ }
+ else if (Check::m_data->m_additionalSchema) {
+ bool ok;
+ ValueList array = value.toList(&ok);
+ if (!ok)
+ return false;
+
+ typename ValueList::const_iterator i;
+ for (i = array.constBegin(); i != array.constEnd(); ++i) {
+ if (!Check::m_data->m_additionalSchema->check(*i, Check::m_schema->m_callbacks)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
};
// 5.7
@@ -1137,6 +1218,10 @@ typename SchemaPrivate<T>::Check *SchemaPrivate<T>::createCheckPoint(const Key &
if (QString::fromLatin1("items") == keyName)
return new CheckItems(this, data, value);
break;
+ case QStaticStringHash<'a','d','d','i','t','i','o','n','a','l','i','t','e','m','s'>::Hash:
+ if (QString::fromLatin1("additionalitems") == keyName)
+ return new CheckAdditionalItems(this, data, value);
+ break;
case QStaticStringHash<'e','x','t','e','n','d','s'>::Hash:
if (QString::fromLatin1("extends") == keyName)
return new CheckExtends(this, data, value);
diff --git a/src/qtjsonschema/schemaobject_p.h b/src/qtjsonschema/schemaobject_p.h
index e8c3516..b230e5a 100644
--- a/src/qtjsonschema/schemaobject_p.h
+++ b/src/qtjsonschema/schemaobject_p.h
@@ -160,12 +160,14 @@ class SchemaPrivate : public QSharedData
NoFlags = 0x0,
ExclusiveMinimum = 0x1,
ExclusiveMaximum = 0x2,
- NoAdditionalProperties = 0x4
+ NoAdditionalProperties = 0x4,
+ NoAdditionalItems = 0x8,
+ HasItems = 0x10
};
Q_DECLARE_FLAGS(Flags, Flag)
Flags m_flags;
QSharedPointer<Value> m_default; // keeps a default value
- QSharedPointer< Schema<T> > m_additionalPropertySchema;
+ QSharedPointer< Schema<T> > m_additionalSchema;
};
class Check {
@@ -216,6 +218,8 @@ class SchemaPrivate : public QSharedData
class CheckAdditionalProperties;
// 5.5
class CheckItems;
+ // 5.6
+ class CheckAdditionalItems;
// 5.7
class CheckRequired;
// 5.9
diff --git a/tests/auto/jsonschema/tst_jsonschema.cpp b/tests/auto/jsonschema/tst_jsonschema.cpp
index c11e001..522fb00 100644
--- a/tests/auto/jsonschema/tst_jsonschema.cpp
+++ b/tests/auto/jsonschema/tst_jsonschema.cpp
@@ -60,7 +60,8 @@ private slots:
void testAdditionalPropertiesValidation();
// 5.5 items
void testItemsValidation();
- // TODO: 5.6 additionalItems
+ // 5.6 additionalItems
+ void testAdditionalItems();
// 5.7
void testRequiredValidation();
// TODO: 5.8 dependencies
@@ -228,17 +229,17 @@ void tst_JsonSchema::testAdditionalPropertiesValidation()
array.append(QLatin1String("foo"));
array.append(QLatin1String("two")); //["foo", "two"]
QVERIFY(validate(array, "{ \"items\" : { \"type\" : \"string\" }, \"additionalProperties\" : false }"));
-#ifdef FIX
QVERIFY(validate(array, "{ \"items\" : [ { \"type\" : \"string\" }, { \"type\" : \"string\" } ], \"additionalProperties\" : false }"));
array.append(3); // ["foo", "two", 3]
QVERIFY(validate(array,
"{ \"items\" : [ { \"type\" : \"string\" }, { \"type\" : \"string\" } ], \"additionalProperties\" : { \"type\" : \"number\" } }"));
+ QVERIFY(!validate(array,
+ "{ \"items\" : [ { \"type\" : \"string\" }, { \"type\" : \"string\" } ], \"additionalProperties\" : { \"type\" : \"string\" } }"));
array[2] = QLatin1String("three"); // ["foo", "two", "three"]
QVERIFY(validate(array,
"{ \"items\" : [ { \"type\" : \"string\" }, { \"type\" : \"string\" }, { \"type\" : \"string\" } ], \"additionalProperties\" : { \"type\" : \"number\" } }"));
-#endif
}
// 5.5 items
@@ -254,7 +255,7 @@ void tst_JsonSchema::testItemsValidation()
array.append(2); // ["foo", 2]
QVERIFY(!validate(array, "{ \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }")); // INVALID
QVERIFY(!validate(array, "{ \"type\" : \"array\", \"items\" : { \"type\" : \"number\" } }")); // INVALID
-//fix QVERIFY(validate(array, "{ \"type\" : \"array\", \"items\" : [{ \"type\" : \"string\" }, { \"type\" : \"number\" }] }"));
+ QVERIFY(validate(array, "{ \"type\" : \"array\", \"items\" : [{ \"type\" : \"string\" }, { \"type\" : \"number\" }] }"));
array.removeAt(0); // [2]
QVERIFY(!validate(array, "{ \"type\" : \"array\", \"items\" : { \"type\" : \"string\" } }")); // INVALID
@@ -263,7 +264,38 @@ void tst_JsonSchema::testItemsValidation()
array.append(QLatin1String("foo"));
array.append(QLatin1String("two")); //["foo", "two"]
// should fail!!!!!
-//fix QVERIFY(!validate(array, "{ \"type\" : \"array\", \"items\" : [{ \"type\" : \"string\" }, { \"type\" : \"number\" }] }"));
+ QVERIFY(!validate(array, "{ \"type\" : \"array\", \"items\" : [{ \"type\" : \"string\" }, { \"type\" : \"number\" }] }"));
+}
+
+// 5.6 additionalItems
+void tst_JsonSchema::testAdditionalItems()
+{
+ //array tests
+ QJsonArray array;
+ array.append(1); // [1]
+ array.append(2); // [1, 2]
+ array.append(3); // [1, 2, 3]
+
+ QVERIFY(validate(array, "{ \"additionalItems\" : true }"));
+ QVERIFY(validate(array, "{ \"additionalItems\" : { \"type\" : \"number\" } }"));
+ QVERIFY(!validate(array, "{ \"additionalItems\" : false }"));
+ QVERIFY(!validate(array, "{ \"additionalItems\" : { \"type\" : \"string\" } }"));
+
+ array = QJsonArray();
+ array.append(QLatin1String("1")); // ['1']
+ array.append(QLatin1String("2")); // ['1','2']
+
+ QVERIFY(validate(array, "{ \"items\" : { \"type\" : \"string\" }, \"additionalItems\" : false }"));
+ QVERIFY(validate(array, "{ \"items\" : [ { \"type\" : \"string\" }, { \"type\" : \"string\" } ], \"additionalItems\" : false }"));
+
+ array.append(3); // ['1', '2', 3]
+ QVERIFY(validate(array, "{ \"items\" : [ { \"type\" : \"string\" }, { \"type\" : \"string\" } ], \"additionalItems\" : { \"type\" : \"number\" } }"));
+
+ array[2] = QLatin1String("3"); // ['1', '2', '3']
+ QVERIFY(validate(array, "{ \"items\" : [ { \"type\" : \"string\" }, { \"type\" : \"string\" }, { \"type\" : \"string\" } ], \"additionalItems\": { \"type\" : \"number\" } }"));
+
+ QVERIFY(!validate(array, "{ \"items\" : [ { \"type\" : \"string\" }, { \"type\" : \"string\" } ],\"additionalItems\": false }"));
+ QVERIFY(!validate(array, "{ \"items\" : [ { \"type\" : \"string\" }, { \"type\" : \"string\" } ],\"additionalItems\": { \"type\" : \"number\" } }"));
}
// 5.7