diff options
Diffstat (limited to 'tests/auto/declarative/qmldebug/tst_qmldebug.cpp')
-rw-r--r-- | tests/auto/declarative/qmldebug/tst_qmldebug.cpp | 346 |
1 files changed, 171 insertions, 175 deletions
diff --git a/tests/auto/declarative/qmldebug/tst_qmldebug.cpp b/tests/auto/declarative/qmldebug/tst_qmldebug.cpp index a7573da..0890557 100644 --- a/tests/auto/declarative/qmldebug/tst_qmldebug.cpp +++ b/tests/auto/declarative/qmldebug/tst_qmldebug.cpp @@ -51,12 +51,18 @@ #include <QtDeclarative/qmlcontext.h> #include <QtDeclarative/qmlcomponent.h> #include <QtDeclarative/qmlexpression.h> +#include <QtDeclarative/qmlmetatype.h> +#include <QtDeclarative/qmlmetaproperty.h> +#include <QtDeclarative/qmlcontext.h> +#include <QtDeclarative/qmlbinding.h> #include <private/qmldebug_p.h> +#include <private/qmlenginedebug_p.h> #include <private/qmldebugclient_p.h> #include <private/qmldebugservice_p.h> #include <private/qmlgraphicsrectangle_p.h> #include <private/qmlgraphicstext_p.h> +#include <private/qmldeclarativedata_p.h> class tst_QmlDebug : public QObject @@ -74,101 +80,18 @@ protected slots: } private: + QmlDebugObjectReference findRootObject(); + QmlDebugPropertyReference findProperty(const QList<QmlDebugPropertyReference> &props, const QString &name); + QObject *findObjectWithId(const QObjectList &objects, int id); + void waitForQuery(QmlDebugQuery *query); + void recursiveObjectTest(QObject *o, const QmlDebugObjectReference &oref, bool recursive); + QmlDebugConnection *m_conn; QmlEngineDebug *m_dbg; QmlEngine *m_engine; QmlGraphicsItem *m_rootItem; - QHash<QByteArray, QVariant> m_savedValueChanges; - void waitForQuery(QmlDebugQuery *query) - { - QCOMPARE(query->parent(), this); - QEventLoop loop; - QTimer timer; - QVERIFY(query->state() == QmlDebugQuery::Waiting); - connect(query, SIGNAL(stateChanged(State)), &loop, SLOT(quit())); - connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); - timer.start(5000); - loop.exec(); - if (!timer.isActive()) - QFAIL("query timed out"); - } - - void verifyRootObject(const QmlDebugObjectReference &obj) - { - // verifies object according to component definition in main() - - QCOMPARE(obj.debugId(), QmlDebugService::idForObject(m_rootItem)); - QCOMPARE(obj.className(), QLatin1String("Item")); - QCOMPARE(obj.name(), m_rootItem->objectName()); - QCOMPARE(obj.contextDebugId(), QmlDebugService::idForObject(qmlContext(m_rootItem))); - - QmlDebugFileReference source = obj.source(); - QCOMPARE(source.url(), QUrl("file://")); - QCOMPARE(source.lineNumber(), 3); - QCOMPARE(source.columnNumber(), 3); - - QList<QmlDebugPropertyReference> props = obj.properties(); - QHash<QString, QVariant> expected; - - expected["width"] = 10; - expected["height"] = 20; - verifyProperties(props, expected); - } - - void verifyProperties(const QList<QmlDebugPropertyReference> &actual, const QHash<QString, QVariant> &expected) - { - foreach(const QmlDebugPropertyReference &p, actual) { - if (expected.contains(p.name())) - QCOMPARE(p.value(), expected[p.name()]); - } - } - - QmlDebugObjectReference findRootObject() - { - QmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); - waitForQuery(q_engines); - - if (q_engines->engines().count() == 0) - return QmlDebugObjectReference(); - QmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this); - waitForQuery(q_context); - - if (q_context->rootContext().objects().count() == 0) - return QmlDebugObjectReference(); - QmlDebugObjectQuery *q_obj = m_dbg->queryObject(q_context->rootContext().objects()[0], this); - waitForQuery(q_obj); - - QmlDebugObjectReference result = q_obj->object(); - - delete q_engines; - delete q_context; - delete q_obj; - - return result; - } - - QmlDebugPropertyReference findProperty(const QList<QmlDebugPropertyReference> &props, const QString &name) - { - foreach(const QmlDebugPropertyReference &p, props) { - if (p.name() == name) - return p; - } - return QmlDebugPropertyReference(); - } - - int countNotifiableProperties(const QObject *obj) - { - int count = 0; - for (int i=0; i<obj->metaObject()->propertyCount(); i++) { - QMetaProperty p = obj->metaObject()->property(i); - if (p.hasNotifySignal()) - count++; - } - return count; - } - private slots: void initTestCase(); @@ -180,11 +103,115 @@ private slots: void queryAvailableEngines(); void queryRootContexts(); void queryObject(); - void queryObjectRecursive(); + void queryObject_data(); void queryExpressionResult(); void queryExpressionResult_data(); }; +QmlDebugObjectReference tst_QmlDebug::findRootObject() +{ + QmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); + waitForQuery(q_engines); + + if (q_engines->engines().count() == 0) + return QmlDebugObjectReference(); + QmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this); + waitForQuery(q_context); + + if (q_context->rootContext().objects().count() == 0) + return QmlDebugObjectReference(); + QmlDebugObjectQuery *q_obj = m_dbg->queryObject(q_context->rootContext().objects()[0], this); + waitForQuery(q_obj); + + QmlDebugObjectReference result = q_obj->object(); + + delete q_engines; + delete q_context; + delete q_obj; + + return result; +} + +QmlDebugPropertyReference tst_QmlDebug::findProperty(const QList<QmlDebugPropertyReference> &props, const QString &name) +{ + foreach(const QmlDebugPropertyReference &p, props) { + if (p.name() == name) + return p; + } + return QmlDebugPropertyReference(); +} + +QObject *tst_QmlDebug::findObjectWithId(const QObjectList &objects, int id) +{ + foreach (QObject *o, objects) { + if (id == QmlDebugService::idForObject(o)) + return o; + } + return 0; +} + +void tst_QmlDebug::waitForQuery(QmlDebugQuery *query) +{ + QVERIFY(query); + QCOMPARE(query->parent(), this); + QEventLoop loop; + QTimer timer; + QVERIFY(query->state() == QmlDebugQuery::Waiting); + connect(query, SIGNAL(stateChanged(State)), &loop, SLOT(quit())); + connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + timer.start(5000); + loop.exec(); + if (!timer.isActive()) + QFAIL("query timed out"); +} + +void tst_QmlDebug::recursiveObjectTest(QObject *o, const QmlDebugObjectReference &oref, bool recursive) +{ + const QMetaObject *meta = o->metaObject(); + + QmlType *type = QmlMetaType::qmlType(o->metaObject()); + QString className = type ? type->qmlTypeName() : QString(); + className = className.mid(className.lastIndexOf(QLatin1Char('/'))+1); + + QCOMPARE(oref.debugId(), QmlDebugService::idForObject(o)); + QCOMPARE(oref.name(), o->objectName()); + QCOMPARE(oref.className(), className); + QCOMPARE(oref.contextDebugId(), QmlDebugService::idForObject(qmlContext(o))); + + foreach (const QmlDebugObjectReference &cref, oref.children()) { + // ignore children with no context + if (cref.contextDebugId() < 0) + continue; + + QObject *childObject = findObjectWithId(o->children(), cref.debugId()); + QVERIFY2(childObject, qPrintable(QString("Can't find QObject* for %1").arg(cref.className()))); + + if (recursive) + recursiveObjectTest(childObject, cref, true); + } + + foreach (const QmlDebugPropertyReference &p, oref.properties()) { + QMetaProperty pmeta = meta->property(meta->indexOfProperty(p.name().toUtf8().constData())); + QVERIFY(pmeta.isValid()); + + QCOMPARE(p.name(), QString::fromUtf8(pmeta.name())); + + if (pmeta.type() < QVariant::UserType) // TODO test complex types + QCOMPARE(p.value(), pmeta.read(o)); + + if (p.name() == "parent") + QVERIFY(p.valueTypeName() == "QGraphicsObject*" || p.valueTypeName() == "QmlGraphicsItem*"); + else + QCOMPARE(p.valueTypeName(), QString::fromUtf8(pmeta.typeName())); + + QmlAbstractBinding *binding = QmlMetaProperty(o, p.name()).binding(); + if (binding) + QCOMPARE(binding->expression(), p.binding()); + + QCOMPARE(p.hasNotifySignal(), pmeta.hasNotifySignal()); + } +} + void tst_QmlDebug::initTestCase() { m_dbg = new QmlEngineDebug(m_conn, this); @@ -219,7 +246,7 @@ void tst_QmlDebug::watch_property() // restore original value and verify spy doesn't get a signal since watch has been removed m_rootItem->setProperty("width", origWidth); - QTest::qWait(500); + QTest::qWait(100); QCOMPARE(spy.count(), 1); QCOMPARE(spy.at(0).at(0).value<QByteArray>(), prop.name().toUtf8()); @@ -274,7 +301,7 @@ void tst_QmlDebug::watch_object() m_savedValueChanges.clear(); m_rootItem->setProperty("width", origWidth); m_rootItem->setProperty("height", origHeight); - QTest::qWait(500); + QTest::qWait(100); QCOMPARE(m_savedValueChanges.count(), 0); if (newWidth.isNull() || newHeight.isNull()) { @@ -326,8 +353,8 @@ void tst_QmlDebug::watch_expression() delete watch; // restore original value and verify spy doesn't get a signal since watch has been removed - m_rootItem->setProperty("width", origWidth); // may increase spy count before QCOMPARE() - QTest::qWait(500); + m_rootItem->setProperty("width", origWidth); + QTest::qWait(100); QCOMPARE(spy.count(), expectedSpyCount); width = origWidth + increment; @@ -352,7 +379,7 @@ void tst_QmlDebug::queryAvailableEngines() QmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); waitForQuery(q_engines); - // TODO have multiple engines + // TODO test multiple engines QList<QmlDebugEngineReference> engines = q_engines->engines(); QCOMPARE(engines.count(), 1); @@ -377,7 +404,7 @@ void tst_QmlDebug::queryRootContexts() QCOMPARE(context.debugId(), QmlDebugService::idForObject(actualContext)); QCOMPARE(context.name(), actualContext->objectName()); - QCOMPARE(context.objects().count(), 1); + QCOMPARE(context.objects().count(), 2); // 2 objects created for engine in main() // root context query sends only root object data - it doesn't fill in // the children or property info @@ -393,104 +420,70 @@ void tst_QmlDebug::queryRootContexts() void tst_QmlDebug::queryObject() { - QmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); - waitForQuery(q_engines); - - QmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this); - waitForQuery(q_context); - - QmlDebugObjectQuery *q_obj = m_dbg->queryObject(q_context->rootContext().objects()[0], this); - waitForQuery(q_obj); - - QmlDebugObjectReference obj = q_obj->object(); - verifyRootObject(obj); + QFETCH(bool, recursive); - QVERIFY(obj.children().count() >= 2); - - // non-recursive query, children data not available - foreach(const QmlDebugObjectReference &child, obj.children()) - QCOMPARE(child.properties().count(), 0); - - delete q_engines; - delete q_context; - delete q_obj; -} - -void tst_QmlDebug::queryObjectRecursive() -{ QmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); waitForQuery(q_engines); QmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this); waitForQuery(q_context); - QmlDebugObjectQuery *q_obj = m_dbg->queryObjectRecursive(q_context->rootContext().objects()[0], this); + QmlDebugObjectQuery *q_obj = 0; + if (recursive) + q_obj = m_dbg->queryObjectRecursive(q_context->rootContext().objects()[0], this); + else + q_obj = m_dbg->queryObject(q_context->rootContext().objects()[0], this); waitForQuery(q_obj); QmlDebugObjectReference obj = q_obj->object(); - verifyRootObject(obj); delete q_engines; delete q_context; delete q_obj; - QList<QmlDebugObjectReference> children = obj.children(); - QVERIFY(children.count() >= 2); // there may be additional properties e.g. StateGroup - - QList<QmlDebugPropertyReference> props; - QHash<QString, QVariant> expected; - - QmlDebugObjectReference rectRef; - QmlDebugObjectReference textRef; - foreach (const QmlDebugObjectReference &child, children) { - if (child.className() == "Rectangle") { - props = child.properties(); - QVERIFY(props.count() > 0); - expected.clear(); - expected["width"] = 500; - expected["height"] = 600; - expected["color"] = "blue"; - verifyProperties(props, expected); - rectRef = child; - } else if (child.className() == "Text") { - props = child.properties(); - QVERIFY(props.count() > 0); - expected.clear(); - expected["color"] = "red"; - verifyProperties(props, expected); - textRef = child; + // check source as defined in main() + QmlDebugFileReference source = obj.source(); + QCOMPARE(source.url(), QUrl("file://")); + QCOMPARE(source.lineNumber(), 2); + QCOMPARE(source.columnNumber(), 1); + + // generically test all properties, children and childrens' properties + recursiveObjectTest(m_rootItem, obj, recursive); + + if (recursive) { + foreach(const QmlDebugObjectReference &child, obj.children()) + QVERIFY(child.properties().count() > 0); + + QmlDebugObjectReference rect; + QmlDebugObjectReference text; + foreach (const QmlDebugObjectReference &child, obj.children()) { + if (child.className() == "Rectangle") + rect = child; + else if (child.className() == "Text") + text = child; } - } - QVERIFY(!rectRef.className().isEmpty()); - QVERIFY(!textRef.className().isEmpty()); + // test specific property values + QCOMPARE(findProperty(rect.properties(), "width").value(), qVariantFromValue(500)); + QCOMPARE(findProperty(rect.properties(), "height").value(), qVariantFromValue(600)); + QCOMPARE(findProperty(rect.properties(), "color").value(), qVariantFromValue(QColor("blue"))); - QObject *rectObj = 0; - QObject *textObj = 0; - foreach (QObject *o, m_rootItem->children()) { - if (o->metaObject()->className() == QmlGraphicsRectangle::staticMetaObject.className()) - rectObj = o; - else if (o->metaObject()->className() == QmlGraphicsText::staticMetaObject.className()) - textObj = o; - } + QCOMPARE(findProperty(text.properties(), "color").value(), qVariantFromValue(QColor("blue"))); - QVERIFY(rectObj); - QVERIFY(textObj); - - for (int i=0; i<rectObj->metaObject()->propertyCount(); i++) { - QMetaProperty p = rectObj->metaObject()->property(i); - QmlDebugPropertyReference pd = findProperty(rectRef.properties(), p.name()); - if (!pd.name().isEmpty()) { - QCOMPARE(pd.name(), QString::fromUtf8(p.name())); - if (p.type() < QVariant::UserType) - QCOMPARE(pd.value(), p.read(rectObj)); - if (pd.name() != "parent") - QCOMPARE(pd.valueTypeName(), QString::fromUtf8(p.typeName())); - QCOMPARE(pd.hasNotifySignal(), p.hasNotifySignal()); - } + } else { + foreach(const QmlDebugObjectReference &child, obj.children()) + QCOMPARE(child.properties().count(), 0); } } +void tst_QmlDebug::queryObject_data() +{ + QTest::addColumn<bool>("recursive"); + + QTest::newRow("non-recursive") << false; + QTest::newRow("recursive") << true; +} + void tst_QmlDebug::queryExpressionResult() { QFETCH(QString, expr); @@ -570,17 +563,20 @@ int main(int argc, char *argv[]) QmlComponent component(&engine, "import Qt 4.6\n" - "\n" // don't remove, line number is tested - " Item {\n" // don't remove spaces, column number is tested + "Item {\n" "width: 10; height: 20;\n" "Rectangle { id: blueRect; width: 500; height: 600; color: \"blue\"; }" - "Text { color: \"red\"; }" + "Text { color: blueRect.color; }" "}\n", QUrl("file://")); Q_ASSERT(component.isReady()); QObject *o = component.create(); QObject::connect(&thread, SIGNAL(testsFinished()), o, SLOT(deleteLater())); + // allows us to test that multiple contexts can be detected + QObject *o2 = component.create(); + QObject::connect(&thread, SIGNAL(testsFinished()), o2, SLOT(deleteLater())); + // start the test thread.m_engine = &engine; thread.m_item = qobject_cast<QmlGraphicsItem*>(o); |