aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/debugger
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/debugger')
-rw-r--r--tests/auto/qml/debugger/debugger.pro16
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/data/test.qml51
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro21
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp242
-rw-r--r--tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro10
-rw-r--r--tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp263
-rw-r--r--tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro11
-rw-r--r--tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp197
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml53
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml60
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/condition.qml54
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml54
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/exception.qml51
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml48
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml53
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml57
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/test.js53
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/test.qml54
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/timer.qml52
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro29
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp1790
-rw-r--r--tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro11
-rw-r--r--tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp216
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebug/qqmlenginedebug.pro11
-rw-r--r--tests/auto/qml/debugger/qqmlenginedebug/tst_qqmlenginedebug.cpp1235
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/app/app.pro9
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/app/main.cpp71
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/app/qtquick2.qml5
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro3
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp186
-rw-r--r--tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.pro12
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml9
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml5
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro15
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp310
-rw-r--r--tests/auto/qml/debugger/qv8profilerservice/data/console.qml14
-rw-r--r--tests/auto/qml/debugger/qv8profilerservice/data/exit.qml11
-rw-r--r--tests/auto/qml/debugger/qv8profilerservice/data/test.qml5
-rw-r--r--tests/auto/qml/debugger/qv8profilerservice/qv8profilerservice.pro16
-rw-r--r--tests/auto/qml/debugger/qv8profilerservice/tst_qv8profilerservice.cpp294
-rw-r--r--tests/auto/qml/debugger/shared/debugutil.cpp190
-rw-r--r--tests/auto/qml/debugger/shared/debugutil_p.h127
42 files changed, 5974 insertions, 0 deletions
diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro
new file mode 100644
index 0000000000..4f9ebbc350
--- /dev/null
+++ b/tests/auto/qml/debugger/debugger.pro
@@ -0,0 +1,16 @@
+TEMPLATE = subdirs
+
+PRIVATETESTS += \
+ qqmlenginedebug \
+ qqmldebugclient \
+ qqmldebugservice \
+ qqmldebugjs \
+ qqmlinspector \
+ qqmlprofilerservice \
+ qpacketprotocol \
+ qv8profilerservice \
+ qdebugmessageservice
+
+contains(QT_CONFIG, private_tests) {
+ SUBDIRS += $$PRIVATETESTS
+}
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/data/test.qml b/tests/auto/qml/debugger/qdebugmessageservice/data/test.qml
new file mode 100644
index 0000000000..ab86c7d468
--- /dev/null
+++ b/tests/auto/qml/debugger/qdebugmessageservice/data/test.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ width: 360
+ height: 360
+ Component.onCompleted: {
+ console.log("console.log")
+ console.count("console.count");
+ }
+}
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro b/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro
new file mode 100644
index 0000000000..afda4b23bd
--- /dev/null
+++ b/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro
@@ -0,0 +1,21 @@
+CONFIG += testcase
+TARGET = tst_qdebugmessageservice
+QT += network qml-private testlib
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/debugutil_p.h
+
+SOURCES += tst_qdebugmessageservice.cpp \
+ ../shared/debugutil.cpp
+
+INCLUDEPATH += ../shared
+
+include(../../../shared/util.pri)
+
+testDataFiles.files = data
+testDataFiles.path = .
+DEPLOYMENT += testDataFiles
+
+CONFIG += parallel_test
+
+OTHER_FILES += data/test.qml
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
new file mode 100644
index 0000000000..a19fd4b766
--- /dev/null
+++ b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/private/qqmldebugclient_p.h>
+
+//QQmlDebugTest
+#include "../shared/debugutil_p.h"
+#include "../../../shared/util.h"
+
+#include <QtCore/QString>
+#include <QtTest/QtTest>
+
+const char *NORMALMODE = "-qmljsdebugger=port:3777,block";
+const char *QMLFILE = "test.qml";
+
+class QQmlDebugMsgClient;
+class tst_QDebugMessageService : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_QDebugMessageService();
+
+ void init();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void cleanup();
+
+ void retrieveDebugOutput();
+
+private:
+ QQmlDebugProcess *m_process;
+ QQmlDebugMsgClient *m_client;
+ QQmlDebugConnection *m_connection;
+};
+
+struct LogEntry {
+ LogEntry(QtMsgType _type, QString _message)
+ : type(_type), message(_message) {}
+
+ QtMsgType type;
+ QString message;
+ int line;
+ QString file;
+ QString function;
+
+ QString toString() const { return QString::number(type) + ": " + message; }
+};
+
+bool operator==(const LogEntry &t1, const LogEntry &t2)
+{
+ return t1.type == t2.type && t1.message == t2.message
+ && t1.line == t2.line && t1.file == t2.file
+ && t1.function == t2.function;
+}
+
+class QQmlDebugMsgClient : public QQmlDebugClient
+{
+ Q_OBJECT
+public:
+ QQmlDebugMsgClient(QQmlDebugConnection *connection)
+ : QQmlDebugClient(QLatin1String("DebugMessages"), connection)
+ {
+ }
+
+ QList<LogEntry> logBuffer;
+
+protected:
+ //inherited from QQmlDebugClient
+ void stateChanged(State state);
+ void messageReceived(const QByteArray &data);
+
+signals:
+ void enabled();
+ void debugOutput();
+};
+
+void QQmlDebugMsgClient::stateChanged(State state)
+{
+ if (state == Enabled) {
+ emit enabled();
+ }
+}
+
+void QQmlDebugMsgClient::messageReceived(const QByteArray &data)
+{
+ QDataStream ds(data);
+ QByteArray command;
+ ds >> command;
+
+ if (command == "MESSAGE") {
+ int type;
+ QByteArray message;
+ QByteArray file;
+ QByteArray function;
+ int line;
+ ds >> type >> message >> file >> line >> function;
+ QVERIFY(ds.atEnd());
+
+ QVERIFY(type >= QtDebugMsg);
+ QVERIFY(type <= QtFatalMsg);
+
+ LogEntry entry((QtMsgType)type, QString::fromUtf8(message));
+ entry.line = line;
+ entry.file = QString::fromUtf8(file);
+ entry.function = QString::fromUtf8(function);
+ logBuffer << entry;
+ emit debugOutput();
+ } else {
+ QFAIL("Unknown message");
+ }
+}
+
+tst_QDebugMessageService::tst_QDebugMessageService()
+{
+}
+
+void tst_QDebugMessageService::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ m_process = 0;
+ m_client = 0;
+ m_connection = 0;
+}
+
+void tst_QDebugMessageService::cleanupTestCase()
+{
+ if (m_process)
+ delete m_process;
+
+ if (m_client)
+ delete m_client;
+
+ if (m_connection)
+ delete m_connection;
+}
+
+void tst_QDebugMessageService::init()
+{
+ m_connection = new QQmlDebugConnection();
+ m_process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene");
+ m_client = new QQmlDebugMsgClient(m_connection);
+
+ m_process->start(QStringList() << QLatin1String(NORMALMODE) << QQmlDataTest::instance()->testFile(QMLFILE));
+ if (!m_process->waitForSessionStart()) {
+ QFAIL(QString("Could not launch app. Application output: \n%1").arg(m_process->output()).toAscii());
+ }
+
+ m_connection->connectToHost("127.0.0.1", 3777);
+ QVERIFY(m_connection->waitForConnected());
+
+ QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(enabled())));
+}
+
+void tst_QDebugMessageService::cleanup()
+{
+ if (QTest::currentTestFailed())
+ qDebug() << m_process->output();
+ if (m_process)
+ delete m_process;
+
+ if (m_client)
+ delete m_client;
+
+ if (m_connection)
+ delete m_connection;
+
+ m_process = 0;
+ m_client = 0;
+ m_connection = 0;
+}
+
+void tst_QDebugMessageService::retrieveDebugOutput()
+{
+ init();
+
+ int maxTries = 2;
+ while ((m_client->logBuffer.size() < 2)
+ || (maxTries-- > 0))
+ QQmlDebugTest::waitForSignal(m_client, SIGNAL(debugOutput()), 1000);
+
+ QVERIFY(m_client->logBuffer.size() >= 2);
+
+ const QString path =
+ QUrl::fromLocalFile(QQmlDataTest::instance()->testFile(QMLFILE)).toString();
+ LogEntry entry1(QtDebugMsg, QLatin1String("console.log"));
+ entry1.line = 48;
+ entry1.file = path;
+ entry1.function = QLatin1String("onCompleted");
+ LogEntry entry2(QtDebugMsg, QLatin1String("console.count: 1"));
+ entry2.line = 49;
+ entry2.file = path;
+ entry2.function = QLatin1String("onCompleted");
+
+ QVERIFY(m_client->logBuffer.contains(entry1));
+ QVERIFY(m_client->logBuffer.contains(entry2));
+}
+
+QTEST_MAIN(tst_QDebugMessageService)
+
+#include "tst_qdebugmessageservice.moc"
diff --git a/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro b/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro
new file mode 100644
index 0000000000..88439196a7
--- /dev/null
+++ b/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro
@@ -0,0 +1,10 @@
+CONFIG += testcase
+TARGET = tst_qpacketprotocol
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/debugutil_p.h
+SOURCES += tst_qpacketprotocol.cpp \
+ ../shared/debugutil.cpp
+
+CONFIG += parallel_test
+QT += qml-private network testlib
diff --git a/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp b/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp
new file mode 100644
index 0000000000..c02dd2d8fa
--- /dev/null
+++ b/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QSignalSpy>
+#include <QTimer>
+#include <QTcpSocket>
+#include <QTcpServer>
+#include <QDebug>
+#include <QBuffer>
+
+#include <private/qpacketprotocol_p.h>
+
+#include "../shared/debugutil_p.h"
+
+class tst_QPacketProtocol : public QObject
+{
+ Q_OBJECT
+
+private:
+ QTcpServer *m_server;
+ QTcpSocket *m_client;
+ QTcpSocket *m_serverConn;
+
+private slots:
+ void init();
+ void cleanup();
+
+ void maximumPacketSize();
+ void setMaximumPacketSize();
+ void setMaximumPacketSize_data();
+ void send();
+ void send_data();
+ void packetsAvailable();
+ void packetsAvailable_data();
+ void clear();
+ void read();
+ void device();
+
+ void tst_QPacket_clear();
+};
+
+void tst_QPacketProtocol::init()
+{
+ m_server = new QTcpServer(this);
+ m_serverConn = 0;
+ QVERIFY(m_server->listen(QHostAddress("127.0.0.1")));
+
+ m_client = new QTcpSocket(this);
+ m_client->connectToHost(m_server->serverAddress(), m_server->serverPort());
+
+ QVERIFY(m_client->waitForConnected());
+ QVERIFY(m_server->waitForNewConnection(5000));
+ m_serverConn = m_server->nextPendingConnection();
+}
+
+void tst_QPacketProtocol::cleanup()
+{
+ delete m_client;
+ delete m_serverConn;
+ delete m_server;
+}
+
+void tst_QPacketProtocol::maximumPacketSize()
+{
+ QPacketProtocol p(m_client);
+ QCOMPARE(p.maximumPacketSize(), 0x7FFFFFFF);
+}
+
+void tst_QPacketProtocol::setMaximumPacketSize()
+{
+ QFETCH(qint32, size);
+ QFETCH(qint32, expected);
+
+ QPacketProtocol out(m_serverConn);
+ QCOMPARE(out.setMaximumPacketSize(size), expected);
+}
+
+void tst_QPacketProtocol::setMaximumPacketSize_data()
+{
+ QTest::addColumn<int>("size");
+ QTest::addColumn<int>("expected");
+
+ QTest::newRow("invalid") << qint32(sizeof(qint32) - 1) << qint32(0x7FFFFFFF);
+ QTest::newRow("still invalid") << qint32(sizeof(qint32)) << qint32(0x7FFFFFFF);
+ QTest::newRow("valid") << qint32(sizeof(qint32) + 1) << qint32(sizeof(qint32) + 1);
+}
+
+void tst_QPacketProtocol::send()
+{
+ QFETCH(bool, useAutoSend);
+
+ QPacketProtocol in(m_client);
+ QPacketProtocol out(m_serverConn);
+
+ QByteArray ba;
+ int num;
+
+ if (useAutoSend) {
+ out.send() << "Hello world" << 123;
+ } else {
+ QPacket packet;
+ packet << "Hello world" << 123;
+ out.send(packet);
+ }
+
+ QVERIFY(QQmlDebugTest::waitForSignal(&in, SIGNAL(readyRead())));
+
+ QPacket p = in.read();
+ p >> ba >> num;
+ QCOMPARE(ba, QByteArray("Hello world") + '\0');
+ QCOMPARE(num, 123);
+}
+
+void tst_QPacketProtocol::send_data()
+{
+ QTest::addColumn<bool>("useAutoSend");
+
+ QTest::newRow("auto send") << true;
+ QTest::newRow("no auto send") << false;
+}
+
+void tst_QPacketProtocol::packetsAvailable()
+{
+ QFETCH(int, packetCount);
+
+ QPacketProtocol out(m_client);
+ QPacketProtocol in(m_serverConn);
+
+ QCOMPARE(out.packetsAvailable(), qint64(0));
+ QCOMPARE(in.packetsAvailable(), qint64(0));
+
+ for (int i=0; i<packetCount; i++)
+ out.send() << "Hello";
+
+ QVERIFY(QQmlDebugTest::waitForSignal(&in, SIGNAL(readyRead())));
+ QCOMPARE(in.packetsAvailable(), qint64(packetCount));
+}
+
+void tst_QPacketProtocol::packetsAvailable_data()
+{
+ QTest::addColumn<int>("packetCount");
+
+ QTest::newRow("1") << 1;
+ QTest::newRow("2") << 2;
+ QTest::newRow("10") << 10;
+}
+
+void tst_QPacketProtocol::clear()
+{
+ QPacketProtocol in(m_client);
+ QPacketProtocol out(m_serverConn);
+
+ out.send() << 123;
+ out.send() << 456;
+ QVERIFY(QQmlDebugTest::waitForSignal(&in, SIGNAL(readyRead())));
+
+ in.clear();
+ QVERIFY(in.read().isEmpty());
+}
+
+void tst_QPacketProtocol::read()
+{
+ QPacketProtocol in(m_client);
+ QPacketProtocol out(m_serverConn);
+
+ QVERIFY(in.read().isEmpty());
+
+ out.send() << 123;
+ out.send() << 456;
+ QVERIFY(QQmlDebugTest::waitForSignal(&in, SIGNAL(readyRead())));
+
+ int num;
+
+ QPacket p1 = in.read();
+ QVERIFY(!p1.isEmpty());
+ p1 >> num;
+ QCOMPARE(num, 123);
+
+ QPacket p2 = in.read();
+ QVERIFY(!p2.isEmpty());
+ p2 >> num;
+ QCOMPARE(num, 456);
+
+ QVERIFY(in.read().isEmpty());
+}
+
+void tst_QPacketProtocol::device()
+{
+ QPacketProtocol p(m_client);
+ QVERIFY(p.device() == m_client);
+}
+
+void tst_QPacketProtocol::tst_QPacket_clear()
+{
+ QPacketProtocol protocol(m_client);
+
+ QPacket packet;
+
+ packet << "Hello world!" << 123;
+ protocol.send(packet);
+
+ packet.clear();
+ QVERIFY(packet.isEmpty());
+ packet << "Goodbyte world!" << 789;
+ protocol.send(packet);
+
+ QByteArray ba;
+ int num;
+ QPacketProtocol in(m_serverConn);
+ QVERIFY(QQmlDebugTest::waitForSignal(&in, SIGNAL(readyRead())));
+
+ QPacket p1 = in.read();
+ p1 >> ba >> num;
+ QCOMPARE(ba, QByteArray("Hello world!") + '\0');
+ QCOMPARE(num, 123);
+
+ QPacket p2 = in.read();
+ p2 >> ba >> num;
+ QCOMPARE(ba, QByteArray("Goodbyte world!") + '\0');
+ QCOMPARE(num, 789);
+}
+
+QTEST_MAIN(tst_QPacketProtocol)
+
+#include "tst_qpacketprotocol.moc"
diff --git a/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro b/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro
new file mode 100644
index 0000000000..d298b5c087
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro
@@ -0,0 +1,11 @@
+CONFIG += testcase
+TARGET = tst_qqmldebugclient
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/debugutil_p.h
+SOURCES += tst_qqmldebugclient.cpp \
+ ../shared/debugutil.cpp
+
+CONFIG += declarative_debug
+
+QT += qml-private testlib
diff --git a/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp b/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp
new file mode 100644
index 0000000000..2891076af6
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugclient/tst_qqmldebugclient.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QSignalSpy>
+#include <QTimer>
+#include <QHostAddress>
+#include <QDebug>
+#include <QThread>
+
+#include <QtQml/qqmlengine.h>
+
+#include "../shared/debugutil_p.h"
+
+#define PORT 13770
+#define STR_PORT "13770"
+
+class tst_QQmlDebugClient : public QObject
+{
+ Q_OBJECT
+
+private:
+ QQmlDebugConnection *m_conn;
+
+private slots:
+ void initTestCase();
+
+ void name();
+ void state();
+ void sendMessage();
+ void parallelConnect();
+ void sequentialConnect();
+};
+
+void tst_QQmlDebugClient::initTestCase()
+{
+ const QString waitingMsg = QString("QQmlDebugServer: Waiting for connection on port %1...").arg(PORT);
+ QTest::ignoreMessage(QtWarningMsg, waitingMsg.toAscii().constData());
+ new QQmlEngine(this);
+
+ m_conn = new QQmlDebugConnection(this);
+
+ QQmlDebugTestClient client("tst_QQmlDebugClient::handshake()", m_conn);
+ QQmlDebugTestService service("tst_QQmlDebugClient::handshake()");
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlDebugServer: Connection established");
+ for (int i = 0; i < 50; ++i) {
+ // try for 5 seconds ...
+ m_conn->connectToHost("127.0.0.1", PORT);
+ if (m_conn->waitForConnected())
+ break;
+ QTest::qSleep(100);
+ }
+
+ QVERIFY(m_conn->isConnected());
+
+ QTRY_VERIFY(QQmlDebugService::hasDebuggingClient());
+ QTRY_COMPARE(client.state(), QQmlDebugClient::Enabled);
+}
+
+void tst_QQmlDebugClient::name()
+{
+ QString name = "tst_QQmlDebugClient::name()";
+
+ QQmlDebugClient client(name, m_conn);
+ QCOMPARE(client.name(), name);
+}
+
+void tst_QQmlDebugClient::state()
+{
+ {
+ QQmlDebugConnection dummyConn;
+ QQmlDebugClient client("tst_QQmlDebugClient::state()", &dummyConn);
+ QCOMPARE(client.state(), QQmlDebugClient::NotConnected);
+ QCOMPARE(client.serviceVersion(), -1.0f);
+ }
+
+ QQmlDebugTestClient client("tst_QQmlDebugClient::state()", m_conn);
+ QCOMPARE(client.state(), QQmlDebugClient::Unavailable);
+
+ {
+ QQmlDebugTestService service("tst_QQmlDebugClient::state()", 2);
+ QTRY_COMPARE(client.state(), QQmlDebugClient::Enabled);
+ QCOMPARE(client.serviceVersion(), 2.0f);
+ }
+
+ QTRY_COMPARE(client.state(), QQmlDebugClient::Unavailable);
+
+ // duplicate plugin name
+ QTest::ignoreMessage(QtWarningMsg, "QQmlDebugClient: Conflicting plugin name \"tst_QQmlDebugClient::state()\" ");
+ QQmlDebugClient client2("tst_QQmlDebugClient::state()", m_conn);
+ QCOMPARE(client2.state(), QQmlDebugClient::NotConnected);
+
+ QQmlDebugClient client3("tst_QQmlDebugClient::state3()", 0);
+ QCOMPARE(client3.state(), QQmlDebugClient::NotConnected);
+}
+
+void tst_QQmlDebugClient::sendMessage()
+{
+ QQmlDebugTestService service("tst_QQmlDebugClient::sendMessage()");
+ QQmlDebugTestClient client("tst_QQmlDebugClient::sendMessage()", m_conn);
+
+ QByteArray msg = "hello!";
+
+ QTRY_COMPARE(client.state(), QQmlDebugClient::Enabled);
+
+ client.sendMessage(msg);
+ QByteArray resp = client.waitForResponse();
+ QCOMPARE(resp, msg);
+}
+
+void tst_QQmlDebugClient::parallelConnect()
+{
+ QQmlDebugConnection connection2;
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlDebugServer: Another client is already connected");
+ // will connect & immediately disconnect
+ connection2.connectToHost("127.0.0.1", PORT);
+ QVERIFY(connection2.waitForConnected());
+ QTRY_COMPARE(connection2.state(), QAbstractSocket::UnconnectedState);
+ QVERIFY(m_conn->isConnected());
+}
+
+void tst_QQmlDebugClient::sequentialConnect()
+{
+ QQmlDebugConnection connection2;
+ QQmlDebugTestClient client2("tst_QQmlDebugClient::handshake()", &connection2);
+ QQmlDebugTestService service("tst_QQmlDebugClient::handshake()");
+
+ m_conn->close();
+ QVERIFY(!m_conn->isConnected());
+ QCOMPARE(m_conn->state(), QAbstractSocket::UnconnectedState);
+
+ // Make sure that the disconnect is actually delivered to the server
+ QTest::qWait(100);
+
+ connection2.connectToHost("127.0.0.1", PORT);
+ QTest::ignoreMessage(QtWarningMsg, "QQmlDebugServer: Connection established");
+ QVERIFY(connection2.waitForConnected());
+ QVERIFY(connection2.isConnected());
+ QTRY_VERIFY(client2.state() == QQmlDebugClient::Enabled);
+}
+
+int main(int argc, char *argv[])
+{
+ int _argc = argc + 1;
+ char **_argv = new char*[_argc];
+ for (int i = 0; i < argc; ++i)
+ _argv[i] = argv[i];
+ char arg[] = "-qmljsdebugger=port:" STR_PORT;
+ _argv[_argc - 1] = arg;
+
+ QGuiApplication app(_argc, _argv);
+ tst_QQmlDebugClient tc;
+ return QTest::qExec(&tc, _argc, _argv);
+ delete _argv;
+}
+
+#include "tst_qqmldebugclient.moc"
+
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml b/tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml
new file mode 100644
index 0000000000..1f0f9e22c9
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//DO NOT CHANGE
+
+Item {
+ Component.onCompleted: {
+ //Comment
+
+ var b = 6;
+ }
+}
+
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml b/tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml
new file mode 100644
index 0000000000..fd81b3f805
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//DO NOT CHANGE
+
+Item {
+ id: item
+ property int d: 0
+
+ function doSomething() {
+ var a = 5;
+ var b = 6;
+ }
+
+ Timer {
+ id: timer; interval: 1; running: true; repeat: true
+ onTriggered: doSomething();
+ }
+
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/condition.qml b/tests/auto/qml/debugger/qqmldebugjs/data/condition.qml
new file mode 100644
index 0000000000..ad4144be11
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/condition.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//DO NOT CHANGE
+
+Item {
+ id: item
+ property int a: 0
+ Timer {
+ id: timer; interval: 1; repeat: true; running: true
+ onTriggered: a++
+ }
+}
+
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml b/tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml
new file mode 100644
index 0000000000..993f33a661
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//DO NOT CHANGE
+Item {
+ Component.onCompleted: {
+ var component = Qt.createComponent("oncompleted.qml")
+ if (component.status === Component.Ready) {
+ component.createObject();
+ }
+ }
+}
+
+
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/exception.qml b/tests/auto/qml/debugger/qqmldebugjs/data/exception.qml
new file mode 100644
index 0000000000..b491087a02
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/exception.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//DO NOT CHANGE
+
+Item {
+ id: root
+
+ Component.onCompleted: dummy()
+}
+
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml b/tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml
new file mode 100644
index 0000000000..4fff66a325
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import "test.js" as Script
+
+//DO NOT CHANGE
+Item {
+ Component.onCompleted: Script.printMessage("onCompleted");
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml
new file mode 100644
index 0000000000..e03ba2ca79
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//DO NOT CHANGE
+
+Item {
+ Component.onCompleted: {
+ console.log("Hello world")
+ }
+ id: root
+ property int a: 10
+}
+
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml b/tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml
new file mode 100644
index 0000000000..690f9fd446
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//DO NOT CHANGE
+
+Item {
+ id: item
+ property int d: 0
+
+ function doSomething() {
+ var a = 5;
+ var b = 6;
+ }
+
+ Component.onCompleted: doSomething()
+
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/test.js b/tests/auto/qml/debugger/qqmldebugjs/data/test.js
new file mode 100644
index 0000000000..7de138bdf6
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/test.js
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+function printMessage(msg)
+{
+ print(msg);
+}
+
+function add(a,b)
+{
+ //This is a comment and below is an empty line
+
+ var out = a + b;
+ return out;
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/test.qml b/tests/auto/qml/debugger/qqmldebugjs/data/test.qml
new file mode 100644
index 0000000000..200f26b1c3
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/test.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//DO NOT CHANGE
+
+Item {
+ Component.onCompleted: {
+ var a = [1, 2]
+ var b = {a: "hello", d: 1 }
+ var c
+ var d = 12
+ }
+}
+
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/timer.qml b/tests/auto/qml/debugger/qqmldebugjs/data/timer.qml
new file mode 100644
index 0000000000..d9440415d2
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/timer.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+//DO NOT CHANGE
+Item {
+ Timer {
+ id: timer; interval: 1; running: true; repeat: true; triggeredOnStart: true
+ onTriggered: {
+ console.log("timer");
+ }
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro
new file mode 100644
index 0000000000..72b0e77f71
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro
@@ -0,0 +1,29 @@
+CONFIG += testcase
+TARGET = tst_qqmldebugjs
+QT += qml-private testlib
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/debugutil_p.h
+SOURCES += tst_qqmldebugjs.cpp \
+ ../shared/debugutil.cpp
+
+INCLUDEPATH += ../shared
+
+include (../../../shared/util.pri)
+
+testDataFiles.files = data
+testDataFiles.path = .
+DEPLOYMENT += testDataFiles
+
+CONFIG += parallel_test
+
+OTHER_FILES += data/test.qml data/test.js \
+ data/timer.qml \
+ data/exception.qml \
+ data/oncompleted.qml \
+ data/loadjsfile.qml \
+ data/condition.qml \
+ data/changeBreakpoint.qml \
+ data/stepAction.qml \
+ data/breakpointRelocation.qml \
+ data/createComponent.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
new file mode 100644
index 0000000000..9a8b00bb6c
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -0,0 +1,1790 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QtCore/QProcess>
+#include <QtCore/QTimer>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QMutex>
+#include <QtCore/QLibraryInfo>
+#include <QtQml/private/qqmldebugclient_p.h>
+#include <QtQml/QJSEngine>
+
+//QQmlDebugTest
+#include "../shared/debugutil_p.h"
+#include "../../../shared/util.h"
+
+const char *V8REQUEST = "v8request";
+const char *V8MESSAGE = "v8message";
+const char *SEQ = "seq";
+const char *TYPE = "type";
+const char *COMMAND = "command";
+const char *ARGUMENTS = "arguments";
+const char *STEPACTION = "stepaction";
+const char *STEPCOUNT = "stepcount";
+const char *EXPRESSION = "expression";
+const char *FRAME = "frame";
+const char *GLOBAL = "global";
+const char *DISABLEBREAK = "disable_break";
+const char *HANDLES = "handles";
+const char *INCLUDESOURCE = "includeSource";
+const char *FROMFRAME = "fromFrame";
+const char *TOFRAME = "toFrame";
+const char *BOTTOM = "bottom";
+const char *NUMBER = "number";
+const char *FRAMENUMBER = "frameNumber";
+const char *TYPES = "types";
+const char *IDS = "ids";
+const char *FILTER = "filter";
+const char *FROMLINE = "fromLine";
+const char *TOLINE = "toLine";
+const char *TARGET = "target";
+const char *LINE = "line";
+const char *COLUMN = "column";
+const char *ENABLED = "enabled";
+const char *CONDITION = "condition";
+const char *IGNORECOUNT = "ignoreCount";
+const char *BREAKPOINT = "breakpoint";
+const char *FLAGS = "flags";
+
+const char *CONTINEDEBUGGING = "continue";
+const char *EVALUATE = "evaluate";
+const char *LOOKUP = "lookup";
+const char *BACKTRACE = "backtrace";
+const char *SCOPE = "scope";
+const char *SCOPES = "scopes";
+const char *SCRIPTS = "scripts";
+const char *SOURCE = "source";
+const char *SETBREAKPOINT = "setbreakpoint";
+const char *CHANGEBREAKPOINT = "changebreakpoint";
+const char *CLEARBREAKPOINT = "clearbreakpoint";
+const char *SETEXCEPTIONBREAK = "setexceptionbreak";
+const char *V8FLAGS = "v8flags";
+const char *VERSION = "version";
+const char *DISCONNECT = "disconnect";
+const char *LISTBREAKPOINTS = "listbreakpoints";
+const char *GARBAGECOLLECTOR = "gc";
+//const char *PROFILE = "profile";
+
+const char *CONNECT = "connect";
+const char *INTERRUPT = "interrupt";
+const char *BREAKAFTERCOMPILE = "breakaftercompile";
+
+const char *REQUEST = "request";
+const char *IN = "in";
+const char *NEXT = "next";
+const char *OUT = "out";
+
+const char *FUNCTION = "function";
+const char *SCRIPT = "script";
+const char *SCRIPTREGEXP = "scriptRegExp";
+const char *EVENT = "event";
+
+const char *ALL = "all";
+const char *UNCAUGHT = "uncaught";
+
+//const char *PAUSE = "pause";
+//const char *RESUME = "resume";
+
+const char *BLOCKMODE = "-qmljsdebugger=port:3771,block";
+const char *NORMALMODE = "-qmljsdebugger=port:3771";
+const char *TEST_QMLFILE = "test.qml";
+const char *TEST_JSFILE = "test.js";
+const char *TIMER_QMLFILE = "timer.qml";
+const char *LOADJSFILE_QMLFILE = "loadjsfile.qml";
+const char *EXCEPTION_QMLFILE = "exception.qml";
+const char *ONCOMPLETED_QMLFILE = "oncompleted.qml";
+const char *CREATECOMPONENT_QMLFILE = "createComponent.qml";
+const char *CONDITION_QMLFILE = "condition.qml";
+const char *CHANGEBREAKPOINT_QMLFILE = "changeBreakpoint.qml";
+const char *STEPACTION_QMLFILE = "stepAction.qml";
+const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml";
+
+#define VARIANTMAPINIT \
+ QString obj("{}"); \
+ QJSValue jsonVal = parser.call(QJSValueList() << obj); \
+ jsonVal.setProperty(SEQ,QJSValue(seq++)); \
+ jsonVal.setProperty(TYPE,REQUEST);
+
+
+#undef QVERIFY
+#define QVERIFY(statement) \
+do {\
+ if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) {\
+ if (QTest::currentTestFailed()) \
+ qDebug().nospace() << "\nDEBUGGEE OUTPUT:\n" << process->output();\
+ return;\
+ }\
+} while (0)
+
+
+class QJSDebugClient;
+
+class tst_QQmlDebugJS : public QQmlDataTest
+{
+ Q_OBJECT
+
+ bool init(const QString &qmlFile = QString(TEST_QMLFILE), bool blockMode = true);
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void cleanup();
+
+ void connect();
+ void interrupt();
+ void breakAfterCompile();
+ void getVersion();
+ void getVersionWhenAttaching();
+
+ void applyV8Flags();
+
+ void disconnect();
+
+ void gc();
+
+ void listBreakpoints();
+
+ void setBreakpointInScriptOnCompleted();
+ void setBreakpointInScriptOnComponentCreated();
+ void setBreakpointInScriptOnTimerCallback();
+ void setBreakpointInScriptInDifferentFile();
+ void setBreakpointInScriptOnComment();
+ void setBreakpointInScriptOnEmptyLine();
+ void setBreakpointInScriptWithCondition();
+ //void setBreakpointInFunction(); //NOT SUPPORTED
+ void setBreakpointOnEvent();
+ void setBreakpointWhenAttaching();
+
+ void changeBreakpoint();
+ void changeBreakpointOnCondition();
+
+ void clearBreakpoint();
+
+ void setExceptionBreak();
+
+ void stepNext();
+ void stepNextWithCount();
+ void stepIn();
+ void stepOut();
+ void continueDebugging();
+
+ void backtrace();
+
+ void getFrameDetails();
+
+ void getScopeDetails();
+
+ void evaluateInGlobalScope();
+ void evaluateInLocalScope();
+
+ void getScopes();
+
+ void getScripts();
+
+ void getSource();
+
+ // void profile(); //NOT SUPPORTED
+
+ // void verifyQMLOptimizerDisabled();
+
+private:
+ QQmlDebugProcess *process;
+ QJSDebugClient *client;
+ QQmlDebugConnection *connection;
+ QTime t;
+};
+
+class QJSDebugClient : public QQmlDebugClient
+{
+ Q_OBJECT
+public:
+ enum StepAction
+ {
+ Continue,
+ In,
+ Out,
+ Next
+ };
+
+ enum Exception
+ {
+ All,
+ Uncaught
+ };
+
+// enum ProfileCommand
+// {
+// Pause,
+// Resume
+// };
+
+ QJSDebugClient(QQmlDebugConnection *connection)
+ : QQmlDebugClient(QLatin1String("V8Debugger"), connection),
+ seq(0)
+ {
+ parser = jsEngine.evaluate(QLatin1String("JSON.parse"));
+ stringify = jsEngine.evaluate(QLatin1String("JSON.stringify"));
+ }
+
+ void connect();
+ void interrupt();
+ void breakAfterCompile(bool enabled);
+
+ void continueDebugging(StepAction stepAction, int stepCount = 1);
+ void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
+ void lookup(QList<int> handles, bool includeSource = false);
+ void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
+ void frame(int number = -1);
+ void scope(int number = -1, int frameNumber = -1);
+ void scopes(int frameNumber = -1);
+ void scripts(int types = 4, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
+ void source(int frame = -1, int fromLine = -1, int toLine = -1);
+ void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = true, QString condition = QString(), int ignoreCount = -1);
+ void changeBreakpoint(int breakpoint, bool enabled = true, QString condition = QString(), int ignoreCount = -1);
+ void clearBreakpoint(int breakpoint);
+ void setExceptionBreak(Exception type, bool enabled = false);
+ void v8flags(QString flags);
+ void version();
+ //void profile(ProfileCommand command); //NOT SUPPORTED
+ void disconnect();
+ void gc();
+ void listBreakpoints();
+
+protected:
+ //inherited from QQmlDebugClient
+ void stateChanged(State state);
+ void messageReceived(const QByteArray &data);
+
+signals:
+ void enabled();
+ void connected();
+ void interruptRequested();
+ void breakAfterCompileRequested();
+ void result();
+ void stopped();
+
+private:
+ void sendMessage(const QByteArray &);
+ void flushSendBuffer();
+ QByteArray packMessage(const QByteArray &type, const QByteArray &message = QByteArray());
+
+private:
+ QJSEngine jsEngine;
+ int seq;
+
+ QList<QByteArray> sendBuffer;
+public:
+ QJSValue parser;
+ QJSValue stringify;
+ QByteArray response;
+
+};
+
+void QJSDebugClient::connect()
+{
+ sendMessage(packMessage(CONNECT));
+}
+
+void QJSDebugClient::interrupt()
+{
+ sendMessage(packMessage(INTERRUPT));
+}
+
+void QJSDebugClient::breakAfterCompile(bool enabled)
+{
+ QByteArray request;
+ QDataStream rs(&request, QIODevice::WriteOnly);
+ rs << enabled;
+ sendMessage(packMessage(BREAKAFTERCOMPILE, request));
+}
+
+void QJSDebugClient::continueDebugging(StepAction action, int count)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "continue",
+ // "arguments" : { "stepaction" : <"in", "next" or "out">,
+ // "stepcount" : <number of steps (default 1)>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(CONTINEDEBUGGING)));
+
+ if (action != Continue) {
+ QJSValue args = parser.call(QJSValueList() << obj);
+ switch (action) {
+ case In: args.setProperty(QLatin1String(STEPACTION),QJSValue(QLatin1String(IN)));
+ break;
+ case Out: args.setProperty(QLatin1String(STEPACTION),QJSValue(QLatin1String(OUT)));
+ break;
+ case Next: args.setProperty(QLatin1String(STEPACTION),QJSValue(QLatin1String(NEXT)));
+ break;
+ default:break;
+ }
+ if (!args.isUndefined()) {
+ if (count != 1)
+ args.setProperty(QLatin1String(STEPCOUNT),QJSValue(count));
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+ }
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::evaluate(QString expr, bool global, bool disableBreak, int frame, const QVariantMap &/*addContext*/)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "evaluate",
+ // "arguments" : { "expression" : <expression to evaluate>,
+ // "frame" : <number>,
+ // "global" : <boolean>,
+ // "disable_break" : <boolean>,
+ // "additional_context" : [
+ // { "name" : <name1>, "handle" : <handle1> },
+ // { "name" : <name2>, "handle" : <handle2> },
+ // ...
+ // ]
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(EVALUATE)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+ args.setProperty(QLatin1String(EXPRESSION),QJSValue(expr));
+
+ if (frame != -1)
+ args.setProperty(QLatin1String(FRAME),QJSValue(frame));
+
+ if (global)
+ args.setProperty(QLatin1String(GLOBAL),QJSValue(global));
+
+ if (disableBreak)
+ args.setProperty(QLatin1String(DISABLEBREAK),QJSValue(disableBreak));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::lookup(QList<int> handles, bool includeSource)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "lookup",
+ // "arguments" : { "handles" : <array of handles>,
+ // "includeSource" : <boolean indicating whether the source will be included when script objects are returned>,
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(LOOKUP)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+
+ QString arr("[]");
+ QJSValue array = parser.call(QJSValueList() << arr);
+ int index = 0;
+ foreach (int handle, handles) {
+ array.setProperty(index++,QJSValue(handle));
+ }
+ args.setProperty(QLatin1String(HANDLES),array);
+
+ if (includeSource)
+ args.setProperty(QLatin1String(INCLUDESOURCE),QJSValue(includeSource));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::backtrace(int fromFrame, int toFrame, bool bottom)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "backtrace",
+ // "arguments" : { "fromFrame" : <number>
+ // "toFrame" : <number>
+ // "bottom" : <boolean, set to true if the bottom of the stack is requested>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(BACKTRACE)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+
+ if (fromFrame != -1)
+ args.setProperty(QLatin1String(FROMFRAME),QJSValue(fromFrame));
+
+ if (toFrame != -1)
+ args.setProperty(QLatin1String(TOFRAME),QJSValue(toFrame));
+
+ if (bottom)
+ args.setProperty(QLatin1String(BOTTOM),QJSValue(bottom));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::frame(int number)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "frame",
+ // "arguments" : { "number" : <frame number>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(FRAME)));
+
+ if (number != -1) {
+ QJSValue args = parser.call(QJSValueList() << obj);
+ args.setProperty(QLatin1String(NUMBER),QJSValue(number));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::scope(int number, int frameNumber)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "scope",
+ // "arguments" : { "number" : <scope number>
+ // "frameNumber" : <frame number, optional uses selected frame if missing>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SCOPE)));
+
+ if (number != -1) {
+ QJSValue args = parser.call(QJSValueList() << obj);
+ args.setProperty(QLatin1String(NUMBER),QJSValue(number));
+
+ if (frameNumber != -1)
+ args.setProperty(QLatin1String(FRAMENUMBER),QJSValue(frameNumber));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::scopes(int frameNumber)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "scopes",
+ // "arguments" : { "frameNumber" : <frame number, optional uses selected frame if missing>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SCOPES)));
+
+ if (frameNumber != -1) {
+ QJSValue args = parser.call(QJSValueList() << obj);
+ args.setProperty(QLatin1String(FRAMENUMBER),QJSValue(frameNumber));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::scripts(int types, QList<int> ids, bool includeSource, QVariant /*filter*/)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "scripts",
+ // "arguments" : { "types" : <types of scripts to retrieve
+ // set bit 0 for native scripts
+ // set bit 1 for extension scripts
+ // set bit 2 for normal scripts
+ // (default is 4 for normal scripts)>
+ // "ids" : <array of id's of scripts to return. If this is not specified all scripts are requrned>
+ // "includeSource" : <boolean indicating whether the source code should be included for the scripts returned>
+ // "filter" : <string or number: filter string or script id.
+ // If a number is specified, then only the script with the same number as its script id will be retrieved.
+ // If a string is specified, then only scripts whose names contain the filter string will be retrieved.>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SCRIPTS)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+ args.setProperty(QLatin1String(TYPES),QJSValue(types));
+
+ if (ids.count()) {
+ QString arr("[]");
+ QJSValue array = parser.call(QJSValueList() << arr);
+ int index = 0;
+ foreach (int id, ids) {
+ array.setProperty(index++,QJSValue(id));
+ }
+ args.setProperty(QLatin1String(IDS),array);
+ }
+
+ if (includeSource)
+ args.setProperty(QLatin1String(INCLUDESOURCE),QJSValue(includeSource));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::source(int frame, int fromLine, int toLine)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "source",
+ // "arguments" : { "frame" : <frame number (default selected frame)>
+ // "fromLine" : <from line within the source default is line 0>
+ // "toLine" : <to line within the source this line is not included in
+ // the result default is the number of lines in the script>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SOURCE)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+
+ if (frame != -1)
+ args.setProperty(QLatin1String(FRAME),QJSValue(frame));
+
+ if (fromLine != -1)
+ args.setProperty(QLatin1String(FROMLINE),QJSValue(fromLine));
+
+ if (toLine != -1)
+ args.setProperty(QLatin1String(TOLINE),QJSValue(toLine));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::setBreakpoint(QString type, QString target, int line, int column, bool enabled, QString condition, int ignoreCount)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "setbreakpoint",
+ // "arguments" : { "type" : <"function" or "script" or "scriptId" or "scriptRegExp">
+ // "target" : <function expression or script identification>
+ // "line" : <line in script or function>
+ // "column" : <character position within the line>
+ // "enabled" : <initial enabled state. True or false, default is true>
+ // "condition" : <string with break point condition>
+ // "ignoreCount" : <number specifying the number of break point hits to ignore, default value is 0>
+ // }
+ // }
+
+ if (type == QLatin1String(EVENT)) {
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ rs << target.toUtf8() << enabled;
+ sendMessage(packMessage(QByteArray("breakonsignal"), reply));
+
+ } else {
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SETBREAKPOINT)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+
+ args.setProperty(QLatin1String(TYPE),QJSValue(type));
+ args.setProperty(QLatin1String(TARGET),QJSValue(target));
+
+ if (line != -1)
+ args.setProperty(QLatin1String(LINE),QJSValue(line));
+
+ if (column != -1)
+ args.setProperty(QLatin1String(COLUMN),QJSValue(column));
+
+ args.setProperty(QLatin1String(ENABLED),QJSValue(enabled));
+
+ if (!condition.isEmpty())
+ args.setProperty(QLatin1String(CONDITION),QJSValue(condition));
+
+ if (ignoreCount != -1)
+ args.setProperty(QLatin1String(IGNORECOUNT),QJSValue(ignoreCount));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+ }
+}
+
+void QJSDebugClient::changeBreakpoint(int breakpoint, bool enabled, QString condition, int ignoreCount)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "changebreakpoint",
+ // "arguments" : { "breakpoint" : <number of the break point to clear>
+ // "enabled" : <initial enabled state. True or false, default is true>
+ // "condition" : <string with break point condition>
+ // "ignoreCount" : <number specifying the number of break point hits }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(CHANGEBREAKPOINT)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+
+ args.setProperty(QLatin1String(BREAKPOINT),QJSValue(breakpoint));
+
+ args.setProperty(QLatin1String(ENABLED),QJSValue(enabled));
+
+ if (!condition.isEmpty())
+ args.setProperty(QLatin1String(CONDITION),QJSValue(condition));
+
+ if (ignoreCount != -1)
+ args.setProperty(QLatin1String(IGNORECOUNT),QJSValue(ignoreCount));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::clearBreakpoint(int breakpoint)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "clearbreakpoint",
+ // "arguments" : { "breakpoint" : <number of the break point to clear>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(CLEARBREAKPOINT)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+
+ args.setProperty(QLatin1String(BREAKPOINT),QJSValue(breakpoint));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::setExceptionBreak(Exception type, bool enabled)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "setexceptionbreak",
+ // "arguments" : { "type" : <string: "all", or "uncaught">,
+ // "enabled" : <optional bool: enables the break type if true>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SETEXCEPTIONBREAK)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+
+ if (type == All)
+ args.setProperty(QLatin1String(TYPE),QJSValue(QLatin1String(ALL)));
+ else if (type == Uncaught)
+ args.setProperty(QLatin1String(TYPE),QJSValue(QLatin1String(UNCAUGHT)));
+
+ if (enabled)
+ args.setProperty(QLatin1String(ENABLED),QJSValue(enabled));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::v8flags(QString flags)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "v8flags",
+ // "arguments" : { "flags" : <string: a sequence of v8 flags just like those used on the command line>
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(V8FLAGS)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+
+ args.setProperty(QLatin1String(FLAGS),QJSValue(flags));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::version()
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "version",
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(VERSION)));
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+//void QJSDebugClient::profile(ProfileCommand command)
+//{
+//// { "seq" : <number>,
+//// "type" : "request",
+//// "command" : "profile",
+//// "arguments" : { "command" : "resume" or "pause" }
+//// }
+// VARIANTMAPINIT;
+// jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(PROFILE)));
+
+// QJSValue args = parser.call(QJSValueList() << obj);
+
+// if (command == Resume)
+// args.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(RESUME)));
+// else
+// args.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(PAUSE)));
+
+// args.setProperty(QLatin1String("modules"),QJSValue(1));
+// if (!args.isUndefined()) {
+// jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+// }
+
+// QJSValue json = stringify.call(QJSValueList() << jsonVal);
+// sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+//}
+
+void QJSDebugClient::disconnect()
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "disconnect",
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(DISCONNECT)));
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(DISCONNECT, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::gc()
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "gc",
+ // "arguments" : { "type" : <string: "all">,
+ // }
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(GARBAGECOLLECTOR)));
+
+ QJSValue args = parser.call(QJSValueList() << obj);
+
+ args.setProperty(QLatin1String(TYPE),QJSValue(QLatin1String(ALL)));
+
+ if (!args.isUndefined()) {
+ jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
+ }
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::listBreakpoints()
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "listbreakpoints",
+ // }
+ VARIANTMAPINIT;
+ jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(LISTBREAKPOINTS)));
+
+ QJSValue json = stringify.call(QJSValueList() << jsonVal);
+ sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
+}
+
+void QJSDebugClient::stateChanged(State state)
+{
+ if (state == Enabled) {
+ flushSendBuffer();
+ emit enabled();
+ }
+}
+
+void QJSDebugClient::messageReceived(const QByteArray &data)
+{
+ QDataStream ds(data);
+ QByteArray command;
+ ds >> command;
+
+ if (command == "V8DEBUG") {
+ QByteArray type;
+ ds >> type >> response;
+
+ if (type == CONNECT) {
+ emit connected();
+
+ } else if (type == INTERRUPT) {
+ emit interruptRequested();
+
+ } else if (type == V8MESSAGE) {
+ QString jsonString(response);
+ QVariantMap value = parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+ QString type = value.value("type").toString();
+
+ if (type == "response") {
+
+ if (!value.value("success").toBool()) {
+// qDebug() << "Error: The test case will fail since no signal is emitted";
+ return;
+ }
+
+ QString debugCommand(value.value("command").toString());
+ if (debugCommand == "backtrace" ||
+ debugCommand == "lookup" ||
+ debugCommand == "setbreakpoint" ||
+ debugCommand == "evaluate" ||
+ debugCommand == "listbreakpoints" ||
+ debugCommand == "version" ||
+ debugCommand == "v8flags" ||
+ debugCommand == "disconnect" ||
+ debugCommand == "gc" ||
+ debugCommand == "changebreakpoint" ||
+ debugCommand == "clearbreakpoint" ||
+ debugCommand == "frame" ||
+ debugCommand == "scope" ||
+ debugCommand == "scopes" ||
+ debugCommand == "scripts" ||
+ debugCommand == "source" ||
+ debugCommand == "setexceptionbreak" /*||
+ debugCommand == "profile"*/) {
+ emit result();
+
+ } else {
+ // DO NOTHING
+ }
+
+ } else if (type == QLatin1String(EVENT)) {
+ QString event(value.value(QLatin1String(EVENT)).toString());
+
+ if (event == "break" ||
+ event == "exception")
+ emit stopped();
+ }
+
+ } else if (type == BREAKAFTERCOMPILE) {
+ emit breakAfterCompileRequested();
+
+ }
+ }
+}
+
+void QJSDebugClient::sendMessage(const QByteArray &msg)
+{
+ if (state() == Enabled) {
+ QQmlDebugClient::sendMessage(msg);
+ } else {
+ sendBuffer.append(msg);
+ }
+}
+
+void QJSDebugClient::flushSendBuffer()
+{
+ foreach (const QByteArray &msg, sendBuffer)
+ QQmlDebugClient::sendMessage(msg);
+ sendBuffer.clear();
+}
+
+QByteArray QJSDebugClient::packMessage(const QByteArray &type, const QByteArray &message)
+{
+ QByteArray reply;
+ QDataStream rs(&reply, QIODevice::WriteOnly);
+ QByteArray cmd = "V8DEBUG";
+ rs << cmd << type << message;
+ return reply;
+}
+
+void tst_QQmlDebugJS::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ t.start();
+ process = 0;
+ client = 0;
+ connection = 0;
+}
+
+void tst_QQmlDebugJS::cleanupTestCase()
+{
+ if (process) {
+ process->stop();
+ delete process;
+ }
+
+ if (client)
+ delete client;
+
+ if (connection)
+ delete connection;
+
+// qDebug() << "Time Elapsed:" << t.elapsed();
+}
+
+bool tst_QQmlDebugJS::init(const QString &qmlFile, bool blockMode)
+{
+ connection = new QQmlDebugConnection();
+ process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene");
+ client = new QJSDebugClient(connection);
+
+ QStringList systemEnvironment = QProcess::systemEnvironment();
+ systemEnvironment << "QML_DISABLE_OPTIMIZER=1";
+ process->setEnvironment(systemEnvironment);
+ if (blockMode)
+ process->start(QStringList() << QLatin1String(BLOCKMODE) << testFile(qmlFile));
+ else
+ process->start(QStringList() << QLatin1String(NORMALMODE) << testFile(qmlFile));
+
+ if (!process->waitForSessionStart()) {
+ return false;
+ }
+
+ connection->connectToHost("127.0.0.1", 3771);
+ if (!connection->waitForConnected())
+ return false;
+
+ return QQmlDebugTest::waitForSignal(client, SIGNAL(enabled()));
+}
+
+void tst_QQmlDebugJS::cleanup()
+{
+ if (process) {
+ process->stop();
+ delete process;
+ }
+
+ if (client)
+ delete client;
+
+ if (connection)
+ delete connection;
+
+ process = 0;
+ client = 0;
+ connection = 0;
+}
+
+void tst_QQmlDebugJS::connect()
+{
+ //void connect()
+
+ QVERIFY(init());
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
+}
+
+void tst_QQmlDebugJS::interrupt()
+{
+ //void connect()
+
+ QVERIFY(init());
+ client->connect();
+
+ client->interrupt();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(interruptRequested())));
+}
+
+void tst_QQmlDebugJS::breakAfterCompile()
+{
+ //void breakAfterCompile(bool enabled)
+
+ QVERIFY(init());
+ client->breakAfterCompile(true);
+ client->connect();
+
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(breakAfterCompileRequested())));
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+}
+
+void tst_QQmlDebugJS::getVersion()
+{
+ //void version()
+
+ QVERIFY(init());
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
+
+ client->version();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getVersionWhenAttaching()
+{
+ //void version()
+
+ QVERIFY(init(QLatin1String(TIMER_QMLFILE), false));
+ client->connect();
+
+ client->version();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::applyV8Flags()
+{
+ //void v8flags(QString flags)
+
+ QVERIFY(init());
+ client->connect();
+
+ client->v8flags(QString());
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::disconnect()
+{
+ //void disconnect()
+
+ QVERIFY(init());
+ client->connect();
+
+ client->disconnect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::gc()
+{
+ //void gc()
+
+ QVERIFY(init());
+ client->connect();
+
+ client->gc();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::listBreakpoints()
+{
+ //void listBreakpoints()
+
+ int sourceLine1 = 47;
+ int sourceLine2 = 48;
+ int sourceLine3 = 49;
+
+ QVERIFY(init());
+ client->connect();
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(TEST_QMLFILE), sourceLine1, -1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(TEST_QMLFILE), sourceLine2, -1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(TEST_QMLFILE), sourceLine3, -1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+ client->listBreakpoints();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QList<QVariant> breakpoints = value.value("body").toMap().value("breakpoints").toList();
+
+ QCOMPARE(breakpoints.count(), 3);
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnCompleted()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+ int sourceLine = 47;
+ QVERIFY(init(ONCOMPLETED_QMLFILE));
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(ONCOMPLETED_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnComponentCreated()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+ int sourceLine = 47;
+ QVERIFY(init(CREATECOMPONENT_QMLFILE));
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(ONCOMPLETED_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnTimerCallback()
+{
+ int sourceLine = 48;
+ QVERIFY(init(TIMER_QMLFILE));
+
+ client->connect();
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(TIMER_QMLFILE), sourceLine, -1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(TIMER_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptInDifferentFile()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+ int sourceLine = 43;
+ QVERIFY(init(LOADJSFILE_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(TEST_JSFILE), sourceLine, -1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(TEST_JSFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnComment()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+ int sourceLine = 47;
+ int actualLine = 49;
+ QVERIFY(init(BREAKPOINTRELOCATION_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnEmptyLine()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+ int sourceLine = 48;
+ int actualLine = 49;
+ QVERIFY(init(BREAKPOINTRELOCATION_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+ int out = 10;
+ int sourceLine = 50;
+ QVERIFY(init(CONDITION_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CONDITION_QMLFILE), sourceLine, 1, true, QLatin1String("a > 10"));
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ //Get the frame index
+ QString jsonString = client->response;
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ int frameIndex = body.value("index").toInt();
+
+ //Verify the value of 'result'
+ client->evaluate(QLatin1String("a"),frameIndex);
+
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ jsonString = client->response;
+ value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ body = value.value("body").toMap();
+
+ QVERIFY(body.value("value").toInt() > out);
+}
+
+void tst_QQmlDebugJS::setBreakpointWhenAttaching()
+{
+ int sourceLine = 49;
+ QVERIFY(init(QLatin1String(TIMER_QMLFILE), false));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(TIMER_QMLFILE), sourceLine);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+}
+
+//void tst_QQmlDebugJS::setBreakpointInFunction()
+//{
+// //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+// int actualLine = 31;
+
+// client->connect();
+// client->setBreakpoint(QLatin1String(FUNCTION), QLatin1String("doSomethingElse"), -1, -1, true);
+
+// QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+// QString jsonString(client->response);
+// QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+// QVariantMap body = value.value("body").toMap();
+
+// QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+// QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(QMLFILE));
+//}
+
+void tst_QQmlDebugJS::setBreakpointOnEvent()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+ QVERIFY(init(TIMER_QMLFILE));
+
+ client->connect();
+
+ client->setBreakpoint(QLatin1String(EVENT), QLatin1String("triggered"), -1, -1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(TIMER_QMLFILE));
+}
+
+
+void tst_QQmlDebugJS::changeBreakpoint()
+{
+ //void changeBreakpoint(int breakpoint, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+ int sourceLine1 = 50;
+ int sourceLine2 = 51;
+ QVERIFY(init(CHANGEBREAKPOINT_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true);
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true);
+
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ //Will hit 1st brakpoint, change this breakpoint enable = false
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+ QList<QVariant> breakpointsHit = body.value("breakpoints").toList();
+
+ int breakpoint = breakpointsHit.at(0).toInt();
+ client->changeBreakpoint(breakpoint,false);
+
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ //Continue with debugging
+ client->continueDebugging(QJSDebugClient::Continue);
+ //Hit 2nd breakpoint
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ //Continue with debugging
+ client->continueDebugging(QJSDebugClient::Continue);
+ //Should stop at 2nd breakpoint
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ jsonString = client->response;
+ value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
+}
+
+void tst_QQmlDebugJS::changeBreakpointOnCondition()
+{
+ //void changeBreakpoint(int breakpoint, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+
+ int sourceLine1 = 50;
+ int sourceLine2 = 51;
+
+ QVERIFY(init(CHANGEBREAKPOINT_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true);
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true);
+
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ //Will hit 1st brakpoint, change this breakpoint enable = false
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+ QList<QVariant> breakpointsHit = body.value("breakpoints").toList();
+
+ int breakpoint = breakpointsHit.at(0).toInt();
+ client->changeBreakpoint(breakpoint, false, QLatin1String("d == 0"));
+
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ //Continue with debugging
+ client->continueDebugging(QJSDebugClient::Continue);
+ //Hit 2nd breakpoint
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ //Continue with debugging
+ client->continueDebugging(QJSDebugClient::Continue);
+ //Should stop at 2nd breakpoint
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ jsonString = client->response;
+ value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
+
+}
+
+void tst_QQmlDebugJS::clearBreakpoint()
+{
+ //void clearBreakpoint(int breakpoint);
+
+ int sourceLine1 = 50;
+ int sourceLine2 = 51;
+ QVERIFY(init(CHANGEBREAKPOINT_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true);
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true);
+
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ //Will hit 1st brakpoint, change this breakpoint enable = false
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+ QList<QVariant> breakpointsHit = body.value("breakpoints").toList();
+
+ int breakpoint = breakpointsHit.at(0).toInt();
+ client->clearBreakpoint(breakpoint);
+
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ //Continue with debugging
+ client->continueDebugging(QJSDebugClient::Continue);
+ //Hit 2nd breakpoint
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ //Continue with debugging
+ client->continueDebugging(QJSDebugClient::Continue);
+ //Should stop at 2nd breakpoint
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ jsonString = client->response;
+ value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
+}
+
+void tst_QQmlDebugJS::setExceptionBreak()
+{
+ //void setExceptionBreak(QString type, bool enabled = false);
+
+ QVERIFY(init(EXCEPTION_QMLFILE));
+ client->setExceptionBreak(QJSDebugClient::All,true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+}
+
+void tst_QQmlDebugJS::stepNext()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+
+ int sourceLine = 50;
+ QVERIFY(init(STEPACTION_QMLFILE));
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->continueDebugging(QJSDebugClient::Next);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine + 1);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::stepNextWithCount()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+
+ int sourceLine = 50;
+ QVERIFY(init(STEPACTION_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->continueDebugging(QJSDebugClient::Next, 2);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine + 2);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::stepIn()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+
+ int sourceLine = 54;
+ int actualLine = 50;
+ QVERIFY(init(STEPACTION_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->continueDebugging(QJSDebugClient::In);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::stepOut()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+
+ int sourceLine = 50;
+ int actualLine = 54;
+ QVERIFY(init(STEPACTION_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->continueDebugging(QJSDebugClient::Out);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::continueDebugging()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+
+ int sourceLine1 = 54;
+ int sourceLine2 = 51;
+ QVERIFY(init(STEPACTION_QMLFILE));
+
+ client->connect();
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true);
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->continueDebugging(QJSDebugClient::Continue);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::backtrace()
+{
+ //void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
+
+ int sourceLine = 47;
+ QVERIFY(init(ONCOMPLETED_QMLFILE));
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->backtrace();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getFrameDetails()
+{
+ //void frame(int number = -1);
+
+ int sourceLine = 47;
+ QVERIFY(init(ONCOMPLETED_QMLFILE));
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->frame();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getScopeDetails()
+{
+ //void scope(int number = -1, int frameNumber = -1);
+
+ int sourceLine = 47;
+ QVERIFY(init(ONCOMPLETED_QMLFILE));
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->scope();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::evaluateInGlobalScope()
+{
+ //void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
+
+ QVERIFY(init());
+
+ client->connect();
+ client->evaluate(QLatin1String("print('Hello World')"), true);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ //Verify the value of 'print'
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("text").toString(),QLatin1String("undefined"));
+}
+
+void tst_QQmlDebugJS::evaluateInLocalScope()
+{
+ //void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
+
+ int sourceLine = 47;
+ QVERIFY(init(ONCOMPLETED_QMLFILE));
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->frame();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ //Get the frame index
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ int frameIndex = body.value("index").toInt();
+
+ client->evaluate(QLatin1String("root.a"), frameIndex);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ //Verify the value of 'timer.interval'
+ jsonString = client->response;
+ value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ body = value.value("body").toMap();
+
+ QCOMPARE(body.value("value").toInt(),10);
+}
+
+void tst_QQmlDebugJS::getScopes()
+{
+ //void scopes(int frameNumber = -1);
+
+ int sourceLine = 47;
+ QVERIFY(init(ONCOMPLETED_QMLFILE));
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->scopes();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getScripts()
+{
+ //void scripts(int types = -1, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
+
+#ifdef Q_OS_MAC
+ QSKIP("QTBUG-23475 - Unreliable test on Mac OS X");
+#endif
+
+ QVERIFY(init());
+
+ client->connect();
+
+ client->scripts();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList()
+ << QJSValue(jsonString)).toVariant().toMap();
+
+ QList<QVariant> scripts = value.value("body").toList();
+
+ QCOMPARE(scripts.count(), 2);
+}
+
+void tst_QQmlDebugJS::getSource()
+{
+ //void source(int frame = -1, int fromLine = -1, int toLine = -1);
+
+ int sourceLine = 47;
+ QVERIFY(init(ONCOMPLETED_QMLFILE));
+
+ client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->source();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+QTEST_MAIN(tst_QQmlDebugJS)
+
+#include "tst_qqmldebugjs.moc"
+
diff --git a/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro b/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro
new file mode 100644
index 0000000000..ecb3b2ca2c
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro
@@ -0,0 +1,11 @@
+CONFIG += testcase
+TARGET = tst_qqmldebugservice
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/debugutil_p.h
+SOURCES += tst_qqmldebugservice.cpp \
+ ../shared/debugutil.cpp
+
+CONFIG += parallel_test declarative_debug
+
+QT += qml-private testlib
diff --git a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp
new file mode 100644
index 0000000000..5af38c2af0
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QSignalSpy>
+#include <QTimer>
+#include <QHostAddress>
+#include <QDebug>
+#include <QThread>
+
+#include <QtQml/qqmlengine.h>
+
+#include <private/qqmldebugclient_p.h>
+#include <private/qqmldebugservice_p.h>
+
+#include "../../../shared/util.h"
+#include "../shared/debugutil_p.h"
+
+#define PORT 13769
+#define STR_PORT "13769"
+
+class tst_QQmlDebugService : public QObject
+{
+ Q_OBJECT
+private:
+ QQmlDebugConnection *m_conn;
+
+private slots:
+ void initTestCase();
+
+ void name();
+ void version();
+ void state();
+ void sendMessage();
+ void idForObject();
+ void objectForId();
+ void objectToString();
+};
+
+void tst_QQmlDebugService::initTestCase()
+{
+ const QString waitingMsg = QString("QQmlDebugServer: Waiting for connection on port %1...").arg(PORT);
+ QTest::ignoreMessage(QtWarningMsg, waitingMsg.toAscii().constData());
+ new QQmlEngine(this);
+
+ m_conn = new QQmlDebugConnection(this);
+
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlDebugServer: Connection established");
+ for (int i = 0; i < 50; ++i) {
+ // try for 5 seconds ...
+ m_conn->connectToHost("127.0.0.1", PORT);
+ if (m_conn->waitForConnected())
+ break;
+ QTest::qSleep(100);
+ }
+ QVERIFY(m_conn->isConnected());
+
+ QTRY_VERIFY(QQmlDebugService::hasDebuggingClient());
+}
+
+void tst_QQmlDebugService::name()
+{
+ QString name = "tst_QQmlDebugService::name()";
+
+ QQmlDebugService service(name, 1);
+ QCOMPARE(service.name(), name);
+}
+
+void tst_QQmlDebugService::version()
+{
+ QString name = "tst_QQmlDebugService::name()";
+
+ QQmlDebugService service(name, 2);
+ QCOMPARE(service.version(), 2.0f);
+}
+
+void tst_QQmlDebugService::state()
+{
+ QQmlDebugTestService service("tst_QQmlDebugService::state()");
+ QCOMPARE(service.state(), QQmlDebugService::Unavailable);
+
+ {
+ QQmlDebugTestClient client("tst_QQmlDebugService::state()", m_conn);
+ QTRY_COMPARE(client.state(), QQmlDebugClient::Enabled);
+ QTRY_COMPARE(service.state(), QQmlDebugService::Enabled);
+ }
+
+
+ QTRY_COMPARE(service.state(), QQmlDebugService::Unavailable);
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlDebugService: Conflicting plugin name \"tst_QQmlDebugService::state()\" ");
+ QQmlDebugTestService duplicate("tst_QQmlDebugService::state()");
+ QCOMPARE(duplicate.state(), QQmlDebugService::NotConnected);
+}
+
+void tst_QQmlDebugService::sendMessage()
+{
+ QQmlDebugTestService service("tst_QQmlDebugService::sendMessage()");
+ QQmlDebugTestClient client("tst_QQmlDebugService::sendMessage()", m_conn);
+
+ QByteArray msg = "hello!";
+
+ QTRY_COMPARE(client.state(), QQmlDebugClient::Enabled);
+ QTRY_COMPARE(service.state(), QQmlDebugService::Enabled);
+
+ client.sendMessage(msg);
+ QByteArray resp = client.waitForResponse();
+ QCOMPARE(resp, msg);
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlDebugService: Conflicting plugin name \"tst_QQmlDebugService::sendMessage()\" ");
+ QQmlDebugTestService duplicate("tst_QQmlDebugService::sendMessage()");
+ duplicate.sendMessage("msg");
+}
+
+void tst_QQmlDebugService::idForObject()
+{
+ QCOMPARE(QQmlDebugService::idForObject(0), -1);
+
+ QObject *objA = new QObject;
+
+ int idA = QQmlDebugService::idForObject(objA);
+ QVERIFY(idA >= 0);
+ QCOMPARE(QQmlDebugService::objectForId(idA), objA);
+
+ int idAA = QQmlDebugService::idForObject(objA);
+ QCOMPARE(idAA, idA);
+
+ QObject *objB = new QObject;
+ int idB = QQmlDebugService::idForObject(objB);
+ QVERIFY(idB != idA);
+ QCOMPARE(QQmlDebugService::objectForId(idB), objB);
+
+ delete objA;
+ delete objB;
+}
+
+void tst_QQmlDebugService::objectForId()
+{
+ QCOMPARE(QQmlDebugService::objectForId(-1), static_cast<QObject*>(0));
+ QCOMPARE(QQmlDebugService::objectForId(1), static_cast<QObject*>(0));
+
+ QObject *obj = new QObject;
+ int id = QQmlDebugService::idForObject(obj);
+ QCOMPARE(QQmlDebugService::objectForId(id), obj);
+
+ delete obj;
+ QCOMPARE(QQmlDebugService::objectForId(id), static_cast<QObject*>(0));
+}
+
+void tst_QQmlDebugService::objectToString()
+{
+ QCOMPARE(QQmlDebugService::objectToString(0), QString("NULL"));
+
+ QObject *obj = new QObject;
+ QCOMPARE(QQmlDebugService::objectToString(obj), QString("QObject: <unnamed>"));
+
+ obj->setObjectName("Hello");
+ QCOMPARE(QQmlDebugService::objectToString(obj), QString("QObject: Hello"));
+ delete obj;
+}
+
+
+int main(int argc, char *argv[])
+{
+ int _argc = argc + 1;
+ char **_argv = new char*[_argc];
+ for (int i = 0; i < argc; ++i)
+ _argv[i] = argv[i];
+ char arg[] = "-qmljsdebugger=port:" STR_PORT;
+ _argv[_argc - 1] = arg;
+
+ QGuiApplication app(_argc, _argv);
+ tst_QQmlDebugService tc;
+ return QTest::qExec(&tc, _argc, _argv);
+ delete _argv;
+}
+
+#include "tst_qqmldebugservice.moc"
diff --git a/tests/auto/qml/debugger/qqmlenginedebug/qqmlenginedebug.pro b/tests/auto/qml/debugger/qqmlenginedebug/qqmlenginedebug.pro
new file mode 100644
index 0000000000..529c4667cf
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlenginedebug/qqmlenginedebug.pro
@@ -0,0 +1,11 @@
+CONFIG += testcase
+TARGET = tst_qqmlenginedebug
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/debugutil_p.h
+SOURCES += tst_qqmlenginedebug.cpp \
+ ../shared/debugutil.cpp
+
+CONFIG += parallel_test declarative_debug
+
+QT += core-private qml-private quick-private v8-private testlib
diff --git a/tests/auto/qml/debugger/qqmlenginedebug/tst_qqmlenginedebug.cpp b/tests/auto/qml/debugger/qqmlenginedebug/tst_qqmlenginedebug.cpp
new file mode 100644
index 0000000000..21ed2f40ff
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlenginedebug/tst_qqmlenginedebug.cpp
@@ -0,0 +1,1235 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QSignalSpy>
+#include <QTimer>
+#include <QHostAddress>
+#include <QDebug>
+#include <QThread>
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlexpression.h>
+#include <QtQml/qqmlproperty.h>
+#include <QtQuick/qquickitem.h>
+
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlboundsignal_p.h>
+#include <private/qqmlenginedebug_p.h>
+#include <private/qqmldebugservice_p.h>
+#include <private/qqmlmetatype_p.h>
+#include <private/qqmlproperty_p.h>
+
+#include "../shared/debugutil_p.h"
+
+Q_DECLARE_METATYPE(QQmlDebugWatch::State)
+
+class tst_QQmlEngineDebug : public QObject
+{
+ Q_OBJECT
+
+private:
+ QQmlDebugObjectReference findRootObject(int context = 0, bool recursive = false);
+ QQmlDebugPropertyReference findProperty(const QList<QQmlDebugPropertyReference> &props, const QString &name) const;
+ void waitForQuery(QQmlDebugQuery *query);
+
+ void recursiveObjectTest(QObject *o, const QQmlDebugObjectReference &oref, bool recursive) const;
+
+ void recursiveCompareObjects(const QQmlDebugObjectReference &a, const QQmlDebugObjectReference &b) const;
+ void recursiveCompareContexts(const QQmlDebugContextReference &a, const QQmlDebugContextReference &b) const;
+ void compareProperties(const QQmlDebugPropertyReference &a, const QQmlDebugPropertyReference &b) const;
+
+ QQmlDebugConnection *m_conn;
+ QQmlEngineDebug *m_dbg;
+ QQmlEngine *m_engine;
+ QQuickItem *m_rootItem;
+
+ QObjectList m_components;
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void watch_property();
+ void watch_object();
+ void watch_expression();
+ void watch_expression_data();
+ void watch_context();
+ void watch_file();
+
+ void queryAvailableEngines();
+ void queryRootContexts();
+ void queryObject();
+ void queryObject_data();
+ void queryExpressionResult();
+ void queryExpressionResult_data();
+
+ void tst_QQmlDebugFileReference();
+ void tst_QQmlDebugEngineReference();
+ void tst_QQmlDebugObjectReference();
+ void tst_QQmlDebugContextReference();
+ void tst_QQmlDebugPropertyReference();
+
+ void setBindingForObject();
+ void setMethodBody();
+ void queryObjectTree();
+ void setBindingInStates();
+};
+
+class NonScriptProperty : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(int nonScriptProp READ nonScriptProp WRITE setNonScriptProp NOTIFY nonScriptPropChanged SCRIPTABLE false)
+public:
+ int nonScriptProp() const { return 0; }
+ void setNonScriptProp(int) {}
+signals:
+ void nonScriptPropChanged();
+};
+QML_DECLARE_TYPE(NonScriptProperty)
+
+
+QQmlDebugObjectReference tst_QQmlEngineDebug::findRootObject(int context, bool recursive)
+{
+ QQmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
+ waitForQuery(q_engines);
+
+ if (q_engines->engines().count() == 0)
+ return QQmlDebugObjectReference();
+ QQmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this);
+ waitForQuery(q_context);
+
+ if (q_context->rootContext().objects().count() == 0)
+ return QQmlDebugObjectReference();
+ QQmlDebugObjectQuery *q_obj = recursive ?
+ m_dbg->queryObjectRecursive(q_context->rootContext().objects()[context], this) :
+ m_dbg->queryObject(q_context->rootContext().objects()[context], this);
+ waitForQuery(q_obj);
+
+ QQmlDebugObjectReference result = q_obj->object();
+
+ delete q_engines;
+ delete q_context;
+ delete q_obj;
+
+ return result;
+}
+
+QQmlDebugPropertyReference tst_QQmlEngineDebug::findProperty(const QList<QQmlDebugPropertyReference> &props, const QString &name) const
+{
+ foreach(const QQmlDebugPropertyReference &p, props) {
+ if (p.name() == name)
+ return p;
+ }
+ return QQmlDebugPropertyReference();
+}
+
+void tst_QQmlEngineDebug::waitForQuery(QQmlDebugQuery *query)
+{
+ QVERIFY(query);
+ QCOMPARE(query->parent(), qobject_cast<QObject*>(this));
+ QVERIFY(query->state() == QQmlDebugQuery::Waiting);
+ if (!QQmlDebugTest::waitForSignal(query, SIGNAL(stateChanged(QQmlDebugQuery::State))))
+ QFAIL("query timed out");
+}
+
+void tst_QQmlEngineDebug::recursiveObjectTest(QObject *o, const QQmlDebugObjectReference &oref, bool recursive) const
+{
+ const QMetaObject *meta = o->metaObject();
+
+ QQmlType *type = QQmlMetaType::qmlType(meta);
+ QString className = type ? QString(type->qmlTypeName()) : QString(meta->className());
+ className = className.mid(className.lastIndexOf(QLatin1Char('/'))+1);
+
+ QCOMPARE(oref.debugId(), QQmlDebugService::idForObject(o));
+ QCOMPARE(oref.name(), o->objectName());
+ QCOMPARE(oref.className(), className);
+ QCOMPARE(oref.contextDebugId(), QQmlDebugService::idForObject(qmlContext(o)));
+
+ const QObjectList &children = o->children();
+ for (int i=0; i<children.count(); i++) {
+ QObject *child = children[i];
+ if (!qmlContext(child))
+ continue;
+ int debugId = QQmlDebugService::idForObject(child);
+ QVERIFY(debugId >= 0);
+
+ QQmlDebugObjectReference cref;
+ foreach (const QQmlDebugObjectReference &ref, oref.children()) {
+ if (ref.debugId() == debugId) {
+ cref = ref;
+ break;
+ }
+ }
+ QVERIFY(cref.debugId() >= 0);
+
+ if (recursive)
+ recursiveObjectTest(child, cref, true);
+ }
+
+ foreach (const QQmlDebugPropertyReference &p, oref.properties()) {
+ QCOMPARE(p.objectDebugId(), QQmlDebugService::idForObject(o));
+
+ // signal properties are fake - they are generated from QQmlBoundSignal children
+ if (p.name().startsWith("on") && p.name().length() > 2 && p.name()[2].isUpper()) {
+ QList<QQmlBoundSignal*> signalHandlers = o->findChildren<QQmlBoundSignal*>();
+ QString signal = p.value().toString();
+ bool found = false;
+ for (int i = 0; i < signalHandlers.count(); ++i)
+ if (signalHandlers.at(i)->expression()->expression() == signal) {
+ found = true;
+ break;
+ }
+ QVERIFY(found);
+ QVERIFY(p.valueTypeName().isEmpty());
+ QVERIFY(p.binding().isEmpty());
+ QVERIFY(!p.hasNotifySignal());
+ continue;
+ }
+
+ QMetaProperty pmeta = meta->property(meta->indexOfProperty(p.name().toUtf8().constData()));
+
+ QCOMPARE(p.name(), QString::fromUtf8(pmeta.name()));
+
+ if (pmeta.type() < QVariant::UserType && pmeta.userType() != QMetaType::QVariant) // TODO test complex types
+ QCOMPARE(p.value(), pmeta.read(o));
+
+ if (p.name() == "parent")
+ QVERIFY(p.valueTypeName() == "QGraphicsObject*" || p.valueTypeName() == "QQuickItem*");
+ else
+ QCOMPARE(p.valueTypeName(), QString::fromUtf8(pmeta.typeName()));
+
+ QQmlAbstractBinding *binding =
+ QQmlPropertyPrivate::binding(QQmlProperty(o, p.name()));
+ if (binding)
+ QCOMPARE(binding->expression(), p.binding());
+
+ QCOMPARE(p.hasNotifySignal(), pmeta.hasNotifySignal());
+
+ QVERIFY(pmeta.isValid());
+ }
+}
+
+void tst_QQmlEngineDebug::recursiveCompareObjects(const QQmlDebugObjectReference &a, const QQmlDebugObjectReference &b) const
+{
+ QCOMPARE(a.debugId(), b.debugId());
+ QCOMPARE(a.className(), b.className());
+ QCOMPARE(a.name(), b.name());
+ QCOMPARE(a.contextDebugId(), b.contextDebugId());
+
+ QCOMPARE(a.source().url(), b.source().url());
+ QCOMPARE(a.source().lineNumber(), b.source().lineNumber());
+ QCOMPARE(a.source().columnNumber(), b.source().columnNumber());
+
+ QCOMPARE(a.properties().count(), b.properties().count());
+ QCOMPARE(a.children().count(), b.children().count());
+
+ QList<QQmlDebugPropertyReference> aprops = a.properties();
+ QList<QQmlDebugPropertyReference> bprops = b.properties();
+
+ for (int i=0; i<aprops.count(); i++)
+ compareProperties(aprops[i], bprops[i]);
+
+ for (int i=0; i<a.children().count(); i++)
+ recursiveCompareObjects(a.children()[i], b.children()[i]);
+}
+
+void tst_QQmlEngineDebug::recursiveCompareContexts(const QQmlDebugContextReference &a, const QQmlDebugContextReference &b) const
+{
+ QCOMPARE(a.debugId(), b.debugId());
+ QCOMPARE(a.name(), b.name());
+ QCOMPARE(a.objects().count(), b.objects().count());
+ QCOMPARE(a.contexts().count(), b.contexts().count());
+
+ for (int i=0; i<a.objects().count(); i++)
+ recursiveCompareObjects(a.objects()[i], b.objects()[i]);
+
+ for (int i=0; i<a.contexts().count(); i++)
+ recursiveCompareContexts(a.contexts()[i], b.contexts()[i]);
+}
+
+void tst_QQmlEngineDebug::compareProperties(const QQmlDebugPropertyReference &a, const QQmlDebugPropertyReference &b) const
+{
+ QCOMPARE(a.objectDebugId(), b.objectDebugId());
+ QCOMPARE(a.name(), b.name());
+ QCOMPARE(a.value(), b.value());
+ QCOMPARE(a.valueTypeName(), b.valueTypeName());
+ QCOMPARE(a.binding(), b.binding());
+ QCOMPARE(a.hasNotifySignal(), b.hasNotifySignal());
+}
+
+void tst_QQmlEngineDebug::initTestCase()
+{
+ qRegisterMetaType<QQmlDebugWatch::State>();
+ qmlRegisterType<NonScriptProperty>("Test", 1, 0, "NonScriptPropertyElement");
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlDebugServer: Waiting for connection on port 3768...");
+ m_engine = new QQmlEngine(this);
+
+ QList<QByteArray> qml;
+ qml << "import QtQuick 2.0\n"
+ "import Test 1.0\n"
+ "Item {"
+ "id: root\n"
+ "width: 10; height: 20; scale: blueRect.scale;"
+ "Rectangle { id: blueRect; width: 500; height: 600; color: \"blue\"; }"
+ "Text { color: blueRect.color; }"
+ "MouseArea {"
+ "onEntered: { console.log('hello') }"
+ "}"
+ "property variant varObj\n"
+ "property variant varObjList: []\n"
+ "property variant varObjMap\n"
+ "Component.onCompleted: {\n"
+ "varObj = blueRect;\n"
+ "var list = varObjList;\n"
+ "list[0] = blueRect;\n"
+ "varObjList = list;\n"
+ "var map = new Object;\n"
+ "map.rect = blueRect;\n"
+ "varObjMap = map;\n"
+ "}\n"
+ "NonScriptPropertyElement {\n"
+ "}\n"
+ "}";
+
+ // add second component to test multiple root contexts
+ qml << "import QtQuick 2.0\n"
+ "Item {}";
+
+ // and a third to test methods
+ qml << "import QtQuick 2.0\n"
+ "Item {"
+ "function myMethodNoArgs() { return 3; }\n"
+ "function myMethod(a) { return a + 9; }\n"
+ "function myMethodIndirect() { myMethod(3); }\n"
+ "}";
+
+ // and a fourth to test states
+ qml << "import QtQuick 2.0\n"
+ "Rectangle {\n"
+ "id:rootRect\n"
+ "width:100\n"
+ "states: [\n"
+ "State {\n"
+ "name:\"state1\"\n"
+ "PropertyChanges {\n"
+ "target:rootRect\n"
+ "width:200\n"
+ "}\n"
+ "}\n"
+ "]\n"
+ "transitions: [\n"
+ "Transition {\n"
+ "from:\"*\"\n"
+ "to:\"state1\"\n"
+ "PropertyAnimation {\n"
+ "target:rootRect\n"
+ "property:\"width\"\n"
+ "duration:100\n"
+ "}\n"
+ "}\n"
+ "]\n"
+ "}\n"
+ ;
+
+ for (int i=0; i<qml.count(); i++) {
+ QQmlComponent component(m_engine);
+ component.setData(qml[i], QUrl::fromLocalFile(""));
+ QVERIFY(component.isReady()); // fails if bad syntax
+ m_components << qobject_cast<QQuickItem*>(component.create());
+ }
+ m_rootItem = qobject_cast<QQuickItem*>(m_components.first());
+
+ // add an extra context to test for multiple contexts
+ QQmlContext *context = new QQmlContext(m_engine->rootContext(), this);
+ context->setObjectName("tst_QQmlDebug_childContext");
+
+ m_conn = new QQmlDebugConnection(this);
+ m_conn->connectToHost("127.0.0.1", 3768);
+
+ QTest::ignoreMessage(QtWarningMsg, "QQmlDebugServer: Connection established");
+ bool ok = m_conn->waitForConnected();
+ QVERIFY(ok);
+ QTRY_VERIFY(QQmlDebugService::hasDebuggingClient());
+ m_dbg = new QQmlEngineDebug(m_conn, this);
+ QTRY_VERIFY(m_dbg->state() == QQmlEngineDebug::Enabled);
+}
+
+void tst_QQmlEngineDebug::cleanupTestCase()
+{
+ delete m_dbg;
+ delete m_conn;
+ qDeleteAll(m_components);
+ delete m_engine;
+}
+
+void tst_QQmlEngineDebug::setMethodBody()
+{
+ QQmlDebugObjectReference obj = findRootObject(2);
+
+ QObject *root = m_components.at(2);
+ // Without args
+ {
+ QVariant rv;
+ QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, rv)));
+ QVERIFY(rv == QVariant(qreal(3)));
+
+
+ QVERIFY(m_dbg->setMethodBody(obj.debugId(), "myMethodNoArgs", "return 7"));
+ QTest::qWait(100);
+
+ QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, rv)));
+ QVERIFY(rv == QVariant(qreal(7)));
+ }
+
+ // With args
+ {
+ QVariant rv;
+ QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19))));
+ QVERIFY(rv == QVariant(qreal(28)));
+
+ QVERIFY(m_dbg->setMethodBody(obj.debugId(), "myMethod", "return a + 7"));
+ QTest::qWait(100);
+
+ QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19))));
+ QVERIFY(rv == QVariant(qreal(26)));
+ }
+}
+
+void tst_QQmlEngineDebug::watch_property()
+{
+ QQmlDebugObjectReference obj = findRootObject();
+ QQmlDebugPropertyReference prop = findProperty(obj.properties(), "width");
+
+ QQmlDebugPropertyWatch *watch;
+
+ QQmlEngineDebug *unconnected = new QQmlEngineDebug(0);
+ watch = unconnected->addWatch(prop, this);
+ QCOMPARE(watch->state(), QQmlDebugWatch::Dead);
+ delete watch;
+ delete unconnected;
+
+ watch = m_dbg->addWatch(QQmlDebugPropertyReference(), this);
+ QVERIFY(QQmlDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QQmlDebugWatch::State))));
+ QCOMPARE(watch->state(), QQmlDebugWatch::Inactive);
+ delete watch;
+
+ watch = m_dbg->addWatch(prop, this);
+ QCOMPARE(watch->state(), QQmlDebugWatch::Waiting);
+ QCOMPARE(watch->objectDebugId(), obj.debugId());
+ QCOMPARE(watch->name(), prop.name());
+
+ QSignalSpy spy(watch, SIGNAL(valueChanged(QByteArray,QVariant)));
+
+ int origWidth = m_rootItem->property("width").toInt();
+ m_rootItem->setProperty("width", origWidth*2);
+
+ // stateChanged() is received before valueChanged()
+ QVERIFY(QQmlDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QQmlDebugWatch::State))));
+ QCOMPARE(watch->state(), QQmlDebugWatch::Active);
+ QCOMPARE(spy.count(), 1);
+
+ m_dbg->removeWatch(watch);
+ delete watch;
+
+ // restore original value and verify spy doesn't get additional signal since watch has been removed
+ m_rootItem->setProperty("width", origWidth);
+ QTest::qWait(100);
+ QCOMPARE(spy.count(), 1);
+
+ QCOMPARE(spy.at(0).at(0).value<QByteArray>(), prop.name().toUtf8());
+ QCOMPARE(spy.at(0).at(1).value<QVariant>(), qVariantFromValue(origWidth*2));
+}
+
+void tst_QQmlEngineDebug::watch_object()
+{
+ QQmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
+ waitForQuery(q_engines);
+
+ QVERIFY(q_engines->engines().count() > 0);
+ QQmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this);
+ waitForQuery(q_context);
+
+ QVERIFY(q_context->rootContext().objects().count() > 0);
+ QQmlDebugObjectQuery *q_obj = m_dbg->queryObject(q_context->rootContext().objects()[0], this);
+ waitForQuery(q_obj);
+
+ QQmlDebugObjectReference obj = q_obj->object();
+
+ delete q_engines;
+ delete q_context;
+ delete q_obj;
+
+ QQmlDebugWatch *watch;
+
+ QQmlEngineDebug *unconnected = new QQmlEngineDebug(0);
+ watch = unconnected->addWatch(obj, this);
+ QCOMPARE(watch->state(), QQmlDebugWatch::Dead);
+ delete watch;
+ delete unconnected;
+
+ watch = m_dbg->addWatch(QQmlDebugObjectReference(), this);
+ QVERIFY(QQmlDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QQmlDebugWatch::State))));
+ QCOMPARE(watch->state(), QQmlDebugWatch::Inactive);
+ delete watch;
+
+ watch = m_dbg->addWatch(obj, this);
+ QCOMPARE(watch->state(), QQmlDebugWatch::Waiting);
+ QCOMPARE(watch->objectDebugId(), obj.debugId());
+
+ QSignalSpy spy(watch, SIGNAL(valueChanged(QByteArray,QVariant)));
+
+ int origWidth = m_rootItem->property("width").toInt();
+ int origHeight = m_rootItem->property("height").toInt();
+ m_rootItem->setProperty("width", origWidth*2);
+ m_rootItem->setProperty("height", origHeight*2);
+
+ // stateChanged() is received before any valueChanged() signals
+ QVERIFY(QQmlDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QQmlDebugWatch::State))));
+ QCOMPARE(watch->state(), QQmlDebugWatch::Active);
+ QVERIFY(spy.count() > 0);
+
+ int newWidth = -1;
+ int newHeight = -1;
+ for (int i=0; i<spy.count(); i++) {
+ const QVariantList &values = spy[i];
+ if (values[0].value<QByteArray>() == "width")
+ newWidth = values[1].value<QVariant>().toInt();
+ else if (values[0].value<QByteArray>() == "height")
+ newHeight = values[1].value<QVariant>().toInt();
+
+ }
+
+ m_dbg->removeWatch(watch);
+ delete watch;
+
+ // since watch has been removed, restoring the original values should not trigger a valueChanged()
+ spy.clear();
+ m_rootItem->setProperty("width", origWidth);
+ m_rootItem->setProperty("height", origHeight);
+ QTest::qWait(100);
+ QCOMPARE(spy.count(), 0);
+
+ QCOMPARE(newWidth, origWidth * 2);
+ QCOMPARE(newHeight, origHeight * 2);
+}
+
+void tst_QQmlEngineDebug::watch_expression()
+{
+ QFETCH(QString, expr);
+ QFETCH(int, increment);
+ QFETCH(int, incrementCount);
+
+ int origWidth = m_rootItem->property("width").toInt();
+
+ QQmlDebugObjectReference obj = findRootObject();
+
+ QQmlDebugObjectExpressionWatch *watch;
+
+ QQmlEngineDebug *unconnected = new QQmlEngineDebug(0);
+ watch = unconnected->addWatch(obj, expr, this);
+ QCOMPARE(watch->state(), QQmlDebugWatch::Dead);
+ delete watch;
+ delete unconnected;
+
+ watch = m_dbg->addWatch(QQmlDebugObjectReference(), expr, this);
+ QVERIFY(QQmlDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QQmlDebugWatch::State))));
+ QCOMPARE(watch->state(), QQmlDebugWatch::Inactive);
+ delete watch;
+
+ watch = m_dbg->addWatch(obj, expr, this);
+ QCOMPARE(watch->state(), QQmlDebugWatch::Waiting);
+ QCOMPARE(watch->objectDebugId(), obj.debugId());
+ QCOMPARE(watch->expression(), expr);
+
+ QSignalSpy spyState(watch, SIGNAL(stateChanged(QQmlDebugWatch::State)));
+
+ QSignalSpy spy(watch, SIGNAL(valueChanged(QByteArray,QVariant)));
+ int expectedSpyCount = incrementCount + 1; // should also get signal with expression's initial value
+
+ int width = origWidth;
+ for (int i=0; i<incrementCount+1; i++) {
+ if (i > 0) {
+ width += increment;
+ m_rootItem->setProperty("width", width);
+ }
+ if (!QQmlDebugTest::waitForSignal(watch, SIGNAL(valueChanged(QByteArray,QVariant))))
+ QFAIL("Did not receive valueChanged() for expression");
+ }
+
+ if (spyState.count() == 0)
+ QVERIFY(QQmlDebugTest::waitForSignal(watch, SIGNAL(stateChanged(QQmlDebugWatch::State))));
+ QCOMPARE(spyState.count(), 1);
+ QCOMPARE(watch->state(), QQmlDebugWatch::Active);
+
+ m_dbg->removeWatch(watch);
+ delete watch;
+
+ // restore original value and verify spy doesn't get a signal since watch has been removed
+ m_rootItem->setProperty("width", origWidth);
+ QTest::qWait(100);
+ QCOMPARE(spy.count(), expectedSpyCount);
+
+ width = origWidth + increment;
+ for (int i=0; i<spy.count(); i++) {
+ QCOMPARE(spy.at(i).at(1).value<QVariant>().toInt(), width);
+ width += increment;
+ }
+}
+
+void tst_QQmlEngineDebug::watch_expression_data()
+{
+ QTest::addColumn<QString>("expr");
+ QTest::addColumn<int>("increment");
+ QTest::addColumn<int>("incrementCount");
+
+ QTest::newRow("width") << "width" << 0 << 0;
+ QTest::newRow("width+10") << "width + 10" << 10 << 5;
+}
+
+void tst_QQmlEngineDebug::watch_context()
+{
+ QQmlDebugContextReference c;
+ QTest::ignoreMessage(QtWarningMsg, "QQmlEngineDebug::addWatch(): Not implemented");
+ QVERIFY(!m_dbg->addWatch(c, QString(), this));
+}
+
+void tst_QQmlEngineDebug::watch_file()
+{
+ QQmlDebugFileReference f;
+ QTest::ignoreMessage(QtWarningMsg, "QQmlEngineDebug::addWatch(): Not implemented");
+ QVERIFY(!m_dbg->addWatch(f, this));
+}
+
+void tst_QQmlEngineDebug::queryAvailableEngines()
+{
+ QQmlDebugEnginesQuery *q_engines;
+
+ QQmlEngineDebug *unconnected = new QQmlEngineDebug(0);
+ q_engines = unconnected->queryAvailableEngines(0);
+ QCOMPARE(q_engines->state(), QQmlDebugQuery::Error);
+ delete q_engines;
+ delete unconnected;
+
+ q_engines = m_dbg->queryAvailableEngines(this);
+ delete q_engines;
+
+ q_engines = m_dbg->queryAvailableEngines(this);
+ QVERIFY(q_engines->engines().isEmpty());
+ waitForQuery(q_engines);
+
+ // TODO test multiple engines
+ QList<QQmlDebugEngineReference> engines = q_engines->engines();
+ QCOMPARE(engines.count(), 1);
+
+ foreach(const QQmlDebugEngineReference &e, engines) {
+ QCOMPARE(e.debugId(), QQmlDebugService::idForObject(m_engine));
+ QCOMPARE(e.name(), m_engine->objectName());
+ }
+
+ // Make query invalid by deleting client
+ q_engines = m_dbg->queryAvailableEngines(this);
+ QCOMPARE(q_engines->state(), QQmlDebugQuery::Waiting);
+ delete m_dbg;
+ QCOMPARE(q_engines->state(), QQmlDebugQuery::Error);
+ delete q_engines;
+ m_dbg = new QQmlEngineDebug(m_conn, this);
+}
+
+void tst_QQmlEngineDebug::queryRootContexts()
+{
+ QQmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
+ waitForQuery(q_engines);
+ int engineId = q_engines->engines()[0].debugId();
+ delete q_engines;
+
+ QQmlDebugRootContextQuery *q_context;
+
+ QQmlEngineDebug *unconnected = new QQmlEngineDebug(0);
+ q_context = unconnected->queryRootContexts(engineId, this);
+ QCOMPARE(q_context->state(), QQmlDebugQuery::Error);
+ delete q_context;
+ delete unconnected;
+
+ q_context = m_dbg->queryRootContexts(engineId, this);
+ delete q_context;
+
+ q_context = m_dbg->queryRootContexts(engineId, this);
+ waitForQuery(q_context);
+
+ QQmlContext *actualContext = m_engine->rootContext();
+ QQmlDebugContextReference context = q_context->rootContext();
+ QCOMPARE(context.debugId(), QQmlDebugService::idForObject(actualContext));
+ QCOMPARE(context.name(), actualContext->objectName());
+
+ QCOMPARE(context.objects().count(), 4); // 4 qml component objects created for context in main()
+
+ // root context query sends only root object data - it doesn't fill in
+ // the children or property info
+ QCOMPARE(context.objects()[0].properties().count(), 0);
+ QCOMPARE(context.objects()[0].children().count(), 0);
+
+ QCOMPARE(context.contexts().count(), 5);
+ QVERIFY(context.contexts()[0].debugId() >= 0);
+ QCOMPARE(context.contexts()[0].name(), QString("tst_QQmlDebug_childContext"));
+
+ // Make query invalid by deleting client
+ q_context = m_dbg->queryRootContexts(engineId, this);
+ QCOMPARE(q_context->state(), QQmlDebugQuery::Waiting);
+ delete m_dbg;
+ QCOMPARE(q_context->state(), QQmlDebugQuery::Error);
+ delete q_context;
+ m_dbg = new QQmlEngineDebug(m_conn, this);
+}
+
+void tst_QQmlEngineDebug::queryObject()
+{
+ QFETCH(bool, recursive);
+
+ QQmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
+ waitForQuery(q_engines);
+
+ QQmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this);
+ waitForQuery(q_context);
+ QQmlDebugObjectReference rootObject = q_context->rootContext().objects()[0];
+
+ QQmlDebugObjectQuery *q_obj = 0;
+
+ QQmlEngineDebug *unconnected = new QQmlEngineDebug(0);
+ q_obj = recursive ? unconnected->queryObjectRecursive(rootObject, this) : unconnected->queryObject(rootObject, this);
+ QCOMPARE(q_obj->state(), QQmlDebugQuery::Error);
+ delete q_obj;
+ delete unconnected;
+
+ q_obj = recursive ? m_dbg->queryObjectRecursive(rootObject, this) : m_dbg->queryObject(rootObject, this);
+ delete q_obj;
+
+ q_obj = recursive ? m_dbg->queryObjectRecursive(rootObject, this) : m_dbg->queryObject(rootObject, this);
+ waitForQuery(q_obj);
+
+ QQmlDebugObjectReference obj = q_obj->object();
+
+ delete q_engines;
+ delete q_context;
+
+ // Make query invalid by deleting client
+ q_obj = recursive ? m_dbg->queryObjectRecursive(rootObject, this) : m_dbg->queryObject(rootObject, this);
+ QCOMPARE(q_obj->state(), QQmlDebugQuery::Waiting);
+ delete m_dbg;
+ QCOMPARE(q_obj->state(), QQmlDebugQuery::Error);
+ delete q_obj;
+ m_dbg = new QQmlEngineDebug(m_conn, this);
+
+ // check source as defined in main()
+ QQmlDebugFileReference source = obj.source();
+ QCOMPARE(source.url(), QUrl::fromLocalFile(""));
+ QCOMPARE(source.lineNumber(), 3);
+ QCOMPARE(source.columnNumber(), 1);
+
+ // generically test all properties, children and childrens' properties
+ recursiveObjectTest(m_rootItem, obj, recursive);
+
+ if (recursive) {
+ foreach(const QQmlDebugObjectReference &child, obj.children())
+ QVERIFY(child.properties().count() > 0);
+
+ QQmlDebugObjectReference rect;
+ QQmlDebugObjectReference text;
+ foreach (const QQmlDebugObjectReference &child, obj.children()) {
+ if (child.className() == "Rectangle")
+ rect = child;
+ else if (child.className() == "Text")
+ text = child;
+ }
+
+ // test specific property values
+ QCOMPARE(findProperty(rect.properties(), "width").value(), qVariantFromValue(500));
+ QCOMPARE(findProperty(rect.properties(), "height").value(), qVariantFromValue(600));
+ QCOMPARE(findProperty(rect.properties(), "color").value(), qVariantFromValue(QColor("blue")));
+
+ QCOMPARE(findProperty(text.properties(), "color").value(), qVariantFromValue(QColor("blue")));
+ } else {
+ foreach(const QQmlDebugObjectReference &child, obj.children())
+ QCOMPARE(child.properties().count(), 0);
+ }
+}
+
+void tst_QQmlEngineDebug::queryObject_data()
+{
+ QTest::addColumn<bool>("recursive");
+
+ QTest::newRow("non-recursive") << false;
+ QTest::newRow("recursive") << true;
+}
+
+void tst_QQmlEngineDebug::queryExpressionResult()
+{
+ QFETCH(QString, expr);
+ QFETCH(QVariant, result);
+
+ QQmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
+ waitForQuery(q_engines); // check immediate deletion is ok
+
+ QQmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this);
+ waitForQuery(q_context);
+ int objectId = q_context->rootContext().objects()[0].debugId();
+
+ QQmlDebugExpressionQuery *q_expr;
+
+ QQmlEngineDebug *unconnected = new QQmlEngineDebug(0);
+ q_expr = unconnected->queryExpressionResult(objectId, expr, this);
+ QCOMPARE(q_expr->state(), QQmlDebugQuery::Error);
+ delete q_expr;
+ delete unconnected;
+
+ q_expr = m_dbg->queryExpressionResult(objectId, expr, this);
+ delete q_expr;
+
+ q_expr = m_dbg->queryExpressionResult(objectId, expr, this);
+ QCOMPARE(q_expr->expression().toString(), expr);
+ waitForQuery(q_expr);
+
+ QCOMPARE(q_expr->result(), result);
+
+ delete q_engines;
+ delete q_context;
+
+ // Make query invalid by deleting client
+ q_expr = m_dbg->queryExpressionResult(objectId, expr, this);
+ QCOMPARE(q_expr->state(), QQmlDebugQuery::Waiting);
+ delete m_dbg;
+ QCOMPARE(q_expr->state(), QQmlDebugQuery::Error);
+ delete q_expr;
+ m_dbg = new QQmlEngineDebug(m_conn, this);
+}
+
+void tst_QQmlEngineDebug::queryExpressionResult_data()
+{
+ QTest::addColumn<QString>("expr");
+ QTest::addColumn<QVariant>("result");
+
+ QTest::newRow("width + 50") << "width + 50" << qVariantFromValue(60);
+ QTest::newRow("blueRect.width") << "blueRect.width" << qVariantFromValue(500);
+ QTest::newRow("bad expr") << "aeaef" << qVariantFromValue(QString("<undefined>"));
+ QTest::newRow("QObject*") << "varObj" << qVariantFromValue(QString("<unnamed object>"));
+ QTest::newRow("list of QObject*") << "varObjList" << qVariantFromValue(QString("<unknown value>"));
+ QVariantMap map;
+ map.insert(QLatin1String("rect"), QVariant(QLatin1String("<unnamed object>")));
+ QTest::newRow("varObjMap") << "varObjMap" << qVariantFromValue(map);
+}
+
+void tst_QQmlEngineDebug::tst_QQmlDebugFileReference()
+{
+ QQmlDebugFileReference ref;
+ QVERIFY(ref.url().isEmpty());
+ QCOMPARE(ref.lineNumber(), -1);
+ QCOMPARE(ref.columnNumber(), -1);
+
+ ref.setUrl(QUrl("http://test"));
+ QCOMPARE(ref.url(), QUrl("http://test"));
+ ref.setLineNumber(1);
+ QCOMPARE(ref.lineNumber(), 1);
+ ref.setColumnNumber(1);
+ QCOMPARE(ref.columnNumber(), 1);
+
+ QQmlDebugFileReference copy(ref);
+ QQmlDebugFileReference copyAssign;
+ copyAssign = ref;
+ foreach (const QQmlDebugFileReference &r, (QList<QQmlDebugFileReference>() << copy << copyAssign)) {
+ QCOMPARE(r.url(), ref.url());
+ QCOMPARE(r.lineNumber(), ref.lineNumber());
+ QCOMPARE(r.columnNumber(), ref.columnNumber());
+ }
+}
+
+void tst_QQmlEngineDebug::tst_QQmlDebugEngineReference()
+{
+ QQmlDebugEngineReference ref;
+ QCOMPARE(ref.debugId(), -1);
+ QVERIFY(ref.name().isEmpty());
+
+ ref = QQmlDebugEngineReference(1);
+ QCOMPARE(ref.debugId(), 1);
+ QVERIFY(ref.name().isEmpty());
+
+ QQmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
+ waitForQuery(q_engines);
+ ref = q_engines->engines()[0];
+ delete q_engines;
+
+ QQmlDebugEngineReference copy(ref);
+ QQmlDebugEngineReference copyAssign;
+ copyAssign = ref;
+ foreach (const QQmlDebugEngineReference &r, (QList<QQmlDebugEngineReference>() << copy << copyAssign)) {
+ QCOMPARE(r.debugId(), ref.debugId());
+ QCOMPARE(r.name(), ref.name());
+ }
+}
+
+void tst_QQmlEngineDebug::tst_QQmlDebugObjectReference()
+{
+ QQmlDebugObjectReference ref;
+ QCOMPARE(ref.debugId(), -1);
+ QCOMPARE(ref.className(), QString());
+ QCOMPARE(ref.name(), QString());
+ QCOMPARE(ref.contextDebugId(), -1);
+ QVERIFY(ref.properties().isEmpty());
+ QVERIFY(ref.children().isEmpty());
+
+ QQmlDebugFileReference source = ref.source();
+ QVERIFY(source.url().isEmpty());
+ QVERIFY(source.lineNumber() < 0);
+ QVERIFY(source.columnNumber() < 0);
+
+ ref = QQmlDebugObjectReference(1);
+ QCOMPARE(ref.debugId(), 1);
+
+ QQmlDebugObjectReference rootObject = findRootObject();
+ QQmlDebugObjectQuery *query = m_dbg->queryObjectRecursive(rootObject, this);
+ waitForQuery(query);
+ ref = query->object();
+ delete query;
+
+ QVERIFY(ref.debugId() >= 0);
+
+ QQmlDebugObjectReference copy(ref);
+ QQmlDebugObjectReference copyAssign;
+ copyAssign = ref;
+ foreach (const QQmlDebugObjectReference &r, (QList<QQmlDebugObjectReference>() << copy << copyAssign))
+ recursiveCompareObjects(r, ref);
+}
+
+void tst_QQmlEngineDebug::tst_QQmlDebugContextReference()
+{
+ QQmlDebugContextReference ref;
+ QCOMPARE(ref.debugId(), -1);
+ QVERIFY(ref.name().isEmpty());
+ QVERIFY(ref.objects().isEmpty());
+ QVERIFY(ref.contexts().isEmpty());
+
+ QQmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
+ waitForQuery(q_engines);
+ QQmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this);
+ waitForQuery(q_context);
+
+ ref = q_context->rootContext();
+ delete q_engines;
+ delete q_context;
+ QVERIFY(ref.debugId() >= 0);
+
+ QQmlDebugContextReference copy(ref);
+ QQmlDebugContextReference copyAssign;
+ copyAssign = ref;
+ foreach (const QQmlDebugContextReference &r, (QList<QQmlDebugContextReference>() << copy << copyAssign))
+ recursiveCompareContexts(r, ref);
+}
+
+void tst_QQmlEngineDebug::tst_QQmlDebugPropertyReference()
+{
+ QQmlDebugObjectReference rootObject = findRootObject();
+ QQmlDebugObjectQuery *query = m_dbg->queryObject(rootObject, this);
+ waitForQuery(query);
+ QQmlDebugObjectReference obj = query->object();
+ delete query;
+
+ QQmlDebugPropertyReference ref = findProperty(obj.properties(), "scale");
+ QVERIFY(ref.objectDebugId() > 0);
+ QVERIFY(!ref.name().isEmpty());
+ QVERIFY(!ref.value().isNull());
+ QVERIFY(!ref.valueTypeName().isEmpty());
+ QVERIFY(!ref.binding().isEmpty());
+ QVERIFY(ref.hasNotifySignal());
+
+ QQmlDebugPropertyReference copy(ref);
+ QQmlDebugPropertyReference copyAssign;
+ copyAssign = ref;
+ foreach (const QQmlDebugPropertyReference &r, (QList<QQmlDebugPropertyReference>() << copy << copyAssign))
+ compareProperties(r, ref);
+}
+
+void tst_QQmlEngineDebug::setBindingForObject()
+{
+ QQmlDebugObjectReference rootObject = findRootObject();
+ QVERIFY(rootObject.debugId() != -1);
+ QQmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties(), "width");
+
+ QCOMPARE(widthPropertyRef.value(), QVariant(10));
+ QCOMPARE(widthPropertyRef.binding(), QString());
+
+ //
+ // set literal
+ //
+ m_dbg->setBindingForObject(rootObject.debugId(), "width", "15", true);
+
+ rootObject = findRootObject();
+ widthPropertyRef = findProperty(rootObject.properties(), "width");
+
+ QCOMPARE(widthPropertyRef.value(), QVariant(15));
+ QCOMPARE(widthPropertyRef.binding(), QString());
+
+ //
+ // set expression
+ //
+ m_dbg->setBindingForObject(rootObject.debugId(), "width", "height", false);
+
+ rootObject = findRootObject();
+ widthPropertyRef = findProperty(rootObject.properties(), "width");
+
+ QCOMPARE(widthPropertyRef.value(), QVariant(20));
+ QCOMPARE(widthPropertyRef.binding(), QString("height"));
+
+ //
+ // reset
+ //
+ m_dbg->resetBindingForObject(rootObject.debugId(), "width");
+
+ rootObject = findRootObject();
+ widthPropertyRef = findProperty(rootObject.properties(), "width");
+
+ // QCOMPARE(widthPropertyRef.value(), QVariant(0)); // TODO: Shouldn't this work?
+ QCOMPARE(widthPropertyRef.binding(), QString());
+
+ //
+ // set handler
+ //
+ rootObject = findRootObject();
+ QCOMPARE(rootObject.children().size(), 5); // Rectangle, Text, MouseArea, Component.onCompleted, NonScriptPropertyElement
+ QQmlDebugObjectReference mouseAreaObject = rootObject.children().at(2);
+ QQmlDebugObjectQuery *q_obj = m_dbg->queryObjectRecursive(mouseAreaObject, this);
+ waitForQuery(q_obj);
+ mouseAreaObject = q_obj->object();
+
+ QCOMPARE(mouseAreaObject.className(), QString("MouseArea"));
+
+ QQmlDebugPropertyReference onEnteredRef = findProperty(mouseAreaObject.properties(), "onEntered");
+
+ QCOMPARE(onEnteredRef.name(), QString("onEntered"));
+ QCOMPARE(onEnteredRef.value(), QVariant("(function onEntered() { { console.log('hello') } })"));
+
+ m_dbg->setBindingForObject(mouseAreaObject.debugId(), "onEntered", "{console.log('hello, world') }", false) ;
+
+ rootObject = findRootObject();
+ mouseAreaObject = rootObject.children().at(2);
+ q_obj = m_dbg->queryObjectRecursive(mouseAreaObject, this);
+ waitForQuery(q_obj);
+ mouseAreaObject = q_obj->object();
+ onEnteredRef = findProperty(mouseAreaObject.properties(), "onEntered");
+ QCOMPARE(onEnteredRef.name(), QString("onEntered"));
+ QCOMPARE(onEnteredRef.value(), QVariant("{console.log('hello, world') }"));
+}
+
+void tst_QQmlEngineDebug::setBindingInStates()
+{
+ // Check if changing bindings of propertychanges works
+
+ const int sourceIndex = 3;
+
+ QQmlDebugObjectReference obj = findRootObject(sourceIndex);
+
+ QVERIFY(obj.debugId() != -1);
+ QVERIFY(obj.children().count() >= 2);
+
+ // We are going to switch state a couple of times, we need to get rid of the transition before
+ QQmlDebugExpressionQuery *q_deleteTransition = m_dbg->queryExpressionResult(obj.debugId(),QString("transitions = []"),this);
+ waitForQuery(q_deleteTransition);
+ delete q_deleteTransition;
+
+
+ // check initial value of the property that is changing
+ QQmlDebugExpressionQuery *q_setState;
+ q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"state1\""),this);
+ waitForQuery(q_setState);
+ delete q_setState;
+
+ obj = findRootObject(sourceIndex);
+ QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),200);
+
+
+ q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"\""),this);
+ waitForQuery(q_setState);
+ delete q_setState;
+
+
+ obj = findRootObject(sourceIndex, true);
+ QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),100);
+
+
+ // change the binding
+ QQmlDebugObjectReference state = obj.children()[1];
+ QCOMPARE(state.className(), QString("State"));
+ QVERIFY(state.children().count() > 0);
+
+ QQmlDebugObjectReference propertyChange = state.children()[0];
+ QVERIFY(propertyChange.debugId() != -1);
+
+ QVERIFY( m_dbg->setBindingForObject(propertyChange.debugId(), "width",QVariant(300),true) );
+
+ // check properties changed in state
+ obj = findRootObject(sourceIndex);
+ QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),100);
+
+
+ q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"state1\""),this);
+ waitForQuery(q_setState);
+ delete q_setState;
+
+ obj = findRootObject(sourceIndex);
+ QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),300);
+
+ // check changing properties of base state from within a state
+ QVERIFY(m_dbg->setBindingForObject(obj.debugId(),"width","height*2",false));
+ QVERIFY(m_dbg->setBindingForObject(obj.debugId(),"height","200",true));
+
+ obj = findRootObject(sourceIndex);
+ QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),300);
+
+ q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"\""),this);
+ waitForQuery(q_setState);
+ delete q_setState;
+
+ obj = findRootObject(sourceIndex);
+ QCOMPARE(findProperty(obj.properties(),"width").value().toInt(), 400);
+
+ // reset binding while in a state
+ q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"state1\""),this);
+ waitForQuery(q_setState);
+ delete q_setState;
+
+ obj = findRootObject(sourceIndex);
+ QCOMPARE(findProperty(obj.properties(),"width").value().toInt(), 300);
+
+ m_dbg->resetBindingForObject(propertyChange.debugId(), "width");
+
+ obj = findRootObject(sourceIndex);
+ QCOMPARE(findProperty(obj.properties(),"width").value().toInt(), 400);
+
+ // re-add binding
+ m_dbg->setBindingForObject(propertyChange.debugId(), "width", "300", true);
+
+ obj = findRootObject(sourceIndex);
+ QCOMPARE(findProperty(obj.properties(),"width").value().toInt(), 300);
+}
+
+void tst_QQmlEngineDebug::queryObjectTree()
+{
+ const int sourceIndex = 3;
+
+ // Check if states/transitions are initialized when fetching root item
+ QQmlDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this);
+ waitForQuery(q_engines);
+
+ QQmlDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this);
+ waitForQuery(q_context);
+
+ QVERIFY(q_context->rootContext().objects().count() > sourceIndex);
+ QQmlDebugObjectReference rootObject = q_context->rootContext().objects()[sourceIndex];
+
+ QQmlDebugObjectQuery *q_obj = m_dbg->queryObjectRecursive(rootObject, this);
+ waitForQuery(q_obj);
+
+ QQmlDebugObjectReference obj = q_obj->object();
+
+ delete q_engines;
+ delete q_context;
+ delete q_obj;
+
+ QVERIFY(obj.debugId() != -1);
+ QVERIFY(obj.children().count() >= 2);
+
+
+
+ // check state
+ QQmlDebugObjectReference state = obj.children()[1];
+ QCOMPARE(state.className(), QString("State"));
+ QVERIFY(state.children().count() > 0);
+
+ QQmlDebugObjectReference propertyChange = state.children()[0];
+ QVERIFY(propertyChange.debugId() != -1);
+
+ QQmlDebugPropertyReference propertyChangeTarget = findProperty(propertyChange.properties(),"target");
+ QCOMPARE(propertyChangeTarget.objectDebugId(), propertyChange.debugId());
+
+ QQmlDebugObjectReference targetReference = qvariant_cast<QQmlDebugObjectReference>(propertyChangeTarget.value());
+ QVERIFY(targetReference.debugId() != -1);
+
+
+
+ // check transition
+ QQmlDebugObjectReference transition = obj.children()[0];
+ QCOMPARE(transition.className(), QString("Transition"));
+ QCOMPARE(findProperty(transition.properties(),"from").value().toString(), QString("*"));
+ QCOMPARE(findProperty(transition.properties(),"to").value(), findProperty(state.properties(),"name").value());
+ QVERIFY(transition.children().count() > 0);
+
+ QQmlDebugObjectReference animation = transition.children()[0];
+ QVERIFY(animation.debugId() != -1);
+
+ QQmlDebugPropertyReference animationTarget = findProperty(animation.properties(),"target");
+ QCOMPARE(animationTarget.objectDebugId(), animation.debugId());
+
+ targetReference = qvariant_cast<QQmlDebugObjectReference>(animationTarget.value());
+ QVERIFY(targetReference.debugId() != -1);
+
+ QCOMPARE(findProperty(animation.properties(),"property").value().toString(), QString("width"));
+ QCOMPARE(findProperty(animation.properties(),"duration").value().toInt(), 100);
+}
+
+int main(int argc, char *argv[])
+{
+ int _argc = argc + 1;
+ char **_argv = new char*[_argc];
+ for (int i = 0; i < argc; ++i)
+ _argv[i] = argv[i];
+ char arg[] = "-qmljsdebugger=port:3768";
+ _argv[_argc - 1] = arg;
+
+ QGuiApplication app(_argc, _argv);
+ tst_QQmlEngineDebug tc;
+ return QTest::qExec(&tc, _argc, _argv);
+ delete _argv;
+}
+
+#include "tst_qqmlenginedebug.moc"
diff --git a/tests/auto/qml/debugger/qqmlinspector/app/app.pro b/tests/auto/qml/debugger/qqmlinspector/app/app.pro
new file mode 100644
index 0000000000..f6ef983735
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlinspector/app/app.pro
@@ -0,0 +1,9 @@
+TARGET = app
+QT += qml quick widgets
+
+CONFIG += declarative_debug
+macx:CONFIG -= app_bundle
+
+SOURCES += main.cpp
+
+OTHER_FILES += qtquick1.qml qtquick2.qml
diff --git a/tests/auto/qml/debugger/qqmlinspector/app/main.cpp b/tests/auto/qml/debugger/qqmlinspector/app/main.cpp
new file mode 100644
index 0000000000..a7ef09c283
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlinspector/app/main.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QDebug>
+#include <QtCore/QStringList>
+#include <QtQuick/QQuickView>
+#include <QtGui/QGuiApplication>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ bool qtquick2 = true;
+ for (int i = 1; i < app.arguments().size(); ++i) {
+ const QString arg = app.arguments().at(i);
+ if (arg == "-qtquick1") {
+ qtquick2 = false;
+ } else if (arg == "-qtquick2") {
+ qtquick2 = true;
+ } else {
+ qWarning() << "Usage: " << app.arguments().at(0) << "[-qtquick1|-qtquick2]";
+ return -1;
+ }
+ }
+
+ if (qtquick2) {
+ QQuickView *view = new QQuickView();
+ view->setSource(QUrl::fromLocalFile("app/qtquick2.qml"));
+ } else {
+ qWarning("No suitable QtQuick1 implementation is available!");
+ }
+ return app.exec();
+}
diff --git a/tests/auto/qml/debugger/qqmlinspector/app/qtquick2.qml b/tests/auto/qml/debugger/qqmlinspector/app/qtquick2.qml
new file mode 100644
index 0000000000..9c36e13c5b
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlinspector/app/qtquick2.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+
+}
diff --git a/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro b/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro
new file mode 100644
index 0000000000..5544f76581
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += tst_qqmlinspector.pro app
diff --git a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
new file mode 100644
index 0000000000..4f74a036d6
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include <QSignalSpy>
+#include <QTimer>
+#include <QHostAddress>
+#include <QDebug>
+#include <QThread>
+
+#include "../../../../../src/plugins/qmltooling/shared/qqmlinspectorprotocol.h"
+#include "../shared/debugutil_p.h"
+
+using namespace QmlJSDebugger;
+
+#define PORT 13772
+#define STR_PORT "13772"
+
+class QQmlInspectorClient : public QQmlDebugClient
+{
+ Q_OBJECT
+
+public:
+ QQmlInspectorClient(QQmlDebugConnection *connection)
+ : QQmlDebugClient(QLatin1String("QQmlObserverMode"), connection)
+ , m_showAppOnTop(false)
+ {
+ }
+
+ bool showAppOnTop() const { return m_showAppOnTop; }
+ void setShowAppOnTop(bool showOnTop);
+
+signals:
+ void showAppOnTopChanged();
+
+protected:
+ void messageReceived(const QByteArray &message);
+
+private:
+ bool m_showAppOnTop;
+};
+
+class tst_QQmlInspector : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QQmlInspector()
+ : m_process(0)
+ , m_connection(0)
+ , m_client(0)
+ {
+ }
+
+
+private:
+ QQmlDebugProcess *m_process;
+ QQmlDebugConnection *m_connection;
+ QQmlInspectorClient *m_client;
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+ void connect();
+ void showAppOnTop();
+};
+
+
+void QQmlInspectorClient::setShowAppOnTop(bool showOnTop)
+{
+ QByteArray message;
+ QDataStream ds(&message, QIODevice::WriteOnly);
+ ds << InspectorProtocol::ShowAppOnTop << showOnTop;
+
+ sendMessage(message);
+}
+
+void QQmlInspectorClient::messageReceived(const QByteArray &message)
+{
+ QDataStream ds(message);
+ InspectorProtocol::Message type;
+ ds >> type;
+
+ switch (type) {
+ case InspectorProtocol::ShowAppOnTop:
+ ds >> m_showAppOnTop;
+ emit showAppOnTopChanged();
+ break;
+ default:
+ qDebug() << "Unhandled message " << (int)type;
+ }
+}
+
+void tst_QQmlInspector::initTestCase()
+{
+}
+
+void tst_QQmlInspector::cleanupTestCase()
+{
+}
+
+void tst_QQmlInspector::init()
+{
+ const QString executable = SRCDIR"/app/app";
+ const QString argument = "-qmljsdebugger=port:"STR_PORT",block";
+
+ m_process = new QQmlDebugProcess(executable);
+ m_process->start(QStringList() << argument);
+ if (!m_process->waitForSessionStart()) {
+ QFAIL(QString("Could not launch app '%1'.\nApplication output:\n%2").arg(executable, m_process->output()).toAscii());
+ }
+
+ QQmlDebugConnection *m_connection = new QQmlDebugConnection();
+ m_client = new QQmlInspectorClient(m_connection);
+
+ m_connection->connectToHost(QLatin1String("127.0.0.1"), PORT);
+}
+
+void tst_QQmlInspector::cleanup()
+{
+ delete m_process;
+ delete m_connection;
+ delete m_client;
+}
+
+void tst_QQmlInspector::connect()
+{
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+}
+
+void tst_QQmlInspector::showAppOnTop()
+{
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->setShowAppOnTop(true);
+ QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(showAppOnTopChanged())));
+ QCOMPARE(m_client->showAppOnTop(), true);
+
+ m_client->setShowAppOnTop(false);
+ QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(showAppOnTopChanged())));
+ QCOMPARE(m_client->showAppOnTop(), false);
+}
+
+QTEST_MAIN(tst_QQmlInspector)
+
+#include "tst_qqmlinspector.moc"
diff --git a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.pro b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.pro
new file mode 100644
index 0000000000..010e97cef7
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.pro
@@ -0,0 +1,12 @@
+CONFIG += testcase
+TARGET = tst_qqmlinspector
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/debugutil_p.h
+SOURCES += tst_qqmlinspector.cpp \
+ ../shared/debugutil.cpp
+
+DEFINES += SRCDIR=\\\"$$PWD\\\"
+CONFIG += parallel_test declarative_debug
+
+QT += qml-private testlib
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml
new file mode 100644
index 0000000000..b250524caa
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+
+Item {
+ Timer {
+ running: true
+ interval: 1
+ onTriggered: Qt.quit();
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml
new file mode 100644
index 0000000000..9c36e13c5b
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+
+}
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro
new file mode 100644
index 0000000000..81fe3d5943
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro
@@ -0,0 +1,15 @@
+CONFIG += testcase
+TARGET = tst_qqmlprofilerservice
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/debugutil_p.h
+
+SOURCES += tst_qqmlprofilerservice.cpp \
+ ../shared/debugutil.cpp
+OTHER_FILES += data/test.qml
+
+include (../../../shared/util.pri)
+
+CONFIG += parallel_test declarative_debug
+
+QT += core-private v8-private qml-private testlib
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
new file mode 100644
index 0000000000..edc120ba85
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -0,0 +1,310 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QLibraryInfo>
+
+#include "QtQml/private/qqmlprofilerservice_p.h"
+#include "../shared/debugutil_p.h"
+#include "../../../shared/util.h"
+
+#define PORT 13773
+#define STR_PORT "13773"
+
+class QQmlProfilerClient : public QQmlDebugClient
+{
+ Q_OBJECT
+
+public:
+ QQmlProfilerClient(QQmlDebugConnection *connection)
+ : QQmlDebugClient(QLatin1String("CanvasFrameRate"), connection)
+ {
+ }
+
+ QList<QQmlProfilerData> traceMessages;
+
+ void setTraceState(bool enabled) {
+ QByteArray message;
+ QDataStream stream(&message, QIODevice::WriteOnly);
+ stream << enabled;
+ sendMessage(message);
+ }
+
+signals:
+ void complete();
+
+protected:
+ void messageReceived(const QByteArray &message);
+};
+
+class tst_QQmlProfilerService : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_QQmlProfilerService()
+ : m_process(0)
+ , m_connection(0)
+ , m_client(0)
+ {
+ }
+
+private:
+ QQmlDebugProcess *m_process;
+ QQmlDebugConnection *m_connection;
+ QQmlProfilerClient *m_client;
+
+ void connect(bool block, const QString &testFile);
+
+private slots:
+ void cleanup();
+
+ void blockingConnectWithTraceEnabled();
+ void blockingConnectWithTraceDisabled();
+ void nonBlockingConnect();
+ void profileOnExit();
+};
+
+void QQmlProfilerClient::messageReceived(const QByteArray &message)
+{
+ QByteArray msg = message;
+ QDataStream stream(&msg, QIODevice::ReadOnly);
+
+
+ QQmlProfilerData data;
+ data.time = -2;
+ data.messageType = -1;
+ data.detailType = -1;
+ data.line = -1;
+ data.framerate = -1;
+ data.animationcount = -1;
+
+ stream >> data.time >> data.messageType;
+
+ QVERIFY(data.time >= -1);
+
+ switch (data.messageType) {
+ case (QQmlProfilerService::Event): {
+ stream >> data.detailType;
+
+ switch (data.detailType) {
+ case QQmlProfilerService::AnimationFrame: {
+ stream >> data.framerate >> data.animationcount;
+ QVERIFY(data.framerate != -1);
+ QVERIFY(data.animationcount != -1);
+ break;
+ }
+ case QQmlProfilerService::FramePaint:
+ case QQmlProfilerService::Mouse:
+ case QQmlProfilerService::Key:
+ case QQmlProfilerService::StartTrace:
+ case QQmlProfilerService::EndTrace:
+ break;
+ default: {
+ QString failMsg = QString("Unknown event type:") + data.detailType;
+ QFAIL(qPrintable(failMsg));
+ break;
+ }
+ }
+ break;
+ }
+ case QQmlProfilerService::Complete: {
+ emit complete();
+ return;
+ }
+ case QQmlProfilerService::RangeStart: {
+ stream >> data.detailType;
+ QVERIFY(data.detailType >= 0 && data.detailType < QQmlProfilerService::MaximumRangeType);
+ break;
+ }
+ case QQmlProfilerService::RangeEnd: {
+ stream >> data.detailType;
+ QVERIFY(data.detailType >= 0 && data.detailType < QQmlProfilerService::MaximumRangeType);
+ break;
+ }
+ case QQmlProfilerService::RangeData: {
+ stream >> data.detailType >> data.detailData;
+ QVERIFY(data.detailType >= 0 && data.detailType < QQmlProfilerService::MaximumRangeType);
+ break;
+ }
+ case QQmlProfilerService::RangeLocation: {
+ stream >> data.detailType >> data.detailData >> data.line >> data.column;
+ QVERIFY(data.detailType >= 0 && data.detailType < QQmlProfilerService::MaximumRangeType);
+ QVERIFY(data.line >= -2);
+ break;
+ }
+ default:
+ QString failMsg = QString("Unknown message type:") + data.messageType;
+ QFAIL(qPrintable(failMsg));
+ break;
+ }
+ QVERIFY(stream.atEnd());
+ traceMessages.append(data);
+}
+
+void tst_QQmlProfilerService::connect(bool block, const QString &testFile)
+{
+ const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene";
+ QStringList arguments;
+
+ if (block)
+ arguments << QString("-qmljsdebugger=port:"STR_PORT",block");
+ else
+ arguments << QString("-qmljsdebugger=port:"STR_PORT);
+
+ arguments << QQmlDataTest::instance()->testFile(testFile);
+
+ m_process = new QQmlDebugProcess(executable);
+ m_process->start(QStringList() << arguments);
+ if (!m_process->waitForSessionStart()) {
+ QString failMsg = QString("Could not launch app '%1'.\nApplication output:\n%2").arg(
+ executable, m_process->output());
+ QFAIL(qPrintable(failMsg));
+ }
+
+ QQmlDebugConnection *m_connection = new QQmlDebugConnection();
+ m_client = new QQmlProfilerClient(m_connection);
+
+ m_connection->connectToHost(QLatin1String("127.0.0.1"), PORT);
+}
+
+void tst_QQmlProfilerService::cleanup()
+{
+ delete m_process;
+ delete m_connection;
+ delete m_client;
+}
+
+void tst_QQmlProfilerService::blockingConnectWithTraceEnabled()
+{
+ connect(true, "test.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->setTraceState(true);
+ m_client->setTraceState(false);
+ if (!QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete()))) {
+ QString failMsg
+ = QString("No trace received in time. App output: \n%1\n").arg(m_process->output());
+ QFAIL(qPrintable(failMsg));
+ }
+
+ QVERIFY(m_client->traceMessages.count());
+ // must start with "StartTrace"
+ QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerService::Event);
+ QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerService::StartTrace);
+
+ // must end with "EndTrace"
+ QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerService::Event);
+ QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerService::EndTrace);
+}
+
+void tst_QQmlProfilerService::blockingConnectWithTraceDisabled()
+{
+ connect(true, "test.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->setTraceState(false);
+ m_client->setTraceState(true);
+ m_client->setTraceState(false);
+ if (!QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete()))) {
+ QString failMsg
+ = QString("No trace received in time. App output: \n%1\n").arg(m_process->output());
+ QFAIL(qPrintable(failMsg));
+ }
+
+ QVERIFY(m_client->traceMessages.count());
+
+ // must start with "StartTrace"
+ QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerService::Event);
+ QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerService::StartTrace);
+
+ // must end with "EndTrace"
+ QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerService::Event);
+ QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerService::EndTrace);
+}
+
+void tst_QQmlProfilerService::nonBlockingConnect()
+{
+ connect(false, "test.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->setTraceState(true);
+ m_client->setTraceState(false);
+ if (!QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete()))) {
+ QString failMsg
+ = QString("No trace received in time. App output: \n%1\n").arg(m_process->output());
+ QFAIL(qPrintable(failMsg));
+ }
+
+ // must start with "StartTrace"
+ QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerService::Event);
+ QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerService::StartTrace);
+
+ // must end with "EndTrace"
+ QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerService::Event);
+ QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerService::EndTrace);
+}
+
+void tst_QQmlProfilerService::profileOnExit()
+{
+ connect(true, "exit.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->setTraceState(true);
+
+ if (!QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete()))) {
+ QString failMsg
+ = QString("No trace received in time. App output: \n%1\n").arg(m_process->output());
+ QFAIL(qPrintable(failMsg));
+ }
+
+ // must start with "StartTrace"
+ QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerService::Event);
+ QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerService::StartTrace);
+
+ // must end with "EndTrace"
+ QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerService::Event);
+ QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerService::EndTrace);
+}
+
+QTEST_MAIN(tst_QQmlProfilerService)
+
+#include "tst_qqmlprofilerservice.moc"
diff --git a/tests/auto/qml/debugger/qv8profilerservice/data/console.qml b/tests/auto/qml/debugger/qv8profilerservice/data/console.qml
new file mode 100644
index 0000000000..c23c820216
--- /dev/null
+++ b/tests/auto/qml/debugger/qv8profilerservice/data/console.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+
+Item {
+ function f()
+ {
+ }
+
+ Component.onCompleted: {
+ console.profile();
+ f();
+ console.profileEnd();
+ }
+}
diff --git a/tests/auto/qml/debugger/qv8profilerservice/data/exit.qml b/tests/auto/qml/debugger/qv8profilerservice/data/exit.qml
new file mode 100644
index 0000000000..604265354c
--- /dev/null
+++ b/tests/auto/qml/debugger/qv8profilerservice/data/exit.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+
+Item {
+ Timer {
+ running: true
+ interval: 1
+ onTriggered: {
+ Qt.quit();
+ }
+ }
+}
diff --git a/tests/auto/qml/debugger/qv8profilerservice/data/test.qml b/tests/auto/qml/debugger/qv8profilerservice/data/test.qml
new file mode 100644
index 0000000000..9c36e13c5b
--- /dev/null
+++ b/tests/auto/qml/debugger/qv8profilerservice/data/test.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+
+}
diff --git a/tests/auto/qml/debugger/qv8profilerservice/qv8profilerservice.pro b/tests/auto/qml/debugger/qv8profilerservice/qv8profilerservice.pro
new file mode 100644
index 0000000000..e980d6594d
--- /dev/null
+++ b/tests/auto/qml/debugger/qv8profilerservice/qv8profilerservice.pro
@@ -0,0 +1,16 @@
+CONFIG += testcase
+TARGET = tst_qv8profilerservice
+macx:CONFIG -= app_bundle
+
+HEADERS += ../shared/debugutil_p.h
+
+SOURCES += tst_qv8profilerservice.cpp \
+ ../shared/debugutil.cpp
+
+include (../../../shared/util.pri)
+
+OTHER_FILES += data/test.qml
+
+CONFIG += parallel_test declarative_debug
+
+QT += qml-private testlib
diff --git a/tests/auto/qml/debugger/qv8profilerservice/tst_qv8profilerservice.cpp b/tests/auto/qml/debugger/qv8profilerservice/tst_qv8profilerservice.cpp
new file mode 100644
index 0000000000..c5992a4403
--- /dev/null
+++ b/tests/auto/qml/debugger/qv8profilerservice/tst_qv8profilerservice.cpp
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QLibraryInfo>
+
+#include "QtQml/private/qv8profilerservice_p.h"
+#include "../shared/debugutil_p.h"
+#include "../../../shared/util.h"
+
+#define PORT 13774
+#define STR_PORT "13774"
+
+class QV8ProfilerClient : public QQmlDebugClient
+{
+ Q_OBJECT
+
+public:
+ QV8ProfilerClient(QQmlDebugConnection *connection)
+ : QQmlDebugClient(QLatin1String("V8Profiler"), connection)
+ {
+ }
+
+ void startProfiling(const QString &name) {
+ QByteArray message;
+ QDataStream stream(&message, QIODevice::WriteOnly);
+ stream << QByteArray("V8PROFILER") << QByteArray("start") << name;
+ sendMessage(message);
+ }
+
+ void stopProfiling(const QString &name) {
+ QByteArray message;
+ QDataStream stream(&message, QIODevice::WriteOnly);
+ stream << QByteArray("V8PROFILER") << QByteArray("stop") << name;
+ sendMessage(message);
+ }
+
+ void takeSnapshot() {
+ QByteArray message;
+ QDataStream stream(&message, QIODevice::WriteOnly);
+ stream << QByteArray("V8SNAPSHOT") << QByteArray("full");
+ sendMessage(message);
+ }
+
+ void deleteSnapshots() {
+ QByteArray message;
+ QDataStream stream(&message, QIODevice::WriteOnly);
+ stream << QByteArray("V8SNAPSHOT") << QByteArray("delete");
+ sendMessage(message);
+ }
+
+ QList<QV8ProfilerData> traceMessages;
+ QList<QByteArray> snapshotMessages;
+
+signals:
+ void started();
+ void complete();
+ void snapshot();
+
+protected:
+ void messageReceived(const QByteArray &message);
+};
+
+class tst_QV8ProfilerService : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_QV8ProfilerService()
+ : m_process(0)
+ , m_connection(0)
+ , m_client(0)
+ {
+ }
+
+private:
+ QQmlDebugProcess *m_process;
+ QQmlDebugConnection *m_connection;
+ QV8ProfilerClient *m_client;
+
+ void connect(bool block, const QString &testFile);
+
+private slots:
+ void cleanup();
+
+ void blockingConnectWithTraceEnabled();
+ void blockingConnectWithTraceDisabled();
+ void nonBlockingConnect();
+ void snapshot();
+ void profileOnExit();
+ void console();
+};
+
+void QV8ProfilerClient::messageReceived(const QByteArray &message)
+{
+ QByteArray msg = message;
+ QDataStream stream(&msg, QIODevice::ReadOnly);
+
+ int messageType;
+ stream >> messageType;
+
+ QVERIFY(messageType >= 0);
+ QVERIFY(messageType < QV8ProfilerService::V8MaximumMessage);
+
+ switch (messageType) {
+ case QV8ProfilerService::V8Entry: {
+ QV8ProfilerData entry;
+ stream >> entry.filename >> entry.functionname >> entry.lineNumber >> entry.totalTime >> entry.selfTime >> entry.treeLevel;
+ traceMessages.append(entry);
+ break;
+ }
+ case QV8ProfilerService::V8Complete:
+ emit complete();
+ break;
+ case QV8ProfilerService::V8SnapshotChunk: {
+ QByteArray json;
+ stream >> json;
+ snapshotMessages.append(json);
+ break;
+ }
+ case QV8ProfilerService::V8SnapshotComplete:
+ emit snapshot();
+ break;
+ case QV8ProfilerService::V8Started:
+ emit started();
+ break;
+ default:
+ QString failMessage = QString("Unknown message type: %1").arg(messageType);
+ QFAIL(qPrintable(failMessage));
+ }
+
+ QVERIFY(stream.atEnd());
+}
+
+void tst_QV8ProfilerService::connect(bool block, const QString &testFile)
+{
+ const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene";
+ QStringList arguments;
+
+ if (block)
+ arguments << QString("-qmljsdebugger=port:"STR_PORT",block");
+ else
+ arguments << QString("-qmljsdebugger=port:"STR_PORT);
+
+ arguments << QQmlDataTest::instance()->testFile(testFile);
+
+ m_process = new QQmlDebugProcess(executable);
+ m_process->start(QStringList() << arguments);
+ if (!m_process->waitForSessionStart()) {
+ QString failMsg = QString("Could not launch app '%1'.\nApplication output:\n%2").arg(
+ executable, m_process->output());
+ QFAIL(qPrintable(failMsg));
+ }
+
+ QQmlDebugConnection *m_connection = new QQmlDebugConnection();
+ m_client = new QV8ProfilerClient(m_connection);
+
+ m_connection->connectToHost(QLatin1String("127.0.0.1"), PORT);
+}
+
+void tst_QV8ProfilerService::cleanup()
+{
+ if (QTest::currentTestFailed())
+ qDebug() << "Application Output:" << m_process->output();
+
+ delete m_process;
+ delete m_connection;
+ delete m_client;
+}
+
+void tst_QV8ProfilerService::blockingConnectWithTraceEnabled()
+{
+ connect(true, "test.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->startProfiling("");
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(started())),
+ "No start signal received in time.");
+ m_client->stopProfiling("");
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())),
+ "No trace received in time.");
+}
+
+void tst_QV8ProfilerService::blockingConnectWithTraceDisabled()
+{
+ connect(true, "test.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->stopProfiling("");
+ if (QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete()), 1000)) {
+ QString failMsg
+ = QString("Unexpected trace received! App output: %1\n\n").arg(m_process->output());
+ QFAIL(qPrintable(failMsg));
+ }
+ m_client->startProfiling("");
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(started())),
+ "No start signal received in time.");
+ m_client->stopProfiling("");
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())),
+ "No trace received in time.");
+}
+
+void tst_QV8ProfilerService::nonBlockingConnect()
+{
+ connect(false, "test.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->startProfiling("");
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(started())),
+ "No start signal received in time.");
+ m_client->stopProfiling("");
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())),
+ "No trace received in time.");
+}
+
+void tst_QV8ProfilerService::snapshot()
+{
+ connect(false, "test.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->takeSnapshot();
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(snapshot())),
+ "No trace received in time.");
+}
+
+void tst_QV8ProfilerService::profileOnExit()
+{
+ connect(true, "exit.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->startProfiling("");
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(started())),
+ "No start signal received in time.");
+
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())),
+ "No trace received in time.");
+ //QVERIFY(!m_client->traceMessages.isEmpty());
+}
+
+void tst_QV8ProfilerService::console()
+{
+ connect(true, "console.qml");
+ QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
+
+ m_client->stopProfiling("");
+
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(started())),
+ "No start signal received in time.");
+ QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())),
+ "No trace received in time.");
+ QVERIFY(!m_client->traceMessages.isEmpty());
+}
+
+QTEST_MAIN(tst_QV8ProfilerService)
+
+#include "tst_qv8profilerservice.moc"
diff --git a/tests/auto/qml/debugger/shared/debugutil.cpp b/tests/auto/qml/debugger/shared/debugutil.cpp
new file mode 100644
index 0000000000..8ed64d3a5d
--- /dev/null
+++ b/tests/auto/qml/debugger/shared/debugutil.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "debugutil_p.h"
+
+#include <QEventLoop>
+#include <QTimer>
+
+#include <private/qqmldebugclient_p.h>
+#include <private/qqmldebugservice_p.h>
+
+bool QQmlDebugTest::waitForSignal(QObject *receiver, const char *member, int timeout) {
+ QEventLoop loop;
+ QTimer timer;
+ timer.setSingleShot(true);
+ QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
+ QObject::connect(receiver, member, &loop, SLOT(quit()));
+ timer.start(timeout);
+ loop.exec();
+ return timer.isActive();
+}
+
+QQmlDebugTestService::QQmlDebugTestService(const QString &s, float version, QObject *parent)
+ : QQmlDebugService(s, version, parent)
+{
+ registerService();
+}
+
+void QQmlDebugTestService::messageReceived(const QByteArray &ba)
+{
+ sendMessage(ba);
+}
+
+void QQmlDebugTestService::stateChanged(State)
+{
+ emit stateHasChanged();
+}
+
+
+QQmlDebugTestClient::QQmlDebugTestClient(const QString &s, QQmlDebugConnection *c)
+ : QQmlDebugClient(s, c)
+{
+}
+
+QByteArray QQmlDebugTestClient::waitForResponse()
+{
+ lastMsg.clear();
+ QQmlDebugTest::waitForSignal(this, SIGNAL(serverMessage(QByteArray)));
+ if (lastMsg.isEmpty()) {
+ qWarning() << "tst_QQmlDebugTestClient: no response from server!";
+ return QByteArray();
+ }
+ return lastMsg;
+}
+
+void QQmlDebugTestClient::stateChanged(State stat)
+{
+ QCOMPARE(stat, state());
+ emit stateHasChanged();
+}
+
+void QQmlDebugTestClient::messageReceived(const QByteArray &ba)
+{
+ lastMsg = ba;
+ emit serverMessage(ba);
+}
+
+QQmlDebugProcess::QQmlDebugProcess(const QString &executable)
+ : m_executable(executable)
+ , m_started(false)
+{
+ m_process.setProcessChannelMode(QProcess::MergedChannels);
+ m_timer.setSingleShot(true);
+ m_timer.setInterval(5000);
+ connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processAppOutput()));
+ connect(&m_timer, SIGNAL(timeout()), &m_eventLoop, SLOT(quit()));
+}
+
+QQmlDebugProcess::~QQmlDebugProcess()
+{
+ stop();
+}
+
+void QQmlDebugProcess::start(const QStringList &arguments)
+{
+ m_mutex.lock();
+ m_process.setEnvironment(m_environment);
+ m_process.start(m_executable, arguments);
+ m_process.waitForStarted();
+ m_timer.start();
+ m_mutex.unlock();
+}
+
+void QQmlDebugProcess::stop()
+{
+ if (m_process.state() != QProcess::NotRunning) {
+ m_process.kill();
+ m_process.waitForFinished(5000);
+ }
+}
+
+bool QQmlDebugProcess::waitForSessionStart()
+{
+ if (m_process.state() != QProcess::Running) {
+ qWarning() << "Could not start up " << m_executable;
+ return false;
+ }
+ m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
+
+ return m_started;
+}
+
+void QQmlDebugProcess::setEnvironment(const QStringList &environment)
+{
+ m_environment = environment;
+}
+
+QString QQmlDebugProcess::output() const
+{
+ return m_output;
+}
+
+void QQmlDebugProcess::processAppOutput()
+{
+ m_mutex.lock();
+
+ QString newOutput = m_process.readAll();
+ m_output.append(newOutput);
+ m_outputBuffer.append(newOutput);
+
+ while (true) {
+ const int nlIndex = m_outputBuffer.indexOf(QLatin1Char('\n'));
+ if (nlIndex < 0) // no further complete lines
+ break;
+ const QString line = m_outputBuffer.left(nlIndex);
+ m_outputBuffer = m_outputBuffer.right(m_outputBuffer.size() - nlIndex - 1);
+
+ if (line.startsWith("Qml debugging is enabled")) // ignore
+ continue;
+ if (line.startsWith("QQmlDebugServer:")) {
+ if (line.contains("Waiting for connection ")) {
+ m_started = true;
+ m_eventLoop.quit();
+ continue;
+ }
+ if (line.contains("Connection established")) {
+ continue;
+ }
+ }
+ }
+ m_mutex.unlock();
+}
diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h
new file mode 100644
index 0000000000..194f8fa14c
--- /dev/null
+++ b/tests/auto/qml/debugger/shared/debugutil_p.h
@@ -0,0 +1,127 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEBUGUTIL_H
+#define DEBUGUTIL_H
+
+#include <QEventLoop>
+#include <QTimer>
+#include <QThread>
+#include <QTest>
+#include <QProcess>
+
+#include <QtQml/qqmlengine.h>
+
+#include <private/qqmldebugclient_p.h>
+#include <private/qqmldebugservice_p.h>
+
+class QQmlDebugTest
+{
+public:
+ static bool waitForSignal(QObject *receiver, const char *member, int timeout = 5000);
+};
+
+class QQmlDebugTestService : public QQmlDebugService
+{
+ Q_OBJECT
+public:
+ QQmlDebugTestService(const QString &s, float version = 1, QObject *parent = 0);
+
+signals:
+ void stateHasChanged();
+
+protected:
+ virtual void messageReceived(const QByteArray &ba);
+ virtual void stateChanged(State state);
+};
+
+class QQmlDebugTestClient : public QQmlDebugClient
+{
+ Q_OBJECT
+public:
+ QQmlDebugTestClient(const QString &s, QQmlDebugConnection *c);
+
+ QByteArray waitForResponse();
+
+signals:
+ void stateHasChanged();
+ void serverMessage(const QByteArray &);
+
+protected:
+ virtual void stateChanged(State state);
+ virtual void messageReceived(const QByteArray &ba);
+
+private:
+ QByteArray lastMsg;
+};
+
+class QQmlDebugProcess : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlDebugProcess(const QString &executable);
+ ~QQmlDebugProcess();
+
+ void setEnvironment(const QStringList &environment);
+
+ void start(const QStringList &arguments);
+ bool waitForSessionStart();
+
+ QString output() const;
+ void stop();
+
+private slots:
+ void processAppOutput();
+
+private:
+ QString m_executable;
+ QProcess m_process;
+ QString m_outputBuffer;
+ QString m_output;
+ QTimer m_timer;
+ QEventLoop m_eventLoop;
+ QMutex m_mutex;
+ bool m_started;
+ QStringList m_environment;
+};
+
+#endif // DEBUGUTIL_H