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