QQmlEngineDebugService: Property Data of type QVariant
[profile/ivi/qtdeclarative.git] / tests / auto / qml / debugger / qqmlenginedebugservice / tst_qqmlenginedebugservice.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QSignalSpy>
43 #include <QTimer>
44 #include <QHostAddress>
45 #include <QDebug>
46 #include <QThread>
47
48 #include <QtQml/qqmlengine.h>
49 #include <QtQml/qqmlcontext.h>
50 #include <QtQml/qqmlcomponent.h>
51 #include <QtQml/qqmlexpression.h>
52 #include <QtQml/qqmlproperty.h>
53 #include <QtQuick/qquickitem.h>
54
55 #include <private/qqmlbinding_p.h>
56 #include <private/qqmlboundsignal_p.h>
57 #include <private/qqmldebugservice_p.h>
58 #include <private/qqmlmetatype_p.h>
59 #include <private/qqmlproperty_p.h>
60
61 #include "debugutil_p.h"
62 #include "qqmlenginedebugclient.h"
63
64 #include "../../../shared/util.h"
65
66 #define QVERIFYOBJECT(statement) \
67     do {\
68     if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) {\
69     return QmlDebugObjectReference();\
70     }\
71     } while (0)
72
73 class NonScriptProperty : public QObject {
74     Q_OBJECT
75     Q_PROPERTY(int nonScriptProp READ nonScriptProp WRITE setNonScriptProp NOTIFY nonScriptPropChanged SCRIPTABLE false)
76 public:
77     int nonScriptProp() const { return 0; }
78     void setNonScriptProp(int) {}
79 signals:
80     void nonScriptPropChanged();
81 };
82 QML_DECLARE_TYPE(NonScriptProperty)
83
84 class tst_QQmlEngineDebugService : public QObject
85 {
86     Q_OBJECT
87
88 private:
89     QmlDebugObjectReference findRootObject(int context = 0,
90                                            bool recursive = false);
91     QmlDebugPropertyReference findProperty(
92             const QList<QmlDebugPropertyReference> &props,
93             const QString &name) const;
94
95     void recursiveObjectTest(QObject *o,
96                              const QmlDebugObjectReference &oref,
97                              bool recursive) const;
98
99     QQmlDebugConnection *m_conn;
100     QQmlEngineDebugClient *m_dbg;
101     QQmlEngine *m_engine;
102     QQuickItem *m_rootItem;
103
104     QObjectList m_components;
105
106 private slots:
107     void initTestCase();
108     void cleanupTestCase();
109
110     void watch_property();
111     void watch_object();
112     void watch_expression();
113     void watch_expression_data();
114     void watch_context();
115     void watch_file();
116
117     void queryAvailableEngines();
118     void queryRootContexts();
119     void queryObject();
120     void queryObject_data();
121     void queryObjectsForLocation();
122     void queryObjectsForLocation_data();
123     void queryExpressionResult();
124     void queryExpressionResult_data();
125     void queryExpressionResultInRootContext();
126     void queryExpressionResultBC();
127     void queryExpressionResultBC_data();
128
129     void setBindingForObject();
130     void resetBindingForObject();
131     void setMethodBody();
132     void queryObjectTree();
133     void setBindingInStates();
134
135     void regression_QTCREATORBUG_7451();
136 };
137
138 QmlDebugObjectReference tst_QQmlEngineDebugService::findRootObject(
139         int context, bool recursive)
140 {
141     bool success = false;
142     m_dbg->queryAvailableEngines(&success);
143     QVERIFYOBJECT(success);
144     QVERIFYOBJECT(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
145
146     QVERIFYOBJECT(m_dbg->engines().count());
147     m_dbg->queryRootContexts(m_dbg->engines()[0].debugId, &success);
148     QVERIFYOBJECT(success);
149     QVERIFYOBJECT(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
150
151     QVERIFYOBJECT(m_dbg->rootContext().contexts.count());
152     QVERIFYOBJECT(m_dbg->rootContext().contexts.last().objects.count());
153     int count = m_dbg->rootContext().contexts.count();
154     recursive ? m_dbg->queryObjectRecursive(m_dbg->rootContext().contexts[count - context - 1].objects[0],
155                                             &success) :
156                 m_dbg->queryObject(m_dbg->rootContext().contexts[count - context - 1].objects[0], &success);
157     QVERIFYOBJECT(success);
158     QVERIFYOBJECT(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
159
160     return m_dbg->object();
161 }
162
163 QmlDebugPropertyReference tst_QQmlEngineDebugService::findProperty(
164         const QList<QmlDebugPropertyReference> &props, const QString &name) const
165 {
166     foreach (const QmlDebugPropertyReference &p, props) {
167         if (p.name == name)
168             return p;
169     }
170     return QmlDebugPropertyReference();
171 }
172
173 void tst_QQmlEngineDebugService::recursiveObjectTest(
174         QObject *o, const QmlDebugObjectReference &oref, bool recursive) const
175 {
176     const QMetaObject *meta = o->metaObject();
177
178     QQmlType *type = QQmlMetaType::qmlType(meta);
179     QString className = type ? QString(type->qmlTypeName())
180                              : QString(meta->className());
181     className = className.mid(className.lastIndexOf(QLatin1Char('/'))+1);
182
183     QCOMPARE(oref.debugId, QQmlDebugService::idForObject(o));
184     QCOMPARE(oref.name, o->objectName());
185     QCOMPARE(oref.className, className);
186     QCOMPARE(oref.contextDebugId, QQmlDebugService::idForObject(
187                  qmlContext(o)));
188
189     const QObjectList &children = o->children();
190     for (int i=0; i<children.count(); i++) {
191         QObject *child = children[i];
192         if (!qmlContext(child))
193             continue;
194         int debugId = QQmlDebugService::idForObject(child);
195         QVERIFY(debugId >= 0);
196
197         QmlDebugObjectReference cref;
198         foreach (const QmlDebugObjectReference &ref, oref.children) {
199             if (ref.debugId == debugId) {
200                 cref = ref;
201                 break;
202             }
203         }
204         QVERIFY(cref.debugId >= 0);
205
206         if (recursive)
207             recursiveObjectTest(child, cref, true);
208     }
209
210     foreach (const QmlDebugPropertyReference &p, oref.properties) {
211         QCOMPARE(p.objectDebugId, QQmlDebugService::idForObject(o));
212
213         // signal properties are fake - they are generated from QQmlAbstractBoundSignal children
214         if (p.name.startsWith("on") && p.name.length() > 2 && p.name[2].isUpper()) {
215             QString signal = p.value.toString();
216             QQmlBoundSignalExpression *expr = QQmlPropertyPrivate::signalExpression(QQmlProperty(o, p.name));
217             QVERIFY(expr && expr->expression() == signal);
218             QVERIFY(p.valueTypeName.isEmpty());
219             QVERIFY(p.binding.isEmpty());
220             QVERIFY(!p.hasNotifySignal);
221             continue;
222         }
223
224         QMetaProperty pmeta = meta->property(meta->indexOfProperty(p.name.toUtf8().constData()));
225
226         QCOMPARE(p.name, QString::fromUtf8(pmeta.name()));
227
228         if (pmeta.type() < QVariant::UserType && pmeta.userType() !=
229                 QMetaType::QVariant) // TODO test complex types
230             QCOMPARE(p.value , pmeta.read(o));
231
232         if (p.name == "parent")
233             QVERIFY(p.valueTypeName == "QGraphicsObject*" ||
234                     p.valueTypeName == "QQuickItem*");
235         else
236             QCOMPARE(p.valueTypeName, QString::fromUtf8(pmeta.typeName()));
237
238         QQmlAbstractBinding *binding =
239                 QQmlPropertyPrivate::binding(
240                     QQmlProperty(o, p.name));
241         if (binding)
242             QCOMPARE(binding->expression(), p.binding);
243
244         QCOMPARE(p.hasNotifySignal, pmeta.hasNotifySignal());
245
246         QVERIFY(pmeta.isValid());
247     }
248 }
249
250 void tst_QQmlEngineDebugService::initTestCase()
251 {
252     qmlRegisterType<NonScriptProperty>("Test", 1, 0, "NonScriptPropertyElement");
253
254     QTest::ignoreMessage(QtDebugMsg, "QML Debugger: Waiting for connection on port 3768...");
255     m_engine = new QQmlEngine(this);
256
257     QList<QByteArray> qml;
258     qml << "import QtQuick 2.0\n"
259            "import Test 1.0\n"
260            "Item {"
261                 "id: root\n"
262                 "width: 10; height: 20; scale: blueRect.scale;"
263                 "Rectangle { id: blueRect; width: 500; height: 600; color: \"blue\"; }"
264                 "Text { font.bold: true; color: blueRect.color; }"
265                 "MouseArea {"
266                     "onEntered: { console.log('hello') }"
267                 "}"
268                 "property variant varObj\n"
269                 "property variant varObjList: []\n"
270                 "property variant varObjMap\n"
271                 "property variant simpleVar: 10.05\n"
272                 "Component.onCompleted: {\n"
273                     "varObj = blueRect;\n"
274                     "var list = varObjList;\n"
275                     "list[0] = blueRect;\n"
276                     "varObjList = list;\n"
277                     "var map = new Object;\n"
278                     "map.rect = blueRect;\n"
279                     "varObjMap = map;\n"
280                 "}\n"
281                 "NonScriptPropertyElement {\n"
282                 "}\n"
283             "}";
284
285     // add second component to test multiple root contexts
286     qml << "import QtQuick 2.0\n"
287             "Item {}";
288
289     // and a third to test methods
290     qml << "import QtQuick 2.0\n"
291             "Item {"
292                 "function myMethodNoArgs() { return 3; }\n"
293                 "function myMethod(a) { return a + 9; }\n"
294                 "function myMethodIndirect() { myMethod(3); }\n"
295             "}";
296
297     // and a fourth to test states
298     qml << "import QtQuick 2.0\n"
299            "Rectangle {\n"
300                 "id:rootRect\n"
301                 "width:100\n"
302                 "states: [\n"
303                     "State {\n"
304                         "name:\"state1\"\n"
305                         "PropertyChanges {\n"
306                             "target:rootRect\n"
307                             "width:200\n"
308                         "}\n"
309                     "}\n"
310                 "]\n"
311                 "transitions: [\n"
312                     "Transition {\n"
313                         "from:\"*\"\n"
314                         "to:\"state1\"\n"
315                         "PropertyAnimation {\n"
316                             "target:rootRect\n"
317                             "property:\"width\"\n"
318                             "duration:100\n"
319                         "}\n"
320                     "}\n"
321                 "]\n"
322            "}\n"
323            ;
324
325     for (int i=0; i<qml.count(); i++) {
326         QQmlComponent component(m_engine);
327         component.setData(qml[i], QUrl::fromLocalFile(""));
328         QVERIFY(component.isReady());  // fails if bad syntax
329         m_components << qobject_cast<QQuickItem*>(component.create());
330     }
331     m_rootItem = qobject_cast<QQuickItem*>(m_components.first());
332
333     // add an extra context to test for multiple contexts
334     QQmlContext *context = new QQmlContext(m_engine->rootContext(), this);
335     context->setObjectName("tst_QQmlDebug_childContext");
336
337     m_conn = new QQmlDebugConnection(this);
338     m_conn->connectToHost("127.0.0.1", 3768);
339
340     bool ok = m_conn->waitForConnected();
341     QVERIFY(ok);
342     QTRY_VERIFY(QQmlDebugService::hasDebuggingClient());
343     m_dbg = new QQmlEngineDebugClient(m_conn);
344     QTRY_VERIFY(m_dbg->state() == QQmlEngineDebugClient::Enabled);
345 }
346
347 void tst_QQmlEngineDebugService::cleanupTestCase()
348 {
349     delete m_conn;
350     qDeleteAll(m_components);
351     delete m_engine;
352 }
353
354 void tst_QQmlEngineDebugService::setMethodBody()
355 {
356     bool success;
357     QmlDebugObjectReference obj = findRootObject(2);
358
359     QObject *root = m_components.at(2);
360     // Without args
361     {
362     QVariant rv;
363     QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection,
364                                       Q_RETURN_ARG(QVariant, rv)));
365     QVERIFY(rv == QVariant(qreal(3)));
366
367
368     QVERIFY(m_dbg->setMethodBody(obj.debugId, "myMethodNoArgs", "return 7",
369                                  &success));
370     QVERIFY(success);
371     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
372
373     QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection,
374                                       Q_RETURN_ARG(QVariant, rv)));
375     QVERIFY(rv == QVariant(qreal(7)));
376     }
377
378     // With args
379     {
380     QVariant rv;
381     QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection,
382                                       Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19))));
383     QVERIFY(rv == QVariant(qreal(28)));
384
385     QVERIFY(m_dbg->setMethodBody(obj.debugId, "myMethod", "return a + 7",
386                                  &success));
387     QVERIFY(success);
388     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
389
390     QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection,
391                                       Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19))));
392     QVERIFY(rv == QVariant(qreal(26)));
393     }
394 }
395
396 void tst_QQmlEngineDebugService::watch_property()
397 {
398     QmlDebugObjectReference obj = findRootObject();
399     QmlDebugPropertyReference prop = findProperty(obj.properties, "width");
400
401     bool success;
402
403     QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
404     unconnected->addWatch(prop, &success);
405     QVERIFY(!success);
406     delete unconnected;
407
408     m_dbg->addWatch(QmlDebugPropertyReference(), &success);
409     QVERIFY(success);
410     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
411     QCOMPARE(m_dbg->valid(), false);
412
413     quint32 id = m_dbg->addWatch(prop, &success);
414     QVERIFY(success);
415     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
416     QCOMPARE(m_dbg->valid(), true);
417
418     QSignalSpy spy(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant)));
419
420     int origWidth = m_rootItem->property("width").toInt();
421     m_rootItem->setProperty("width", origWidth*2);
422
423     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant))));
424     QCOMPARE(spy.count(), 1);
425
426     m_dbg->removeWatch(id, &success);
427     QVERIFY(success);
428     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
429     QCOMPARE(m_dbg->valid(), true);
430
431     // restore original value and verify spy doesn't get additional signal since watch has been removed
432     m_rootItem->setProperty("width", origWidth);
433     QTest::qWait(100);
434     QCOMPARE(spy.count(), 1);
435
436     QCOMPARE(spy.at(0).at(0).value<QByteArray>(), prop.name.toUtf8());
437     QCOMPARE(spy.at(0).at(1).value<QVariant>(), qVariantFromValue(origWidth*2));
438 }
439
440 void tst_QQmlEngineDebugService::watch_object()
441 {
442     QmlDebugObjectReference obj = findRootObject();
443
444     bool success;
445
446     QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
447     unconnected->addWatch(obj, &success);
448     QVERIFY(!success);
449     delete unconnected;
450
451     m_dbg->addWatch(QmlDebugObjectReference(), &success);
452     QVERIFY(success);
453     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
454     QCOMPARE(m_dbg->valid(), false);
455
456     quint32 id = m_dbg->addWatch(obj, &success);
457     QVERIFY(success);
458     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
459     QCOMPARE(m_dbg->valid(), true);
460
461     QSignalSpy spy(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant)));
462
463     int origWidth = m_rootItem->property("width").toInt();
464     int origHeight = m_rootItem->property("height").toInt();
465     m_rootItem->setProperty("width", origWidth*2);
466     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant))));
467     m_rootItem->setProperty("height", origHeight*2);
468     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant))));
469
470     QVERIFY(spy.count() > 0);
471
472     int newWidth = -1;
473     int newHeight = -1;
474     for (int i=0; i<spy.count(); i++) {
475         const QVariantList &values = spy[i];
476         if (values[0].value<QByteArray>() == "width")
477             newWidth = values[1].value<QVariant>().toInt();
478         else if (values[0].value<QByteArray>() == "height")
479             newHeight = values[1].value<QVariant>().toInt();
480
481     }
482
483     m_dbg->removeWatch(id, &success);
484     QVERIFY(success);
485     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
486     QCOMPARE(m_dbg->valid(), true);
487
488     // since watch has been removed, restoring the original values should not trigger a valueChanged()
489     spy.clear();
490     m_rootItem->setProperty("width", origWidth);
491     m_rootItem->setProperty("height", origHeight);
492     QTest::qWait(100);
493     QCOMPARE(spy.count(), 0);
494
495     QCOMPARE(newWidth, origWidth * 2);
496     QCOMPARE(newHeight, origHeight * 2);
497 }
498
499 void tst_QQmlEngineDebugService::watch_expression()
500 {
501     QFETCH(QString, expr);
502     QFETCH(int, increment);
503     QFETCH(int, incrementCount);
504
505     int origWidth = m_rootItem->property("width").toInt();
506
507     QmlDebugObjectReference obj = findRootObject();
508
509     bool success;
510
511     QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
512     unconnected->addWatch(obj, expr, &success);
513     QVERIFY(!success);
514     delete unconnected;
515
516     m_dbg->addWatch(QmlDebugObjectReference(), expr, &success);
517     QVERIFY(success);
518     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
519     QCOMPARE(m_dbg->valid(), false);
520
521     quint32 id = m_dbg->addWatch(obj, expr, &success);
522     QVERIFY(success);
523     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
524     QCOMPARE(m_dbg->valid(), true);
525
526     QSignalSpy spy(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant)));
527
528     int width = origWidth;
529     for (int i=0; i<incrementCount+1; i++) {
530         if (i > 0) {
531             width += increment;
532             m_rootItem->setProperty("width", width);
533             QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant))));
534         }
535     }
536
537     m_dbg->removeWatch(id, &success);
538     QVERIFY(success);
539     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
540     QCOMPARE(m_dbg->valid(), true);
541
542     // restore original value and verify spy doesn't get a signal since watch has been removed
543     m_rootItem->setProperty("width", origWidth);
544     QTest::qWait(100);
545     QCOMPARE(spy.count(), incrementCount);
546
547     width = origWidth + increment;
548     for (int i=0; i<spy.count(); i++) {
549         width += increment;
550         QCOMPARE(spy.at(i).at(1).value<QVariant>().toInt(), width);
551     }
552 }
553
554 void tst_QQmlEngineDebugService::watch_expression_data()
555 {
556     QTest::addColumn<QString>("expr");
557     QTest::addColumn<int>("increment");
558     QTest::addColumn<int>("incrementCount");
559
560     QTest::newRow("width") << "width" << 0 << 0;
561     QTest::newRow("width+10") << "width + 10" << 10 << 5;
562 }
563
564 void tst_QQmlEngineDebugService::watch_context()
565 {
566     QmlDebugContextReference c;
567     QTest::ignoreMessage(QtWarningMsg, "QQmlEngineDebugClient::addWatch(): Not implemented");
568     bool success;
569     m_dbg->addWatch(c, QString(), &success);
570     QVERIFY(!success);
571 }
572
573 void tst_QQmlEngineDebugService::watch_file()
574 {
575     QmlDebugFileReference f;
576     QTest::ignoreMessage(QtWarningMsg, "QQmlEngineDebugClient::addWatch(): Not implemented");
577     bool success;
578     m_dbg->addWatch(f, &success);
579     QVERIFY(!success);
580 }
581
582 void tst_QQmlEngineDebugService::queryAvailableEngines()
583 {
584     bool success;
585
586     QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
587     unconnected->queryAvailableEngines(&success);
588     QVERIFY(!success);
589     delete unconnected;
590
591     m_dbg->queryAvailableEngines(&success);
592     QVERIFY(success);
593     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
594
595     // TODO test multiple engines
596     QList<QmlDebugEngineReference> engines = m_dbg->engines();
597     QCOMPARE(engines.count(), 1);
598
599     foreach (const QmlDebugEngineReference &e, engines) {
600         QCOMPARE(e.debugId, QQmlDebugService::idForObject(m_engine));
601         QCOMPARE(e.name, m_engine->objectName());
602     }
603 }
604
605 void tst_QQmlEngineDebugService::queryRootContexts()
606 {
607     bool success;
608     m_dbg->queryAvailableEngines(&success);
609     QVERIFY(success);
610     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
611     QVERIFY(m_dbg->engines().count());
612     int engineId =  m_dbg->engines()[0].debugId;
613
614     QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
615     unconnected->queryRootContexts(engineId, &success);
616     QVERIFY(!success);
617     delete unconnected;
618
619     m_dbg->queryRootContexts(engineId, &success);
620     QVERIFY(success);
621     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
622
623     QQmlContext *actualContext = m_engine->rootContext();
624     QmlDebugContextReference context = m_dbg->rootContext();
625     QCOMPARE(context.debugId, QQmlDebugService::idForObject(actualContext));
626     QCOMPARE(context.name, actualContext->objectName());
627
628     // root context query sends only root object data - it doesn't fill in
629     // the children or property info
630     QCOMPARE(context.objects.count(), 0);
631     QCOMPARE(context.contexts.count(), 5);
632     QVERIFY(context.contexts[0].debugId >= 0);
633     QCOMPARE(context.contexts[0].name, QString("tst_QQmlDebug_childContext"));
634 }
635
636 void tst_QQmlEngineDebugService::queryObject()
637 {
638     QFETCH(bool, recursive);
639
640     bool success;
641
642     QmlDebugObjectReference rootObject = findRootObject();
643
644     QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
645     recursive ? unconnected->queryObjectRecursive(rootObject, &success) : unconnected->queryObject(rootObject, &success);
646     QVERIFY(!success);
647     delete unconnected;
648
649     recursive ? m_dbg->queryObjectRecursive(rootObject, &success) : m_dbg->queryObject(rootObject, &success);
650     QVERIFY(success);
651     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
652
653     QmlDebugObjectReference obj = m_dbg->object();
654
655     // check source as defined in main()
656     QmlDebugFileReference source = obj.source;
657     QCOMPARE(source.url, QUrl::fromLocalFile(""));
658     QCOMPARE(source.lineNumber, 3);
659     QCOMPARE(source.columnNumber, 1);
660
661     // generically test all properties, children and childrens' properties
662     recursiveObjectTest(m_rootItem, obj, recursive);
663
664     if (recursive) {
665         foreach (const QmlDebugObjectReference &child, obj.children)
666             QVERIFY(child.properties.count() > 0);
667
668         QmlDebugObjectReference rect;
669         QmlDebugObjectReference text;
670         foreach (const QmlDebugObjectReference &child, obj.children) {
671             if (child.className == "Rectangle")
672                 rect = child;
673             else if (child.className == "Text")
674                 text = child;
675         }
676
677         // test specific property values
678         QCOMPARE(findProperty(rect.properties, "width").value, qVariantFromValue(500));
679         QCOMPARE(findProperty(rect.properties, "height").value, qVariantFromValue(600));
680         QCOMPARE(findProperty(rect.properties, "color").value, qVariantFromValue(QColor("blue")));
681
682         QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
683     } else {
684         foreach (const QmlDebugObjectReference &child, obj.children)
685             QCOMPARE(child.properties.count(), 0);
686     }
687 }
688
689 void tst_QQmlEngineDebugService::queryObject_data()
690 {
691     QTest::addColumn<bool>("recursive");
692
693     QTest::newRow("non-recursive") << false;
694     QTest::newRow("recursive") << true;
695 }
696
697 void tst_QQmlEngineDebugService::queryObjectsForLocation()
698 {
699     QFETCH(bool, recursive);
700
701     bool success;
702
703     QmlDebugObjectReference rootObject = findRootObject();
704
705     const QString fileName = QFileInfo(rootObject.source.url.toString()).fileName();
706     int lineNumber = rootObject.source.lineNumber;
707     int columnNumber = rootObject.source.columnNumber;
708
709     QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
710     recursive ? unconnected->queryObjectsForLocationRecursive(fileName, lineNumber,
711                                                               columnNumber, &success)
712               : unconnected->queryObjectsForLocation(fileName, lineNumber,
713                                                      columnNumber, &success);
714     QVERIFY(!success);
715     delete unconnected;
716
717     recursive ? m_dbg->queryObjectsForLocationRecursive(fileName, lineNumber,
718                                                       columnNumber, &success)
719               : m_dbg->queryObjectsForLocation(fileName, lineNumber,
720                                              columnNumber, &success);
721     QVERIFY(success);
722     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
723
724     QVERIFY(m_dbg->objects().count() == 1);
725     QmlDebugObjectReference obj = m_dbg->objects().first();
726
727     // check source as defined in main()
728     QmlDebugFileReference source = obj.source;
729     QCOMPARE(source.url, QUrl(fileName));
730     QCOMPARE(source.lineNumber, lineNumber);
731     QCOMPARE(source.columnNumber, columnNumber);
732
733     // generically test all properties, children and childrens' properties
734     recursiveObjectTest(m_rootItem, obj, recursive);
735
736     if (recursive) {
737         foreach (const QmlDebugObjectReference &child, obj.children)
738             QVERIFY(child.properties.count() > 0);
739
740         QmlDebugObjectReference rect;
741         QmlDebugObjectReference text;
742         foreach (const QmlDebugObjectReference &child, obj.children) {
743             if (child.className == "Rectangle")
744                 rect = child;
745             else if (child.className == "Text")
746                 text = child;
747         }
748
749         // test specific property values
750         QCOMPARE(findProperty(rect.properties, "width").value, qVariantFromValue(500));
751         QCOMPARE(findProperty(rect.properties, "height").value, qVariantFromValue(600));
752         QCOMPARE(findProperty(rect.properties, "color").value, qVariantFromValue(QColor("blue")));
753
754         QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
755     } else {
756         foreach (const QmlDebugObjectReference &child, obj.children)
757             QCOMPARE(child.properties.count(), 0);
758     }
759 }
760
761 void tst_QQmlEngineDebugService::queryObjectsForLocation_data()
762 {
763     QTest::addColumn<bool>("recursive");
764
765     QTest::newRow("non-recursive") << false;
766     QTest::newRow("recursive") << true;
767 }
768
769 void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
770 {
771     QmlDebugObjectReference rootObject = findRootObject();
772     int contextId = rootObject.contextDebugId;
773     QQmlContext *context = qobject_cast<QQmlContext *>(QQmlDebugService::objectForId(contextId));
774     QQmlComponent component(context->engine());
775     QByteArray content;
776     content.append("import QtQuick 2.0\n"
777                "Text {"
778                "y: 10\n"
779                "text: \"test\"\n"
780                "}");
781     component.setData(content, rootObject.source.url);
782     QObject *object = component.create(context);
783     QVERIFY(object);
784     int idNew = QQmlDebugService::idForObject(object);
785     QVERIFY(idNew >= 0);
786
787     const QString fileName = QFileInfo(rootObject.source.url.toString()).fileName();
788     int lineNumber = rootObject.source.lineNumber;
789     int columnNumber = rootObject.source.columnNumber;
790     bool success = false;
791
792     m_dbg->queryObjectsForLocation(fileName, lineNumber,
793                                         columnNumber, &success);
794     QVERIFY(success);
795     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
796
797     foreach (QmlDebugObjectReference child, rootObject.children) {
798         success = false;
799         lineNumber = child.source.lineNumber;
800         columnNumber = child.source.columnNumber;
801         m_dbg->queryObjectsForLocation(fileName, lineNumber,
802                                        columnNumber, &success);
803         QVERIFY(success);
804         QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
805     }
806
807     delete object;
808     QObject *deleted = QQmlDebugService::objectForId(idNew);
809     QVERIFY(!deleted);
810
811     lineNumber = rootObject.source.lineNumber;
812     columnNumber = rootObject.source.columnNumber;
813     success = false;
814     m_dbg->queryObjectsForLocation(fileName, lineNumber,
815                                    columnNumber, &success);
816     QVERIFY(success);
817     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
818
819     foreach (QmlDebugObjectReference child, rootObject.children) {
820         success = false;
821         lineNumber = child.source.lineNumber;
822         columnNumber = child.source.columnNumber;
823         m_dbg->queryObjectsForLocation(fileName, lineNumber,
824                                        columnNumber, &success);
825         QVERIFY(success);
826         QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
827     }
828 }
829
830
831 void tst_QQmlEngineDebugService::queryExpressionResult()
832 {
833     QFETCH(QString, expr);
834     QFETCH(QVariant, result);
835
836     int objectId = findRootObject().debugId;
837
838     bool success;
839
840     QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
841     unconnected->queryExpressionResult(objectId, expr, &success);
842     QVERIFY(!success);
843     delete unconnected;
844
845     m_dbg->queryExpressionResult(objectId, expr, &success);
846     QVERIFY(success);
847     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
848
849     QCOMPARE(m_dbg->resultExpr(), result);
850 }
851
852 void tst_QQmlEngineDebugService::queryExpressionResult_data()
853 {
854     QTest::addColumn<QString>("expr");
855     QTest::addColumn<QVariant>("result");
856
857     QTest::newRow("width + 50") << "width + 50" << qVariantFromValue(60);
858     QTest::newRow("blueRect.width") << "blueRect.width" << qVariantFromValue(500);
859     QTest::newRow("bad expr") << "aeaef" << qVariantFromValue(QString("<undefined>"));
860     QTest::newRow("QObject*") << "varObj" << qVariantFromValue(QString("<unnamed object>"));
861     QTest::newRow("list of QObject*") << "varObjList" << qVariantFromValue(QString("<unknown value>"));
862     QVariantMap map;
863     map.insert(QLatin1String("rect"), QVariant(QLatin1String("<unnamed object>")));
864     QTest::newRow("varObjMap") << "varObjMap" << qVariantFromValue(map);
865     QTest::newRow("simpleVar") << "simpleVar" << qVariantFromValue(10.05);
866 }
867
868 void tst_QQmlEngineDebugService::queryExpressionResultInRootContext()
869 {
870     bool success;
871     const QString exp = QLatin1String("1");
872     m_dbg->queryExpressionResult(-1, exp, &success);
873     QVERIFY(success);
874     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
875
876     QCOMPARE(m_dbg->resultExpr().toString(), exp);
877 }
878
879 void tst_QQmlEngineDebugService::queryExpressionResultBC()
880 {
881     QFETCH(QString, expr);
882     QFETCH(QVariant, result);
883
884     int objectId = findRootObject().debugId;
885
886     bool success;
887
888     QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
889     unconnected->queryExpressionResultBC(objectId, expr, &success);
890     QVERIFY(!success);
891     delete unconnected;
892
893     m_dbg->queryExpressionResultBC(objectId, expr, &success);
894     QVERIFY(success);
895     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
896
897     QCOMPARE(m_dbg->resultExpr(), result);
898 }
899
900 void tst_QQmlEngineDebugService::queryExpressionResultBC_data()
901 {
902     QTest::addColumn<QString>("expr");
903     QTest::addColumn<QVariant>("result");
904
905     QTest::newRow("width + 50") << "width + 50" << qVariantFromValue(60);
906     QTest::newRow("blueRect.width") << "blueRect.width" << qVariantFromValue(500);
907     QTest::newRow("bad expr") << "aeaef" << qVariantFromValue(QString("<undefined>"));
908     QTest::newRow("QObject*") << "varObj" << qVariantFromValue(QString("<unnamed object>"));
909     QTest::newRow("list of QObject*") << "varObjList" << qVariantFromValue(QString("<unknown value>"));
910     QVariantMap map;
911     map.insert(QLatin1String("rect"), QVariant(QLatin1String("<unnamed object>")));
912     QTest::newRow("varObjMap") << "varObjMap" << qVariantFromValue(map);
913     QTest::newRow("simpleVar") << "simpleVar" << qVariantFromValue(10.05);
914 }
915
916 void tst_QQmlEngineDebugService::setBindingForObject()
917 {
918     QmlDebugObjectReference rootObject = findRootObject();
919     QVERIFY(rootObject.debugId != -1);
920     QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
921
922     QCOMPARE(widthPropertyRef.value, QVariant(10));
923     QCOMPARE(widthPropertyRef.binding, QString());
924
925     bool success;
926     //
927     // set literal
928     //
929     m_dbg->setBindingForObject(rootObject.debugId, "width", "15", true,
930                                QString(), -1, &success);
931     QVERIFY(success);
932     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
933     QCOMPARE(m_dbg->valid(), true);
934
935     rootObject = findRootObject();
936     widthPropertyRef =  findProperty(rootObject.properties, "width");
937
938     QCOMPARE(widthPropertyRef.value, QVariant(15));
939     QCOMPARE(widthPropertyRef.binding, QString());
940
941     //
942     // set expression
943     //
944     m_dbg->setBindingForObject(rootObject.debugId, "width", "height", false,
945                                QString(), -1, &success);
946     QVERIFY(success);
947     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
948     QCOMPARE(m_dbg->valid(), true);
949
950     rootObject = findRootObject();
951     widthPropertyRef =  findProperty(rootObject.properties, "width");
952
953     QCOMPARE(widthPropertyRef.value, QVariant(20));
954     QCOMPARE(widthPropertyRef.binding, QString("height"));
955
956     //
957     // set handler
958     //
959     rootObject = findRootObject();
960     QCOMPARE(rootObject.children.size(), 5); // Rectangle, Text, MouseArea, Component.onCompleted, NonScriptPropertyElement
961     QmlDebugObjectReference mouseAreaObject = rootObject.children.at(2);
962     m_dbg->queryObjectRecursive(mouseAreaObject, &success);
963     QVERIFY(success);
964     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
965     mouseAreaObject = m_dbg->object();
966
967     QCOMPARE(mouseAreaObject.className, QString("MouseArea"));
968
969     QmlDebugPropertyReference onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
970
971     QCOMPARE(onEnteredRef.name, QString("onEntered"));
972     QCOMPARE(onEnteredRef.value,  QVariant("(function onEntered() { { console.log('hello') } })"));
973
974     m_dbg->setBindingForObject(mouseAreaObject.debugId, "onEntered",
975                                "{console.log('hello, world') }", false,
976                                QString(), -1, &success);
977     QVERIFY(success);
978     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
979     QCOMPARE(m_dbg->valid(), true);
980
981     rootObject = findRootObject();
982     mouseAreaObject = rootObject.children.at(2);
983     m_dbg->queryObjectRecursive(mouseAreaObject, &success);
984     QVERIFY(success);
985     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
986     mouseAreaObject = m_dbg->object();
987     onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
988     QCOMPARE(onEnteredRef.name, QString("onEntered"));
989     QCOMPARE(onEnteredRef.value,  QVariant("{console.log('hello, world') }"));
990 }
991
992 void tst_QQmlEngineDebugService::resetBindingForObject()
993 {
994     QmlDebugObjectReference rootObject = findRootObject();
995     QVERIFY(rootObject.debugId != -1);
996     QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
997
998     bool success = false;
999
1000     m_dbg->setBindingForObject(rootObject.debugId, "width", "15", true,
1001                                QString(), -1, &success);
1002     QVERIFY(success);
1003     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1004     QCOMPARE(m_dbg->valid(), true);
1005
1006     //
1007     // reset
1008     //
1009     m_dbg->resetBindingForObject(rootObject.debugId, "width", &success);
1010     QVERIFY(success);
1011     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1012     QCOMPARE(m_dbg->valid(), true);
1013
1014     rootObject = findRootObject();
1015     widthPropertyRef =  findProperty(rootObject.properties, "width");
1016
1017     QCOMPARE(widthPropertyRef.value, QVariant(0));
1018     QCOMPARE(widthPropertyRef.binding, QString());
1019
1020     //
1021     // reset nested property
1022     //
1023     success = false;
1024     m_dbg->resetBindingForObject(rootObject.debugId, "font.bold", &success);
1025     QVERIFY(success);
1026     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1027     QCOMPARE(m_dbg->valid(), true);
1028
1029     rootObject = findRootObject();
1030     QmlDebugPropertyReference boldPropertyRef =  findProperty(rootObject.properties, "font.bold");
1031
1032     QCOMPARE(boldPropertyRef.value.toBool(), false);
1033     QCOMPARE(boldPropertyRef.binding, QString());
1034 }
1035
1036 void tst_QQmlEngineDebugService::setBindingInStates()
1037 {
1038     // Check if changing bindings of propertychanges works
1039
1040     const int sourceIndex = 3;
1041
1042     QmlDebugObjectReference obj = findRootObject(sourceIndex);
1043
1044     QVERIFY(obj.debugId != -1);
1045     QVERIFY(obj.children.count() >= 2);
1046     bool success;
1047     // We are going to switch state a couple of times, we need to get rid of the transition before
1048     m_dbg->queryExpressionResult(obj.debugId,QString("transitions = []"), &success);
1049     QVERIFY(success);
1050     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1051
1052
1053     // check initial value of the property that is changing
1054     m_dbg->queryExpressionResult(obj.debugId,QString("state=\"state1\""), &success);
1055     QVERIFY(success);
1056     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1057
1058     obj = findRootObject(sourceIndex);
1059     QCOMPARE(findProperty(obj.properties,"width").value.toInt(),200);
1060
1061
1062     m_dbg->queryExpressionResult(obj.debugId,QString("state=\"\""),
1063                                               &success);
1064     QVERIFY(success);
1065     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1066
1067
1068     obj = findRootObject(sourceIndex, true);
1069     QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
1070
1071
1072     // change the binding
1073     QmlDebugObjectReference state = obj.children[1];
1074     QCOMPARE(state.className, QString("State"));
1075     QVERIFY(state.children.count() > 0);
1076
1077     QmlDebugObjectReference propertyChange = state.children[0];
1078     QVERIFY(propertyChange.debugId != -1);
1079
1080     m_dbg->setBindingForObject(propertyChange.debugId, "width",QVariant(300),true,
1081                                QString(), -1, &success);
1082     QVERIFY(success);
1083     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1084
1085     // check properties changed in state
1086     obj = findRootObject(sourceIndex);
1087     QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
1088
1089
1090     m_dbg->queryExpressionResult(obj.debugId,QString("state=\"state1\""), &success);
1091     QVERIFY(success);
1092     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1093
1094     obj = findRootObject(sourceIndex);
1095     QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
1096
1097     // check changing properties of base state from within a state
1098     m_dbg->setBindingForObject(obj.debugId,"width","height*2",false,
1099                                QString(), -1, &success);
1100     QVERIFY(success);
1101     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1102     m_dbg->setBindingForObject(obj.debugId,"height","200",true,
1103                                QString(), -1, &success);
1104     QVERIFY(success);
1105     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1106
1107     obj = findRootObject(sourceIndex);
1108     QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
1109
1110     m_dbg->queryExpressionResult(obj.debugId,QString("state=\"\""), &success);
1111     QVERIFY(success);
1112     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1113
1114     obj = findRootObject(sourceIndex);
1115     QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
1116
1117     //  reset binding while in a state
1118     m_dbg->queryExpressionResult(obj.debugId,QString("state=\"state1\""), &success);
1119     QVERIFY(success);
1120     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1121
1122     obj = findRootObject(sourceIndex);
1123     QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
1124
1125     m_dbg->resetBindingForObject(propertyChange.debugId, "width", &success);
1126     QVERIFY(success);
1127     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1128     QCOMPARE(m_dbg->valid(), true);
1129
1130     obj = findRootObject(sourceIndex);
1131     QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
1132
1133     // re-add binding
1134     m_dbg->setBindingForObject(propertyChange.debugId, "width", "300", true,
1135                                QString(), -1, &success);
1136     QVERIFY(success);
1137     QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
1138     QCOMPARE(m_dbg->valid(), true);
1139
1140     obj = findRootObject(sourceIndex);
1141     QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
1142 }
1143
1144 void tst_QQmlEngineDebugService::queryObjectTree()
1145 {
1146     const int sourceIndex = 3;
1147
1148     QmlDebugObjectReference obj = findRootObject(sourceIndex, true);
1149
1150     QVERIFY(obj.debugId != -1);
1151     QVERIFY(obj.children.count() >= 2);
1152
1153     // check state
1154     QmlDebugObjectReference state = obj.children[1];
1155     QCOMPARE(state.className, QString("State"));
1156     QVERIFY(state.children.count() > 0);
1157
1158     QmlDebugObjectReference propertyChange = state.children[0];
1159     QVERIFY(propertyChange.debugId != -1);
1160
1161     QmlDebugPropertyReference propertyChangeTarget = findProperty(propertyChange.properties,"target");
1162     QCOMPARE(propertyChangeTarget.objectDebugId, propertyChange.debugId);
1163
1164     QmlDebugObjectReference targetReference = qvariant_cast<QmlDebugObjectReference>(propertyChangeTarget.value);
1165     QVERIFY(targetReference.debugId != -1);
1166
1167
1168
1169     // check transition
1170     QmlDebugObjectReference transition = obj.children[0];
1171     QCOMPARE(transition.className, QString("Transition"));
1172     QCOMPARE(findProperty(transition.properties,"from").value.toString(), QString("*"));
1173     QCOMPARE(findProperty(transition.properties,"to").value, findProperty(state.properties,"name").value);
1174     QVERIFY(transition.children.count() > 0);
1175
1176     QmlDebugObjectReference animation = transition.children[0];
1177     QVERIFY(animation.debugId != -1);
1178
1179     QmlDebugPropertyReference animationTarget = findProperty(animation.properties,"target");
1180     QCOMPARE(animationTarget.objectDebugId, animation.debugId);
1181
1182     targetReference = qvariant_cast<QmlDebugObjectReference>(animationTarget.value);
1183     QVERIFY(targetReference.debugId != -1);
1184
1185     QCOMPARE(findProperty(animation.properties,"property").value.toString(), QString("width"));
1186     QCOMPARE(findProperty(animation.properties,"duration").value.toInt(), 100);
1187 }
1188
1189 int main(int argc, char *argv[])
1190 {
1191     int _argc = argc + 1;
1192     char **_argv = new char*[_argc];
1193     for (int i = 0; i < argc; ++i)
1194         _argv[i] = argv[i];
1195     char arg[] = "-qmljsdebugger=port:3768";
1196     _argv[_argc - 1] = arg;
1197
1198     QGuiApplication app(_argc, _argv);
1199     tst_QQmlEngineDebugService tc;
1200     return QTest::qExec(&tc, _argc, _argv);
1201     delete _argv;
1202 }
1203
1204 #include "tst_qqmlenginedebugservice.moc"