aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/debugger/qqmldebugjs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/debugger/qqmldebugjs')
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml49
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/breakpointRelocation.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/changeBreakpoint.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/condition.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/condition.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/createComponent.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/encodeQmlScope.qml19
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/exception.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/exception.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/loadjsfile.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/oncompleted.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/quit.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/quit.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/stepAction.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/test.js (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.js)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/test.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/timer.qml (renamed from tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/timer.qml)0
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro26
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro25
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp1552
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.cpp43
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.pro12
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp1008
20 files changed, 1099 insertions, 1635 deletions
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml b/tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml
new file mode 100644
index 0000000000..72a8c9559c
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/breakOnAnchor.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.11
+
+
+Item {
+ visible: true
+ Text {
+ anchors.centerIn: parent
+ text: "bla"
+ MouseArea {
+ anchors.fill: parent
+ }
+ }
+
+ Timer {
+ interval: 100;
+ running: true;
+ onTriggered: {
+ Qt.quit();
+ }
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/breakpointRelocation.qml b/tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml
index 06aabc94f9..06aabc94f9 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/breakpointRelocation.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/breakpointRelocation.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/changeBreakpoint.qml b/tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml
index 00a85e56ac..00a85e56ac 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/changeBreakpoint.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/changeBreakpoint.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/condition.qml b/tests/auto/qml/debugger/qqmldebugjs/data/condition.qml
index 3a50ba2eb7..3a50ba2eb7 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/condition.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/condition.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/createComponent.qml b/tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml
index 089cc03733..089cc03733 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/createComponent.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/createComponent.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/encodeQmlScope.qml b/tests/auto/qml/debugger/qqmldebugjs/data/encodeQmlScope.qml
new file mode 100644
index 0000000000..7ea048044f
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/encodeQmlScope.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Item {
+ property int a: 0
+ property int b: 0
+ onAChanged: console.log("inline")
+ onBChanged: {
+ console.log("extra braces");
+ }
+
+ Timer {
+ interval: 10
+ running: true
+ onTriggered: {
+ parent.a += 10;
+ parent.b -= 10;
+ }
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/exception.qml b/tests/auto/qml/debugger/qqmldebugjs/data/exception.qml
index 06f11fa016..06f11fa016 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/exception.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/exception.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/loadjsfile.qml b/tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml
index 088c1b19fd..088c1b19fd 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/loadjsfile.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/loadjsfile.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/oncompleted.qml b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml
index deba24cf91..deba24cf91 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/oncompleted.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/quit.qml b/tests/auto/qml/debugger/qqmldebugjs/data/quit.qml
index bc8c2b90ae..bc8c2b90ae 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/quit.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/quit.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/stepAction.qml b/tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml
index fb0b6c401c..fb0b6c401c 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/stepAction.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/stepAction.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.js b/tests/auto/qml/debugger/qqmldebugjs/data/test.js
index 92e61d103c..92e61d103c 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.js
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/test.js
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.qml b/tests/auto/qml/debugger/qqmldebugjs/data/test.qml
index a36d0cae91..a36d0cae91 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/test.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/test.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/timer.qml b/tests/auto/qml/debugger/qqmldebugjs/data/timer.qml
index 66e6b96e18..66e6b96e18 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/data/timer.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/timer.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro
index bd6debcea1..acd5546a02 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro
+++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs.pro
@@ -1,4 +1,24 @@
-TEMPLATE = subdirs
-SUBDIRS = qqmldebugjs qqmldebugjsserver
+CONFIG += testcase
+TARGET = tst_qqmldebugjs
+QT += testlib gui-private core-private
+macos:CONFIG -= app_bundle
-qqmldebugjs.depends = qqmldebugjsserver
+SOURCES += tst_qqmldebugjs.cpp
+
+INCLUDEPATH += ../shared
+include(../shared/debugutil.pri)
+
+TESTDATA = data/*
+
+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 \
+ data/encodeQmlScope.qml \
+ data/breakOnAnchor.qml
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro
deleted file mode 100644
index cbaf3b5309..0000000000
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro
+++ /dev/null
@@ -1,25 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qqmldebugjs
-QT += qml testlib gui-private core-private
-CONFIG -= debug_and_release_target
-osx:CONFIG -= app_bundle
-
-SOURCES += tst_qqmldebugjs.cpp
-
-INCLUDEPATH += ../../shared
-include(../../../../shared/util.pri)
-include(../../shared/debugutil.pri)
-include(../../shared/qqmlenginedebugclient.pri)
-
-TESTDATA = data/*
-
-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/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
deleted file mode 100644
index d248cf9708..0000000000
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
+++ /dev/null
@@ -1,1552 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "debugutil_p.h"
-#include "../../shared/qqmlenginedebugclient.h"
-#include "../../../../shared/util.h"
-
-#include <private/qqmldebugclient_p.h>
-#include <private/qqmldebugconnection_p.h>
-#include <private/qpacket_p.h>
-
-#include <QtTest/qtest.h>
-#include <QtCore/qprocess.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qlibraryinfo.h>
-#include <QtQml/qjsengine.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 *CONTEXT = "context";
-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 *CLEARBREAKPOINT = "clearbreakpoint";
-const char *SETEXCEPTIONBREAK = "setexceptionbreak";
-const char *VERSION = "version";
-const char *DISCONNECT = "disconnect";
-const char *GARBAGECOLLECTOR = "gc";
-
-const char *CONNECT = "connect";
-const char *INTERRUPT = "interrupt";
-
-const char *REQUEST = "request";
-const char *IN = "in";
-const char *NEXT = "next";
-const char *OUT = "out";
-
-const char *SCRIPT = "script";
-const char *SCRIPTREGEXP = "scriptRegExp";
-const char *EVENT = "event";
-
-const char *ALL = "all";
-const char *UNCAUGHT = "uncaught";
-
-const char *BLOCKMODE = "-qmljsdebugger=port:3771,3800,block";
-const char *NORMALMODE = "-qmljsdebugger=port:3771,3800";
-const char *BLOCKRESTRICTEDMODE = "-qmljsdebugger=port:3771,3800,block,services:V8Debugger";
-const char *NORMALRESTRICTEDMODE = "-qmljsdebugger=port:3771,3800,services:V8Debugger";
-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 *QUIT_QMLFILE = "quit.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
-
- void init(bool qmlscene, const QString &qmlFile = QString(TEST_QMLFILE), bool blockMode = true,
- bool restrictServices = false);
-
-private slots:
- void initTestCase();
- void cleanupTestCase();
-
- void cleanup();
-
- void connect_data();
- void connect();
- void interrupt_data() { targetData(); }
- void interrupt();
- void getVersion_data() { targetData(); }
- void getVersion();
- void getVersionWhenAttaching_data() { targetData(); }
- void getVersionWhenAttaching();
-
- void disconnect_data() { targetData(); }
- void disconnect();
-
- void setBreakpointInScriptOnCompleted_data() { targetData(); }
- void setBreakpointInScriptOnCompleted();
- void setBreakpointInScriptOnComponentCreated_data() { targetData(); }
- void setBreakpointInScriptOnComponentCreated();
- void setBreakpointInScriptOnTimerCallback_data() { targetData(); }
- void setBreakpointInScriptOnTimerCallback();
- void setBreakpointInScriptInDifferentFile_data() { targetData(); }
- void setBreakpointInScriptInDifferentFile();
- void setBreakpointInScriptOnComment_data() { targetData(); }
- void setBreakpointInScriptOnComment();
- void setBreakpointInScriptOnEmptyLine_data() { targetData(); }
- void setBreakpointInScriptOnEmptyLine();
- void setBreakpointInScriptOnOptimizedBinding_data() { targetData(); }
- void setBreakpointInScriptOnOptimizedBinding();
- void setBreakpointInScriptWithCondition_data() { targetData(); }
- void setBreakpointInScriptWithCondition();
- void setBreakpointInScriptThatQuits_data() { targetData(); }
- void setBreakpointInScriptThatQuits();
- void setBreakpointWhenAttaching();
-
- void clearBreakpoint_data() { targetData(); }
- void clearBreakpoint();
-
- void setExceptionBreak_data() { targetData(); }
- void setExceptionBreak();
-
- void stepNext_data() { targetData(); }
- void stepNext();
- void stepIn_data() { targetData(); }
- void stepIn();
- void stepOut_data() { targetData(); }
- void stepOut();
- void continueDebugging_data() { targetData(); }
- void continueDebugging();
-
- void backtrace_data() { targetData(); }
- void backtrace();
-
- void getFrameDetails_data() { targetData(); }
- void getFrameDetails();
-
- void getScopeDetails_data() { targetData(); }
- void getScopeDetails();
-
- void evaluateInGlobalScope();
- void evaluateInLocalScope_data() { targetData(); }
- void evaluateInLocalScope();
-
- void evaluateInContext();
-
- void getScripts_data() { targetData(); }
- void getScripts();
-
-private:
- void targetData();
-
- 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
- };
-
- QJSDebugClient(QQmlDebugConnection *connection)
- : QQmlDebugClient(QLatin1String("V8Debugger"), connection),
- seq(0)
- {
- parser = jsEngine.evaluate(QLatin1String("JSON.parse"));
- stringify = jsEngine.evaluate(QLatin1String("JSON.stringify"));
- }
-
- void connect(bool redundantRefs = false, bool namesAsObjects = false);
- void interrupt();
-
- void continueDebugging(StepAction stepAction);
- void evaluate(QString expr, int frame = -1, int context = -1);
- 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 scripts(int types = 4, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
- void setBreakpoint(QString target, int line = -1, int column = -1, bool enabled = true,
- QString condition = QString(), int ignoreCount = -1);
- void clearBreakpoint(int breakpoint);
- void setExceptionBreak(Exception type, bool enabled = false);
- void version();
- void disconnect();
-
-protected:
- //inherited from QQmlDebugClient
- void stateChanged(State state);
- void messageReceived(const QByteArray &data);
-
-signals:
- void enabled();
- void connected();
- void interruptRequested();
- void result();
- void failure();
- 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(bool redundantRefs, bool namesAsObjects)
-{
- QJSValue jsonVal = parser.call(QJSValueList() << QLatin1String("{}"));
- jsonVal.setProperty("redundantRefs", QJSValue(redundantRefs));
- jsonVal.setProperty("namesAsObjects", QJSValue(namesAsObjects));
- sendMessage(packMessage(CONNECT,
- stringify.call(QJSValueList() << jsonVal).toString().toUtf8()));
-}
-
-void QJSDebugClient::interrupt()
-{
- sendMessage(packMessage(INTERRUPT));
-}
-
-void QJSDebugClient::continueDebugging(StepAction action)
-{
- // { "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()) {
- jsonVal.setProperty(QLatin1String(ARGUMENTS),args);
- }
- }
- QJSValue json = stringify.call(QJSValueList() << jsonVal);
- sendMessage(packMessage(V8REQUEST, json.toString().toUtf8()));
-}
-
-void QJSDebugClient::evaluate(QString expr, int frame, int context)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "evaluate",
- // "arguments" : { "expression" : <expression to evaluate>,
- // "frame" : <number>,
- // "context" : <object ID>
- // }
- // }
- 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 (context != -1)
- args.setProperty(QLatin1String(CONTEXT), QJSValue(context));
-
- 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::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::setBreakpoint(QString target, int line, int column, bool enabled,
- QString condition, int ignoreCount)
-{
- // { "seq" : <number>,
- // "type" : "request",
- // "command" : "setbreakpoint",
- // "arguments" : { "type" : "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>
- // }
- // }
-
- VARIANTMAPINIT;
- jsonVal.setProperty(QLatin1String(COMMAND),QJSValue(QLatin1String(SETBREAKPOINT)));
-
- QJSValue args = parser.call(QJSValueList() << obj);
-
- args.setProperty(QLatin1String(TYPE),QJSValue(QLatin1String(SCRIPTREGEXP)));
- 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::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::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::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::stateChanged(State state)
-{
- if (state == Enabled) {
- flushSendBuffer();
- emit enabled();
- }
-}
-
-void QJSDebugClient::messageReceived(const QByteArray &data)
-{
- QPacket ds(connection()->currentDataStreamVersion(), 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()) {
- emit failure();
- qDebug() << "Received success == false response from application";
- return;
- }
-
- QString debugCommand(value.value("command").toString());
- if (debugCommand == "backtrace" ||
- debugCommand == "lookup" ||
- debugCommand == "setbreakpoint" ||
- debugCommand == "evaluate" ||
- debugCommand == "version" ||
- 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();
- }
-
- }
- }
-}
-
-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)
-{
- QPacket rs(connection()->currentDataStreamVersion());
- QByteArray cmd = "V8DEBUG";
- rs << cmd << type << message;
- return rs.data();
-}
-
-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;
-}
-
-void tst_QQmlDebugJS::init(bool qmlscene, const QString &qmlFile, bool blockMode,
- bool restrictServices)
-{
- connection = new QQmlDebugConnection();
- if (qmlscene)
- process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) +
- "/qmlscene", this);
- else
- process = new QQmlDebugProcess(QCoreApplication::applicationDirPath() +
- QLatin1String("/qqmldebugjsserver"), this);
- client = new QJSDebugClient(connection);
- QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(connection);
-
- const char *args = 0;
- if (blockMode)
- args = restrictServices ? BLOCKRESTRICTEDMODE : BLOCKMODE;
- else
- args = restrictServices ? NORMALRESTRICTEDMODE : NORMALMODE;
-
- process->start(QStringList() << QLatin1String(args) << testFile(qmlFile));
-
- QVERIFY(process->waitForSessionStart());
-
- const int port = process->debugPort();
- connection->connectToHost("127.0.0.1", port);
- QVERIFY(connection->waitForConnected());
-
-
- if (client->state() != QQmlDebugClient::Enabled)
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(enabled())));
-
- foreach (QQmlDebugClient *otherClient, others)
- QCOMPARE(otherClient->state(), restrictServices ? QQmlDebugClient::Unavailable :
- QQmlDebugClient::Enabled);
- qDeleteAll(others);
-}
-
-void tst_QQmlDebugJS::cleanup()
-{
- if (QTest::currentTestFailed()) {
- qDebug() << "Process State:" << process->state();
- qDebug() << "Application Output:" << process->output();
- }
-
- if (process) {
- process->stop();
- delete process;
- }
-
- if (client)
- delete client;
-
- if (connection)
- delete connection;
-
- process = 0;
- client = 0;
- connection = 0;
-}
-
-void tst_QQmlDebugJS::connect_data()
-{
- QTest::addColumn<bool>("blockMode");
- QTest::addColumn<bool>("restrictMode");
- QTest::addColumn<bool>("qmlscene");
- QTest::newRow("normal / unrestricted / custom") << false << false << false;
- QTest::newRow("block / unrestricted / custom") << true << false << false;
- QTest::newRow("normal / restricted / custom") << false << true << false;
- QTest::newRow("block / restricted / custom") << true << true << false;
- QTest::newRow("normal / unrestricted / qmlscene") << false << false << true;
- QTest::newRow("block / unrestricted / qmlscene") << true << false << true;
- QTest::newRow("normal / restricted / qmlscene") << false << true << true;
- QTest::newRow("block / restricted / qmlscene") << true << true << true;
-}
-
-void tst_QQmlDebugJS::connect()
-{
- QFETCH(bool, blockMode);
- QFETCH(bool, restrictMode);
- QFETCH(bool, qmlscene);
- init(qmlscene, QString(TEST_QMLFILE), blockMode, restrictMode);
- client->connect();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
-}
-
-void tst_QQmlDebugJS::interrupt()
-{
- //void connect()
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene);
- client->connect(redundantRefs, namesAsObjects);
-
- client->interrupt();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(interruptRequested())));
-}
-
-void tst_QQmlDebugJS::getVersion()
-{
- //void version()
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
-
- client->version();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::getVersionWhenAttaching()
-{
- //void version()
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- init(qmlscene, QLatin1String(TIMER_QMLFILE), false);
- client->connect(redundantRefs, namesAsObjects);
-
- client->version();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::disconnect()
-{
- //void disconnect()
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene);
- client->connect(redundantRefs, namesAsObjects);
-
- client->disconnect();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-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)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, CREATECOMPONENT_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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()
-{
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- int sourceLine = 35;
- init(qmlscene, TIMER_QMLFILE);
-
- client->connect(redundantRefs, namesAsObjects);
- //We can set the breakpoint after connect() here because the timer is repeating and if we miss
- //its first iteration we can still catch the second one.
- client->setBreakpoint(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)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 31;
- init(qmlscene, LOADJSFILE_QMLFILE);
-
- client->setBreakpoint(QLatin1String(TEST_JSFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- int actualLine = 36;
- init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 35;
- int actualLine = 36;
- init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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::setBreakpointInScriptOnOptimizedBinding()
-{
- //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 39;
- init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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(BREAKPOINTRELOCATION_QMLFILE));
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
-{
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- int out = 10;
- int sourceLine = 37;
- init(qmlscene, CONDITION_QMLFILE);
-
- client->connect(redundantRefs, namesAsObjects);
- //The breakpoint is in a timer loop so we can set it after connect().
- client->setBreakpoint(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;
- QJSValue val = client->parser.call(QJSValueList() << QJSValue(jsonString));
- QVERIFY(val.isObject());
- QJSValue body = val.property(QStringLiteral("body"));
- QVERIFY(body.isObject());
- val = body.property("value");
- QVERIFY(val.isNumber());
-
- const int a = val.toInt();
- QVERIFY(a > out);
-}
-
-void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
-{
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene, QUIT_QMLFILE);
-
- int sourceLine = 36;
-
- client->setBreakpoint(QLatin1String(QUIT_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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(QUIT_QMLFILE));
-
- client->continueDebugging(QJSDebugClient::Continue);
- QVERIFY(process->waitForFinished());
- QCOMPARE(process->exitStatus(), QProcess::NormalExit);
-}
-
-void tst_QQmlDebugJS::setBreakpointWhenAttaching()
-{
- int sourceLine = 35;
- init(true, QLatin1String(TIMER_QMLFILE), false);
-
- client->connect();
-
- QSKIP("\nThe breakpoint may not hit because the engine may run in JIT mode or not have debug\n"
- "instructions, as we've connected in non-blocking mode above. That means we may have\n"
- "connected after the engine was already running, with all the QML already compiled.");
-
- //The breakpoint is in a timer loop so we can set it after connect().
- client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine);
-
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-}
-
-void tst_QQmlDebugJS::clearBreakpoint()
-{
- //void clearBreakpoint(int breakpoint);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine1 = 37;
- int sourceLine2 = 38;
- init(qmlscene, CHANGEBREAKPOINT_QMLFILE);
-
- client->connect(redundantRefs, namesAsObjects);
- //The breakpoints are in a timer loop so we can set them after connect().
- //Furthermore the breakpoints should be hit in the right order because setting of breakpoints
- //can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below)
- client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true);
- client->setBreakpoint(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);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- init(qmlscene, EXCEPTION_QMLFILE);
- client->setExceptionBreak(QJSDebugClient::All,true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-}
-
-void tst_QQmlDebugJS::stepNext()
-{
- //void continueDebugging(StepAction stepAction, int stepCount = 1);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 37;
- init(qmlscene, STEPACTION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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::stepIn()
-{
- //void continueDebugging(StepAction stepAction, int stepCount = 1);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 41;
- int actualLine = 37;
- init(qmlscene, STEPACTION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 37;
- int actualLine = 41;
- init(qmlscene, STEPACTION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine1 = 41;
- int sourceLine2 = 38;
- init(qmlscene, STEPACTION_QMLFILE);
-
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true);
- client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->backtrace();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::getFrameDetails()
-{
- //void frame(int number = -1);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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);
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
-
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- client->scope();
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-}
-
-void tst_QQmlDebugJS::evaluateInGlobalScope()
-{
- //void evaluate(QString expr, int frame = -1);
- init(true);
-
- client->connect();
-
- do {
- // The engine might not be initialized, yet. We just try until it shows up.
- client->evaluate(QLatin1String("console.log('Hello World')"));
- } while (!QQmlDebugTest::waitForSignal(client, SIGNAL(result()), 500));
-
- //Verify the return value of 'console.log()', which is "undefined"
- QString jsonString(client->response);
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
- QVariantMap body = value.value("body").toMap();
- QCOMPARE(body.value("type").toString(),QLatin1String("undefined"));
-}
-
-void tst_QQmlDebugJS::evaluateInLocalScope()
-{
- //void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- int sourceLine = 34;
- init(qmlscene, ONCOMPLETED_QMLFILE);
-
- client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- 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::evaluateInContext()
-{
- connection = new QQmlDebugConnection();
- process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath)
- + "/qmlscene", this);
- client = new QJSDebugClient(connection);
- QScopedPointer<QQmlEngineDebugClient> engineClient(new QQmlEngineDebugClient(connection));
- process->start(QStringList() << QLatin1String(BLOCKMODE) << testFile(ONCOMPLETED_QMLFILE));
-
- QVERIFY(process->waitForSessionStart());
-
- connection->connectToHost("127.0.0.1", process->debugPort());
- QVERIFY(connection->waitForConnected());
-
- QTRY_COMPARE(client->state(), QQmlEngineDebugClient::Enabled);
- QTRY_COMPARE(engineClient->state(), QQmlEngineDebugClient::Enabled);
- client->connect();
-
- // "a" not accessible without extra context
- client->evaluate(QLatin1String("a + 10"), -1, -1);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(failure())));
-
- bool success = false;
- engineClient->queryAvailableEngines(&success);
- QVERIFY(success);
- QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
-
- QVERIFY(engineClient->engines().count());
- engineClient->queryRootContexts(engineClient->engines()[0].debugId, &success);
- QVERIFY(success);
- QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
-
- auto contexts = engineClient->rootContext().contexts;
- QCOMPARE(contexts.count(), 1);
- auto objects = contexts[0].objects;
- QCOMPARE(objects.count(), 1);
- engineClient->queryObjectRecursive(objects[0], &success);
- QVERIFY(success);
- QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
- auto object = engineClient->object();
-
- // "a" accessible in context of surrounding object
- client->evaluate(QLatin1String("a + 10"), -1, object.debugId);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
-
- QString jsonString = client->response;
- QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
-
- QVariantMap body = value.value("body").toMap();
- QTRY_COMPARE(body.value("value").toInt(), 20);
-}
-
-void tst_QQmlDebugJS::getScripts()
-{
- //void scripts(int types = -1, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
-
- QFETCH(bool, qmlscene);
- QFETCH(bool, redundantRefs);
- QFETCH(bool, namesAsObjects);
- init(qmlscene);
-
- client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true);
- client->connect(redundantRefs, namesAsObjects);
- QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
-
- 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(), 1);
- QVERIFY(scripts.first().toMap()[QStringLiteral("name")].toString().endsWith(QStringLiteral("data/test.qml")));
-}
-
-void tst_QQmlDebugJS::targetData()
-{
- QTest::addColumn<bool>("qmlscene");
- QTest::addColumn<bool>("redundantRefs");
- QTest::addColumn<bool>("namesAsObjects");
- QTest::newRow("custom / redundant / objects") << false << true << true;
- QTest::newRow("qmlscene / redundant / objects") << true << true << true;
- QTest::newRow("custom / redundant / strings") << false << true << false;
- QTest::newRow("qmlscene / redundant / strings") << true << true << false;
- QTest::newRow("custom / sparse / objects") << false << false << true;
- QTest::newRow("qmlscene / sparse / objects") << true << false << true;
- QTest::newRow("custom / sparse / strings") << false << false << false;
- QTest::newRow("qmlscene / sparse / strings") << true << false << false;
-}
-
-QTEST_MAIN(tst_QQmlDebugJS)
-
-#include "tst_qqmldebugjs.moc"
-
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.cpp b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.cpp
deleted file mode 100644
index 6a4ec5cc75..0000000000
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtGui/qguiapplication.h>
-#include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlapplicationengine.h>
-
-int main(int argc, char *argv[])
-{
- QGuiApplication app(argc, argv);
- QQmlEngine someWeirdEngine; // add another engine to cause some trouble
-
- QQmlApplicationEngine engine;
- engine.load(QUrl::fromLocalFile(QLatin1String(argv[argc - 1])));
-
- return app.exec();
-}
-
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.pro b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.pro
deleted file mode 100644
index 837eaed9f1..0000000000
--- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjsserver/qqmldebugjsserver.pro
+++ /dev/null
@@ -1,12 +0,0 @@
-QT += qml testlib
-osx:CONFIG -= app_bundle
-CONFIG -= debug_and_release_target
-INCLUDEPATH += ../../shared
-SOURCES += qqmldebugjsserver.cpp
-DEFINES += QT_QML_DEBUG_NO_WARNING
-
-DESTDIR = ../qqmldebugjs
-
-target.path = $$[QT_INSTALL_TESTS]/tst_qqmldebugjs
-INSTALLS += target
-
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..1ac28c473b
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -0,0 +1,1008 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "debugutil_p.h"
+#include "qqmldebugprocess_p.h"
+#include "../../../shared/util.h"
+
+#include <private/qqmlenginedebugclient_p.h>
+#include <private/qv4debugclient_p.h>
+#include <private/qqmldebugconnection_p.h>
+#include <private/qpacket_p.h>
+
+#include <QtTest/qtest.h>
+#include <QtTest/qtestsystem.h>
+#include <QtCore/qprocess.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonarray.h>
+
+const char *BLOCKMODE = "-qmljsdebugger=port:3771,3800,block";
+const char *NORMALMODE = "-qmljsdebugger=port:3771,3800";
+const char *BLOCKRESTRICTEDMODE = "-qmljsdebugger=port:3771,3800,block,services:V8Debugger";
+const char *NORMALRESTRICTEDMODE = "-qmljsdebugger=port:3771,3800,services:V8Debugger";
+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 *QUIT_QMLFILE = "quit.qml";
+const char *CHANGEBREAKPOINT_QMLFILE = "changeBreakpoint.qml";
+const char *STEPACTION_QMLFILE = "stepAction.qml";
+const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml";
+const char *ENCODEQMLSCOPE_QMLFILE = "encodeQmlScope.qml";
+const char *BREAKONANCHOR_QMLFILE = "breakOnAnchor.qml";
+
+#undef QVERIFY
+#define QVERIFY(statement) \
+do {\
+ if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) {\
+ if (QTest::currentTestFailed()) \
+ qDebug().nospace() << "\nDEBUGGEE OUTPUT:\n" << m_process->output();\
+ return;\
+ }\
+} while (0)
+
+class tst_QQmlDebugJS : public QQmlDebugTest
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase() override;
+
+ void connect_data();
+ void connect();
+ void interrupt_data() { targetData(); }
+ void interrupt();
+ void getVersion_data() { targetData(); }
+ void getVersion();
+ void getVersionWhenAttaching_data() { targetData(); }
+ void getVersionWhenAttaching();
+
+ void disconnect_data() { targetData(); }
+ void disconnect();
+
+ void setBreakpointInScriptOnCompleted_data() { targetData(); }
+ void setBreakpointInScriptOnCompleted();
+ void setBreakpointInScriptOnComponentCreated_data() { targetData(); }
+ void setBreakpointInScriptOnComponentCreated();
+ void setBreakpointInScriptOnTimerCallback_data() { targetData(); }
+ void setBreakpointInScriptOnTimerCallback();
+ void setBreakpointInScriptInDifferentFile_data() { targetData(); }
+ void setBreakpointInScriptInDifferentFile();
+ void setBreakpointInScriptOnComment_data() { targetData(); }
+ void setBreakpointInScriptOnComment();
+ void setBreakpointInScriptOnEmptyLine_data() { targetData(); }
+ void setBreakpointInScriptOnEmptyLine();
+ void setBreakpointInScriptOnOptimizedBinding_data() { targetData(); }
+ void setBreakpointInScriptOnOptimizedBinding();
+ void setBreakpointInScriptWithCondition_data() { targetData(); }
+ void setBreakpointInScriptWithCondition();
+ void setBreakpointInScriptThatQuits_data() { targetData(); }
+ void setBreakpointInScriptThatQuits();
+ void setBreakpointWhenAttaching();
+
+ void clearBreakpoint_data() { targetData(); }
+ void clearBreakpoint();
+
+ void changeBreakpoint_data() { targetData(); }
+ void changeBreakpoint();
+
+ void setExceptionBreak_data() { targetData(); }
+ void setExceptionBreak();
+
+ void stepNext_data() { targetData(); }
+ void stepNext();
+ void stepIn_data() { targetData(); }
+ void stepIn();
+ void stepOut_data() { targetData(); }
+ void stepOut();
+ void continueDebugging_data() { targetData(); }
+ void continueDebugging();
+
+ void backtrace_data() { targetData(); }
+ void backtrace();
+
+ void getFrameDetails_data() { targetData(); }
+ void getFrameDetails();
+
+ void getScopeDetails_data() { targetData(); }
+ void getScopeDetails();
+
+ void evaluateInGlobalScope();
+ void evaluateInLocalScope_data() { targetData(); }
+ void evaluateInLocalScope();
+
+ void evaluateInContext();
+
+ void getScripts_data() { targetData(); }
+ void getScripts();
+
+ void encodeQmlScope();
+ void breakOnAnchor();
+
+private:
+ ConnectResult init(bool qmlscene, const QString &qmlFile = QString(TEST_QMLFILE),
+ bool blockMode = true, bool restrictServices = false);
+ QList<QQmlDebugClient *> createClients() override;
+ QPointer<QV4DebugClient> m_client;
+
+ void targetData();
+ bool waitForClientSignal(const char *signal, int timeout = 30000);
+ void checkVersionParameters();
+
+ QTime t;
+};
+
+
+
+void tst_QQmlDebugJS::initTestCase()
+{
+ QQmlDebugTest::initTestCase();
+ t.start();
+}
+
+QQmlDebugTest::ConnectResult tst_QQmlDebugJS::init(bool qmlscene, const QString &qmlFile,
+ bool blockMode, bool restrictServices)
+{
+ const QString executable = qmlscene
+ ? QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene"
+ : debugJsServerPath("qqmldebugjs");
+ return QQmlDebugTest::connect(
+ executable, restrictServices ? QStringLiteral("V8Debugger") : QString(),
+ testFile(qmlFile), blockMode);
+}
+
+void tst_QQmlDebugJS::connect_data()
+{
+ QTest::addColumn<bool>("blockMode");
+ QTest::addColumn<bool>("restrictMode");
+ QTest::addColumn<bool>("qmlscene");
+ QTest::newRow("normal / unrestricted / custom") << false << false << false;
+ QTest::newRow("block / unrestricted / custom") << true << false << false;
+ QTest::newRow("normal / restricted / custom") << false << true << false;
+ QTest::newRow("block / restricted / custom") << true << true << false;
+ QTest::newRow("normal / unrestricted / qmlscene") << false << false << true;
+ QTest::newRow("block / unrestricted / qmlscene") << true << false << true;
+ QTest::newRow("normal / restricted / qmlscene") << false << true << true;
+ QTest::newRow("block / restricted / qmlscene") << true << true << true;
+}
+
+void tst_QQmlDebugJS::connect()
+{
+ QFETCH(bool, blockMode);
+ QFETCH(bool, restrictMode);
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene, QString(TEST_QMLFILE), blockMode, restrictMode), ConnectSuccess);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(connected())));
+}
+
+void tst_QQmlDebugJS::interrupt()
+{
+ //void connect()
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene), ConnectSuccess);
+ m_client->connect();
+
+ m_client->interrupt();
+ QVERIFY(waitForClientSignal(SIGNAL(interrupted())));
+}
+
+void tst_QQmlDebugJS::getVersion()
+{
+ //void version()
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene), ConnectSuccess);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(connected())));
+
+ m_client->version();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+ checkVersionParameters();
+}
+
+void tst_QQmlDebugJS::getVersionWhenAttaching()
+{
+ //void version()
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene, QLatin1String(TIMER_QMLFILE), false), ConnectSuccess);
+ m_client->connect();
+
+ m_client->version();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+ checkVersionParameters();
+}
+
+void tst_QQmlDebugJS::disconnect()
+{
+ //void disconnect()
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene), ConnectSuccess);
+ m_client->connect();
+
+ m_client->disconnect();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+}
+
+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)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().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)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, CREATECOMPONENT_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(ONCOMPLETED_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnTimerCallback()
+{
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 35;
+ QCOMPARE(init(qmlscene, TIMER_QMLFILE), ConnectSuccess);
+
+ m_client->connect();
+ //We can set the breakpoint after connect() here because the timer is repeating and if we miss
+ //its first iteration we can still catch the second one.
+ m_client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine, -1, true);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().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)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 31;
+ QCOMPARE(init(qmlscene, LOADJSFILE_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(TEST_JSFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().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)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ int actualLine = 36;
+ QCOMPARE(init(qmlscene, BREAKPOINTRELOCATION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped()), 1));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().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)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 35;
+ int actualLine = 36;
+ QCOMPARE(init(qmlscene, BREAKPOINTRELOCATION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped()), 1));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 39;
+ QCOMPARE(init(qmlscene, BREAKPOINTRELOCATION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
+{
+ QFETCH(bool, qmlscene);
+
+ int out = 10;
+ int sourceLine = 37;
+ QCOMPARE(init(qmlscene, CONDITION_QMLFILE), ConnectSuccess);
+
+ m_client->connect();
+ //The breakpoint is in a timer loop so we can set it after connect().
+ m_client->setBreakpoint(QLatin1String(CONDITION_QMLFILE), sourceLine, 1, true, QLatin1String("a > 10"));
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ //Get the frame index
+ {
+ const QJsonObject body = m_client->response().body.toObject();
+ int frameIndex = body.value("index").toInt();
+
+ //Verify the value of 'result'
+ m_client->evaluate(QLatin1String("a"),frameIndex);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+ }
+
+ const QJsonObject body = m_client->response().body.toObject();
+ QVERIFY(!body.isEmpty());
+ QJsonValue val = body.value("value");
+ QVERIFY(val.isDouble());
+
+ const int a = val.toInt();
+ QVERIFY(a > out);
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptThatQuits()
+{
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene, QUIT_QMLFILE), ConnectSuccess);
+
+ int sourceLine = 36;
+
+ m_client->setBreakpoint(QLatin1String(QUIT_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(), QLatin1String(QUIT_QMLFILE));
+
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ QVERIFY(m_process->waitForFinished());
+ QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
+}
+
+void tst_QQmlDebugJS::setBreakpointWhenAttaching()
+{
+ int sourceLine = 35;
+ QCOMPARE(init(true, QLatin1String(TIMER_QMLFILE), false), ConnectSuccess);
+
+ m_client->connect();
+
+ QSKIP("\nThe breakpoint may not hit because the engine may run in JIT mode or not have debug\n"
+ "instructions, as we've connected in non-blocking mode above. That means we may have\n"
+ "connected after the engine was already running, with all the QML already compiled.");
+
+ //The breakpoint is in a timer loop so we can set it after connect().
+ m_client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine);
+
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+}
+
+void tst_QQmlDebugJS::clearBreakpoint()
+{
+ //void clearBreakpoint(int breakpoint);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine1 = 37;
+ int sourceLine2 = 38;
+ QCOMPARE(init(qmlscene, CHANGEBREAKPOINT_QMLFILE), ConnectSuccess);
+
+ m_client->connect();
+ //The breakpoints are in a timer loop so we can set them after connect().
+ //Furthermore the breakpoints should be hit in the right order because setting of breakpoints
+ //can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below)
+ m_client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true);
+ m_client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true);
+
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ {
+ //Will hit 1st brakpoint, change this breakpoint enable = false
+ const QJsonObject body = m_client->response().body.toObject();
+ const QJsonArray breakpointsHit = body.value("breakpoints").toArray();
+
+ int breakpoint = breakpointsHit.at(0).toInt();
+ m_client->clearBreakpoint(breakpoint);
+
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ //Continue with debugging
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ //Hit 2nd breakpoint
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ //Continue with debugging
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ }
+
+ //Should stop at 2nd breakpoint
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ {
+ const QJsonObject body = m_client->response().body.toObject();
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
+ }
+}
+
+void tst_QQmlDebugJS::changeBreakpoint()
+{
+ //void clearBreakpoint(int breakpoint);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine2 = 37;
+ int sourceLine1 = 38;
+ QCOMPARE(init(qmlscene, CHANGEBREAKPOINT_QMLFILE), ConnectSuccess);
+
+ bool isStopped = false;
+ QObject::connect(m_client.data(), &QV4DebugClient::stopped, this, [&]() { isStopped = true; });
+
+ auto continueDebugging = [&]() {
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ isStopped = false;
+ };
+
+ m_client->connect();
+
+ auto extractBody = [&]() {
+ return m_client->response().body.toObject();
+ };
+
+ auto extractBreakPointId = [&](const QJsonObject &body) {
+ const QJsonArray breakpointsHit = body.value("breakpoints").toArray();
+ if (breakpointsHit.size() != 1)
+ return -1;
+ return breakpointsHit[0].toInt();
+ };
+
+ auto setBreakPoint = [&](int sourceLine, bool enabled) {
+ int id = -1;
+ auto connection = QObject::connect(m_client.data(), &QV4DebugClient::result, [&]() {
+ id = extractBody().value("breakpoint").toInt();
+ });
+
+ m_client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine, -1, enabled);
+ bool success = QTest::qWaitFor([&]() { return id >= 0; });
+ Q_UNUSED(success);
+
+ QObject::disconnect(connection);
+ return id;
+ };
+
+ //The breakpoints are in a timer loop so we can set them after connect().
+ //Furthermore the breakpoints should be hit in the right order because setting of breakpoints
+ //can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below)
+ const int breakpoint1 = setBreakPoint(sourceLine1, false);
+ QVERIFY(breakpoint1 >= 0);
+
+ const int breakpoint2 = setBreakPoint(sourceLine2, true);
+ QVERIFY(breakpoint2 >= 0);
+
+ auto verifyBreakpoint = [&](int sourceLine, int breakpointId) {
+ QTRY_VERIFY_WITH_TIMEOUT(isStopped, 30000);
+ const QJsonObject body = extractBody();
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(extractBreakPointId(body), breakpointId);
+ };
+
+ verifyBreakpoint(sourceLine2, breakpoint2);
+
+ continueDebugging();
+ verifyBreakpoint(sourceLine2, breakpoint2);
+
+ m_client->changeBreakpoint(breakpoint2, false);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ m_client->changeBreakpoint(breakpoint1, true);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ continueDebugging();
+ verifyBreakpoint(sourceLine1, breakpoint1);
+
+ continueDebugging();
+ verifyBreakpoint(sourceLine1, breakpoint1);
+
+ m_client->changeBreakpoint(breakpoint2, true);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ m_client->changeBreakpoint(breakpoint1, false);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ for (int i = 0; i < 3; ++i) {
+ continueDebugging();
+ verifyBreakpoint(sourceLine2, breakpoint2);
+ }
+}
+
+void tst_QQmlDebugJS::setExceptionBreak()
+{
+ //void setExceptionBreak(QString type, bool enabled = false);
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene, EXCEPTION_QMLFILE), ConnectSuccess);
+ m_client->setExceptionBreak(QV4DebugClient::All,true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+}
+
+void tst_QQmlDebugJS::stepNext()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 37;
+ QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->continueDebugging(QV4DebugClient::Next);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = m_client->response().body.toObject();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine + 1);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(STEPACTION_QMLFILE));
+}
+
+static QJsonObject responseBody(QV4DebugClient *client)
+{
+ return client->response().body.toObject();
+}
+
+void tst_QQmlDebugJS::stepIn()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 41;
+ int actualLine = 36;
+ QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+ QCOMPARE(responseBody(m_client).value("sourceLine").toInt(), sourceLine);
+
+ m_client->continueDebugging(QV4DebugClient::In);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = responseBody(m_client);
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::stepOut()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 37;
+ int actualLine = 41;
+ QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+ QCOMPARE(responseBody(m_client).value("sourceLine").toInt(), sourceLine);
+
+ m_client->continueDebugging(QV4DebugClient::Out);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = responseBody(m_client);
+ QCOMPARE(body.value("sourceLine").toInt(), actualLine);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::continueDebugging()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine1 = 41;
+ int sourceLine2 = 38;
+ QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true);
+ m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ const QJsonObject body = responseBody(m_client);
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine2);
+ QCOMPARE(QFileInfo(body.value("script").toObject().value("name").toString()).fileName(),
+ QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::backtrace()
+{
+ //void backtrace(int fromFrame = -1, int toFrame = -1, bool bottom = false);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->backtrace();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getFrameDetails()
+{
+ //void frame(int number = -1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->frame();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getScopeDetails()
+{
+ //void scope(int number = -1, int frameNumber = -1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->scope();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::evaluateInGlobalScope()
+{
+ //void evaluate(QString expr, int frame = -1);
+ QCOMPARE(init(true), ConnectSuccess);
+
+ m_client->connect();
+
+ for (int i = 0; i < 10; ++i) {
+ // The engine might not be initialized, yet. We just try until it shows up.
+ m_client->evaluate(QLatin1String("console.log('Hello World')"));
+ if (waitForClientSignal(SIGNAL(result()), 500))
+ break;
+ }
+
+ //Verify the return value of 'console.log()', which is "undefined"
+ QCOMPARE(responseBody(m_client).value("type").toString(), QLatin1String("undefined"));
+}
+
+void tst_QQmlDebugJS::evaluateInLocalScope()
+{
+ //void evaluate(QString expr, bool global = false, bool disableBreak = false, int frame = -1, const QVariantMap &addContext = QVariantMap());
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess);
+
+ m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->frame();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ {
+ //Get the frame index
+ const QJsonObject body = responseBody(m_client);
+ int frameIndex = body.value("index").toInt();
+ m_client->evaluate(QLatin1String("root.a"), frameIndex);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+ }
+
+ {
+ //Verify the value of 'timer.interval'
+ const QJsonObject body = responseBody(m_client);
+ QCOMPARE(body.value("value").toInt(),10);
+ }
+}
+
+void tst_QQmlDebugJS::evaluateInContext()
+{
+ m_connection = new QQmlDebugConnection();
+ m_process = new QQmlDebugProcess(
+ QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this);
+ m_client = new QV4DebugClient(m_connection);
+ QScopedPointer<QQmlEngineDebugClient> engineClient(new QQmlEngineDebugClient(m_connection));
+ m_process->start(QStringList() << QLatin1String(BLOCKMODE) << testFile(ONCOMPLETED_QMLFILE));
+
+ QVERIFY(m_process->waitForSessionStart());
+
+ m_connection->connectToHost("127.0.0.1", m_process->debugPort());
+ QVERIFY(m_connection->waitForConnected());
+
+ QTRY_COMPARE(m_client->state(), QQmlEngineDebugClient::Enabled);
+ QTRY_COMPARE(engineClient->state(), QQmlEngineDebugClient::Enabled);
+ m_client->connect();
+
+ // "a" not accessible without extra context
+ m_client->evaluate(QLatin1String("a + 10"), -1, -1);
+ QVERIFY(waitForClientSignal(SIGNAL(failure())));
+
+ bool success = false;
+ engineClient->queryAvailableEngines(&success);
+ QVERIFY(success);
+ QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
+
+ QVERIFY(engineClient->engines().count());
+ engineClient->queryRootContexts(engineClient->engines()[0], &success);
+ QVERIFY(success);
+ QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
+
+ auto contexts = engineClient->rootContext().contexts;
+ QCOMPARE(contexts.count(), 1);
+ auto objects = contexts[0].objects;
+ QCOMPARE(objects.count(), 1);
+ engineClient->queryObjectRecursive(objects[0], &success);
+ QVERIFY(success);
+ QVERIFY(QQmlDebugTest::waitForSignal(engineClient.data(), SIGNAL(result())));
+ auto object = engineClient->object();
+
+ // "a" accessible in context of surrounding object
+ m_client->evaluate(QLatin1String("a + 10"), -1, object.debugId);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ QTRY_COMPARE(responseBody(m_client).value("value").toInt(), 20);
+}
+
+void tst_QQmlDebugJS::getScripts()
+{
+ //void scripts(int types = -1, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
+ QFETCH(bool, qmlscene);
+
+ QCOMPARE(init(qmlscene), ConnectSuccess);
+
+ m_client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true);
+ m_client->connect();
+ QVERIFY(waitForClientSignal(SIGNAL(stopped())));
+
+ m_client->scripts();
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ const QJsonArray scripts = m_client->response().body.toArray();
+
+ QCOMPARE(scripts.count(), 1);
+ QVERIFY(scripts.first().toObject()[QStringLiteral("name")].toString()
+ .endsWith(QStringLiteral("data/test.qml")));
+}
+
+void tst_QQmlDebugJS::encodeQmlScope()
+{
+ QString file(ENCODEQMLSCOPE_QMLFILE);
+ QCOMPARE(init(true, file), ConnectSuccess);
+
+ int numFrames = 0;
+ int numExpectedScopes = 0;
+ int numReceivedScopes = 0;
+ bool isStopped = false;
+ bool scopesFailed = false;
+
+ QObject::connect(m_client.data(), &QV4DebugClient::failure, this, [&]() {
+ qWarning() << "received failure" << m_client->response().body;
+ scopesFailed = true;
+ m_process->stop();
+ numFrames = 2;
+ isStopped = false;
+ });
+
+ QObject::connect(m_client.data(), &QV4DebugClient::stopped, this, [&]() {
+ m_client->frame();
+ isStopped = true;
+ });
+
+ QObject::connect(m_client.data(), &QV4DebugClient::result, this, [&]() {
+ const QV4DebugClient::Response value = m_client->response();
+
+ if (value.command == QString("scope")) {
+ // If the scope commands fail we get a failure() signal above.
+ if (++numReceivedScopes == numExpectedScopes) {
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ isStopped = false;
+ }
+ } else if (value.command == QString("frame")) {
+
+ // We want at least a global scope and some kind of local scope here.
+ const QJsonArray scopes = value.body.toObject().value("scopes").toArray();
+ if (scopes.count() < 2)
+ scopesFailed = true;
+
+ for (const QJsonValue &scope : scopes) {
+ ++numExpectedScopes;
+ m_client->scope(scope.toObject().value("index").toInt());
+ }
+
+ ++numFrames;
+ }
+ });
+
+ m_client->setBreakpoint(file, 6);
+ m_client->setBreakpoint(file, 8);
+ m_client->connect();
+
+ QTRY_COMPARE(numFrames, 2);
+ QVERIFY(numExpectedScopes > 3);
+ QVERIFY(!scopesFailed);
+ QTRY_VERIFY(!isStopped);
+ QCOMPARE(numReceivedScopes, numExpectedScopes);
+}
+
+void tst_QQmlDebugJS::breakOnAnchor()
+{
+ QString file(BREAKONANCHOR_QMLFILE);
+ QCOMPARE(init(true, file), ConnectSuccess);
+
+ int breaks = 0;
+ bool stopped = false;
+ QObject::connect(m_client.data(), &QV4DebugClient::stopped, this, [&]() {
+ stopped = true;
+ ++breaks;
+ m_client->evaluate("this", 0, -1);
+ });
+
+ QObject::connect(m_client.data(), &QV4DebugClient::result, this, [&]() {
+ if (stopped) {
+ m_client->continueDebugging(QV4DebugClient::Continue);
+ stopped = false;
+ }
+ });
+
+ QObject::connect(m_client.data(), &QV4DebugClient::failure, this, [&]() {
+ qWarning() << "received failure" << m_client->response().body;
+ });
+
+ m_client->setBreakpoint(file, 34);
+ m_client->setBreakpoint(file, 37);
+
+ QTRY_COMPARE(m_process->state(), QProcess::Running);
+
+ m_client->connect();
+
+ QTRY_COMPARE(m_process->state(), QProcess::NotRunning);
+ QCOMPARE(m_process->exitStatus(), QProcess::NormalExit);
+
+ QCOMPARE(breaks, 2);
+}
+
+QList<QQmlDebugClient *> tst_QQmlDebugJS::createClients()
+{
+ m_client = new QV4DebugClient(m_connection);
+ return QList<QQmlDebugClient *>({m_client});
+}
+
+void tst_QQmlDebugJS::targetData()
+{
+ QTest::addColumn<bool>("qmlscene");
+ QTest::newRow("custom") << false;
+ QTest::newRow("qmlscene") << true;
+}
+
+bool tst_QQmlDebugJS::waitForClientSignal(const char *signal, int timeout)
+{
+ return QQmlDebugTest::waitForSignal(m_client.data(), signal, timeout);
+}
+
+void tst_QQmlDebugJS::checkVersionParameters()
+{
+ const QV4DebugClient::Response value = m_client->response();
+ QCOMPARE(value.command, QString("version"));
+ const QJsonObject body = value.body.toObject();
+ QCOMPARE(body.value("UnpausedEvaluate").toBool(), true);
+ QCOMPARE(body.value("ContextEvaluate").toBool(), true);
+ QCOMPARE(body.value("ChangeBreakpoint").toBool(), true);
+}
+
+QTEST_MAIN(tst_QQmlDebugJS)
+
+#include "tst_qqmldebugjs.moc"
+