From 7073c61891b6b0bb92aea512692a7686568656f4 Mon Sep 17 00:00:00 2001 From: Alexei Rousskikh Date: Thu, 16 Feb 2012 13:39:08 -0500 Subject: initial default schema property implementation Change-Id: I7a876291cbea19a00bb692cdf9000bcb7a586904 Reviewed-by: Andrew Christian --- src/qtjsonschema/checkpoints_p.h | 104 ++++++++++++++++++++++ src/qtjsonschema/jsonobjecttypes_impl_p.h | 15 ++++ src/qtjsonschema/jsonobjecttypes_p.h | 1 + src/qtjsonschema/schemaobject_p.h | 13 +++ src/qtjsonschema/schemavalidator.h | 2 +- tests/auto/jsonschema/tst_jsonschema.cpp | 10 +++ tests/auto/jsonstream/schemas/PaintEvent.json | 3 +- tests/auto/jsonstream/schemas/PaintTextEvent.json | 13 ++- 8 files changed, 157 insertions(+), 4 deletions(-) diff --git a/src/qtjsonschema/checkpoints_p.h b/src/qtjsonschema/checkpoints_p.h index 480f7c1..9ca8a1d 100644 --- a/src/qtjsonschema/checkpoints_p.h +++ b/src/qtjsonschema/checkpoints_p.h @@ -324,6 +324,65 @@ public: } return true; } + + + void checkDefault(Value& value, Object &_object) const + { + bool ok; + Object object = value.toObject(&ok); + if (!ok) + return; + + //qDebug() << Q_FUNC_INFO; + + // create missing properties list + QList strs; + QHashIterator > it(m_checks); + while (it.hasNext()) { + it.next(); + strs << it.key(); + } + + foreach (const Key &key, object.propertyNames()) { + QVarLengthArray empty; + QVarLengthArray checks = m_checks.value(key, empty); + Value property = object.property(key); + + // remove from missing properties list + strs.removeOne(key); + + if (_object[key].isObject()) { + foreach (Check *check, checks) { + Object oo(_object[key].toObject()); + check->checkDefault(property, oo); + _object[key] = oo; + } + } + } + + // add defaults for missing properties + foreach (const Key &key, strs) { + QVarLengthArray empty; + QVarLengthArray checks = m_checks.value(key, empty); + Value property = object.property(key); + + if (checks.first()->getDefault()) { // basic type + _object.insert(key, checks.first()->getDefault()->value()); + } + else { // looks like object or array + Object object; + foreach (Check *check, checks) { + Value value("", Object()); + check->checkDefault(value, object); + } + + if (!object.isEmpty()) { + _object.insert(key, object); + } + } + } + } + private: QHash > m_checks; }; @@ -676,6 +735,24 @@ private: ValueList m_enum; }; +// 5.20 +template +class SchemaPrivate::CheckDefault : public Check { +public: + CheckDefault(SchemaPrivate *schema, QSharedPointer &data, const Value& value) + : Check(schema, data, "Default check failed for %1") + { + // used shared data to store + Check::m_data->m_default = QSharedPointer(new Value(value)); + } + + virtual bool doCheck(const Value &value) + { + return true; + } +private: +}; + // 5.23 template class SchemaPrivate::CheckFormat : public Check { @@ -849,6 +926,14 @@ public: } return true; } + + void checkDefault(Value& value, Object &_object) const + { + for (int i = 0; i < m_extendedSchema.count(); ++i) { + m_extendedSchema[i].checkDefault(value, _object); + } + } + private: QVarLengthArray, 4> m_extendedSchema; }; @@ -883,6 +968,13 @@ public: // qDebug() << Q_FUNC_INFO << result; return result; } + + void checkDefault(Value& value, Object &_object) const + { + m_newSchema.checkDefault(value, _object); + + } + private: Schema m_newSchema; }; @@ -982,6 +1074,10 @@ typename SchemaPrivate::Check *SchemaPrivate::createCheckPoint(const Key & if (QString::fromLatin1("format") == keyName) return new CheckFormat(this, data, value); break; + case QStaticStringHash<'d','e','f','a','u','l','t'>::Hash: + if (QString::fromLatin1("default") == keyName) + return new CheckDefault(this, data, value); + break; case QStaticStringHash<'d','i','v','i','s','i','b','l','e','b','y'>::Hash: if (QString::fromLatin1("divisibleby") == keyName) return new CheckDivisibleBy(this, data, value); @@ -1042,6 +1138,14 @@ bool SchemaPrivate::check(const Value &value) const return true; } +template +void SchemaPrivate::checkDefault(Value &value, Object &object) const +{ + foreach (Check *check, m_checks) { + check->checkDefault(value, object); + } +} + } // namespace SchemaValidation QT_END_HEADER diff --git a/src/qtjsonschema/jsonobjecttypes_impl_p.h b/src/qtjsonschema/jsonobjecttypes_impl_p.h index 23e4398..dfa8918 100644 --- a/src/qtjsonschema/jsonobjecttypes_impl_p.h +++ b/src/qtjsonschema/jsonobjecttypes_impl_p.h @@ -290,6 +290,21 @@ inline bool JsonObjectTypes::Value::compare(const Value & val) const return v0 == v1; } +inline QJsonValue JsonObjectTypes::Value::value() const +{ + switch (m_type) { + case Map: + return map().value(m_property); + case List: + return list().at(m_index); + case RootMap: + return m_value; + default: + Q_ASSERT(false); + } + return QJsonValue(); +} + inline const QJsonObject JsonObjectTypes::Value::map() const { Q_ASSERT(m_type == Map); diff --git a/src/qtjsonschema/jsonobjecttypes_p.h b/src/qtjsonschema/jsonobjecttypes_p.h index ab5faa0..0fb665f 100644 --- a/src/qtjsonschema/jsonobjecttypes_p.h +++ b/src/qtjsonschema/jsonobjecttypes_p.h @@ -128,6 +128,7 @@ public: inline Object toObject(bool *ok) const; inline bool compare(const Value &) const; + inline QJsonValue value() const; private: inline const QJsonObject map() const; diff --git a/src/qtjsonschema/schemaobject_p.h b/src/qtjsonschema/schemaobject_p.h index bedc638..68c5d94 100644 --- a/src/qtjsonschema/schemaobject_p.h +++ b/src/qtjsonschema/schemaobject_p.h @@ -109,6 +109,10 @@ class Schema { public: inline bool check(const Value &value, Service *callbackToUseForCheck) const; + void checkDefault(Value &value, Object &object) const + { + d_ptr->checkDefault(value, object); + } Schema() : d_ptr(new SchemaPrivate()) @@ -151,6 +155,7 @@ class SchemaPrivate : public QSharedData }; Q_DECLARE_FLAGS(Flags, Flag) Flags m_flags; + QSharedPointer m_default; // keeps a default value }; class Check { @@ -177,6 +182,10 @@ class SchemaPrivate : public QSharedData return result; } + Value* getDefault() const { return m_data && m_data->m_default ? m_data->m_default.data() : 0; } + + virtual void checkDefault(Value& value, Object &object) const {} // do nothing in generic case + protected: SchemaPrivate *m_schema; QSharedPointer m_data; // is used to exchange information between attributes @@ -217,6 +226,8 @@ class SchemaPrivate : public QSharedData class CheckMaxLength; // 5.19 class CheckEnum; + // 5.20 + class CheckDefault; // 5.21 class CheckTitle; // 5.23 @@ -267,6 +278,8 @@ public: return m_checks.size(); } + void checkDefault(Value &value, Object &object) const; + private: QVarLengthArray m_checks; qint32 m_maxRequired; diff --git a/src/qtjsonschema/schemavalidator.h b/src/qtjsonschema/schemavalidator.h index 0941d60..71b66c8 100644 --- a/src/qtjsonschema/schemavalidator.h +++ b/src/qtjsonschema/schemavalidator.h @@ -109,7 +109,7 @@ public: public: virtual ~SchemaNameMatcher() {} - // knowing exact schema name aloows skip schema iteration and validate with a single schema only + // knowing exact schema name allows to skip schema iteration and validate with a single schema only virtual QString getSchemaName(const QJsonObject &) { return QString::null; } // limit schemas iteration by matching json object with some schemas diff --git a/tests/auto/jsonschema/tst_jsonschema.cpp b/tests/auto/jsonschema/tst_jsonschema.cpp index 487d2e8..fc493f8 100644 --- a/tests/auto/jsonschema/tst_jsonschema.cpp +++ b/tests/auto/jsonschema/tst_jsonschema.cpp @@ -77,6 +77,7 @@ private slots: // 5.19 void testEnumValidation(); // TODO: 5.20 default + void testDefaultValidation(); // 5.21 void testTitleValidation(); // 5.22 @@ -334,6 +335,15 @@ void tst_JsonSchema::testEnumValidation() //FIX QVERIFY(!validate({}, "{ \"properties\" : { \"a\" : { \"enum\" : [\"a\"], \"optional\" : false, \"required\" : true } } }")); } + +// 5.20 +void tst_JsonSchema::testDefaultValidation() +{ +// QVERIFY(validate("{ \"b\" : true }", "{ \"type\":\"object\", \"properties\" : { \"a\" : { \"type\":\"string\", \"default\": \"hoi\"} } }")); + QVERIFY(validate("{ \"b\" : true }", "{ \"type\":\"object\", \"properties\" : { \"a\" : { \"type\":\"string\", \"default\": \"hoi\"}, \"c\" : { \"type\":\"array\", \"default\":[\"a\",\"b\",\"c\"]} } }")); +} + + // 5.21 void tst_JsonSchema::testTitleValidation() { diff --git a/tests/auto/jsonstream/schemas/PaintEvent.json b/tests/auto/jsonstream/schemas/PaintEvent.json index 60e263a..8b65415 100644 --- a/tests/auto/jsonstream/schemas/PaintEvent.json +++ b/tests/auto/jsonstream/schemas/PaintEvent.json @@ -5,6 +5,7 @@ "properties": { "event": {"type":"string", "pattern":"Paint\\w*Event", "required":true }, "x": {"type":"number", "minimum": 0, "maximum": 1024, "required":true }, - "y": {"type":"number", "minimum": 0, "maximum": 768, "required":true } + "y": {"type":"number", "minimum": 0, "maximum": 768, "required":true }, + "owner" : {"type":"string", "default": "painter" } } } diff --git a/tests/auto/jsonstream/schemas/PaintTextEvent.json b/tests/auto/jsonstream/schemas/PaintTextEvent.json index 6c90882..b8da0c7 100644 --- a/tests/auto/jsonstream/schemas/PaintTextEvent.json +++ b/tests/auto/jsonstream/schemas/PaintTextEvent.json @@ -1,5 +1,5 @@ { - "title": "PaintLineEvent schema", + "title": "PaintTextEvent schema", "extends": { "$ref": "PaintEvent" }, "description": "Inform the application to paint a text", "type": "object", @@ -7,6 +7,15 @@ "event": {"type":"string", "pattern":"PaintTextEvent", "required":true }, "text": {"type":"string", "required":true }, "font-size": {"type":"number", "minimum": 0 }, - "bold": {"type":"boolean"} + "bold": {"type":"boolean"}, + "font-name": {"type":"string", "default": "times"}, + "settings": { + "type": "object", + "properties": { + "border-color": { "type": "string", "default": "red" }, + "border-width": { "type": "number", "default": 5 }, + "border": {"type":"boolean", "default": true} + } + } } } -- cgit v1.2.3