aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp')
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp1435
1 files changed, 1435 insertions, 0 deletions
diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
new file mode 100644
index 0000000000..b800cc3715
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -0,0 +1,1435 @@
+/****************************************************************************
+**
+** 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/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>
+
+#if defined (Q_OS_WINCE)
+#undef IN
+#undef OUT
+#endif
+
+const char *V8REQUEST = "v8request";
+const char *V8MESSAGE = "v8message";
+const char *SEQ = "seq";
+const char *TYPE = "type";
+const char *COMMAND = "command";
+const char *ARGUMENTS = "arguments";
+const char *STEPACTION = "stepaction";
+const char *STEPCOUNT = "stepcount";
+const char *EXPRESSION = "expression";
+const char *FRAME = "frame";
+const char *GLOBAL = "global";
+const char *DISABLEBREAK = "disable_break";
+const char *HANDLES = "handles";
+const char *INCLUDESOURCE = "includeSource";
+const char *FROMFRAME = "fromFrame";
+const char *TOFRAME = "toFrame";
+const char *BOTTOM = "bottom";
+const char *NUMBER = "number";
+const char *FRAMENUMBER = "frameNumber";
+const char *TYPES = "types";
+const char *IDS = "ids";
+const char *FILTER = "filter";
+const char *FROMLINE = "fromLine";
+const char *TOLINE = "toLine";
+const char *TARGET = "target";
+const char *LINE = "line";
+const char *COLUMN = "column";
+const char *ENABLED = "enabled";
+const char *CONDITION = "condition";
+const char *IGNORECOUNT = "ignoreCount";
+const char *BREAKPOINT = "breakpoint";
+const char *FLAGS = "flags";
+
+const char *CONTINEDEBUGGING = "continue";
+const char *EVALUATE = "evaluate";
+const char *LOOKUP = "lookup";
+const char *BACKTRACE = "backtrace";
+const char *SCOPE = "scope";
+const char *SCOPES = "scopes";
+const char *SCRIPTS = "scripts";
+const char *SOURCE = "source";
+const char *SETBREAKPOINT = "setbreakpoint";
+const char *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 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();
+ void interrupt();
+
+ void continueDebugging(StepAction stepAction);
+ void evaluate(QString expr, int frame = -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 stopped();
+
+private:
+ void sendMessage(const QByteArray &);
+ void flushSendBuffer();
+ QByteArray packMessage(const QByteArray &type, const QByteArray &message = QByteArray());
+
+private:
+ QJSEngine jsEngine;
+ int seq;
+
+ QList<QByteArray> sendBuffer;
+public:
+ QJSValue parser;
+ QJSValue stringify;
+ QByteArray response;
+
+};
+
+void QJSDebugClient::connect()
+{
+ sendMessage(packMessage(CONNECT));
+}
+
+void QJSDebugClient::interrupt()
+{
+ sendMessage(packMessage(INTERRUPT));
+}
+
+void QJSDebugClient::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)
+{
+ // { "seq" : <number>,
+ // "type" : "request",
+ // "command" : "evaluate",
+ // "arguments" : { "expression" : <expression to evaluate>,
+ // "frame" : <number>
+ // }
+ // }
+ 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 (!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()) {
+ 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);
+ init(qmlscene);
+ client->connect();
+
+ client->interrupt();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(interruptRequested())));
+}
+
+void tst_QQmlDebugJS::getVersion()
+{
+ //void version()
+
+ QFETCH(bool, qmlscene);
+ init(qmlscene);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected())));
+
+ client->version();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getVersionWhenAttaching()
+{
+ //void version()
+ QFETCH(bool, qmlscene);
+
+ init(qmlscene, QLatin1String(TIMER_QMLFILE), false);
+ client->connect();
+
+ client->version();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::disconnect()
+{
+ //void disconnect()
+
+ QFETCH(bool, qmlscene);
+ init(qmlscene);
+ client->connect();
+
+ 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);
+
+ int sourceLine = 34;
+ init(qmlscene, ONCOMPLETED_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(ONCOMPLETED_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnComponentCreated()
+{
+ //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1)
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ init(qmlscene, CREATECOMPONENT_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(ONCOMPLETED_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptOnTimerCallback()
+{
+ QFETCH(bool, qmlscene);
+ int sourceLine = 35;
+ init(qmlscene, TIMER_QMLFILE);
+
+ 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.
+ 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);
+
+ int sourceLine = 31;
+ init(qmlscene, LOADJSFILE_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(TEST_JSFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(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;
+ init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ 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);
+
+ int sourceLine = 35;
+ int actualLine = 36;
+ init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ 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);
+
+ int sourceLine = 39;
+ init(qmlscene, BREAKPOINTRELOCATION_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(BREAKPOINTRELOCATION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::setBreakpointInScriptWithCondition()
+{
+ QFETCH(bool, qmlscene);
+ int out = 10;
+ int sourceLine = 37;
+ init(qmlscene, CONDITION_QMLFILE);
+
+ client->connect();
+ //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);
+ init(qmlscene, QUIT_QMLFILE);
+
+ int sourceLine = 36;
+
+ client->setBreakpoint(QLatin1String(QUIT_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(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);
+
+ int sourceLine1 = 37;
+ int sourceLine2 = 38;
+ init(qmlscene, CHANGEBREAKPOINT_QMLFILE);
+
+ 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)
+ 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);
+
+ init(qmlscene, EXCEPTION_QMLFILE);
+ client->setExceptionBreak(QJSDebugClient::All,true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+}
+
+void tst_QQmlDebugJS::stepNext()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 37;
+ init(qmlscene, STEPACTION_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->continueDebugging(QJSDebugClient::Next);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ QCOMPARE(body.value("sourceLine").toInt(), sourceLine + 1);
+ QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE));
+}
+
+void tst_QQmlDebugJS::stepIn()
+{
+ //void continueDebugging(StepAction stepAction, int stepCount = 1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 41;
+ int actualLine = 37;
+ init(qmlscene, STEPACTION_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true);
+ client->connect();
+ 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);
+
+ int sourceLine = 37;
+ int actualLine = 41;
+ init(qmlscene, STEPACTION_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ 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);
+
+ 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();
+ 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);
+
+ int sourceLine = 34;
+ init(qmlscene, ONCOMPLETED_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->backtrace();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getFrameDetails()
+{
+ //void frame(int number = -1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ init(qmlscene, ONCOMPLETED_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->frame();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::getScopeDetails()
+{
+ //void scope(int number = -1, int frameNumber = -1);
+ QFETCH(bool, qmlscene);
+
+ int sourceLine = 34;
+ init(qmlscene, ONCOMPLETED_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->scope();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+}
+
+void tst_QQmlDebugJS::evaluateInGlobalScope()
+{
+ //void evaluate(QString expr, 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);
+ int sourceLine = 34;
+ init(qmlscene, ONCOMPLETED_QMLFILE);
+
+ client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true);
+ client->connect();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped())));
+
+ client->frame();
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ //Get the frame index
+ QString jsonString(client->response);
+ QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ QVariantMap body = value.value("body").toMap();
+
+ int frameIndex = body.value("index").toInt();
+
+ client->evaluate(QLatin1String("root.a"), frameIndex);
+ QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result())));
+
+ //Verify the value of 'timer.interval'
+ jsonString = client->response;
+ value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap();
+
+ body = value.value("body").toMap();
+
+ QCOMPARE(body.value("value").toInt(),10);
+}
+
+void tst_QQmlDebugJS::getScripts()
+{
+ //void scripts(int types = -1, QList<int> ids = QList<int>(), bool includeSource = false, QVariant filter = QVariant());
+
+ QFETCH(bool, qmlscene);
+ init(qmlscene);
+
+ client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true);
+ client->connect();
+ 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::newRow("custom") << false;
+ QTest::newRow("qmlscene") << true;
+}
+
+QTEST_MAIN(tst_QQmlDebugJS)
+
+#include "tst_qqmldebugjs.moc"
+