diff options
author | Alexei Rousskikh <ext-alexei.rousskikh@nokia.com> | 2012-02-27 17:02:10 -0500 |
---|---|---|
committer | Andrew Christian <andrew.christian@nokia.com> | 2012-02-28 11:54:52 +0100 |
commit | 5d54f9ea2bcf97be6990cae0245b046ffe3bcb0f (patch) | |
tree | c26582206d3b8f83329a59d4d96fb762716b41fe | |
parent | 77263148f5dc5460329577aac1a9aa26f2521ed3 (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.h | 103 | ||||
-rw-r--r-- | src/qtjsonschema/schemaobject_p.h | 8 | ||||
-rw-r--r-- | tests/auto/jsonschema/tst_jsonschema.cpp | 42 |
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 |