summaryrefslogtreecommitdiffstats
path: root/tests/auto/qscriptenginedebugger
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 10:34:13 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 10:34:13 +0100
commit67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch)
tree1dbf50b3dff8d5ca7e9344733968c72704eb15ff /tests/auto/qscriptenginedebugger
Long live Qt!
Diffstat (limited to 'tests/auto/qscriptenginedebugger')
-rw-r--r--tests/auto/qscriptenginedebugger/.gitignore1
-rw-r--r--tests/auto/qscriptenginedebugger/qscriptenginedebugger.pro3
-rw-r--r--tests/auto/qscriptenginedebugger/tst_qscriptenginedebugger.cpp744
3 files changed, 748 insertions, 0 deletions
diff --git a/tests/auto/qscriptenginedebugger/.gitignore b/tests/auto/qscriptenginedebugger/.gitignore
new file mode 100644
index 0000000000..d9ed376a81
--- /dev/null
+++ b/tests/auto/qscriptenginedebugger/.gitignore
@@ -0,0 +1 @@
+tst_qscriptenginedebugger
diff --git a/tests/auto/qscriptenginedebugger/qscriptenginedebugger.pro b/tests/auto/qscriptenginedebugger/qscriptenginedebugger.pro
new file mode 100644
index 0000000000..6b504ecae1
--- /dev/null
+++ b/tests/auto/qscriptenginedebugger/qscriptenginedebugger.pro
@@ -0,0 +1,3 @@
+load(qttest_p4)
+QT += script scripttools
+SOURCES += tst_qscriptenginedebugger.cpp
diff --git a/tests/auto/qscriptenginedebugger/tst_qscriptenginedebugger.cpp b/tests/auto/qscriptenginedebugger/tst_qscriptenginedebugger.cpp
new file mode 100644
index 0000000000..aa5da048be
--- /dev/null
+++ b/tests/auto/qscriptenginedebugger/tst_qscriptenginedebugger.cpp
@@ -0,0 +1,744 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qscriptengine.h>
+#include <qscriptenginedebugger.h>
+#include <qaction.h>
+#include <qlineedit.h>
+#include <qmainwindow.h>
+#include <qmenu.h>
+#include <qplaintextedit.h>
+#include <qtoolbar.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+// Will try to wait for the condition while allowing event processing
+#define QTRY_COMPARE(__expr, __expected) \
+ do { \
+ const int __step = 50; \
+ const int __timeout = 5000; \
+ if ((__expr) != (__expected)) { \
+ QTest::qWait(0); \
+ } \
+ for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
+ QTest::qWait(__step); \
+ } \
+ QCOMPARE(__expr, __expected); \
+ } while(0)
+
+// Can't use QTest::qWait() because it causes event loop to hang on some platforms
+static void qsWait(int ms)
+{
+ QTimer timer;
+ timer.setSingleShot(true);
+ timer.setInterval(ms);
+ timer.start();
+ QEventLoop loop;
+ QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
+ loop.exec();
+ QCoreApplication::processEvents();
+}
+
+class tst_QScriptEngineDebugger : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QScriptEngineDebugger();
+ virtual ~tst_QScriptEngineDebugger();
+
+private slots:
+ void attachAndDetach();
+ void action();
+ void widget();
+ void standardObjects();
+ void debuggerSignals();
+ void consoleCommands();
+ void multithreadedDebugging();
+};
+
+tst_QScriptEngineDebugger::tst_QScriptEngineDebugger()
+{
+}
+
+tst_QScriptEngineDebugger::~tst_QScriptEngineDebugger()
+{
+}
+
+void tst_QScriptEngineDebugger::attachAndDetach()
+{
+ {
+ QScriptEngineDebugger debugger;
+ debugger.attachTo(0);
+ QScriptEngine engine;
+ debugger.attachTo(&engine);
+ }
+ {
+ QScriptEngineDebugger debugger;
+ QScriptEngine engine;
+ debugger.attachTo(&engine);
+ debugger.detach();
+ }
+ {
+ QScriptEngineDebugger debugger;
+ QScriptEngine engine;
+ debugger.attachTo(&engine);
+ debugger.detach();
+ QScriptEngine engine2;
+ debugger.attachTo(&engine2);
+ }
+ {
+ QScriptEngineDebugger debugger;
+ QScriptEngine engine;
+ debugger.attachTo(&engine);
+ debugger.detach();
+ QScriptEngine engine2;
+ debugger.attachTo(&engine2);
+ debugger.detach();
+ }
+#ifndef Q_OS_WINCE // demands too much memory for WinCE
+ {
+ QScriptEngineDebugger debugger;
+ QScriptEngine engine;
+ debugger.attachTo(&engine);
+ QScriptEngineDebugger debugger2;
+ debugger2.attachTo(&engine);
+ }
+#endif
+}
+
+void tst_QScriptEngineDebugger::action()
+{
+ QScriptEngine engine;
+ QScriptEngineDebugger debugger;
+ debugger.attachTo(&engine);
+ QList<QScriptEngineDebugger::DebuggerAction> actions;
+ actions
+ << QScriptEngineDebugger::InterruptAction
+ << QScriptEngineDebugger::ContinueAction
+ << QScriptEngineDebugger::StepIntoAction
+ << QScriptEngineDebugger::StepOverAction
+ << QScriptEngineDebugger::StepOutAction
+ << QScriptEngineDebugger::RunToCursorAction
+ << QScriptEngineDebugger::RunToNewScriptAction
+ << QScriptEngineDebugger::ToggleBreakpointAction
+ << QScriptEngineDebugger::ClearDebugOutputAction
+ << QScriptEngineDebugger::ClearErrorLogAction
+ << QScriptEngineDebugger::ClearConsoleAction
+ << QScriptEngineDebugger::FindInScriptAction
+ << QScriptEngineDebugger::FindNextInScriptAction
+ << QScriptEngineDebugger::FindPreviousInScriptAction
+ << QScriptEngineDebugger::GoToLineAction;
+ QList<QAction*> lst;
+ for (int i = 0; i < actions.size(); ++i) {
+ QScriptEngineDebugger::DebuggerAction da = actions.at(i);
+ QAction *act = debugger.action(da);
+ QVERIFY(act != 0);
+ QCOMPARE(act, debugger.action(da));
+ QCOMPARE(act->parent(), (QObject*)&debugger);
+ QVERIFY(lst.indexOf(act) == -1);
+ lst.append(act);
+ }
+}
+
+void tst_QScriptEngineDebugger::widget()
+{
+ QScriptEngine engine;
+ QScriptEngineDebugger debugger;
+ debugger.attachTo(&engine);
+ QList<QScriptEngineDebugger::DebuggerWidget> widgets;
+ widgets
+ << QScriptEngineDebugger::ConsoleWidget
+ << QScriptEngineDebugger::StackWidget
+ << QScriptEngineDebugger::ScriptsWidget
+ << QScriptEngineDebugger::LocalsWidget
+ << QScriptEngineDebugger::CodeWidget
+ << QScriptEngineDebugger::CodeFinderWidget
+ << QScriptEngineDebugger::BreakpointsWidget
+ << QScriptEngineDebugger::DebugOutputWidget
+ << QScriptEngineDebugger::ErrorLogWidget;
+ QList<QWidget*> lst;
+ for (int i = 0; i < widgets.size(); ++i) {
+ QScriptEngineDebugger::DebuggerWidget dw = widgets.at(i);
+ QWidget *wid = debugger.widget(dw);
+ QVERIFY(wid != 0);
+ QCOMPARE(wid, debugger.widget(dw));
+ QVERIFY(lst.indexOf(wid) == -1);
+ lst.append(wid);
+ QCOMPARE(static_cast<QWidget *>(wid->parent()), (QWidget*)0);
+ }
+}
+
+void tst_QScriptEngineDebugger::standardObjects()
+{
+ QScriptEngine engine;
+ QScriptEngineDebugger debugger;
+ debugger.attachTo(&engine);
+
+ QMainWindow *win = debugger.standardWindow();
+ QCOMPARE(static_cast<QWidget *>(win->parent()), (QWidget*)0);
+
+ QMenu *menu = debugger.createStandardMenu();
+ QCOMPARE(static_cast<QWidget *>(menu->parent()), (QWidget*)0);
+ QToolBar *toolBar = debugger.createStandardToolBar();
+ QCOMPARE(static_cast<QWidget *>(toolBar->parent()), (QWidget*)0);
+
+ QMenu *menu2 = debugger.createStandardMenu(win);
+ QCOMPARE(static_cast<QWidget *>(menu2->parent()), (QWidget*)win);
+ QVERIFY(menu2 != menu);
+ QToolBar *toolBar2 = debugger.createStandardToolBar(win);
+ QCOMPARE(static_cast<QWidget *>(toolBar2->parent()), (QWidget*)win);
+ QVERIFY(toolBar2 != toolBar);
+
+ delete menu;
+ delete toolBar;
+}
+
+void tst_QScriptEngineDebugger::debuggerSignals()
+{
+ QScriptEngine engine;
+ QScriptEngineDebugger debugger;
+ debugger.attachTo(&engine);
+ debugger.setAutoShowStandardWindow(false);
+ QSignalSpy evaluationSuspendedSpy(&debugger, SIGNAL(evaluationSuspended()));
+ QSignalSpy evaluationResumedSpy(&debugger, SIGNAL(evaluationResumed()));
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()),
+ debugger.action(QScriptEngineDebugger::ContinueAction),
+ SLOT(trigger()));
+ engine.evaluate("123");
+ QCOMPARE(evaluationSuspendedSpy.count(), 0);
+ QCOMPARE(evaluationResumedSpy.count(), 0);
+ engine.evaluate("debugger");
+ QCoreApplication::processEvents();
+ QCOMPARE(evaluationSuspendedSpy.count(), 1);
+ QCOMPARE(evaluationResumedSpy.count(), 1);
+}
+
+static void executeConsoleCommand(QLineEdit *inputEdit, QPlainTextEdit *outputEdit,
+ const QString &text)
+{
+ QString before = outputEdit->toPlainText();
+ inputEdit->setText(text);
+ QTest::keyPress(inputEdit, Qt::Key_Enter);
+ const int delay = 100;
+ qsWait(delay);
+ QString after = outputEdit->toPlainText();
+ int retryCount = 10;
+LAgain:
+ while ((before == after) && (retryCount != 0)) {
+ qsWait(delay);
+ after = outputEdit->toPlainText();
+ --retryCount;
+ }
+ if (before != after) {
+ before = after;
+ qsWait(delay);
+ after = outputEdit->toPlainText();
+ if (before != after) {
+ retryCount = 10;
+ goto LAgain;
+ }
+ }
+}
+
+class DebuggerCommandExecutor : public QObject
+{
+ Q_OBJECT
+public:
+ DebuggerCommandExecutor(QLineEdit *inputEdit,
+ QPlainTextEdit *outputEdit,
+ const QString &text,
+ QObject *parent = 0)
+ : QObject(parent), m_inputEdit(inputEdit),
+ m_outputEdit(outputEdit), m_commands(text) {}
+ DebuggerCommandExecutor(QLineEdit *inputEdit,
+ QPlainTextEdit *outputEdit,
+ const QStringList &commands,
+ QObject *parent = 0)
+ : QObject(parent), m_inputEdit(inputEdit),
+ m_outputEdit(outputEdit), m_commands(commands) {}
+public Q_SLOTS:
+ void execute() {
+ for (int i = 0; i < m_commands.size(); ++i)
+ executeConsoleCommand(m_inputEdit, m_outputEdit, m_commands.at(i));
+ }
+private:
+ QLineEdit *m_inputEdit;
+ QPlainTextEdit *m_outputEdit;
+ QStringList m_commands;
+};
+
+void tst_QScriptEngineDebugger::consoleCommands()
+{
+ QSKIP("This test can hang / misbehave because of timing/event loop issues (task 241300)", SkipAll);
+
+ QScriptEngine engine;
+ QScriptEngineDebugger debugger;
+ debugger.setAutoShowStandardWindow(false);
+ debugger.attachTo(&engine);
+
+ QWidget *consoleWidget = debugger.widget(QScriptEngineDebugger::ConsoleWidget);
+ QLineEdit *inputEdit = qFindChild<QLineEdit*>(consoleWidget);
+ QVERIFY(inputEdit != 0);
+ QPlainTextEdit *outputEdit = qFindChild<QPlainTextEdit*>(consoleWidget);
+ QVERIFY(outputEdit != 0);
+
+ QVERIFY(outputEdit->toPlainText().startsWith("Welcome to the Qt Script debugger."));
+ outputEdit->clear();
+
+ // print()
+ {
+ QWidget *debugOutputWidget = debugger.widget(QScriptEngineDebugger::DebugOutputWidget);
+ QPlainTextEdit *debugOutputEdit = qFindChild<QPlainTextEdit*>(debugOutputWidget);
+ QVERIFY(debugOutputEdit != 0);
+
+ QVERIFY(debugOutputEdit->toPlainText().isEmpty());
+ executeConsoleCommand(inputEdit, outputEdit, "print('Test of debug output')");
+ QCOMPARE(debugOutputEdit->toPlainText(), QString::fromLatin1("Test of debug output"));
+
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> print('Test of debug output')"));
+ }
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info scripts");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info scripts\nNo scripts loaded."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".break foo.qs:123");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .break foo.qs:123\nBreakpoint 1: foo.qs, line 123."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".break 123");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .break 123\nNo script."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tyes\tfoo.qs:123"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".disable 1");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .disable 1"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tno\tfoo.qs:123"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".disable 1");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .disable 1"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".disable 123");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .disable 123\nNo breakpoint number 123."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".enable 1");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .enable 1"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tyes\tfoo.qs:123"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".enable 123");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .enable 123\nNo breakpoint number 123."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".condition 1 i > 456");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .condition 1 i > 456"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tyes\tfoo.qs:123\n\tstop only if i > 456"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".condition 1");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .condition 1\nBreakpoint 1 now unconditional."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tyes\tfoo.qs:123"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".condition 123");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .condition 123\nNo breakpoint number 123."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".ignore 1");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .ignore 1\nMissing argument (ignore-count)."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".ignore 1 10");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .ignore 1 10\nBreakpoint 1 will be ignored the next 10 time(s)."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".delete 1");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .delete 1"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nNo breakpoints set."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".tbreak bar.qs:456");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .tbreak bar.qs:456\nBreakpoint 2: bar.qs, line 456."));
+
+ {
+ QString script;
+ script.append("function foo(i) {\n");
+ for (int i = 0; i < 100; ++i)
+ script.append(QString::fromLatin1(" i = i + %0;\n").arg(i));
+ script.append(" return i;\n}");
+ engine.evaluate(script, "foo.qs");
+ }
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info scripts");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info scripts\n\tfoo.qs"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".list foo.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .list foo.qs\n"
+ "1\tfunction foo(i) {\n"
+ "2\t i = i + 0;\n"
+ "3\t i = i + 1;\n"
+ "4\t i = i + 2;\n"
+ "5\t i = i + 3;\n"
+ "6\t i = i + 4;\n"
+ "7\t i = i + 5;\n"
+ "8\t i = i + 6;\n"
+ "9\t i = i + 7;\n"
+ "10\t i = i + 8;"));
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".list");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .list\n"
+ "No script."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".backtrace");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .backtrace\n#0 <global>()@:-1"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".down");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .down\nAlready at bottom (innermost) frame."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".up");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .up\nAlready at top (outermost) frame."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".frame");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .frame\n#0 <global>()@:-1"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".break foo.qs:789");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .break foo.qs:789\nBreakpoint 3: foo.qs, line 789."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".clear foo.qs:789");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .clear foo.qs:789\nDeleted breakpoint 3."));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n2\tyes\tbar.qs:456"));
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".info locals");
+ QVERIFY(outputEdit->toPlainText().startsWith("qsdb> .info locals\n"
+ "NaN : NaN\n"
+ "Infinity : Infinity\n"
+ "undefined : undefined\n"
+ "print : function () { [native] }\n"
+ "parseInt : function () { [native] }\n"
+ "parseFloat : function () { [native] }\n"
+ "isNaN : function () { [native] }\n"
+ "isFinite : function () { [native] }\n"
+ "decodeURI : function () { [native] }\n"
+ "decodeURIComponent : function () { [native] }\n"
+ "encodeURI : function () { [native] }\n"
+ "encodeURIComponent : function () { [native] }\n"
+ "escape : function () { [native] }\n"
+ "unescape : function () { [native] }\n"
+ "version : function () { [native] }\n"
+ "gc : function () { [native] }\n"
+ "Object : function () { [native] }\n"
+ "Function : function () { [native] }\n"
+ "Number : function () { [native] }\n"
+ "Boolean : function () { [native] }"));
+
+ outputEdit->clear();
+ QVERIFY(!engine.globalObject().property("a").isValid());
+ executeConsoleCommand(inputEdit, outputEdit, ".eval a = 123");
+ QVERIFY(engine.globalObject().property("a").isNumber());
+ QCOMPARE(engine.globalObject().property("a").toInt32(), 123);
+
+ outputEdit->clear();
+ QVERIFY(!engine.globalObject().property("b").isValid());
+ executeConsoleCommand(inputEdit, outputEdit, "b = 456");
+ QVERIFY(engine.globalObject().property("b").isNumber());
+ QCOMPARE(engine.globalObject().property("b").toInt32(), 456);
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".break myscript.qs:1");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .break myscript.qs:1\nBreakpoint 4: myscript.qs, line 1."));
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, ".continue");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("void(123);", "myscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n1\tvoid(123);\nqsdb> .continue"));
+ }
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, ".step");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n"
+ "1\tvoid(123);\n"
+ "qsdb> .step\n"
+ "2\tvoid(456);\n"
+ "qsdb> .step"));
+ }
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, ".step 2");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n1\tvoid(123);\nqsdb> .step 2"));
+ }
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, ".next");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n"
+ "1\tvoid(123);\n"
+ "qsdb> .next\n"
+ "2\tvoid(456);\n"
+ "qsdb> .next"));
+ }
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, ".next 2");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n"
+ "1\tvoid(123);\n"
+ "qsdb> .next 2"));
+ }
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, ".finish");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n1\tvoid(123);\nqsdb> .finish"));
+ }
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, ".return");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("void(123);\nvoid(456);\n789;", "myscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n1\tvoid(123);\nqsdb> .return"));
+ }
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, QStringList() << ".list" << ".continue");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("void(123);\nvoid(456);\n789;", "myscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n"
+ "1\tvoid(123);\n"
+ "qsdb> .list\n"
+ "1\tvoid(123);\n"
+ "2\tvoid(456);\n"
+ "3\t789;\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "8\n"
+ "9\n"
+ "10\n"
+ "qsdb> .continue"));
+ }
+
+ {
+ QString script;
+ script.append("function bar(i) {\n");
+ for (int i = 0; i < 10; ++i)
+ script.append(QString::fromLatin1(" i = i + %0;\n").arg(i));
+ script.append(" return i;\n}");
+ engine.evaluate(script, "bar.qs");
+ }
+
+ outputEdit->clear();
+ executeConsoleCommand(inputEdit, outputEdit, ".break bar.qs:7");
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, QStringList()
+ << ".list"
+ << ".up"
+ << ".list"
+ << ".frame"
+ << ".down"
+ << ".list"
+ << ".continue");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("bar(123);", "testscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 5 at bar.qs, line 7.\n"
+ "7\t i = i + 5;\n"
+ "qsdb> .list\n"
+ "2\t i = i + 0;\n"
+ "3\t i = i + 1;\n"
+ "4\t i = i + 2;\n"
+ "5\t i = i + 3;\n"
+ "6\t i = i + 4;\n"
+ "7\t i = i + 5;\n"
+ "8\t i = i + 6;\n"
+ "9\t i = i + 7;\n"
+ "10\t i = i + 8;\n"
+ "11\t i = i + 9;\n"
+ "qsdb> .up\n"
+ "#1 <global>()@testscript.qs:1\n"
+ "qsdb> .list\n"
+ "1\tbar(123);\n"
+ "2\n"
+ "3\n"
+ "4\n"
+ "5\n"
+ "6\n"
+ "7\n"
+ "8\n"
+ "9\n"
+ "10\n"
+ "qsdb> .frame\n"
+ "#1 <global>()@testscript.qs:1\n"
+ "qsdb> .down\n"
+ "#0 bar(123)@bar.qs:7\n"
+ "qsdb> .list\n"
+ "2\t i = i + 0;\n"
+ "3\t i = i + 1;\n"
+ "4\t i = i + 2;\n"
+ "5\t i = i + 3;\n"
+ "6\t i = i + 4;\n"
+ "7\t i = i + 5;\n"
+ "8\t i = i + 6;\n"
+ "9\t i = i + 7;\n"
+ "10\t i = i + 8;\n"
+ "11\t i = i + 9;\n"
+ "qsdb> .continue"));
+ }
+
+ {
+ DebuggerCommandExecutor executor(inputEdit, outputEdit, QStringList()
+ << ".list 9"
+ << ".continue");
+ QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
+ outputEdit->clear();
+ engine.evaluate("bar(123);", "testscript.qs");
+ QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 5 at bar.qs, line 7.\n"
+ "7\t i = i + 5;\n"
+ "qsdb> .list 9\n"
+ "4\t i = i + 2;\n"
+ "5\t i = i + 3;\n"
+ "6\t i = i + 4;\n"
+ "7\t i = i + 5;\n"
+ "8\t i = i + 6;\n"
+ "9\t i = i + 7;\n"
+ "10\t i = i + 8;\n"
+ "11\t i = i + 9;\n"
+ "12\t return i;\n"
+ "13\t}\n"
+ "qsdb> .continue"));
+ }
+}
+
+class ScriptEvaluator : public QObject
+{
+ Q_OBJECT
+public:
+ ScriptEvaluator(QObject *parent = 0)
+ : QObject(parent) {
+ m_engine = new QScriptEngine(this);
+ }
+ QScriptEngine *engine() const {
+ return m_engine;
+ }
+public Q_SLOTS:
+ QScriptValue evaluate(const QString &program) {
+ return m_engine->evaluate(program);
+ }
+private:
+ QScriptEngine *m_engine;
+};
+
+void tst_QScriptEngineDebugger::multithreadedDebugging()
+{
+ ScriptEvaluator eval;
+ QThread thread;
+ eval.moveToThread(&thread);
+ eval.engine()->moveToThread(&thread);
+ QScriptEngineDebugger debugger;
+ QSignalSpy evaluationSuspendedSpy(&debugger, SIGNAL(evaluationSuspended()));
+ QSignalSpy evaluationResumedSpy(&debugger, SIGNAL(evaluationResumed()));
+ debugger.attachTo(eval.engine());
+ QMetaObject::invokeMethod(&eval, "evaluate", Qt::QueuedConnection, Q_ARG(QString, "debugger"));
+ QSignalSpy threadFinishedSpy(&thread, SIGNAL(finished()));
+ thread.start();
+ QTRY_COMPARE(evaluationSuspendedSpy.count(), 1);
+ QTRY_COMPARE(evaluationResumedSpy.count(), 0);
+ thread.quit();
+ QTRY_COMPARE(threadFinishedSpy.count(), 1);
+}
+
+QTEST_MAIN(tst_QScriptEngineDebugger)
+#include "tst_qscriptenginedebugger.moc"