tests/auto/qscriptenginedebugger/tst_qscriptenginedebugger.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QtTest/QtTest>
       
    44 
       
    45 #include <qscriptengine.h>
       
    46 #include <qscriptenginedebugger.h>
       
    47 #include <qaction.h>
       
    48 #include <qlineedit.h>
       
    49 #include <qmainwindow.h>
       
    50 #include <qmenu.h>
       
    51 #include <qplaintextedit.h>
       
    52 #include <qtoolbar.h>
       
    53 
       
    54 //TESTED_CLASS=
       
    55 //TESTED_FILES=
       
    56 
       
    57 // Will try to wait for the condition while allowing event processing
       
    58 #define QTRY_COMPARE(__expr, __expected) \
       
    59     do { \
       
    60         const int __step = 50; \
       
    61         const int __timeout = 5000; \
       
    62         if ((__expr) != (__expected)) { \
       
    63             QTest::qWait(0); \
       
    64         } \
       
    65         for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
       
    66             QTest::qWait(__step); \
       
    67         } \
       
    68         QCOMPARE(__expr, __expected); \
       
    69     } while(0)
       
    70 
       
    71 // Can't use QTest::qWait() because it causes event loop to hang on some platforms
       
    72 static void qsWait(int ms)
       
    73 {
       
    74     QTimer timer;
       
    75     timer.setSingleShot(true);
       
    76     timer.setInterval(ms);
       
    77     timer.start();
       
    78     QEventLoop loop;
       
    79     QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
       
    80     loop.exec();
       
    81     QCoreApplication::processEvents();
       
    82 }
       
    83 
       
    84 class tst_QScriptEngineDebugger : public QObject
       
    85 {
       
    86     Q_OBJECT
       
    87 
       
    88 public:
       
    89     tst_QScriptEngineDebugger();
       
    90     virtual ~tst_QScriptEngineDebugger();
       
    91 
       
    92 private slots:
       
    93     void attachAndDetach();
       
    94     void action();
       
    95     void widget();
       
    96     void standardObjects();
       
    97     void debuggerSignals();
       
    98     void consoleCommands();
       
    99     void multithreadedDebugging();
       
   100 };
       
   101 
       
   102 tst_QScriptEngineDebugger::tst_QScriptEngineDebugger()
       
   103 {
       
   104 }
       
   105 
       
   106 tst_QScriptEngineDebugger::~tst_QScriptEngineDebugger()
       
   107 {
       
   108 }
       
   109 
       
   110 void tst_QScriptEngineDebugger::attachAndDetach()
       
   111 {
       
   112 #if defined(Q_OS_WINCE) && _WIN32_WCE < 0x600
       
   113     QSKIP("skipped due to high mem usage until task 261062 is fixed", SkipAll);
       
   114 #endif
       
   115     {
       
   116         QScriptEngineDebugger debugger;
       
   117         QCOMPARE(debugger.state(), QScriptEngineDebugger::SuspendedState);
       
   118         debugger.attachTo(0);
       
   119         QScriptEngine engine;
       
   120         debugger.attachTo(&engine);
       
   121         QCOMPARE(debugger.state(), QScriptEngineDebugger::SuspendedState);
       
   122     }
       
   123     {
       
   124         QScriptEngineDebugger debugger;
       
   125         QScriptEngine engine;
       
   126         QScriptValue oldPrint = engine.globalObject().property("print");
       
   127         QVERIFY(oldPrint.isFunction());
       
   128         QVERIFY(!engine.globalObject().property("__FILE__").isValid());
       
   129         QVERIFY(!engine.globalObject().property("__LINE__").isValid());
       
   130 
       
   131         debugger.attachTo(&engine);
       
   132         QVERIFY(engine.globalObject().property("__FILE__").isUndefined());
       
   133         QVERIFY(engine.globalObject().property("__LINE__").isNumber());
       
   134         QVERIFY(!engine.globalObject().property("print").strictlyEquals(oldPrint));
       
   135 
       
   136         debugger.detach();
       
   137         QVERIFY(engine.globalObject().property("print").strictlyEquals(oldPrint));
       
   138         QVERIFY(!engine.globalObject().property("__FILE__").isValid());
       
   139         QVERIFY(!engine.globalObject().property("__LINE__").isValid());
       
   140     }
       
   141     {
       
   142         QScriptEngineDebugger debugger;
       
   143         QScriptEngine engine;
       
   144         debugger.attachTo(&engine);
       
   145         debugger.detach();
       
   146         QScriptEngine engine2;
       
   147         debugger.attachTo(&engine2);
       
   148     }
       
   149     {
       
   150         QScriptEngineDebugger debugger;
       
   151         QScriptEngine engine;
       
   152         debugger.attachTo(&engine);
       
   153         debugger.detach();
       
   154         QScriptEngine engine2;
       
   155         debugger.attachTo(&engine2);
       
   156         debugger.detach();
       
   157     }
       
   158 #ifndef Q_OS_WINCE // demands too much memory for WinCE
       
   159     {
       
   160         QScriptEngineDebugger debugger;
       
   161         QScriptEngine engine;
       
   162         debugger.attachTo(&engine);
       
   163         QScriptEngineDebugger debugger2;
       
   164         debugger2.attachTo(&engine);
       
   165     }
       
   166 #endif
       
   167     {
       
   168         QScriptEngine *engine = new QScriptEngine;
       
   169         QScriptEngineDebugger debugger;
       
   170         debugger.attachTo(engine);
       
   171         delete engine;
       
   172         QScriptEngine engine2;
       
   173         debugger.attachTo(&engine2);
       
   174     }
       
   175 }
       
   176 
       
   177 void tst_QScriptEngineDebugger::action()
       
   178 {
       
   179 #if defined(Q_OS_WINCE) && _WIN32_WCE < 0x600
       
   180     QSKIP("skipped due to high mem usage until task 261062 is fixed", SkipAll);
       
   181 #endif
       
   182 
       
   183     QScriptEngine engine;
       
   184     QScriptEngineDebugger debugger;
       
   185     debugger.attachTo(&engine);
       
   186     QList<QScriptEngineDebugger::DebuggerAction> actions;
       
   187     actions
       
   188         << QScriptEngineDebugger::InterruptAction
       
   189         << QScriptEngineDebugger::ContinueAction
       
   190         << QScriptEngineDebugger::StepIntoAction
       
   191         << QScriptEngineDebugger::StepOverAction
       
   192         << QScriptEngineDebugger::StepOutAction
       
   193         << QScriptEngineDebugger::RunToCursorAction
       
   194         << QScriptEngineDebugger::RunToNewScriptAction
       
   195         << QScriptEngineDebugger::ToggleBreakpointAction
       
   196         << QScriptEngineDebugger::ClearDebugOutputAction
       
   197         << QScriptEngineDebugger::ClearErrorLogAction
       
   198         << QScriptEngineDebugger::ClearConsoleAction
       
   199         << QScriptEngineDebugger::FindInScriptAction
       
   200         << QScriptEngineDebugger::FindNextInScriptAction
       
   201         << QScriptEngineDebugger::FindPreviousInScriptAction
       
   202         << QScriptEngineDebugger::GoToLineAction;
       
   203     QList<QAction*> lst;
       
   204     for (int i = 0; i < actions.size(); ++i) {
       
   205         QScriptEngineDebugger::DebuggerAction da = actions.at(i);
       
   206         QAction *act = debugger.action(da);
       
   207         QVERIFY(act != 0);
       
   208         QCOMPARE(act, debugger.action(da));
       
   209         QCOMPARE(act->parent(), (QObject*)&debugger);
       
   210         QVERIFY(lst.indexOf(act) == -1);
       
   211         lst.append(act);
       
   212     }
       
   213 }
       
   214 
       
   215 void tst_QScriptEngineDebugger::widget()
       
   216 {
       
   217 #if defined(Q_OS_WINCE) && _WIN32_WCE < 0x600
       
   218     QSKIP("skipped due to high mem usage until task 261062 is fixed", SkipAll);
       
   219 #endif
       
   220 
       
   221     QScriptEngine engine;
       
   222     QScriptEngineDebugger debugger;
       
   223     debugger.attachTo(&engine);
       
   224     QList<QScriptEngineDebugger::DebuggerWidget> widgets;
       
   225     widgets
       
   226         << QScriptEngineDebugger::ConsoleWidget
       
   227         << QScriptEngineDebugger::StackWidget
       
   228         << QScriptEngineDebugger::ScriptsWidget
       
   229         << QScriptEngineDebugger::LocalsWidget
       
   230         << QScriptEngineDebugger::CodeWidget
       
   231         << QScriptEngineDebugger::CodeFinderWidget
       
   232         << QScriptEngineDebugger::BreakpointsWidget
       
   233         << QScriptEngineDebugger::DebugOutputWidget
       
   234         << QScriptEngineDebugger::ErrorLogWidget;
       
   235     QList<QWidget*> lst;
       
   236     for (int i = 0; i < widgets.size(); ++i) {
       
   237         QScriptEngineDebugger::DebuggerWidget dw = widgets.at(i);
       
   238         QWidget *wid = debugger.widget(dw);
       
   239         QVERIFY(wid != 0);
       
   240         QCOMPARE(wid, debugger.widget(dw));
       
   241         QVERIFY(lst.indexOf(wid) == -1);
       
   242         lst.append(wid);
       
   243         QCOMPARE(static_cast<QWidget *>(wid->parent()), (QWidget*)0);
       
   244     }
       
   245 }
       
   246 
       
   247 void tst_QScriptEngineDebugger::standardObjects()
       
   248 {
       
   249 #if defined(Q_OS_WINCE) && _WIN32_WCE < 0x600
       
   250     QSKIP("skipped due to high mem usage until task 261062 is fixed", SkipAll);
       
   251 #endif
       
   252 
       
   253     QScriptEngine engine;
       
   254     QScriptEngineDebugger debugger;
       
   255     debugger.attachTo(&engine);
       
   256 
       
   257     QMainWindow *win = debugger.standardWindow();
       
   258     QCOMPARE(static_cast<QWidget *>(win->parent()), (QWidget*)0);
       
   259 
       
   260     QMenu *menu = debugger.createStandardMenu();
       
   261     QCOMPARE(static_cast<QWidget *>(menu->parent()), (QWidget*)0);
       
   262     QToolBar *toolBar = debugger.createStandardToolBar();
       
   263     QCOMPARE(static_cast<QWidget *>(toolBar->parent()), (QWidget*)0);
       
   264 
       
   265     QMenu *menu2 = debugger.createStandardMenu(win);
       
   266     QCOMPARE(static_cast<QWidget *>(menu2->parent()), (QWidget*)win);
       
   267     QVERIFY(menu2 != menu);
       
   268     QToolBar *toolBar2 = debugger.createStandardToolBar(win);
       
   269     QCOMPARE(static_cast<QWidget *>(toolBar2->parent()), (QWidget*)win);
       
   270     QVERIFY(toolBar2 != toolBar);
       
   271 
       
   272     delete menu;
       
   273     delete toolBar;
       
   274 }
       
   275 
       
   276 void tst_QScriptEngineDebugger::debuggerSignals()
       
   277 {
       
   278 #if defined(Q_OS_WINCE) && _WIN32_WCE < 0x600
       
   279     QSKIP("skipped due to high mem usage until task 261062 is fixed", SkipAll);
       
   280 #endif
       
   281 
       
   282     QScriptEngine engine;
       
   283     QScriptEngineDebugger debugger;
       
   284     debugger.attachTo(&engine);
       
   285     debugger.setAutoShowStandardWindow(false);
       
   286     QSignalSpy evaluationSuspendedSpy(&debugger, SIGNAL(evaluationSuspended()));
       
   287     QSignalSpy evaluationResumedSpy(&debugger, SIGNAL(evaluationResumed()));
       
   288     QObject::connect(&debugger, SIGNAL(evaluationSuspended()),
       
   289                      debugger.action(QScriptEngineDebugger::ContinueAction),
       
   290                      SLOT(trigger()));
       
   291     engine.evaluate("123");
       
   292     QCOMPARE(evaluationSuspendedSpy.count(), 0);
       
   293     QCOMPARE(evaluationResumedSpy.count(), 0);
       
   294     engine.evaluate("debugger");
       
   295     QCoreApplication::processEvents();
       
   296     QCOMPARE(evaluationSuspendedSpy.count(), 1);
       
   297     QCOMPARE(evaluationResumedSpy.count(), 1);
       
   298 }
       
   299 
       
   300 static void executeConsoleCommand(QLineEdit *inputEdit, QPlainTextEdit *outputEdit,
       
   301                                   const QString &text)
       
   302 {
       
   303     QString before = outputEdit->toPlainText();
       
   304     inputEdit->setText(text);
       
   305     QTest::keyPress(inputEdit, Qt::Key_Enter);
       
   306     const int delay = 100;
       
   307     qsWait(delay);
       
   308     QString after = outputEdit->toPlainText();
       
   309     int retryCount = 10;
       
   310 LAgain:
       
   311     while ((before == after) && (retryCount != 0)) {
       
   312         qsWait(delay);
       
   313         after = outputEdit->toPlainText();
       
   314         --retryCount;
       
   315     }
       
   316     if (before != after) {
       
   317         before = after;
       
   318         qsWait(delay);
       
   319         after = outputEdit->toPlainText();
       
   320         if (before != after) {
       
   321             retryCount = 10;
       
   322             goto LAgain;
       
   323         }
       
   324     }
       
   325 }
       
   326 
       
   327 class DebuggerCommandExecutor : public QObject
       
   328 {
       
   329     Q_OBJECT
       
   330 public:
       
   331     DebuggerCommandExecutor(QLineEdit *inputEdit,
       
   332                             QPlainTextEdit *outputEdit,
       
   333                             const QString &text,
       
   334                             QObject *parent = 0)
       
   335         : QObject(parent), m_inputEdit(inputEdit),
       
   336           m_outputEdit(outputEdit), m_commands(text) {}
       
   337     DebuggerCommandExecutor(QLineEdit *inputEdit,
       
   338                             QPlainTextEdit *outputEdit,
       
   339                             const QStringList &commands,
       
   340                             QObject *parent = 0)
       
   341         : QObject(parent), m_inputEdit(inputEdit),
       
   342           m_outputEdit(outputEdit), m_commands(commands) {}
       
   343 public Q_SLOTS:
       
   344     void execute() {
       
   345         for (int i = 0; i < m_commands.size(); ++i)
       
   346             executeConsoleCommand(m_inputEdit, m_outputEdit, m_commands.at(i));
       
   347     }
       
   348 private:
       
   349     QLineEdit *m_inputEdit;
       
   350     QPlainTextEdit *m_outputEdit;
       
   351     QStringList m_commands;
       
   352 };
       
   353 
       
   354 void tst_QScriptEngineDebugger::consoleCommands()
       
   355 {
       
   356     QSKIP("This test can hang / misbehave because of timing/event loop issues (task 241300)", SkipAll);
       
   357 
       
   358     QScriptEngine engine;
       
   359     QScriptEngineDebugger debugger;
       
   360     debugger.setAutoShowStandardWindow(false);
       
   361     debugger.attachTo(&engine);
       
   362 
       
   363     QWidget *consoleWidget = debugger.widget(QScriptEngineDebugger::ConsoleWidget);
       
   364     QLineEdit *inputEdit = qFindChild<QLineEdit*>(consoleWidget);
       
   365     QVERIFY(inputEdit != 0);
       
   366     QPlainTextEdit *outputEdit = qFindChild<QPlainTextEdit*>(consoleWidget);
       
   367     QVERIFY(outputEdit != 0);
       
   368 
       
   369     QVERIFY(outputEdit->toPlainText().startsWith("Welcome to the Qt Script debugger."));
       
   370     outputEdit->clear();
       
   371 
       
   372     // print()
       
   373     {
       
   374         QWidget *debugOutputWidget = debugger.widget(QScriptEngineDebugger::DebugOutputWidget);
       
   375         QPlainTextEdit *debugOutputEdit = qFindChild<QPlainTextEdit*>(debugOutputWidget);
       
   376         QVERIFY(debugOutputEdit != 0);
       
   377 
       
   378         QVERIFY(debugOutputEdit->toPlainText().isEmpty());
       
   379         executeConsoleCommand(inputEdit, outputEdit, "print('Test of debug output')");
       
   380         QCOMPARE(debugOutputEdit->toPlainText(), QString::fromLatin1("Test of debug output"));
       
   381 
       
   382         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> print('Test of debug output')"));
       
   383     }
       
   384 
       
   385     outputEdit->clear();
       
   386     executeConsoleCommand(inputEdit, outputEdit, ".info scripts");
       
   387     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info scripts\nNo scripts loaded."));
       
   388 
       
   389     outputEdit->clear();
       
   390     executeConsoleCommand(inputEdit, outputEdit, ".break foo.qs:123");
       
   391     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .break foo.qs:123\nBreakpoint 1: foo.qs, line 123."));
       
   392 
       
   393     outputEdit->clear();
       
   394     executeConsoleCommand(inputEdit, outputEdit, ".break 123");
       
   395     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .break 123\nNo script."));
       
   396 
       
   397     outputEdit->clear();
       
   398     executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
       
   399     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tyes\tfoo.qs:123"));
       
   400 
       
   401     outputEdit->clear();
       
   402     executeConsoleCommand(inputEdit, outputEdit, ".disable 1");
       
   403     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .disable 1"));
       
   404 
       
   405     outputEdit->clear();
       
   406     executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
       
   407     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tno\tfoo.qs:123"));
       
   408 
       
   409     outputEdit->clear();
       
   410     executeConsoleCommand(inputEdit, outputEdit, ".disable 1");
       
   411     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .disable 1"));
       
   412 
       
   413     outputEdit->clear();
       
   414     executeConsoleCommand(inputEdit, outputEdit, ".disable 123");
       
   415     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .disable 123\nNo breakpoint number 123."));
       
   416 
       
   417     outputEdit->clear();
       
   418     executeConsoleCommand(inputEdit, outputEdit, ".enable 1");
       
   419     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .enable 1"));
       
   420 
       
   421     outputEdit->clear();
       
   422     executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
       
   423     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tyes\tfoo.qs:123"));
       
   424 
       
   425     outputEdit->clear();
       
   426     executeConsoleCommand(inputEdit, outputEdit, ".enable 123");
       
   427     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .enable 123\nNo breakpoint number 123."));
       
   428 
       
   429     outputEdit->clear();
       
   430     executeConsoleCommand(inputEdit, outputEdit, ".condition 1 i > 456");
       
   431     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .condition 1 i > 456"));
       
   432 
       
   433     outputEdit->clear();
       
   434     executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
       
   435     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tyes\tfoo.qs:123\n\tstop only if i > 456"));
       
   436 
       
   437     outputEdit->clear();
       
   438     executeConsoleCommand(inputEdit, outputEdit, ".condition 1");
       
   439     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .condition 1\nBreakpoint 1 now unconditional."));
       
   440 
       
   441     outputEdit->clear();
       
   442     executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
       
   443     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n1\tyes\tfoo.qs:123"));
       
   444 
       
   445     outputEdit->clear();
       
   446     executeConsoleCommand(inputEdit, outputEdit, ".condition 123");
       
   447     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .condition 123\nNo breakpoint number 123."));
       
   448 
       
   449     outputEdit->clear();
       
   450     executeConsoleCommand(inputEdit, outputEdit, ".ignore 1");
       
   451     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .ignore 1\nMissing argument (ignore-count)."));
       
   452 
       
   453     outputEdit->clear();
       
   454     executeConsoleCommand(inputEdit, outputEdit, ".ignore 1 10");
       
   455     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .ignore 1 10\nBreakpoint 1 will be ignored the next 10 time(s)."));
       
   456 
       
   457     outputEdit->clear();
       
   458     executeConsoleCommand(inputEdit, outputEdit, ".delete 1");
       
   459     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .delete 1"));
       
   460 
       
   461     outputEdit->clear();
       
   462     executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
       
   463     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nNo breakpoints set."));
       
   464 
       
   465     outputEdit->clear();
       
   466     executeConsoleCommand(inputEdit, outputEdit, ".tbreak bar.qs:456");
       
   467     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .tbreak bar.qs:456\nBreakpoint 2: bar.qs, line 456."));
       
   468 
       
   469     {
       
   470         QString script;
       
   471         script.append("function foo(i) {\n");
       
   472         for (int i = 0; i < 100; ++i)
       
   473             script.append(QString::fromLatin1("    i = i + %0;\n").arg(i));
       
   474         script.append("    return i;\n}");
       
   475         engine.evaluate(script, "foo.qs");
       
   476     }
       
   477     outputEdit->clear();
       
   478     executeConsoleCommand(inputEdit, outputEdit, ".info scripts");
       
   479     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info scripts\n\tfoo.qs"));
       
   480 
       
   481     outputEdit->clear();
       
   482     executeConsoleCommand(inputEdit, outputEdit, ".list foo.qs");
       
   483     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .list foo.qs\n"
       
   484                                                             "1\tfunction foo(i) {\n"
       
   485                                                             "2\t    i = i + 0;\n"
       
   486                                                             "3\t    i = i + 1;\n"
       
   487                                                             "4\t    i = i + 2;\n"
       
   488                                                             "5\t    i = i + 3;\n"
       
   489                                                             "6\t    i = i + 4;\n"
       
   490                                                             "7\t    i = i + 5;\n"
       
   491                                                             "8\t    i = i + 6;\n"
       
   492                                                             "9\t    i = i + 7;\n"
       
   493                                                             "10\t    i = i + 8;"));
       
   494     outputEdit->clear();
       
   495     executeConsoleCommand(inputEdit, outputEdit, ".list");
       
   496     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .list\n"
       
   497                                                             "No script."));
       
   498 
       
   499     outputEdit->clear();
       
   500     executeConsoleCommand(inputEdit, outputEdit, ".backtrace");
       
   501     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .backtrace\n#0  <global>() at -1"));
       
   502 
       
   503     outputEdit->clear();
       
   504     executeConsoleCommand(inputEdit, outputEdit, ".down");
       
   505     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .down\nAlready at bottom (innermost) frame."));
       
   506 
       
   507     outputEdit->clear();
       
   508     executeConsoleCommand(inputEdit, outputEdit, ".up");
       
   509     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .up\nAlready at top (outermost) frame."));
       
   510 
       
   511     outputEdit->clear();
       
   512     executeConsoleCommand(inputEdit, outputEdit, ".frame");
       
   513     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .frame\n#0  <global>() at -1"));
       
   514 
       
   515     outputEdit->clear();
       
   516     executeConsoleCommand(inputEdit, outputEdit, ".break foo.qs:789");
       
   517     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .break foo.qs:789\nBreakpoint 3: foo.qs, line 789."));
       
   518 
       
   519     outputEdit->clear();
       
   520     executeConsoleCommand(inputEdit, outputEdit, ".clear foo.qs:789");
       
   521     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .clear foo.qs:789\nDeleted breakpoint 3."));
       
   522 
       
   523     outputEdit->clear();
       
   524     executeConsoleCommand(inputEdit, outputEdit, ".info breakpoints");
       
   525     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .info breakpoints\nId\tEnabled\tWhere\n2\tyes\tbar.qs:456"));
       
   526 
       
   527     outputEdit->clear();
       
   528     executeConsoleCommand(inputEdit, outputEdit, ".info locals");
       
   529     QVERIFY(outputEdit->toPlainText().startsWith("qsdb> .info locals\n"
       
   530                                                  "NaN                : NaN\n"
       
   531                                                  "Infinity           : Infinity\n"
       
   532                                                  "undefined          : undefined\n"
       
   533                                                  "print              : function () { [native] }\n"
       
   534                                                  "parseInt           : function () { [native] }\n"
       
   535                                                  "parseFloat         : function () { [native] }\n"
       
   536                                                  "isNaN              : function () { [native] }\n"
       
   537                                                  "isFinite           : function () { [native] }\n"
       
   538                                                  "decodeURI          : function () { [native] }\n"
       
   539                                                  "decodeURIComponent : function () { [native] }\n"
       
   540                                                  "encodeURI          : function () { [native] }\n"
       
   541                                                  "encodeURIComponent : function () { [native] }\n"
       
   542                                                  "escape             : function () { [native] }\n"
       
   543                                                  "unescape           : function () { [native] }\n"
       
   544                                                  "version            : function () { [native] }\n"
       
   545                                                  "gc                 : function () { [native] }\n"
       
   546                                                  "Object             : function () { [native] }\n"
       
   547                                                  "Function           : function () { [native] }\n"
       
   548                                                  "Number             : function () { [native] }\n"
       
   549                                                  "Boolean            : function () { [native] }"));
       
   550 
       
   551     outputEdit->clear();
       
   552     QVERIFY(!engine.globalObject().property("a").isValid());
       
   553     executeConsoleCommand(inputEdit, outputEdit, ".eval a = 123");
       
   554     QVERIFY(engine.globalObject().property("a").isNumber());
       
   555     QCOMPARE(engine.globalObject().property("a").toInt32(), 123);
       
   556 
       
   557     outputEdit->clear();
       
   558     QVERIFY(!engine.globalObject().property("b").isValid());
       
   559     executeConsoleCommand(inputEdit, outputEdit, "b = 456");
       
   560     QVERIFY(engine.globalObject().property("b").isNumber());
       
   561     QCOMPARE(engine.globalObject().property("b").toInt32(), 456);
       
   562 
       
   563     outputEdit->clear();
       
   564     executeConsoleCommand(inputEdit, outputEdit, ".break myscript.qs:1");
       
   565     QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("qsdb> .break myscript.qs:1\nBreakpoint 4: myscript.qs, line 1."));
       
   566 
       
   567     {
       
   568         DebuggerCommandExecutor executor(inputEdit, outputEdit, ".continue");
       
   569         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   570         outputEdit->clear();
       
   571         engine.evaluate("void(123);", "myscript.qs");
       
   572         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n1\tvoid(123);\nqsdb> .continue"));
       
   573     }
       
   574 
       
   575     {
       
   576         DebuggerCommandExecutor executor(inputEdit, outputEdit, ".step");
       
   577         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   578         outputEdit->clear();
       
   579         engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
       
   580         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n"
       
   581                                                                 "1\tvoid(123);\n"
       
   582                                                                 "qsdb> .step\n"
       
   583                                                                 "2\tvoid(456);\n"
       
   584                                                                 "qsdb> .step"));
       
   585     }
       
   586 
       
   587     {
       
   588         DebuggerCommandExecutor executor(inputEdit, outputEdit, ".step 2");
       
   589         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   590         outputEdit->clear();
       
   591         engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
       
   592         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n1\tvoid(123);\nqsdb> .step 2"));
       
   593     }
       
   594 
       
   595     {
       
   596         DebuggerCommandExecutor executor(inputEdit, outputEdit, ".next");
       
   597         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   598         outputEdit->clear();
       
   599         engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
       
   600         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n"
       
   601                                                                 "1\tvoid(123);\n"
       
   602                                                                 "qsdb> .next\n"
       
   603                                                                 "2\tvoid(456);\n"
       
   604                                                                 "qsdb> .next"));
       
   605     }
       
   606 
       
   607     {
       
   608         DebuggerCommandExecutor executor(inputEdit, outputEdit, ".next 2");
       
   609         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   610         outputEdit->clear();
       
   611         engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
       
   612         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n"
       
   613                                                                 "1\tvoid(123);\n"
       
   614                                                                 "qsdb> .next 2"));
       
   615     }
       
   616 
       
   617     {
       
   618         DebuggerCommandExecutor executor(inputEdit, outputEdit, ".finish");
       
   619         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   620         outputEdit->clear();
       
   621         engine.evaluate("void(123);\nvoid(456);", "myscript.qs");
       
   622         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n1\tvoid(123);\nqsdb> .finish"));
       
   623     }
       
   624 
       
   625     {
       
   626         DebuggerCommandExecutor executor(inputEdit, outputEdit, ".return");
       
   627         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   628         outputEdit->clear();
       
   629         engine.evaluate("void(123);\nvoid(456);\n789;", "myscript.qs");
       
   630         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n1\tvoid(123);\nqsdb> .return"));
       
   631     }
       
   632 
       
   633     {
       
   634         DebuggerCommandExecutor executor(inputEdit, outputEdit, QStringList() << ".list" << ".continue");
       
   635         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   636         outputEdit->clear();
       
   637         engine.evaluate("void(123);\nvoid(456);\n789;", "myscript.qs");
       
   638         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 4 at myscript.qs, line 1.\n"
       
   639                                                                 "1\tvoid(123);\n"
       
   640                                                                 "qsdb> .list\n"
       
   641                                                                 "1\tvoid(123);\n"
       
   642                                                                 "2\tvoid(456);\n"
       
   643                                                                 "3\t789;\n"
       
   644                                                                 "4\n"
       
   645                                                                 "5\n"
       
   646                                                                 "6\n"
       
   647                                                                 "7\n"
       
   648                                                                 "8\n"
       
   649                                                                 "9\n"
       
   650                                                                 "10\n"
       
   651                                                                 "qsdb> .continue"));
       
   652     }
       
   653 
       
   654     {
       
   655         QString script;
       
   656         script.append("function bar(i) {\n");
       
   657         for (int i = 0; i < 10; ++i)
       
   658             script.append(QString::fromLatin1("    i = i + %0;\n").arg(i));
       
   659         script.append("    return i;\n}");
       
   660         engine.evaluate(script, "bar.qs");
       
   661     }
       
   662 
       
   663     outputEdit->clear();
       
   664     executeConsoleCommand(inputEdit, outputEdit, ".break bar.qs:7");
       
   665 
       
   666     {
       
   667         DebuggerCommandExecutor executor(inputEdit, outputEdit, QStringList()
       
   668                                          << ".list"
       
   669                                          << ".up"
       
   670                                          << ".list"
       
   671                                          << ".frame"
       
   672                                          << ".down"
       
   673                                          << ".list"
       
   674                                          << ".continue");
       
   675         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   676         outputEdit->clear();
       
   677         engine.evaluate("bar(123);", "testscript.qs");
       
   678         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 5 at bar.qs, line 7.\n"
       
   679                                                                 "7\t    i = i + 5;\n"
       
   680                                                                 "qsdb> .list\n"
       
   681                                                                 "2\t    i = i + 0;\n"
       
   682                                                                 "3\t    i = i + 1;\n"
       
   683                                                                 "4\t    i = i + 2;\n"
       
   684                                                                 "5\t    i = i + 3;\n"
       
   685                                                                 "6\t    i = i + 4;\n"
       
   686                                                                 "7\t    i = i + 5;\n"
       
   687                                                                 "8\t    i = i + 6;\n"
       
   688                                                                 "9\t    i = i + 7;\n"
       
   689                                                                 "10\t    i = i + 8;\n"
       
   690                                                                 "11\t    i = i + 9;\n"
       
   691                                                                 "qsdb> .up\n"
       
   692                                                                 "#1  <global>()@testscript.qs:1\n"
       
   693                                                                 "qsdb> .list\n"
       
   694                                                                 "1\tbar(123);\n"
       
   695                                                                 "2\n"
       
   696                                                                 "3\n"
       
   697                                                                 "4\n"
       
   698                                                                 "5\n"
       
   699                                                                 "6\n"
       
   700                                                                 "7\n"
       
   701                                                                 "8\n"
       
   702                                                                 "9\n"
       
   703                                                                 "10\n"
       
   704                                                                 "qsdb> .frame\n"
       
   705                                                                 "#1  <global>()@testscript.qs:1\n"
       
   706                                                                 "qsdb> .down\n"
       
   707                                                                 "#0  bar(123)@bar.qs:7\n"
       
   708                                                                 "qsdb> .list\n"
       
   709                                                                 "2\t    i = i + 0;\n"
       
   710                                                                 "3\t    i = i + 1;\n"
       
   711                                                                 "4\t    i = i + 2;\n"
       
   712                                                                 "5\t    i = i + 3;\n"
       
   713                                                                 "6\t    i = i + 4;\n"
       
   714                                                                 "7\t    i = i + 5;\n"
       
   715                                                                 "8\t    i = i + 6;\n"
       
   716                                                                 "9\t    i = i + 7;\n"
       
   717                                                                 "10\t    i = i + 8;\n"
       
   718                                                                 "11\t    i = i + 9;\n"
       
   719                                                                 "qsdb> .continue"));
       
   720     }
       
   721 
       
   722     {
       
   723         DebuggerCommandExecutor executor(inputEdit, outputEdit, QStringList()
       
   724                                          << ".list 9"
       
   725                                          << ".continue");
       
   726         QObject::connect(&debugger, SIGNAL(evaluationSuspended()), &executor, SLOT(execute()), Qt::QueuedConnection);
       
   727         outputEdit->clear();
       
   728         engine.evaluate("bar(123);", "testscript.qs");
       
   729         QCOMPARE(outputEdit->toPlainText(), QString::fromLatin1("Breakpoint 5 at bar.qs, line 7.\n"
       
   730                                                                 "7\t    i = i + 5;\n"
       
   731                                                                 "qsdb> .list 9\n"
       
   732                                                                 "4\t    i = i + 2;\n"
       
   733                                                                 "5\t    i = i + 3;\n"
       
   734                                                                 "6\t    i = i + 4;\n"
       
   735                                                                 "7\t    i = i + 5;\n"
       
   736                                                                 "8\t    i = i + 6;\n"
       
   737                                                                 "9\t    i = i + 7;\n"
       
   738                                                                 "10\t    i = i + 8;\n"
       
   739                                                                 "11\t    i = i + 9;\n"
       
   740                                                                 "12\t    return i;\n"
       
   741                                                                 "13\t}\n"
       
   742                                                                 "qsdb> .continue"));
       
   743     }
       
   744 }
       
   745 
       
   746 class ScriptEvaluator : public QObject
       
   747 {
       
   748     Q_OBJECT
       
   749 public:
       
   750     ScriptEvaluator(QObject *parent = 0)
       
   751         : QObject(parent) {
       
   752         m_engine = new QScriptEngine(this);
       
   753     }
       
   754     QScriptEngine *engine() const {
       
   755         return m_engine;
       
   756     }
       
   757 public Q_SLOTS:
       
   758     QScriptValue evaluate(const QString &program) {
       
   759         return m_engine->evaluate(program);
       
   760     }
       
   761 private:
       
   762     QScriptEngine *m_engine;
       
   763 };
       
   764 
       
   765 void tst_QScriptEngineDebugger::multithreadedDebugging()
       
   766 {
       
   767 #ifdef Q_OS_WINCE
       
   768     QSKIP("This tests uses too much memory for Windows CE", SkipAll);
       
   769 #endif
       
   770     ScriptEvaluator eval;
       
   771     QThread thread;
       
   772     eval.moveToThread(&thread);
       
   773     eval.engine()->moveToThread(&thread);
       
   774     QScriptEngineDebugger debugger;
       
   775     QSignalSpy evaluationSuspendedSpy(&debugger, SIGNAL(evaluationSuspended()));
       
   776     QSignalSpy evaluationResumedSpy(&debugger, SIGNAL(evaluationResumed()));
       
   777     debugger.attachTo(eval.engine());
       
   778     QMetaObject::invokeMethod(&eval, "evaluate", Qt::QueuedConnection, Q_ARG(QString, "debugger"));
       
   779     QSignalSpy threadFinishedSpy(&thread, SIGNAL(finished()));
       
   780     thread.start();
       
   781     QTRY_COMPARE(evaluationSuspendedSpy.count(), 1);
       
   782     QTRY_COMPARE(evaluationResumedSpy.count(), 0);
       
   783     thread.quit();
       
   784     QTRY_COMPARE(threadFinishedSpy.count(), 1);
       
   785 }
       
   786 
       
   787 QTEST_MAIN(tst_QScriptEngineDebugger)
       
   788 #include "tst_qscriptenginedebugger.moc"