util/tests/auto/qscriptengineagent/tst_qscriptengineagent.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 <QtScript/qscriptengineagent.h>
       
    46 #include <QtScript/qscriptengine.h>
       
    47 #include <QtScript/qscriptprogram.h>
       
    48 #include <qscriptvalueiterator.h>
       
    49 
       
    50 //TESTED_CLASS=
       
    51 //TESTED_FILES=
       
    52 
       
    53 QT_BEGIN_NAMESPACE
       
    54 extern bool qt_script_isJITEnabled();
       
    55 QT_END_NAMESPACE
       
    56 
       
    57 class tst_QScriptEngineAgent : public QObject
       
    58 {
       
    59     Q_OBJECT
       
    60     Q_PROPERTY(double testProperty READ testProperty WRITE setTestProperty)
       
    61 
       
    62 public:
       
    63     tst_QScriptEngineAgent();
       
    64     virtual ~tst_QScriptEngineAgent();
       
    65 
       
    66     double testProperty() const { return m_testProperty; }
       
    67     void setTestProperty(double val) { m_testProperty = val; }
       
    68 
       
    69 public slots:
       
    70     double testSlot(double arg) { return arg; }
       
    71 
       
    72 signals:
       
    73     void testSignal(double arg);
       
    74 
       
    75 private slots:
       
    76     void scriptLoadAndUnload_statement();
       
    77     void scriptLoadAndUnload();
       
    78     void scriptLoadAndUnload_eval();
       
    79     void contextPushAndPop();
       
    80     void functionEntryAndExit_semicolon();
       
    81     void functionEntryAndExit_expression();
       
    82     void functionEntryAndExit_functionCall();
       
    83     void functionEntryAndExit_functionCallWithoutReturn();
       
    84     void functionEntryAndExit_functionDefinition();
       
    85     void functionEntryAndExit_native();
       
    86     void functionEntryAndExit_native2();
       
    87     void functionEntryAndExit_nativeThrowing();
       
    88     void functionEntryAndExit_builtin_data();
       
    89     void functionEntryAndExit_builtin();
       
    90     void functionEntryAndExit_objects();
       
    91     void functionEntryAndExit_slots();
       
    92     void functionEntryAndExit_property_set();
       
    93     void functionEntryAndExit_property_get();
       
    94     void functionEntryAndExit_call();
       
    95     void functionEntryAndExit_functionReturn_construct();
       
    96     void functionEntryAndExit_functionReturn_call();
       
    97     void functionEntryAndExit_objectCall();
       
    98     void positionChange_1();
       
    99     void positionChange_2();
       
   100     void exceptionThrowAndCatch();
       
   101     void eventOrder_assigment();
       
   102     void eventOrder_functionDefinition();
       
   103     void eventOrder_throwError();
       
   104     void eventOrder_throwAndCatch();
       
   105     void eventOrder_functions();
       
   106     void eventOrder_throwCatchFinally();
       
   107     void eventOrder_signalsHandling();
       
   108     void recursiveObserve();
       
   109     void multipleAgents();
       
   110     void syntaxError();
       
   111     void extension_invoctaion();
       
   112     void extension();
       
   113     void isEvaluatingInExtension();
       
   114     void hasUncaughtException();
       
   115     void evaluateProgram();
       
   116     void evaluateProgram_SyntaxError();
       
   117     void evaluateNullProgram();
       
   118     void QTBUG6108();
       
   119 
       
   120 private:
       
   121     double m_testProperty;
       
   122 };
       
   123 
       
   124 tst_QScriptEngineAgent::tst_QScriptEngineAgent()
       
   125 {
       
   126 }
       
   127 
       
   128 tst_QScriptEngineAgent::~tst_QScriptEngineAgent()
       
   129 {
       
   130 }
       
   131 
       
   132 struct ScriptEngineEvent
       
   133 {
       
   134     enum Type {
       
   135         ScriptLoad,
       
   136         ScriptUnload,//1
       
   137         ContextPush,
       
   138         ContextPop,  //3
       
   139         FunctionEntry, //4
       
   140         FunctionExit, //5
       
   141         PositionChange,
       
   142         ExceptionThrow,//7
       
   143         ExceptionCatch,
       
   144         DebuggerInvocationRequest
       
   145     };
       
   146 
       
   147     Type type;
       
   148 
       
   149     qint64 scriptId;
       
   150     QString script;
       
   151     QString fileName;
       
   152     int lineNumber;
       
   153     int columnNumber;
       
   154     QScriptValue value;
       
   155     bool hasExceptionHandler;
       
   156 
       
   157     ScriptEngineEvent(qint64 scriptId,
       
   158                       const QString &script, const QString &fileName,
       
   159                       int lineNumber)
       
   160         : type(ScriptLoad), scriptId(scriptId),
       
   161           script(script), fileName(fileName),
       
   162           lineNumber(lineNumber)
       
   163         { }
       
   164 
       
   165     ScriptEngineEvent(Type type, qint64 scriptId = -777)
       
   166         : type(type), scriptId(scriptId)
       
   167         { }
       
   168 
       
   169     ScriptEngineEvent(Type type, qint64 scriptId,
       
   170                       const QScriptValue &value)
       
   171         : type(type), scriptId(scriptId),
       
   172           value(value)
       
   173         { }
       
   174 
       
   175     ScriptEngineEvent(qint64 scriptId,
       
   176                       int lineNumber, int columnNumber)
       
   177         : type(PositionChange), scriptId(scriptId),
       
   178           lineNumber(lineNumber), columnNumber(columnNumber)
       
   179         { }
       
   180 
       
   181     ScriptEngineEvent(qint64 scriptId,
       
   182                       const QScriptValue &exception, bool hasHandler)
       
   183         : type(ExceptionThrow), scriptId(scriptId),
       
   184           value(exception), hasExceptionHandler(hasHandler)
       
   185         { }
       
   186 
       
   187     static QString typeToQString(Type t)
       
   188     {
       
   189         switch (t) {
       
   190             case ScriptEngineEvent::ScriptLoad: return "ScriptLoad";
       
   191             case ScriptEngineEvent::ScriptUnload: return "ScriptUnload";
       
   192             case ScriptEngineEvent::ContextPush: return "ContextPush";
       
   193             case ScriptEngineEvent::ContextPop: return "ContextPop";
       
   194             case ScriptEngineEvent::FunctionEntry: return "FunctionEntry";
       
   195             case ScriptEngineEvent::FunctionExit: return "FunctionExit";
       
   196             case ScriptEngineEvent::PositionChange: return "PositionChange";
       
   197             case ScriptEngineEvent::ExceptionThrow: return "ExceptionThrow";
       
   198             case ScriptEngineEvent::ExceptionCatch: return "ExceptionCatch";
       
   199             case ScriptEngineEvent::DebuggerInvocationRequest: return "DebuggerInvocationRequest";
       
   200             }
       
   201     }
       
   202 };
       
   203 
       
   204 class ScriptEngineSpy : public QScriptEngineAgent, public QList<ScriptEngineEvent>
       
   205 {
       
   206 public:
       
   207     enum IgnoreFlag {
       
   208         IgnoreScriptLoad = 0x001,
       
   209         IgnoreScriptUnload = 0x002,
       
   210         IgnoreFunctionEntry = 0x004,
       
   211         IgnoreFunctionExit = 0x008,
       
   212         IgnorePositionChange = 0x010,
       
   213         IgnoreExceptionThrow = 0x020,
       
   214         IgnoreExceptionCatch = 0x040,
       
   215         IgnoreContextPush = 0x0100,
       
   216         IgnoreContextPop = 0x0200,
       
   217         IgnoreDebuggerInvocationRequest = 0x0400
       
   218     };
       
   219 
       
   220     ScriptEngineSpy(QScriptEngine *engine, int ignores = 0);
       
   221     ~ScriptEngineSpy();
       
   222 
       
   223     void enableIgnoreFlags(int flags)
       
   224         { m_ignores |= flags; }
       
   225     void disableIgnoreFlags(int flags)
       
   226         { m_ignores &= ~flags; }
       
   227 
       
   228 protected:
       
   229     void scriptLoad(qint64 id, const QString &script,
       
   230                     const QString &fileName, int lineNumber);
       
   231     void scriptUnload(qint64 id);
       
   232 
       
   233     void contextPush();
       
   234     void contextPop();
       
   235 
       
   236     void functionEntry(qint64 scriptId);
       
   237     void functionExit(qint64 scriptId, const QScriptValue &returnValue);
       
   238 
       
   239     void positionChange(qint64 scriptId,
       
   240                         int lineNumber, int columnNumber);
       
   241 
       
   242     void exceptionThrow(qint64 scriptId, const QScriptValue &exception,
       
   243                         bool hasHandler);
       
   244     void exceptionCatch(qint64 scriptId, const QScriptValue &exception);
       
   245 
       
   246     bool supportsExtension(Extension ext) const;
       
   247     QVariant extension(Extension ext, const QVariant &arg);
       
   248 
       
   249 private:
       
   250     int m_ignores;
       
   251 };
       
   252 
       
   253 ScriptEngineSpy::ScriptEngineSpy(QScriptEngine *engine, int ignores)
       
   254     : QScriptEngineAgent(engine)
       
   255 {
       
   256     m_ignores = ignores;
       
   257     engine->setAgent(this);
       
   258 }
       
   259 
       
   260 ScriptEngineSpy::~ScriptEngineSpy()
       
   261 {
       
   262 }
       
   263 
       
   264 void ScriptEngineSpy::scriptLoad(qint64 id, const QString &script,
       
   265                                  const QString &fileName, int lineNumber)
       
   266 {
       
   267     if (!(m_ignores & IgnoreScriptLoad))
       
   268         append(ScriptEngineEvent(id, script, fileName, lineNumber));
       
   269 }
       
   270 
       
   271 void ScriptEngineSpy::scriptUnload(qint64 id)
       
   272 {
       
   273     if (!(m_ignores & IgnoreScriptUnload))
       
   274         append(ScriptEngineEvent(ScriptEngineEvent::ScriptUnload, id));
       
   275 }
       
   276 
       
   277 void ScriptEngineSpy::contextPush()
       
   278 {
       
   279     if (!(m_ignores & IgnoreContextPush))
       
   280         append(ScriptEngineEvent(ScriptEngineEvent::ContextPush));
       
   281 }
       
   282 
       
   283 void ScriptEngineSpy::contextPop()
       
   284 {
       
   285     if (!(m_ignores & IgnoreContextPop))
       
   286         append(ScriptEngineEvent(ScriptEngineEvent::ContextPop));
       
   287 }
       
   288 
       
   289 void ScriptEngineSpy::functionEntry(qint64 scriptId)
       
   290 {
       
   291     if (!(m_ignores & IgnoreFunctionEntry))
       
   292         append(ScriptEngineEvent(ScriptEngineEvent::FunctionEntry, scriptId));
       
   293 }
       
   294 
       
   295 void ScriptEngineSpy::functionExit(qint64 scriptId,
       
   296                                    const QScriptValue &returnValue)
       
   297 {
       
   298     if (!(m_ignores & IgnoreFunctionExit))
       
   299         append(ScriptEngineEvent(ScriptEngineEvent::FunctionExit, scriptId, returnValue));
       
   300 }
       
   301 
       
   302 void ScriptEngineSpy::positionChange(qint64 scriptId,
       
   303                                      int lineNumber, int columnNumber)
       
   304 {
       
   305     if (!(m_ignores & IgnorePositionChange))
       
   306         append(ScriptEngineEvent(scriptId, lineNumber, columnNumber));
       
   307 }
       
   308 
       
   309 void ScriptEngineSpy::exceptionThrow(qint64 scriptId,
       
   310                                      const QScriptValue &exception, bool hasHandler)
       
   311 {
       
   312     if (!(m_ignores & IgnoreExceptionThrow))
       
   313         append(ScriptEngineEvent(scriptId, exception, hasHandler));
       
   314 }
       
   315 
       
   316 void ScriptEngineSpy::exceptionCatch(qint64 scriptId,
       
   317                                      const QScriptValue &exception)
       
   318 {
       
   319     if (!(m_ignores & IgnoreExceptionCatch))
       
   320         append(ScriptEngineEvent(ScriptEngineEvent::ExceptionCatch, scriptId, exception));
       
   321 }
       
   322 
       
   323 bool ScriptEngineSpy::supportsExtension(Extension ext) const
       
   324 {
       
   325     if (ext == DebuggerInvocationRequest)
       
   326         return !(m_ignores & IgnoreDebuggerInvocationRequest);
       
   327     return false;
       
   328 }
       
   329 
       
   330 QVariant ScriptEngineSpy::extension(Extension ext, const QVariant &arg)
       
   331 {
       
   332     if (ext == DebuggerInvocationRequest) {
       
   333         QVariantList lst = arg.toList();
       
   334         qint64 scriptId = lst.at(0).toLongLong();
       
   335         int lineNumber = lst.at(1).toInt();
       
   336         int columnNumber = lst.at(2).toInt();
       
   337         ScriptEngineEvent evt(scriptId, lineNumber, columnNumber);
       
   338         evt.type = ScriptEngineEvent::DebuggerInvocationRequest;
       
   339         append(evt);
       
   340         return QString::fromLatin1("extension(DebuggerInvocationRequest)");
       
   341     }
       
   342     return QVariant();
       
   343 }
       
   344 
       
   345 void tst_QScriptEngineAgent::scriptLoadAndUnload_statement()
       
   346 {
       
   347     QScriptEngine eng;
       
   348     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreScriptLoad
       
   349                                                        | ScriptEngineSpy::IgnoreScriptUnload));
       
   350     QCOMPARE(eng.agent(), (QScriptEngineAgent*)spy);
       
   351     {
       
   352         spy->clear();
       
   353         QString code = ";";
       
   354         QString fileName = "foo.qs";
       
   355         int lineNumber = 123;
       
   356         eng.evaluate(code, fileName, lineNumber);
       
   357 
       
   358         QCOMPARE(spy->count(), 2);
       
   359 
       
   360         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
   361         QVERIFY(spy->at(0).scriptId != -1);
       
   362         QCOMPARE(spy->at(0).script, code);
       
   363         QCOMPARE(spy->at(0).fileName, fileName);
       
   364         QCOMPARE(spy->at(0).lineNumber, lineNumber);
       
   365 
       
   366         QCOMPARE(spy->at(1).type, ScriptEngineEvent::ScriptUnload);
       
   367         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
   368     }
       
   369 
       
   370     {
       
   371         spy->clear();
       
   372         QString code = ";";
       
   373         QString fileName = "bar.qs";
       
   374         int lineNumber = 456;
       
   375         eng.evaluate(code, fileName, lineNumber);
       
   376 
       
   377         QCOMPARE(spy->count(), 2);
       
   378 
       
   379         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
   380         QVERIFY(spy->at(0).scriptId != -1);
       
   381         QCOMPARE(spy->at(0).script, code);
       
   382         QCOMPARE(spy->at(0).fileName, fileName);
       
   383         QCOMPARE(spy->at(0).lineNumber, lineNumber);
       
   384 
       
   385         QCOMPARE(spy->at(1).type, ScriptEngineEvent::ScriptUnload);
       
   386         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
   387     }
       
   388     delete spy;
       
   389 }
       
   390 
       
   391 void tst_QScriptEngineAgent::scriptLoadAndUnload()
       
   392 {
       
   393     QScriptEngine eng;
       
   394     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreScriptLoad
       
   395                                                        | ScriptEngineSpy::IgnoreScriptUnload));
       
   396     QCOMPARE(eng.agent(), (QScriptEngineAgent*)spy);
       
   397     {
       
   398         spy->clear();
       
   399         QString code = "function foo() { print('ciao'); }";
       
   400         QString fileName = "baz.qs";
       
   401         int lineNumber = 789;
       
   402         eng.evaluate(code, fileName, lineNumber);
       
   403 
       
   404         QCOMPARE(spy->count(), 1);
       
   405 
       
   406         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
   407         QVERIFY(spy->at(0).scriptId != -1);
       
   408         QCOMPARE(spy->at(0).script, code);
       
   409         QCOMPARE(spy->at(0).fileName, fileName);
       
   410         QCOMPARE(spy->at(0).lineNumber, lineNumber);
       
   411 
       
   412         code = "foo = null";
       
   413         eng.evaluate(code);
       
   414         QCOMPARE(spy->count(), 3);
       
   415 
       
   416         QCOMPARE(spy->at(1).type, ScriptEngineEvent::ScriptLoad);
       
   417         QVERIFY(spy->at(1).scriptId != -1);
       
   418         QVERIFY(spy->at(1).scriptId != spy->at(0).scriptId);
       
   419         QCOMPARE(spy->at(1).script, code);
       
   420         QCOMPARE(spy->at(1).lineNumber, 1);
       
   421 
       
   422         QCOMPARE(spy->at(2).type, ScriptEngineEvent::ScriptUnload);
       
   423         QCOMPARE(spy->at(2).scriptId, spy->at(1).scriptId);
       
   424 
       
   425         eng.collectGarbage(); // foo() is GC'ed
       
   426         QCOMPARE(spy->count(), 4);
       
   427         QCOMPARE(spy->at(3).type, ScriptEngineEvent::ScriptUnload);
       
   428         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
   429     }
       
   430 
       
   431     {
       
   432         spy->clear();
       
   433         QString code = "function foo() { return function() { print('ciao'); } }";
       
   434         QString fileName = "foo.qs";
       
   435         int lineNumber = 123;
       
   436         eng.evaluate(code, fileName, lineNumber);
       
   437 
       
   438         QCOMPARE(spy->count(), 1);
       
   439 
       
   440         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
   441         QVERIFY(spy->at(0).scriptId != -1);
       
   442         QCOMPARE(spy->at(0).script, code);
       
   443         QCOMPARE(spy->at(0).fileName, fileName);
       
   444         QCOMPARE(spy->at(0).lineNumber, lineNumber);
       
   445 
       
   446         code = "bar = foo(); foo = null";
       
   447         eng.evaluate(code);
       
   448         QCOMPARE(spy->count(), 3);
       
   449 
       
   450         QCOMPARE(spy->at(1).type, ScriptEngineEvent::ScriptLoad);
       
   451         QVERIFY(spy->at(1).scriptId != -1);
       
   452         QVERIFY(spy->at(1).scriptId != spy->at(0).scriptId);
       
   453         QCOMPARE(spy->at(1).script, code);
       
   454 
       
   455         QCOMPARE(spy->at(2).type, ScriptEngineEvent::ScriptUnload);
       
   456         QCOMPARE(spy->at(2).scriptId, spy->at(1).scriptId);
       
   457 
       
   458         eng.collectGarbage(); // foo() is not GC'ed
       
   459         QCOMPARE(spy->count(), 3);
       
   460 
       
   461         code = "bar = null";
       
   462         eng.evaluate(code);
       
   463         QCOMPARE(spy->count(), 5);
       
   464 
       
   465         eng.collectGarbage(); // foo() is GC'ed
       
   466         QCOMPARE(spy->count(), 6);
       
   467     }
       
   468     delete spy;
       
   469 }
       
   470 
       
   471 void tst_QScriptEngineAgent::scriptLoadAndUnload_eval()
       
   472 {
       
   473     QScriptEngine eng;
       
   474     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreScriptLoad
       
   475                                                        | ScriptEngineSpy::IgnoreScriptUnload));
       
   476     {
       
   477         spy->clear();
       
   478         eng.evaluate("eval('function foo() { print(123); }')");
       
   479 
       
   480         QEXPECT_FAIL("","QTBUG-6140 Eval is threaded in different way that in old backend", Abort);
       
   481         QCOMPARE(spy->count(), 3);
       
   482 
       
   483         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
   484         QVERIFY(spy->at(0).scriptId != -1);
       
   485 
       
   486         QCOMPARE(spy->at(1).type, ScriptEngineEvent::ScriptLoad);
       
   487         QVERIFY(spy->at(1).scriptId != -1);
       
   488         QVERIFY(spy->at(1).scriptId != spy->at(0).scriptId);
       
   489 
       
   490         QCOMPARE(spy->at(2).type, ScriptEngineEvent::ScriptUnload);
       
   491         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
   492     }
       
   493     delete spy;
       
   494 }
       
   495 
       
   496 void tst_QScriptEngineAgent::contextPushAndPop()
       
   497 {
       
   498     QScriptEngine eng;
       
   499     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreContextPush
       
   500                                                        | ScriptEngineSpy::IgnoreContextPop));
       
   501 
       
   502     {
       
   503         spy->clear();
       
   504         eng.pushContext();
       
   505         eng.popContext();
       
   506         QCOMPARE(spy->count(), 2);
       
   507 
       
   508         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ContextPush);
       
   509         QCOMPARE(spy->at(1).type, ScriptEngineEvent::ContextPop);
       
   510     }
       
   511 }
       
   512 
       
   513 static QScriptValue nativeFunctionReturningArg(QScriptContext *ctx, QScriptEngine *)
       
   514 {
       
   515     return ctx->argument(0);
       
   516 }
       
   517 
       
   518 static QScriptValue nativeFunctionThrowingError(QScriptContext *ctx, QScriptEngine *)
       
   519 {
       
   520     return ctx->throwError(ctx->argument(0).toString());
       
   521 }
       
   522 
       
   523 static QScriptValue nativeFunctionCallingArg(QScriptContext *ctx, QScriptEngine *)
       
   524 {
       
   525     return ctx->argument(0).call();
       
   526 }
       
   527 
       
   528 /** check behaiviour of ';' */
       
   529 void tst_QScriptEngineAgent::functionEntryAndExit_semicolon()
       
   530 {
       
   531     QScriptEngine eng;
       
   532     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   533                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   534     {
       
   535         spy->clear();
       
   536         eng.evaluate(";");
       
   537 
       
   538         QCOMPARE(spy->count(), 2);
       
   539 
       
   540         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   541         QVERIFY(spy->at(0).scriptId != -1);
       
   542 
       
   543         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionExit);
       
   544         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
   545         QVERIFY(spy->at(1).value.isUndefined());
       
   546     }
       
   547     delete spy;
       
   548 }
       
   549 
       
   550 /** check behaiviour of expression */
       
   551 void tst_QScriptEngineAgent::functionEntryAndExit_expression()
       
   552 {
       
   553     QScriptEngine eng;
       
   554     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   555                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   556     {
       
   557         spy->clear();
       
   558         eng.evaluate("1 + 2");
       
   559 
       
   560         QCOMPARE(spy->count(), 2);
       
   561 
       
   562         // evaluate() entry
       
   563         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   564         QVERIFY(spy->at(0).scriptId != -1);
       
   565 
       
   566         // evaluate() exit
       
   567         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionExit);
       
   568         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
   569         QVERIFY(spy->at(1).value.isNumber());
       
   570         QCOMPARE(spy->at(1).value.toNumber(), qsreal(3));
       
   571     }
       
   572     delete spy;
       
   573 }
       
   574 
       
   575 /** check behaiviour of standard function call */
       
   576 void tst_QScriptEngineAgent::functionEntryAndExit_functionCall()
       
   577 {
       
   578     QScriptEngine eng;
       
   579     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   580                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   581     {
       
   582         spy->clear();
       
   583         QVERIFY(eng.evaluate("(function() { return 123; } )()").toNumber()==123);
       
   584 
       
   585         QCOMPARE(spy->count(), 4);
       
   586 
       
   587         // evaluate() entry
       
   588         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   589         QVERIFY(spy->at(0).scriptId != -1);
       
   590 
       
   591         // anonymous function entry
       
   592         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
   593         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
   594 
       
   595         // anonymous function exit
       
   596         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit);
       
   597         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
   598         QVERIFY(spy->at(2).value.isNumber());
       
   599         QCOMPARE(spy->at(2).value.toNumber(), qsreal(123));
       
   600 
       
   601         // evaluate() exit
       
   602         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
   603         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
   604         QVERIFY(spy->at(3).value.isNumber());
       
   605         QCOMPARE(spy->at(3).value.toNumber(), qsreal(123));
       
   606     }
       
   607     delete spy;
       
   608 }
       
   609 
       
   610 /** check behaiviour of standard function call */
       
   611 void tst_QScriptEngineAgent::functionEntryAndExit_functionCallWithoutReturn()
       
   612 {
       
   613     QScriptEngine eng;
       
   614     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   615                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   616     {
       
   617         spy->clear();
       
   618         eng.evaluate("(function() { var a = 123; } )()");
       
   619 
       
   620         QCOMPARE(spy->count(), 4);
       
   621 
       
   622         // evaluate() entry
       
   623         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   624         QVERIFY(spy->at(0).scriptId != -1);
       
   625 
       
   626         // anonymous function entry
       
   627         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
   628         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
   629 
       
   630         // anonymous function exit
       
   631         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit);
       
   632         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
   633 
       
   634         // evaluate() exit
       
   635         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
   636         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
   637     }
       
   638     delete spy;
       
   639 }
       
   640 
       
   641 /** check behaiviour of function definition */
       
   642 void tst_QScriptEngineAgent::functionEntryAndExit_functionDefinition()
       
   643 {
       
   644     QScriptEngine eng;
       
   645     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   646                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   647     {
       
   648         spy->clear();
       
   649         eng.evaluate("function foo() { return 456; }");
       
   650         QCOMPARE(spy->count(), 2);
       
   651 
       
   652         // evaluate() entry
       
   653         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   654         QVERIFY(spy->at(0).scriptId != -1);
       
   655 
       
   656         // evaluate() exit
       
   657         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionExit);
       
   658         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
   659         QVERIFY(spy->at(1).value.isUndefined());
       
   660 
       
   661         eng.evaluate("foo()");
       
   662         QCOMPARE(spy->count(), 6);
       
   663 
       
   664         // evaluate() entry
       
   665         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionEntry);
       
   666         QVERIFY(spy->at(2).scriptId != spy->at(0).scriptId);
       
   667 
       
   668         // foo() entry
       
   669         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionEntry);
       
   670         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
   671 
       
   672         // foo() exit
       
   673         QCOMPARE(spy->at(4).type, ScriptEngineEvent::FunctionExit);
       
   674         QCOMPARE(spy->at(4).scriptId, spy->at(0).scriptId);
       
   675         QVERIFY(spy->at(4).value.isNumber());
       
   676         QCOMPARE(spy->at(4).value.toNumber(), qsreal(456));
       
   677 
       
   678         // evaluate() exit
       
   679         QCOMPARE(spy->at(5).type, ScriptEngineEvent::FunctionExit);
       
   680         QCOMPARE(spy->at(5).scriptId, spy->at(2).scriptId);
       
   681         QVERIFY(spy->at(5).value.isNumber());
       
   682         QCOMPARE(spy->at(5).value.toNumber(), qsreal(456));
       
   683     }
       
   684     delete spy;
       
   685 }
       
   686 
       
   687 /** check behaiviour of native function */
       
   688 void tst_QScriptEngineAgent::functionEntryAndExit_native()
       
   689 {
       
   690     QScriptEngine eng;
       
   691     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   692                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   693     // native functions
       
   694     {
       
   695         QScriptValue fun = eng.newFunction(nativeFunctionReturningArg);
       
   696         eng.globalObject().setProperty("nativeFunctionReturningArg", fun);
       
   697 
       
   698         spy->clear();
       
   699         eng.evaluate("nativeFunctionReturningArg(123)");
       
   700 
       
   701         QCOMPARE(spy->count(), 4);
       
   702 
       
   703         // evaluate() entry
       
   704         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   705 
       
   706         // native function entry
       
   707         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
   708         QCOMPARE(spy->at(1).scriptId, qint64(-1));
       
   709 
       
   710         // native function exit
       
   711         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit);
       
   712         QCOMPARE(spy->at(2).scriptId, qint64(-1));
       
   713         QVERIFY(spy->at(2).value.isNumber());
       
   714         QCOMPARE(spy->at(2).value.toNumber(), qsreal(123));
       
   715 
       
   716         // evaluate() exit
       
   717         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
   718         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
   719         QVERIFY(spy->at(3).value.isNumber());
       
   720         QCOMPARE(spy->at(3).value.toNumber(), qsreal(123));
       
   721     }
       
   722     delete spy;
       
   723 }
       
   724 
       
   725 /** check behaiviour of native function */
       
   726 void tst_QScriptEngineAgent::functionEntryAndExit_native2()
       
   727 {
       
   728     QScriptEngine eng;
       
   729     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   730                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   731     {
       
   732         QScriptValue fun = eng.newFunction(nativeFunctionCallingArg);
       
   733         eng.globalObject().setProperty("nativeFunctionCallingArg", fun);
       
   734 
       
   735         spy->clear();
       
   736         eng.evaluate("nativeFunctionCallingArg(function() { return 123; })");
       
   737         QCOMPARE(spy->count(), 6);
       
   738 
       
   739         // evaluate() entry
       
   740         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   741 
       
   742         // native function entry
       
   743         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
   744         QCOMPARE(spy->at(1).scriptId, qint64(-1));
       
   745 
       
   746         // script function entry
       
   747         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionEntry);
       
   748         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
   749 
       
   750         // script function exit
       
   751         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
   752         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
   753 
       
   754         // native function exit
       
   755         QCOMPARE(spy->at(4).type, ScriptEngineEvent::FunctionExit);
       
   756         QCOMPARE(spy->at(4).scriptId, qint64(-1));
       
   757         QVERIFY(spy->at(4).value.isNumber());
       
   758         QCOMPARE(spy->at(4).value.toNumber(), qsreal(123));
       
   759 
       
   760         // evaluate() exit
       
   761         QCOMPARE(spy->at(5).type, ScriptEngineEvent::FunctionExit);
       
   762         QCOMPARE(spy->at(5).scriptId, spy->at(0).scriptId);
       
   763         QVERIFY(spy->at(5).value.isNumber());
       
   764         QCOMPARE(spy->at(5).value.toNumber(), qsreal(123));
       
   765     }
       
   766     delete spy;
       
   767 }
       
   768 
       
   769 /** check behaiviour of native function throwing error*/
       
   770 void tst_QScriptEngineAgent::functionEntryAndExit_nativeThrowing()
       
   771 {
       
   772     /* This function was changed from old backend. JSC return more Entrys / Exits, (exactly +1)
       
   773        in exception creation time */
       
   774 
       
   775     QScriptEngine eng;
       
   776     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   777                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   778     {
       
   779         QScriptValue fun = eng.newFunction(nativeFunctionThrowingError);
       
   780         eng.globalObject().setProperty("nativeFunctionThrowingError", fun);
       
   781 
       
   782         spy->clear();
       
   783         eng.evaluate("nativeFunctionThrowingError('ciao')");
       
   784         QCOMPARE(spy->count(), 6);
       
   785 
       
   786         // evaluate() entry
       
   787         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   788 
       
   789         // native function entry
       
   790         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
   791         QCOMPARE(spy->at(1).scriptId, qint64(-1));
       
   792 
       
   793         // Exception constructor entry
       
   794         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionEntry);
       
   795         QCOMPARE(spy->at(2).scriptId, qint64(-1));
       
   796 
       
   797         // Exception constructor exit
       
   798         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
   799         QCOMPARE(spy->at(3).scriptId, qint64(-1));
       
   800         QVERIFY(spy->at(3).value.isError());
       
   801 
       
   802         // native function exit
       
   803         QCOMPARE(spy->at(4).type, ScriptEngineEvent::FunctionExit);
       
   804         QCOMPARE(spy->at(4).scriptId, qint64(-1));
       
   805         QVERIFY(spy->at(4).value.isError());
       
   806 
       
   807         // evaluate() exit
       
   808         QCOMPARE(spy->at(5).type, ScriptEngineEvent::FunctionExit);
       
   809         QCOMPARE(spy->at(5).scriptId, spy->at(0).scriptId);
       
   810         QVERIFY(spy->at(5).value.isError());
       
   811     }
       
   812     delete spy;
       
   813 }
       
   814 
       
   815 void tst_QScriptEngineAgent::functionEntryAndExit_builtin_data()
       
   816 {
       
   817   QTest::addColumn<QString>("script");
       
   818   QTest::addColumn<QString>("result");
       
   819 
       
   820   QTest::newRow("string native") << "'ciao'.toString()" << "ciao";
       
   821   QTest::newRow("string object") << "String('ciao').toString()" << "ciao";
       
   822   QTest::newRow("number native") << "(123).toString()" << "123";
       
   823   QTest::newRow("number object") << "Number(123).toString()" << "123";
       
   824   QTest::newRow("array native") << "['s','a'].toString()" << "s, a";
       
   825   QTest::newRow("array object") << "Array('s', 'a').toString()" << "s,a";
       
   826   QTest::newRow("boolean native") << "false.toString()" << "false";
       
   827   QTest::newRow("boolean object") << "Boolean(true).toString()" << "true";
       
   828   QTest::newRow("regexp native") << "/a/.toString()" << "/a/";
       
   829   QTest::newRow("regexp object") << "RegExp('a').toString()" << "/a/";
       
   830 }
       
   831 
       
   832 /** check behaiviour of built-in function */
       
   833 void tst_QScriptEngineAgent::functionEntryAndExit_builtin()
       
   834 {
       
   835     QSKIP("The test fails on platforms others than Linux. The issue will be fixed with next JSC update", SkipAll);
       
   836     QFETCH(QString, script);
       
   837     QFETCH(QString, result);
       
   838     QScriptEngine eng;
       
   839     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   840                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   841     {
       
   842         spy->clear();
       
   843         eng.evaluate(script);
       
   844 
       
   845         if (qt_script_isJITEnabled()) {
       
   846             QEXPECT_FAIL("string native", "QTBUG-6187 Some events are missing when JIT is enabled", Abort);
       
   847             QEXPECT_FAIL("number native", "QTBUG-6187 Some events are missing when JIT is enabled", Abort);
       
   848             QEXPECT_FAIL("array native", "QTBUG-6187 Some events are missing when JIT is enabled", Abort);
       
   849             QEXPECT_FAIL("boolean native", "QTBUG-6187 Some events are missing when JIT is enabled", Abort);
       
   850             QEXPECT_FAIL("regexp native", "QTBUG-6187 Some events are missing when JIT is enabled", Abort);
       
   851         }
       
   852         QCOMPARE(spy->count(), 4);
       
   853 
       
   854         // evaluate() entry
       
   855         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   856 
       
   857         // built-in native function entry
       
   858         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
   859         QCOMPARE(spy->at(1).scriptId, qint64(-1));
       
   860 
       
   861         // built-in native function exit
       
   862         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit);
       
   863         QCOMPARE(spy->at(2).scriptId, qint64(-1));
       
   864         QCOMPARE(spy->at(2).value.toString(), QString(result));
       
   865 
       
   866         // evaluate() exit
       
   867         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
   868         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
   869         QVERIFY(spy->at(3).value.isString());
       
   870         QCOMPARE(spy->at(3).value.toString(), QString(result));
       
   871     }
       
   872     delete spy;
       
   873 }
       
   874 
       
   875 /** check behaiviour of object creation*/
       
   876 void tst_QScriptEngineAgent::functionEntryAndExit_objects()
       
   877 {
       
   878     QScriptEngine eng;
       
   879     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   880                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   881     {
       
   882         spy->clear();
       
   883         eng.evaluate("Array(); Boolean(); Date(); Function(); Number(); Object(); RegExp(); String()");
       
   884         QCOMPARE(spy->count(), 18);
       
   885 
       
   886         // evaluate() entry
       
   887         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   888 
       
   889         // Array constructor entry
       
   890         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
   891         QCOMPARE(spy->at(1).scriptId, qint64(-1));
       
   892 
       
   893         // Array constructor exit
       
   894         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit);
       
   895         QCOMPARE(spy->at(2).scriptId, qint64(-1));
       
   896         QVERIFY(spy->at(2).value.isArray());
       
   897 
       
   898         // Boolean constructor entry
       
   899         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionEntry);
       
   900         QCOMPARE(spy->at(3).scriptId, qint64(-1));
       
   901 
       
   902         // Boolean constructor exit
       
   903         QCOMPARE(spy->at(4).type, ScriptEngineEvent::FunctionExit);
       
   904         QCOMPARE(spy->at(4).scriptId, qint64(-1));
       
   905         QVERIFY(spy->at(4).value.isBoolean());
       
   906 
       
   907         // Date constructor entry
       
   908         QCOMPARE(spy->at(5).type, ScriptEngineEvent::FunctionEntry);
       
   909         QCOMPARE(spy->at(5).scriptId, qint64(-1));
       
   910 
       
   911         // Date constructor exit
       
   912         QCOMPARE(spy->at(6).type, ScriptEngineEvent::FunctionExit);
       
   913         QCOMPARE(spy->at(6).scriptId, qint64(-1));
       
   914         QVERIFY(spy->at(6).value.isString());
       
   915 
       
   916         // Function constructor entry
       
   917         QCOMPARE(spy->at(7).type, ScriptEngineEvent::FunctionEntry);
       
   918         QCOMPARE(spy->at(7).scriptId, qint64(-1));
       
   919 
       
   920         // Function constructor exit
       
   921         QCOMPARE(spy->at(8).type, ScriptEngineEvent::FunctionExit);
       
   922         QCOMPARE(spy->at(8).scriptId, qint64(-1));
       
   923         QVERIFY(spy->at(8).value.isFunction());
       
   924 
       
   925         // Number constructor entry
       
   926         QCOMPARE(spy->at(9).type, ScriptEngineEvent::FunctionEntry);
       
   927         QCOMPARE(spy->at(9).scriptId, qint64(-1));
       
   928 
       
   929         // Number constructor exit
       
   930         QCOMPARE(spy->at(10).type, ScriptEngineEvent::FunctionExit);
       
   931         QCOMPARE(spy->at(10).scriptId, qint64(-1));
       
   932         QVERIFY(spy->at(10).value.isNumber());
       
   933 
       
   934         // Object constructor entry
       
   935         QCOMPARE(spy->at(11).type, ScriptEngineEvent::FunctionEntry);
       
   936         QCOMPARE(spy->at(11).scriptId, qint64(-1));
       
   937 
       
   938         // Object constructor exit
       
   939         QCOMPARE(spy->at(12).type, ScriptEngineEvent::FunctionExit);
       
   940         QCOMPARE(spy->at(12).scriptId, qint64(-1));
       
   941         QVERIFY(spy->at(12).value.isObject());
       
   942 
       
   943         // RegExp constructor entry
       
   944         QCOMPARE(spy->at(13).type, ScriptEngineEvent::FunctionEntry);
       
   945         QCOMPARE(spy->at(13).scriptId, qint64(-1));
       
   946 
       
   947         // RegExp constructor exit
       
   948         QCOMPARE(spy->at(14).type, ScriptEngineEvent::FunctionExit);
       
   949         QCOMPARE(spy->at(14).scriptId, qint64(-1));
       
   950         QVERIFY(spy->at(14).value.isRegExp());
       
   951 
       
   952         // String constructor entry
       
   953         QCOMPARE(spy->at(15).type, ScriptEngineEvent::FunctionEntry);
       
   954         QCOMPARE(spy->at(15).scriptId, qint64(-1));
       
   955 
       
   956         // String constructor exit
       
   957         QCOMPARE(spy->at(16).type, ScriptEngineEvent::FunctionExit);
       
   958         QCOMPARE(spy->at(16).scriptId, qint64(-1));
       
   959         QVERIFY(spy->at(16).value.isString());
       
   960 
       
   961         // evaluate() exit
       
   962         QCOMPARE(spy->at(17).type, ScriptEngineEvent::FunctionExit);
       
   963         QCOMPARE(spy->at(17).scriptId, spy->at(0).scriptId);
       
   964         QVERIFY(spy->at(17).value.isString());
       
   965         QCOMPARE(spy->at(17).value.toString(), QString());
       
   966     }
       
   967     delete spy;
       
   968 }
       
   969 
       
   970 /** check behaiviour of slots*/
       
   971 void tst_QScriptEngineAgent::functionEntryAndExit_slots()
       
   972 {
       
   973     QScriptEngine eng;
       
   974     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
   975                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
   976     // slots
       
   977     {
       
   978         eng.globalObject().setProperty("qobj", eng.newQObject(this));
       
   979         spy->clear();
       
   980         eng.evaluate("qobj.testSlot(123)");
       
   981         QCOMPARE(spy->count(), 4);
       
   982         // evaluate() entry
       
   983         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
   984         // testSlot() entry
       
   985         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
   986         QCOMPARE(spy->at(1).scriptId, qint64(-1));
       
   987         // testSlot() exit
       
   988         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit);
       
   989         QCOMPARE(spy->at(2).scriptId, qint64(-1));
       
   990         QVERIFY(spy->at(2).value.isNumber());
       
   991         QCOMPARE(spy->at(2).value.toNumber(), qsreal(123));
       
   992         // evaluate() exit
       
   993         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
   994     }
       
   995     delete spy;
       
   996 }
       
   997 
       
   998 /** check behaiviour of property accessors*/
       
   999 void tst_QScriptEngineAgent::functionEntryAndExit_property_set()
       
  1000 {
       
  1001     QScriptEngine eng;
       
  1002     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
  1003                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
  1004     // property accessors
       
  1005     {
       
  1006         eng.globalObject().setProperty("qobj", eng.newQObject(this));
       
  1007         // set
       
  1008         spy->clear();
       
  1009         eng.evaluate("qobj.testProperty = 456");
       
  1010         QCOMPARE(spy->count(), 4);
       
  1011         // evaluate() entry
       
  1012         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
  1013         // setTestProperty() entry
       
  1014         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
  1015         QCOMPARE(spy->at(1).scriptId, qint64(-1));
       
  1016         // setTestProperty() exit
       
  1017         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit);
       
  1018         QCOMPARE(spy->at(2).scriptId, qint64(-1));
       
  1019         QVERIFY(spy->at(2).value.isNumber());
       
  1020         QCOMPARE(spy->at(2).value.toNumber(), testProperty());
       
  1021         // evaluate() exit
       
  1022         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
  1023         QVERIFY(spy->at(3).value.strictlyEquals(spy->at(2).value));
       
  1024     }
       
  1025     delete spy;
       
  1026 }
       
  1027 
       
  1028 /** check behaiviour of property accessors*/
       
  1029 void tst_QScriptEngineAgent::functionEntryAndExit_property_get()
       
  1030 {
       
  1031     QScriptEngine eng;
       
  1032     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
  1033                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
  1034     // property accessors
       
  1035     {
       
  1036         eng.globalObject().setProperty("qobj", eng.newQObject(this));
       
  1037         // set
       
  1038         eng.evaluate("qobj.testProperty = 456");
       
  1039         // get
       
  1040         spy->clear();
       
  1041         eng.evaluate("qobj.testProperty");
       
  1042         QCOMPARE(spy->count(), 4);
       
  1043         // evaluate() entry
       
  1044         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
  1045         // testProperty() entry
       
  1046         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
  1047         QCOMPARE(spy->at(1).scriptId, qint64(-1));
       
  1048         // testProperty() exit
       
  1049         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit);
       
  1050         QCOMPARE(spy->at(2).scriptId, qint64(-1));
       
  1051         QVERIFY(spy->at(2).value.isNumber());
       
  1052         QCOMPARE(spy->at(2).value.toNumber(), testProperty());
       
  1053         // evaluate() exit
       
  1054         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
  1055         QVERIFY(spy->at(3).value.strictlyEquals(spy->at(2).value));
       
  1056     }
       
  1057     delete spy;
       
  1058 }
       
  1059 
       
  1060 
       
  1061 /** check behaiviour of calling script functions from c++*/
       
  1062 void tst_QScriptEngineAgent::functionEntryAndExit_call()
       
  1063 {
       
  1064     QScriptEngine eng;
       
  1065     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
  1066                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
  1067     // calling script functions from C++
       
  1068 
       
  1069     {
       
  1070         QScriptValue fun = eng.evaluate("function foo() { return 123; }; foo");
       
  1071         QVERIFY(fun.isFunction());
       
  1072 
       
  1073         spy->clear();
       
  1074         fun.call();
       
  1075         QCOMPARE(spy->count(), 2);
       
  1076 
       
  1077         // entry
       
  1078         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
  1079         QVERIFY(spy->at(0).scriptId != -1);
       
  1080 
       
  1081         // exit
       
  1082         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionExit);
       
  1083         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1084         QVERIFY(spy->at(1).value.isNumber());
       
  1085         QCOMPARE(spy->at(1).value.toNumber(), qsreal(123));
       
  1086     }
       
  1087     delete spy;
       
  1088 }
       
  1089 
       
  1090 /** check behaiviour of native function returnning arg*/
       
  1091 void tst_QScriptEngineAgent::functionEntryAndExit_functionReturn_call()
       
  1092 {
       
  1093     QScriptEngine eng;
       
  1094     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
  1095                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
  1096     {
       
  1097         QScriptValue fun = eng.newFunction(nativeFunctionReturningArg);
       
  1098 
       
  1099         spy->clear();
       
  1100         QScriptValueList args;
       
  1101         args << QScriptValue(&eng, 123);
       
  1102         fun.call(QScriptValue(), args);
       
  1103         QCOMPARE(spy->count(), 2);
       
  1104 
       
  1105         // entry
       
  1106         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
  1107         QVERIFY(spy->at(0).scriptId == -1);
       
  1108 
       
  1109         // exit
       
  1110         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionExit);
       
  1111         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1112         QVERIFY(spy->at(1).value.strictlyEquals(args.at(0)));
       
  1113     }
       
  1114     delete spy;
       
  1115 }
       
  1116 
       
  1117 void tst_QScriptEngineAgent::functionEntryAndExit_functionReturn_construct()
       
  1118 {
       
  1119     QScriptEngine eng;
       
  1120     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
  1121                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
  1122     {
       
  1123         QScriptValue fun = eng.newFunction(nativeFunctionReturningArg);
       
  1124 
       
  1125         spy->clear();
       
  1126         QScriptValueList args;
       
  1127         args << QScriptValue(&eng, 123);
       
  1128         QScriptValue obj = fun.construct(args);
       
  1129 
       
  1130         QVERIFY(args.at(0).isValid());
       
  1131         QVERIFY(args.at(0).isNumber());
       
  1132         QVERIFY(args.at(0).toNumber() == 123);
       
  1133 
       
  1134         QCOMPARE(spy->count(), 2);
       
  1135 
       
  1136         // entry
       
  1137         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
  1138         QVERIFY(spy->at(0).scriptId == -1);
       
  1139 
       
  1140         // exit
       
  1141         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionExit);
       
  1142         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1143 
       
  1144         QVERIFY(spy->at(1).value.strictlyEquals(args.at(0)));
       
  1145     }
       
  1146 
       
  1147     delete spy;
       
  1148 }
       
  1149 
       
  1150 /** check behaiviour of object creation with args (?)*/
       
  1151 void tst_QScriptEngineAgent::functionEntryAndExit_objectCall()
       
  1152 {
       
  1153     QScriptEngine eng;
       
  1154     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreFunctionEntry
       
  1155                                                        | ScriptEngineSpy::IgnoreFunctionExit));
       
  1156     for (int x = 0; x < 2; ++x) {
       
  1157         QScriptValue fun = eng.evaluate("Boolean");
       
  1158 
       
  1159         QVERIFY(!fun.isError());
       
  1160 
       
  1161         spy->clear();
       
  1162         QScriptValueList args;
       
  1163         args << QScriptValue(&eng, true);
       
  1164         if (x)
       
  1165             fun.construct(args);
       
  1166         else
       
  1167             fun.call(QScriptValue(), args);
       
  1168         QCOMPARE(spy->count(), 2);
       
  1169 
       
  1170         // entry
       
  1171         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry);
       
  1172         QVERIFY(spy->at(0).scriptId == -1);
       
  1173 
       
  1174         // exit
       
  1175         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionExit);
       
  1176         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1177         QVERIFY(spy->at(1).value.equals(args.at(0)));
       
  1178     }
       
  1179     delete spy;
       
  1180 }
       
  1181 
       
  1182 void tst_QScriptEngineAgent::positionChange_1()
       
  1183 {
       
  1184     QScriptEngine eng;
       
  1185     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnorePositionChange));
       
  1186     {
       
  1187         spy->clear();
       
  1188         eng.evaluate(";");
       
  1189         QEXPECT_FAIL("","QTBUG-6142 JSC do not evaluate ';' to statemant",Continue);
       
  1190         QCOMPARE(spy->count(), 1);
       
  1191         if (spy->count()) {
       
  1192             QEXPECT_FAIL("","QTBUG-6142 JSC do not evaluate ';' to statemant",Continue);
       
  1193             QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1194             QEXPECT_FAIL("","QTBUG-6142 JSC do not evaluate ';' to statemant",Continue);
       
  1195             QVERIFY(spy->at(0).scriptId != -1);
       
  1196             QEXPECT_FAIL("","QTBUG-6142 JSC do not evaluate ';' to statemant",Continue);
       
  1197             QCOMPARE(spy->at(0).lineNumber, 1);
       
  1198             QEXPECT_FAIL("","QTBUG-6142 JSC do not evaluate ';' to statemant",Continue);
       
  1199             QCOMPARE(spy->at(0).columnNumber, 1);
       
  1200         }
       
  1201     }
       
  1202 
       
  1203     {
       
  1204         spy->clear();
       
  1205         int lineNumber = 123;
       
  1206         eng.evaluate("1 + 2", "foo.qs", lineNumber);
       
  1207         QCOMPARE(spy->count(), 1);
       
  1208 
       
  1209         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1210         QVERIFY(spy->at(0).scriptId != -1);
       
  1211         QCOMPARE(spy->at(0).lineNumber, lineNumber);
       
  1212         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1213     }
       
  1214 
       
  1215     {
       
  1216         spy->clear();
       
  1217         int lineNumber = 123;
       
  1218         eng.evaluate("var i = 0", "foo.qs", lineNumber);
       
  1219         QCOMPARE(spy->count(), 1);
       
  1220 
       
  1221         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1222         QVERIFY(spy->at(0).scriptId != -1);
       
  1223         QCOMPARE(spy->at(0).lineNumber, lineNumber);
       
  1224         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1225     }
       
  1226 
       
  1227     QStringList lineTerminators;
       
  1228     lineTerminators << "\n" << "\r" << "\n\r" << "\r\n";
       
  1229     for (int i = 0; i < lineTerminators.size(); ++i) {
       
  1230         spy->clear();
       
  1231         int lineNumber = 456;
       
  1232         QString code = "1 + 2; 3 + 4;";
       
  1233         code.append(lineTerminators.at(i));
       
  1234         code.append("5 + 6");
       
  1235         eng.evaluate(code, "foo.qs", lineNumber);
       
  1236         QCOMPARE(spy->count(), 3);
       
  1237 
       
  1238         // 1 + 2
       
  1239         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1240         QVERIFY(spy->at(0).scriptId != -1);
       
  1241         QCOMPARE(spy->at(0).lineNumber, lineNumber);
       
  1242         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1243 
       
  1244         // 3 + 4
       
  1245         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1246         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1247         QCOMPARE(spy->at(1).lineNumber, lineNumber);
       
  1248         QCOMPARE(spy->at(1).columnNumber, 8);
       
  1249 
       
  1250         // 5 + 6
       
  1251         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1252         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
  1253         QCOMPARE(spy->at(2).lineNumber, lineNumber + 1);
       
  1254         QCOMPARE(spy->at(2).columnNumber, 1);
       
  1255     }
       
  1256     delete spy;
       
  1257 }
       
  1258 
       
  1259 void tst_QScriptEngineAgent::positionChange_2()
       
  1260 {
       
  1261     QScriptEngine eng;
       
  1262     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnorePositionChange));
       
  1263     {
       
  1264         spy->clear();
       
  1265         int lineNumber = 789;
       
  1266         eng.evaluate("function foo() { return 123; }", "foo.qs", lineNumber);
       
  1267         QCOMPARE(spy->count(), 0);
       
  1268 
       
  1269         eng.evaluate("foo()");
       
  1270         QCOMPARE(spy->count(), 2);
       
  1271 
       
  1272         // foo()
       
  1273         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1274         QVERIFY(spy->at(0).scriptId != -1);
       
  1275         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1276         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1277 
       
  1278         // return 123
       
  1279         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1280         QVERIFY(spy->at(1).scriptId != spy->at(0).scriptId);
       
  1281         QCOMPARE(spy->at(1).lineNumber, lineNumber);
       
  1282         QCOMPARE(spy->at(1).columnNumber, 18);
       
  1283     }
       
  1284 
       
  1285     {
       
  1286         spy->clear();
       
  1287         eng.evaluate("if (true) i = 1; else i = 0;");
       
  1288         QCOMPARE(spy->count(), 2);
       
  1289 
       
  1290         // if
       
  1291         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1292         QVERIFY(spy->at(0).scriptId != -1);
       
  1293         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1294         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1295 
       
  1296         // i = 1
       
  1297         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1298         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1299         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1300         QCOMPARE(spy->at(1).columnNumber, 11);
       
  1301     }
       
  1302 
       
  1303     {
       
  1304         spy->clear();
       
  1305         eng.evaluate("for (var i = 0; i < 2; ++i) { }");
       
  1306         QCOMPARE(spy->count(), 1);
       
  1307 
       
  1308         // for
       
  1309         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1310         QVERIFY(spy->at(0).scriptId != -1);
       
  1311         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1312         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1313     }
       
  1314 
       
  1315     {
       
  1316         spy->clear();
       
  1317         eng.evaluate("for (var i = 0; i < 2; ++i) { void(i); }");
       
  1318         QCOMPARE(spy->count(), 3);
       
  1319 
       
  1320         // for
       
  1321         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1322         QVERIFY(spy->at(0).scriptId != -1);
       
  1323         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1324         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1325 
       
  1326         // void(i)
       
  1327         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1328         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1329         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1330         QCOMPARE(spy->at(1).columnNumber, 31);
       
  1331 
       
  1332         // void(i)
       
  1333         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1334         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
  1335         QCOMPARE(spy->at(2).lineNumber, 1);
       
  1336         QCOMPARE(spy->at(2).columnNumber, 31);
       
  1337     }
       
  1338 
       
  1339     {
       
  1340         spy->clear();
       
  1341         eng.evaluate("var i = 0; while (i < 2) { ++i; }");
       
  1342         QCOMPARE(spy->count(), 4);
       
  1343 
       
  1344         // i = 0
       
  1345         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1346         QVERIFY(spy->at(0).scriptId != -1);
       
  1347         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1348         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1349 
       
  1350         // while
       
  1351         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1352         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1353         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1354         QCOMPARE(spy->at(1).columnNumber, 12);
       
  1355 
       
  1356         // ++i
       
  1357         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1358         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
  1359         QCOMPARE(spy->at(2).lineNumber, 1);
       
  1360         QCOMPARE(spy->at(2).columnNumber, 28);
       
  1361 
       
  1362         // ++i
       
  1363         QCOMPARE(spy->at(3).type, ScriptEngineEvent::PositionChange);
       
  1364         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
  1365         QCOMPARE(spy->at(3).lineNumber, 1);
       
  1366         QCOMPARE(spy->at(3).columnNumber, 28);
       
  1367     }
       
  1368 
       
  1369     {
       
  1370         spy->clear();
       
  1371         eng.evaluate("var i = 0; do { ++i; } while (i < 2)");
       
  1372         QCOMPARE(spy->count(), 5);
       
  1373 
       
  1374         // i = 0
       
  1375         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1376         QVERIFY(spy->at(0).scriptId != -1);
       
  1377         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1378         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1379 
       
  1380         // do
       
  1381         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1382         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1383         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1384         QCOMPARE(spy->at(1).columnNumber, 12);
       
  1385 
       
  1386         // ++i
       
  1387         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1388         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
  1389         QCOMPARE(spy->at(2).lineNumber, 1);
       
  1390         QCOMPARE(spy->at(2).columnNumber, 17);
       
  1391 
       
  1392         // do
       
  1393         QCOMPARE(spy->at(3).type, ScriptEngineEvent::PositionChange);
       
  1394         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
  1395         QCOMPARE(spy->at(3).lineNumber, 1);
       
  1396         QCOMPARE(spy->at(3).columnNumber, 12);
       
  1397 
       
  1398         // ++i
       
  1399         QCOMPARE(spy->at(4).type, ScriptEngineEvent::PositionChange);
       
  1400         QCOMPARE(spy->at(4).scriptId, spy->at(0).scriptId);
       
  1401         QCOMPARE(spy->at(4).lineNumber, 1);
       
  1402         QCOMPARE(spy->at(4).columnNumber, 17);
       
  1403     }
       
  1404 
       
  1405     {
       
  1406         spy->clear();
       
  1407         eng.evaluate("for (var i in { }) { void(i); }");
       
  1408         QCOMPARE(spy->count(), 1);
       
  1409 
       
  1410         // for
       
  1411         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1412         QVERIFY(spy->at(0).scriptId != -1);
       
  1413         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1414         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1415     }
       
  1416 
       
  1417     {
       
  1418         spy->clear();
       
  1419         eng.evaluate("for ( ; ; ) { break; }");
       
  1420         QCOMPARE(spy->count(), 2);
       
  1421 
       
  1422         // for
       
  1423         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1424         QVERIFY(spy->at(0).scriptId != -1);
       
  1425         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1426         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1427 
       
  1428         // break
       
  1429         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1430         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1431         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1432         QCOMPARE(spy->at(1).columnNumber, 15);
       
  1433     }
       
  1434 
       
  1435     {
       
  1436         spy->clear();
       
  1437         eng.evaluate("for (var i = 0 ; i < 2; ++i) { continue; }");
       
  1438         QCOMPARE(spy->count(), 3);
       
  1439 
       
  1440         // for
       
  1441         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1442         QVERIFY(spy->at(0).scriptId != -1);
       
  1443         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1444         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1445 
       
  1446         // continue
       
  1447         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1448         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1449         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1450         QCOMPARE(spy->at(1).columnNumber, 32);
       
  1451 
       
  1452         // continue
       
  1453         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1454         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
  1455         QCOMPARE(spy->at(2).lineNumber, 1);
       
  1456         QCOMPARE(spy->at(2).columnNumber, 32);
       
  1457     }
       
  1458 
       
  1459     {
       
  1460         spy->clear();
       
  1461         eng.evaluate("with (this) { }");
       
  1462         QCOMPARE(spy->count(), 1);
       
  1463 
       
  1464         // with
       
  1465         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1466         QVERIFY(spy->at(0).scriptId != -1);
       
  1467         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1468         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1469     }
       
  1470 
       
  1471     {
       
  1472         spy->clear();
       
  1473         eng.evaluate("switch (undefined) { }");
       
  1474         QCOMPARE(spy->count(), 1);
       
  1475 
       
  1476         // switch
       
  1477         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1478         QVERIFY(spy->at(0).scriptId != -1);
       
  1479         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1480         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1481     }
       
  1482 
       
  1483     {
       
  1484         spy->clear();
       
  1485         eng.evaluate("switch (undefined) { default: i = 5; }");
       
  1486         QCOMPARE(spy->count(), 2);
       
  1487 
       
  1488         // switch
       
  1489         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1490         QVERIFY(spy->at(0).scriptId != -1);
       
  1491         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1492         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1493 
       
  1494         // i = 5
       
  1495         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1496         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1497         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1498         QCOMPARE(spy->at(1).columnNumber, 31);
       
  1499     }
       
  1500 
       
  1501     {
       
  1502         spy->clear();
       
  1503         eng.evaluate("switch (undefined) { case undefined: i = 5; break; }");
       
  1504         QCOMPARE(spy->count(), 3);
       
  1505 
       
  1506         // switch
       
  1507         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1508         QVERIFY(spy->at(0).scriptId != -1);
       
  1509         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1510         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1511 
       
  1512         // i = 5
       
  1513         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1514         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1515         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1516         QCOMPARE(spy->at(1).columnNumber, 38);
       
  1517 
       
  1518         // break
       
  1519         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1520         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
  1521         QCOMPARE(spy->at(2).lineNumber, 1);
       
  1522         QCOMPARE(spy->at(2).columnNumber, 45);
       
  1523     }
       
  1524 
       
  1525     {
       
  1526         spy->clear();
       
  1527         eng.evaluate("throw 1");
       
  1528         QCOMPARE(spy->count(), 1);
       
  1529 
       
  1530         // throw
       
  1531         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1532         QVERIFY(spy->at(0).scriptId != -1);
       
  1533         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1534         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1535     }
       
  1536 
       
  1537     {
       
  1538         spy->clear();
       
  1539         eng.evaluate("try { throw 1; } catch(e) { i = e; } finally { i = 2; }");
       
  1540         QCOMPARE(spy->count(), 3);
       
  1541 
       
  1542         // throw 1
       
  1543         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1544         QVERIFY(spy->at(0).scriptId != -1);
       
  1545         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1546         QCOMPARE(spy->at(0).columnNumber, 7);
       
  1547 
       
  1548         // i = e
       
  1549         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1550         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1551         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1552         QCOMPARE(spy->at(1).columnNumber, 29);
       
  1553 
       
  1554         // i = 2
       
  1555         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1556         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
  1557         QCOMPARE(spy->at(2).lineNumber, 1);
       
  1558         QCOMPARE(spy->at(2).columnNumber, 48);
       
  1559     }
       
  1560 
       
  1561     {
       
  1562         spy->clear();
       
  1563         eng.evaluate("try { i = 1; } catch(e) { i = 2; } finally { i = 3; }");
       
  1564         QCOMPARE(spy->count(), 2);
       
  1565 
       
  1566         // i = 1
       
  1567         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1568         QVERIFY(spy->at(0).scriptId != -1);
       
  1569         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1570         QCOMPARE(spy->at(0).columnNumber, 7);
       
  1571 
       
  1572         // i = 3
       
  1573         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1574         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1575         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1576         QCOMPARE(spy->at(1).columnNumber, 46);
       
  1577     }
       
  1578 
       
  1579     {
       
  1580         QEXPECT_FAIL("","QTBUG-6142 I believe the test is wrong. Expressions shouldn't call positionChange "
       
  1581                      "because statement '1+2' will call it at least twice, why debugger have to "
       
  1582                      "stop here so many times?", Abort);
       
  1583         spy->clear();
       
  1584         eng.evaluate("c = {a: 10, b: 20}");
       
  1585         QCOMPARE(spy->count(), 2);
       
  1586 
       
  1587         // a: 10
       
  1588         QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange);
       
  1589         QVERIFY(spy->at(0).scriptId != -1);
       
  1590         QCOMPARE(spy->at(0).lineNumber, 1);
       
  1591         QCOMPARE(spy->at(0).columnNumber, 1);
       
  1592 
       
  1593         // b: 20
       
  1594         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  1595         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1596         QCOMPARE(spy->at(1).lineNumber, 1);
       
  1597         QCOMPARE(spy->at(1).columnNumber, 20);
       
  1598     }
       
  1599     delete spy;
       
  1600 }
       
  1601 
       
  1602 void tst_QScriptEngineAgent::exceptionThrowAndCatch()
       
  1603 {
       
  1604     QScriptEngine eng;
       
  1605     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreExceptionThrow
       
  1606                                                        | ScriptEngineSpy::IgnoreExceptionCatch));
       
  1607     {
       
  1608         spy->clear();
       
  1609         eng.evaluate(";");
       
  1610         QCOMPARE(spy->count(), 0);
       
  1611     }
       
  1612 
       
  1613     {
       
  1614         spy->clear();
       
  1615         eng.evaluate("try { i = 5; } catch (e) { }");
       
  1616         QCOMPARE(spy->count(), 0);
       
  1617     }
       
  1618 
       
  1619     {
       
  1620         spy->clear();
       
  1621         eng.evaluate("throw new Error('ciao');");
       
  1622         QCOMPARE(spy->count(), 1);
       
  1623 
       
  1624         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ExceptionThrow);
       
  1625         QVERIFY(spy->at(0).scriptId != -1);
       
  1626         QVERIFY(!spy->at(0).hasExceptionHandler);
       
  1627         QVERIFY(spy->at(0).value.isError());
       
  1628         QCOMPARE(spy->at(0).value.toString(), QString("Error: ciao"));
       
  1629     }
       
  1630 
       
  1631     {
       
  1632         spy->clear();
       
  1633         eng.evaluate("try { throw new Error('ciao'); } catch (e) { }");
       
  1634         QCOMPARE(spy->count(), 2);
       
  1635 
       
  1636         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ExceptionThrow);
       
  1637         QVERIFY(spy->at(0).scriptId != -1);
       
  1638         QVERIFY(spy->at(0).hasExceptionHandler);
       
  1639         QVERIFY(spy->at(0).value.isError());
       
  1640         QCOMPARE(spy->at(0).value.toString(), QString("Error: ciao"));
       
  1641         QVERIFY(spy->at(0).scriptId != -1);
       
  1642 
       
  1643         QCOMPARE(spy->at(1).type, ScriptEngineEvent::ExceptionCatch);
       
  1644         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1645         QVERIFY(spy->at(1).value.strictlyEquals(spy->at(0).value));
       
  1646     }
       
  1647 }
       
  1648 
       
  1649 void tst_QScriptEngineAgent::eventOrder_assigment()
       
  1650 {
       
  1651     QScriptEngine eng;
       
  1652     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  1653     {
       
  1654         spy->clear();
       
  1655         eng.evaluate("i = 3; i = 5");
       
  1656         QCOMPARE(spy->count(), 6);
       
  1657         // load
       
  1658         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  1659         // evaluate() entry
       
  1660         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
  1661         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  1662         // i = 3
       
  1663         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1664         QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
  1665         // i = 5
       
  1666         QCOMPARE(spy->at(3).type, ScriptEngineEvent::PositionChange);
       
  1667         QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
  1668         // evaluate() exit
       
  1669         QCOMPARE(spy->at(4).type, ScriptEngineEvent::FunctionExit);
       
  1670         QCOMPARE(spy->at(4).scriptId, spy->at(0).scriptId);
       
  1671         // unload
       
  1672         QCOMPARE(spy->at(5).type, ScriptEngineEvent::ScriptUnload);
       
  1673         QCOMPARE(spy->at(5).scriptId, spy->at(0).scriptId);
       
  1674     }
       
  1675     delete spy;
       
  1676 }
       
  1677 
       
  1678 void tst_QScriptEngineAgent::eventOrder_functionDefinition()
       
  1679 {
       
  1680     QScriptEngine eng;
       
  1681     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  1682     {
       
  1683         spy->clear();
       
  1684         eng.evaluate("function foo(arg) { void(arg); }");
       
  1685         QCOMPARE(spy->count(), 3);
       
  1686         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  1687         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
  1688         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit);
       
  1689 
       
  1690         eng.evaluate("foo(123)");
       
  1691         QCOMPARE(spy->count(), 13);
       
  1692         // load
       
  1693         QCOMPARE(spy->at(3).type, ScriptEngineEvent::ScriptLoad);
       
  1694         QVERIFY(spy->at(3).scriptId != spy->at(0).scriptId);
       
  1695         // evaluate() entry
       
  1696         QCOMPARE(spy->at(4).type, ScriptEngineEvent::FunctionEntry);
       
  1697         QCOMPARE(spy->at(4).scriptId, spy->at(3).scriptId);
       
  1698         // foo()
       
  1699         QCOMPARE(spy->at(5).type, ScriptEngineEvent::PositionChange);
       
  1700         QCOMPARE(spy->at(5).scriptId, spy->at(3).scriptId);
       
  1701         // new context
       
  1702         QCOMPARE(spy->at(6).type, ScriptEngineEvent::ContextPush);
       
  1703         // foo() entry
       
  1704         QCOMPARE(spy->at(7).type, ScriptEngineEvent::FunctionEntry);
       
  1705         QCOMPARE(spy->at(7).scriptId, spy->at(0).scriptId);
       
  1706         // void(arg)
       
  1707         QCOMPARE(spy->at(8).type, ScriptEngineEvent::PositionChange);
       
  1708         QCOMPARE(spy->at(8).scriptId, spy->at(0).scriptId);
       
  1709         // foo() exit
       
  1710         QCOMPARE(spy->at(9).type, ScriptEngineEvent::FunctionExit);
       
  1711         QCOMPARE(spy->at(9).scriptId, spy->at(0).scriptId);
       
  1712         // restore context
       
  1713         QCOMPARE(spy->at(10).type, ScriptEngineEvent::ContextPop);
       
  1714         // evaluate() exit
       
  1715         QCOMPARE(spy->at(11).type, ScriptEngineEvent::FunctionExit);
       
  1716         QCOMPARE(spy->at(11).scriptId, spy->at(3).scriptId);
       
  1717         // unload
       
  1718         QCOMPARE(spy->at(12).type, ScriptEngineEvent::ScriptUnload);
       
  1719         QCOMPARE(spy->at(12).scriptId, spy->at(3).scriptId);
       
  1720 
       
  1721         eng.evaluate("foo = null");
       
  1722         eng.collectGarbage();
       
  1723     }
       
  1724     delete spy;
       
  1725 }
       
  1726 
       
  1727 void tst_QScriptEngineAgent::eventOrder_throwError()
       
  1728 {
       
  1729     QScriptEngine eng;
       
  1730     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  1731     {
       
  1732         spy->clear();
       
  1733         eng.evaluate("throw new Error('ciao')");
       
  1734         QCOMPARE(spy->count(), 10);
       
  1735         // load
       
  1736         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  1737         // evaluate() entry
       
  1738         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
  1739         // throw
       
  1740         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1741         // new context
       
  1742         QCOMPARE(spy->at(3).type, ScriptEngineEvent::ContextPush);
       
  1743         // Error constructor entry
       
  1744         QCOMPARE(spy->at(4).type, ScriptEngineEvent::FunctionEntry);
       
  1745         // Error constructor exit
       
  1746         QCOMPARE(spy->at(5).type, ScriptEngineEvent::FunctionExit);
       
  1747         // restore context
       
  1748         QCOMPARE(spy->at(6).type, ScriptEngineEvent::ContextPop);
       
  1749         // exception
       
  1750         QCOMPARE(spy->at(7).type, ScriptEngineEvent::ExceptionThrow);
       
  1751         QVERIFY(!spy->at(7).hasExceptionHandler);
       
  1752         // evaluate() exit
       
  1753         QCOMPARE(spy->at(8).type, ScriptEngineEvent::FunctionExit);
       
  1754         // unload
       
  1755         QCOMPARE(spy->at(9).type, ScriptEngineEvent::ScriptUnload);
       
  1756     }
       
  1757     delete spy;
       
  1758 }
       
  1759 
       
  1760 void tst_QScriptEngineAgent::eventOrder_throwAndCatch()
       
  1761 {
       
  1762     QScriptEngine eng;
       
  1763     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  1764     {
       
  1765         spy->clear();
       
  1766         eng.evaluate("try { throw new Error('ciao') } catch (e) { void(e); }");
       
  1767         QCOMPARE(spy->count(), 12);
       
  1768         // load
       
  1769         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  1770         // evaluate() entry
       
  1771         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
  1772         // throw
       
  1773         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1774         // new context
       
  1775         QCOMPARE(spy->at(3).type, ScriptEngineEvent::ContextPush);
       
  1776         // Error constructor entry
       
  1777         QCOMPARE(spy->at(4).type, ScriptEngineEvent::FunctionEntry);
       
  1778         // Error constructor exit
       
  1779         QCOMPARE(spy->at(5).type, ScriptEngineEvent::FunctionExit);
       
  1780         // restore context
       
  1781         QCOMPARE(spy->at(6).type, ScriptEngineEvent::ContextPop);
       
  1782         // exception
       
  1783         QCOMPARE(spy->at(7).type, ScriptEngineEvent::ExceptionThrow);
       
  1784         QVERIFY(spy->at(7).value.isError());
       
  1785         QVERIFY(spy->at(7).hasExceptionHandler);
       
  1786         // catch
       
  1787         QCOMPARE(spy->at(8).type, ScriptEngineEvent::ExceptionCatch);
       
  1788         QVERIFY(spy->at(8).value.isError());
       
  1789         // void(e)
       
  1790         QCOMPARE(spy->at(9).type, ScriptEngineEvent::PositionChange);
       
  1791         // evaluate() exit
       
  1792         QCOMPARE(spy->at(10).type, ScriptEngineEvent::FunctionExit);
       
  1793         QVERIFY(spy->at(10).value.isUndefined());
       
  1794         // unload
       
  1795         QCOMPARE(spy->at(11).type, ScriptEngineEvent::ScriptUnload);
       
  1796     }
       
  1797     delete spy;
       
  1798 }
       
  1799 
       
  1800 void tst_QScriptEngineAgent::eventOrder_functions()
       
  1801 {
       
  1802     QScriptEngine eng;
       
  1803     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  1804     {
       
  1805         spy->clear();
       
  1806         eng.evaluate("function foo(arg) { return bar(arg); }");
       
  1807         eng.evaluate("function bar(arg) { return arg; }");
       
  1808         QCOMPARE(spy->count(), 6);
       
  1809 
       
  1810         eng.evaluate("foo(123)");
       
  1811         QCOMPARE(spy->count(), 21);
       
  1812 
       
  1813         // load
       
  1814         QCOMPARE(spy->at(6).type, ScriptEngineEvent::ScriptLoad);
       
  1815         // evaluate() entry
       
  1816         QCOMPARE(spy->at(7).type, ScriptEngineEvent::FunctionEntry);
       
  1817         // foo(123)
       
  1818         QCOMPARE(spy->at(8).type, ScriptEngineEvent::PositionChange);
       
  1819         // new context
       
  1820         QCOMPARE(spy->at(9).type, ScriptEngineEvent::ContextPush);
       
  1821         // foo() entry
       
  1822         QCOMPARE(spy->at(10).type, ScriptEngineEvent::FunctionEntry);
       
  1823         QCOMPARE(spy->at(10).scriptId, spy->at(0).scriptId);
       
  1824         // return bar(arg)
       
  1825         QCOMPARE(spy->at(11).type, ScriptEngineEvent::PositionChange);
       
  1826         QCOMPARE(spy->at(11).scriptId, spy->at(0).scriptId);
       
  1827         // new context
       
  1828         QCOMPARE(spy->at(12).type, ScriptEngineEvent::ContextPush);
       
  1829         // bar() entry
       
  1830         QCOMPARE(spy->at(13).type, ScriptEngineEvent::FunctionEntry);
       
  1831         QCOMPARE(spy->at(13).scriptId, spy->at(3).scriptId);
       
  1832         // return arg
       
  1833         QCOMPARE(spy->at(14).type, ScriptEngineEvent::PositionChange);
       
  1834         QCOMPARE(spy->at(14).scriptId, spy->at(3).scriptId);
       
  1835         // bar() exit
       
  1836         QCOMPARE(spy->at(15).type, ScriptEngineEvent::FunctionExit);
       
  1837         QCOMPARE(spy->at(15).scriptId, spy->at(3).scriptId);
       
  1838         QVERIFY(spy->at(15).value.isNumber());
       
  1839         // restore context
       
  1840         QCOMPARE(spy->at(16).type, ScriptEngineEvent::ContextPop);
       
  1841         // foo() exit
       
  1842         QCOMPARE(spy->at(17).type, ScriptEngineEvent::FunctionExit);
       
  1843         QCOMPARE(spy->at(17).scriptId, spy->at(0).scriptId);
       
  1844         QVERIFY(spy->at(17).value.isNumber());
       
  1845         // restore context
       
  1846         QCOMPARE(spy->at(18).type, ScriptEngineEvent::ContextPop);
       
  1847         // evaluate() exit
       
  1848         QCOMPARE(spy->at(19).type, ScriptEngineEvent::FunctionExit);
       
  1849         QCOMPARE(spy->at(19).scriptId, spy->at(6).scriptId);
       
  1850         QVERIFY(spy->at(19).value.isNumber());
       
  1851         // unload
       
  1852         QCOMPARE(spy->at(20).type, ScriptEngineEvent::ScriptUnload);
       
  1853         QCOMPARE(spy->at(20).scriptId, spy->at(6).scriptId);
       
  1854 
       
  1855         // redefine bar()
       
  1856         eng.evaluate("function bar(arg) { throw new Error(arg); }");
       
  1857         eng.collectGarbage();
       
  1858         QCOMPARE(spy->count(), 25);
       
  1859         QCOMPARE(spy->at(21).type, ScriptEngineEvent::ScriptLoad);
       
  1860         QCOMPARE(spy->at(22).type, ScriptEngineEvent::FunctionEntry);
       
  1861         QCOMPARE(spy->at(23).type, ScriptEngineEvent::FunctionExit);
       
  1862         QCOMPARE(spy->at(24).type, ScriptEngineEvent::ScriptUnload);
       
  1863         QCOMPARE(spy->at(24).scriptId, spy->at(3).scriptId);
       
  1864 
       
  1865         eng.evaluate("foo('ciao')");
       
  1866 
       
  1867         QCOMPARE(spy->count(), 45);
       
  1868 
       
  1869         // load
       
  1870         QCOMPARE(spy->at(25).type, ScriptEngineEvent::ScriptLoad);
       
  1871         // evaluate() entry
       
  1872         QCOMPARE(spy->at(26).type, ScriptEngineEvent::FunctionEntry);
       
  1873         // foo('ciao')
       
  1874         QCOMPARE(spy->at(27).type, ScriptEngineEvent::PositionChange);
       
  1875         // new context
       
  1876         QCOMPARE(spy->at(28).type, ScriptEngineEvent::ContextPush);
       
  1877         // foo() entry
       
  1878         QCOMPARE(spy->at(29).type, ScriptEngineEvent::FunctionEntry);
       
  1879         QCOMPARE(spy->at(29).scriptId, spy->at(0).scriptId);
       
  1880         // return bar(arg)
       
  1881         QCOMPARE(spy->at(30).type, ScriptEngineEvent::PositionChange);
       
  1882         QCOMPARE(spy->at(30).scriptId, spy->at(0).scriptId);
       
  1883         // new context
       
  1884         QCOMPARE(spy->at(31).type, ScriptEngineEvent::ContextPush);
       
  1885         // bar() entry
       
  1886         QCOMPARE(spy->at(32).type, ScriptEngineEvent::FunctionEntry);
       
  1887         QCOMPARE(spy->at(32).scriptId, spy->at(21).scriptId);
       
  1888         // throw
       
  1889         QCOMPARE(spy->at(33).type, ScriptEngineEvent::PositionChange);
       
  1890         QCOMPARE(spy->at(33).scriptId, spy->at(21).scriptId);
       
  1891         // new context
       
  1892         QCOMPARE(spy->at(34).type, ScriptEngineEvent::ContextPush);
       
  1893         // Error constructor entry
       
  1894         QCOMPARE(spy->at(35).type, ScriptEngineEvent::FunctionEntry);
       
  1895         QCOMPARE(spy->at(35).scriptId, qint64(-1));
       
  1896         // Error constructor exit
       
  1897         QCOMPARE(spy->at(36).type, ScriptEngineEvent::FunctionExit);
       
  1898         QCOMPARE(spy->at(36).scriptId, qint64(-1));
       
  1899         // restore context
       
  1900         QCOMPARE(spy->at(37).type, ScriptEngineEvent::ContextPop);
       
  1901         // exception
       
  1902         QCOMPARE(spy->at(38).type, ScriptEngineEvent::ExceptionThrow);
       
  1903         QCOMPARE(spy->at(38).scriptId, spy->at(21).scriptId);
       
  1904         QVERIFY(!spy->at(38).hasExceptionHandler);
       
  1905         // bar() exit
       
  1906         QCOMPARE(spy->at(39).type, ScriptEngineEvent::FunctionExit);
       
  1907         QCOMPARE(spy->at(39).scriptId, spy->at(21).scriptId);
       
  1908         QVERIFY(spy->at(39).value.isError());
       
  1909         // restore context
       
  1910         QCOMPARE(spy->at(40).type, ScriptEngineEvent::ContextPop);
       
  1911         // foo() exit
       
  1912         QCOMPARE(spy->at(41).type, ScriptEngineEvent::FunctionExit);
       
  1913         QCOMPARE(spy->at(41).scriptId, spy->at(0).scriptId);
       
  1914         QVERIFY(spy->at(41).value.isError());
       
  1915         // restore context
       
  1916         QCOMPARE(spy->at(42).type, ScriptEngineEvent::ContextPop);
       
  1917         // evaluate() exit
       
  1918         QCOMPARE(spy->at(43).type, ScriptEngineEvent::FunctionExit);
       
  1919         QCOMPARE(spy->at(43).scriptId, spy->at(26).scriptId);
       
  1920         QVERIFY(spy->at(43).value.isError());
       
  1921         // unload
       
  1922         QCOMPARE(spy->at(44).type, ScriptEngineEvent::ScriptUnload);
       
  1923         QCOMPARE(spy->at(44).scriptId, spy->at(25).scriptId);
       
  1924     }
       
  1925     delete spy;
       
  1926 }
       
  1927 
       
  1928 void tst_QScriptEngineAgent::eventOrder_throwCatchFinally()
       
  1929 {
       
  1930     QScriptEngine eng;
       
  1931     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  1932     {
       
  1933         spy->clear();
       
  1934         eng.evaluate("try { throw 1; } catch(e) { i = e; } finally { i = 2; }");
       
  1935         QCOMPARE(spy->count(), 9);
       
  1936 
       
  1937         // load
       
  1938         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  1939         // evaluate() entry
       
  1940         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
  1941         // throw 1
       
  1942         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1943         // i = e
       
  1944         QCOMPARE(spy->at(3).type, ScriptEngineEvent::ExceptionThrow);
       
  1945         // catch
       
  1946         QCOMPARE(spy->at(4).type, ScriptEngineEvent::ExceptionCatch);
       
  1947         // i = e
       
  1948         QCOMPARE(spy->at(5).type, ScriptEngineEvent::PositionChange);
       
  1949         // i = 2
       
  1950         QCOMPARE(spy->at(6).type, ScriptEngineEvent::PositionChange);
       
  1951         // evaluate() exit
       
  1952         QCOMPARE(spy->at(7).type, ScriptEngineEvent::FunctionExit);
       
  1953         // unload
       
  1954         QCOMPARE(spy->at(8).type, ScriptEngineEvent::ScriptUnload);
       
  1955     }
       
  1956     delete spy;
       
  1957 }
       
  1958 
       
  1959 void tst_QScriptEngineAgent::eventOrder_signalsHandling()
       
  1960 {
       
  1961     QScriptEngine eng;
       
  1962     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  1963     // signal handling
       
  1964     {
       
  1965         spy->clear();
       
  1966         QScriptValue fun = eng.evaluate("(function(arg) { throw Error(arg); })");
       
  1967         QVERIFY(fun.isFunction());
       
  1968         QCOMPARE(spy->count(), 4);
       
  1969         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  1970         QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
  1971         QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  1972         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
  1973 
       
  1974         qScriptConnect(this, SIGNAL(testSignal(double)),
       
  1975                        QScriptValue(), fun);
       
  1976 
       
  1977         emit testSignal(123);
       
  1978 
       
  1979         QCOMPARE(spy->count(), 14);
       
  1980         // new context
       
  1981         QCOMPARE(spy->at(4).type, ScriptEngineEvent::ContextPush);
       
  1982         // anonymous function entry
       
  1983         QCOMPARE(spy->at(5).type, ScriptEngineEvent::FunctionEntry);
       
  1984         QCOMPARE(spy->at(5).scriptId, spy->at(0).scriptId);
       
  1985         // throw statement
       
  1986         QCOMPARE(spy->at(6).type, ScriptEngineEvent::PositionChange);
       
  1987         QCOMPARE(spy->at(6).scriptId, spy->at(0).scriptId);
       
  1988         // new context
       
  1989         QCOMPARE(spy->at(7).type, ScriptEngineEvent::ContextPush);
       
  1990         // Error constructor entry
       
  1991         QCOMPARE(spy->at(8).type, ScriptEngineEvent::FunctionEntry);
       
  1992         QCOMPARE(spy->at(8).scriptId, qint64(-1));
       
  1993         // Error constructor exit
       
  1994         QCOMPARE(spy->at(9).type, ScriptEngineEvent::FunctionExit);
       
  1995         QCOMPARE(spy->at(9).scriptId, qint64(-1));
       
  1996         // restore context
       
  1997         QCOMPARE(spy->at(10).type, ScriptEngineEvent::ContextPop);
       
  1998         // exception
       
  1999         QCOMPARE(spy->at(11).type, ScriptEngineEvent::ExceptionThrow);
       
  2000         QCOMPARE(spy->at(11).scriptId, spy->at(0).scriptId);
       
  2001         QVERIFY(spy->at(11).value.isError());
       
  2002         QVERIFY(!spy->at(11).hasExceptionHandler);
       
  2003         // anonymous function exit
       
  2004         QCOMPARE(spy->at(12).type, ScriptEngineEvent::FunctionExit);
       
  2005         QCOMPARE(spy->at(12).scriptId, spy->at(0).scriptId);
       
  2006         QVERIFY(spy->at(12).value.isError());
       
  2007         // restore context
       
  2008         QCOMPARE(spy->at(13).type, ScriptEngineEvent::ContextPop);
       
  2009     }
       
  2010     delete spy;
       
  2011 }
       
  2012 
       
  2013 class DoubleAgent : public ScriptEngineSpy
       
  2014 {
       
  2015 public:
       
  2016     DoubleAgent(QScriptEngine *engine) : ScriptEngineSpy(engine) { }
       
  2017     ~DoubleAgent() { }
       
  2018 
       
  2019     void positionChange(qint64 scriptId, int lineNumber, int columnNumber)
       
  2020     {
       
  2021         if (lineNumber == 123)
       
  2022             engine()->evaluate("1 + 2");
       
  2023         ScriptEngineSpy::positionChange(scriptId, lineNumber, columnNumber);
       
  2024     }
       
  2025 };
       
  2026 
       
  2027 void tst_QScriptEngineAgent::recursiveObserve()
       
  2028 {
       
  2029     QScriptEngine eng;
       
  2030     DoubleAgent *spy = new DoubleAgent(&eng);
       
  2031 
       
  2032     eng.evaluate("3 + 4", "foo.qs", 123);
       
  2033 
       
  2034     QCOMPARE(spy->count(), 10);
       
  2035 
       
  2036     int i = 0;
       
  2037     // load "3 + 4"    
       
  2038     QCOMPARE(spy->at(i).type, ScriptEngineEvent::ScriptLoad);
       
  2039     i++;
       
  2040     // evaluate() entry
       
  2041     QCOMPARE(spy->at(i).type, ScriptEngineEvent::FunctionEntry);
       
  2042     i++;
       
  2043     // load "1 + 2"
       
  2044     QCOMPARE(spy->at(i).type, ScriptEngineEvent::ScriptLoad);
       
  2045     i++;
       
  2046     // evaluate() entry
       
  2047     QCOMPARE(spy->at(i).type, ScriptEngineEvent::FunctionEntry);
       
  2048     i++;
       
  2049     // 1 + 2
       
  2050     QCOMPARE(spy->at(i).type, ScriptEngineEvent::PositionChange);
       
  2051     QCOMPARE(spy->at(i).scriptId, spy->at(2).scriptId);
       
  2052     i++;
       
  2053     // evaluate() exit
       
  2054     QCOMPARE(spy->at(i).type, ScriptEngineEvent::FunctionExit);
       
  2055     i++;
       
  2056     // unload "1 + 2"
       
  2057     QCOMPARE(spy->at(i).type, ScriptEngineEvent::ScriptUnload);
       
  2058     QCOMPARE(spy->at(i).scriptId, spy->at(2).scriptId);
       
  2059     i++;
       
  2060     // 3 + 4
       
  2061     QCOMPARE(spy->at(i).type, ScriptEngineEvent::PositionChange);
       
  2062     QCOMPARE(spy->at(i).scriptId, spy->at(0).scriptId);
       
  2063     i++;
       
  2064     // evaluate() exit
       
  2065     QCOMPARE(spy->at(i).type, ScriptEngineEvent::FunctionExit);
       
  2066     i++;
       
  2067     // unload "3 + 4"
       
  2068     QCOMPARE(spy->at(i).type, ScriptEngineEvent::ScriptUnload);
       
  2069     QCOMPARE(spy->at(i).scriptId, spy->at(0).scriptId);
       
  2070 }
       
  2071 
       
  2072 
       
  2073 /** When second agent is attached to Engine the first one should be deatached */
       
  2074 void tst_QScriptEngineAgent::multipleAgents()
       
  2075 {
       
  2076     QScriptEngine eng;
       
  2077     QCOMPARE(eng.agent(), (QScriptEngineAgent *)0);
       
  2078     ScriptEngineSpy *spy1 = new ScriptEngineSpy(&eng);
       
  2079     QCOMPARE(eng.agent(), (QScriptEngineAgent*)spy1);
       
  2080     ScriptEngineSpy *spy2 = new ScriptEngineSpy(&eng);
       
  2081     QCOMPARE(eng.agent(), (QScriptEngineAgent*)spy2);
       
  2082 
       
  2083     eng.evaluate("1 + 2");
       
  2084     QCOMPARE(spy1->count(), 0);
       
  2085     QCOMPARE(spy2->count(), 5);
       
  2086 
       
  2087     spy2->clear();
       
  2088     eng.setAgent(spy1);
       
  2089     eng.evaluate("1 + 2");
       
  2090     QCOMPARE(spy2->count(), 0);
       
  2091     QCOMPARE(spy1->count(), 5);
       
  2092 }
       
  2093 
       
  2094 void tst_QScriptEngineAgent::syntaxError()
       
  2095 {
       
  2096     /* This test was changed. Old backend didn't generate events in exception objects creation time
       
  2097         JSC does */
       
  2098     QScriptEngine eng;
       
  2099     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  2100     {
       
  2101         int i = 0;
       
  2102         spy->clear();
       
  2103         eng.evaluate("{");
       
  2104         
       
  2105         QCOMPARE(spy->count(), 9);
       
  2106 
       
  2107         QCOMPARE(spy->at(i).type, ScriptEngineEvent::ScriptLoad);
       
  2108         QVERIFY(spy->at(i).scriptId != -1);
       
  2109         i = 1;
       
  2110         QCOMPARE(spy->at(i).type, ScriptEngineEvent::FunctionEntry);
       
  2111         QCOMPARE(spy->at(i).scriptId, spy->at(0).scriptId);
       
  2112 
       
  2113         //create exception
       
  2114 
       
  2115         i = 2;
       
  2116         QCOMPARE(spy->at(i).type, ScriptEngineEvent::ContextPush);
       
  2117         i = 3;
       
  2118         QCOMPARE(spy->at(i).type, ScriptEngineEvent::FunctionEntry);
       
  2119         QVERIFY(spy->at(i).scriptId == -1);
       
  2120         i = 4;
       
  2121         QCOMPARE(spy->at(i).type, ScriptEngineEvent::FunctionExit);
       
  2122         QVERIFY(spy->at(i).scriptId == -1);
       
  2123         i = 5;
       
  2124         QCOMPARE(spy->at(i).type, ScriptEngineEvent::ContextPop);
       
  2125         i = 6;
       
  2126         QCOMPARE(spy->at(i).type, ScriptEngineEvent::ExceptionThrow);
       
  2127         QCOMPARE(spy->at(i).scriptId, spy->at(0).scriptId);
       
  2128         QVERIFY(!spy->at(i).hasExceptionHandler);
       
  2129         QVERIFY(spy->at(i).value.isError());
       
  2130         QEXPECT_FAIL("","QTBUG-6137 There are other messages in JSC",Continue);
       
  2131         QCOMPARE(spy->at(i).value.toString(), QString("SyntaxError: Expected `}'"));
       
  2132         QCOMPARE(spy->at(i).scriptId, spy->at(0).scriptId);
       
  2133         i = 7;
       
  2134         //exit script
       
  2135         QCOMPARE(spy->at(i).type, ScriptEngineEvent::FunctionExit);
       
  2136         QCOMPARE(spy->at(i).scriptId, spy->at(0).scriptId);
       
  2137         i = 8;
       
  2138         QCOMPARE(spy->at(i).type, ScriptEngineEvent::ScriptUnload);
       
  2139         QCOMPARE(spy->at(i).scriptId, spy->at(0).scriptId);
       
  2140     }
       
  2141 }
       
  2142 
       
  2143 void tst_QScriptEngineAgent::extension_invoctaion()
       
  2144 {
       
  2145     QScriptEngine eng;
       
  2146     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreDebuggerInvocationRequest
       
  2147                                                    | ScriptEngineSpy::IgnoreScriptLoad));
       
  2148     // DebuggerInvocationRequest
       
  2149     {
       
  2150         spy->clear();
       
  2151 
       
  2152         QString fileName = "foo.qs";
       
  2153         int lineNumber = 123;
       
  2154         QScriptValue ret = eng.evaluate("debugger", fileName, lineNumber);
       
  2155 
       
  2156         QCOMPARE(spy->count(), 2);
       
  2157         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  2158         QCOMPARE(spy->at(1).type, ScriptEngineEvent::DebuggerInvocationRequest);
       
  2159         QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  2160         QCOMPARE(spy->at(1).lineNumber, lineNumber);
       
  2161         QCOMPARE(spy->at(1).columnNumber, 1);
       
  2162 
       
  2163         QEXPECT_FAIL("","QTBUG-6135 In JSC Eval('debugger') returns undefined",Abort);
       
  2164         QVERIFY(ret.isString());
       
  2165         QCOMPARE(ret.toString(), QString::fromLatin1("extension(DebuggerInvocationRequest)"));
       
  2166     }
       
  2167     delete spy;
       
  2168 }
       
  2169 
       
  2170 void tst_QScriptEngineAgent::extension()
       
  2171 {
       
  2172     QScriptEngine eng;
       
  2173     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng, ~(ScriptEngineSpy::IgnoreDebuggerInvocationRequest
       
  2174                                                    | ScriptEngineSpy::IgnoreScriptLoad));
       
  2175 
       
  2176     {
       
  2177         spy->clear();
       
  2178         spy->enableIgnoreFlags(ScriptEngineSpy::IgnoreDebuggerInvocationRequest);
       
  2179 
       
  2180         QScriptValue ret = eng.evaluate("debugger");
       
  2181 
       
  2182         QCOMPARE(spy->count(), 1);
       
  2183         QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  2184         QVERIFY(ret.isUndefined());
       
  2185     }
       
  2186     delete spy;
       
  2187 }
       
  2188 
       
  2189 class TestIsEvaluatingAgent : public QScriptEngineAgent
       
  2190 {
       
  2191 public:
       
  2192     TestIsEvaluatingAgent(QScriptEngine *engine)
       
  2193         : QScriptEngineAgent(engine), wasEvaluating(false)
       
  2194     { engine->setAgent(this); }
       
  2195     bool supportsExtension(Extension ext) const
       
  2196     { return ext == DebuggerInvocationRequest; }
       
  2197     QVariant extension(Extension, const QVariant &)
       
  2198     { wasEvaluating = engine()->isEvaluating(); return QVariant(); }
       
  2199 
       
  2200     bool wasEvaluating;
       
  2201 };
       
  2202 
       
  2203 void tst_QScriptEngineAgent::isEvaluatingInExtension()
       
  2204 {
       
  2205     QScriptEngine eng;
       
  2206     TestIsEvaluatingAgent *spy = new TestIsEvaluatingAgent(&eng);
       
  2207     QVERIFY(!spy->wasEvaluating);
       
  2208     eng.evaluate("debugger");
       
  2209     QVERIFY(spy->wasEvaluating);
       
  2210 }
       
  2211 
       
  2212 class NewSpy :public QScriptEngineAgent
       
  2213 {
       
  2214     bool m_result;
       
  2215 public:
       
  2216   NewSpy(QScriptEngine* eng) : QScriptEngineAgent(eng), m_result(false) {}
       
  2217   void functionExit (qint64, const QScriptValue &scriptValue)
       
  2218   {
       
  2219       if (engine()->hasUncaughtException()) m_result = true;
       
  2220   }
       
  2221 
       
  2222   bool isPass() { return m_result; }
       
  2223   void reset() { m_result =  false; }
       
  2224 };
       
  2225 
       
  2226 void tst_QScriptEngineAgent::hasUncaughtException()
       
  2227 {
       
  2228   QScriptEngine eng;
       
  2229   NewSpy* spy = new NewSpy(&eng);
       
  2230   eng.setAgent(spy);
       
  2231   QScriptValue scriptValue;
       
  2232 
       
  2233   // Check unhandled exception.
       
  2234   eng.evaluate("function init () {Unknown.doSth ();}");
       
  2235   scriptValue = QScriptValue(eng.globalObject().property("init")).call();
       
  2236   QVERIFY(eng.hasUncaughtException());
       
  2237   QVERIFY2(spy->isPass(), "At least one of a functionExit event should set hasUncaughtException flag.");
       
  2238   spy->reset();
       
  2239 
       
  2240   // Check catched exception.
       
  2241   eng.evaluate("function innerFoo() { throw new Error('ciao') }");
       
  2242   eng.evaluate("function foo() {try { innerFoo() } catch (e) {} }");
       
  2243   scriptValue = QScriptValue(eng.globalObject().property("foo")).call();
       
  2244   QVERIFY(!eng.hasUncaughtException());
       
  2245   QVERIFY2(spy->isPass(), "At least one of a functionExit event should set hasUncaughtException flag.");
       
  2246 }
       
  2247 
       
  2248 void tst_QScriptEngineAgent::evaluateProgram()
       
  2249 {
       
  2250     QScriptEngine eng;
       
  2251     QScriptProgram program("1 + 2", "foo.js", 123);
       
  2252     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  2253     qint64 scriptId = -1;
       
  2254     for (int x = 0; x < 10; ++x) {
       
  2255         spy->clear();
       
  2256         (void)eng.evaluate(program);
       
  2257         QCOMPARE(spy->count(), (x == 0) ? 4 : 3);
       
  2258 
       
  2259         if (x == 0) {
       
  2260             // script is only loaded on first execution
       
  2261             QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  2262             scriptId = spy->at(0).scriptId;
       
  2263             QVERIFY(scriptId != -1);
       
  2264             QCOMPARE(spy->at(0).script, program.sourceCode());
       
  2265             QCOMPARE(spy->at(0).fileName, program.fileName());
       
  2266             QCOMPARE(spy->at(0).lineNumber, program.firstLineNumber());
       
  2267             spy->removeFirst();
       
  2268         }
       
  2269 
       
  2270         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry); // evaluate()
       
  2271         QCOMPARE(spy->at(0).scriptId, scriptId);
       
  2272 
       
  2273         QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange);
       
  2274         QCOMPARE(spy->at(1).scriptId, scriptId);
       
  2275         QCOMPARE(spy->at(1).lineNumber, program.firstLineNumber());
       
  2276 
       
  2277         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionExit); // evaluate()
       
  2278         QCOMPARE(spy->at(2).scriptId, scriptId);
       
  2279         QVERIFY(spy->at(2).value.isNumber());
       
  2280         QCOMPARE(spy->at(2).value.toNumber(), qsreal(3));
       
  2281     }
       
  2282 }
       
  2283 
       
  2284 void tst_QScriptEngineAgent::evaluateProgram_SyntaxError()
       
  2285 {
       
  2286     QScriptEngine eng;
       
  2287     QScriptProgram program("this is not valid syntax", "foo.js", 123);
       
  2288     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  2289     qint64 scriptId = -1;
       
  2290     for (int x = 0; x < 10; ++x) {
       
  2291         spy->clear();
       
  2292         (void)eng.evaluate(program);
       
  2293         QCOMPARE(spy->count(), (x == 0) ? 8 : 7);
       
  2294 
       
  2295         if (x == 0) {
       
  2296             // script is only loaded on first execution
       
  2297             QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  2298             scriptId = spy->at(0).scriptId;
       
  2299             QVERIFY(scriptId != -1);
       
  2300             QCOMPARE(spy->at(0).script, program.sourceCode());
       
  2301             QCOMPARE(spy->at(0).fileName, program.fileName());
       
  2302             QCOMPARE(spy->at(0).lineNumber, program.firstLineNumber());
       
  2303             spy->removeFirst();
       
  2304         }
       
  2305 
       
  2306         QCOMPARE(spy->at(0).type, ScriptEngineEvent::FunctionEntry); // evaluate()
       
  2307         QCOMPARE(spy->at(0).scriptId, scriptId);
       
  2308 
       
  2309         QCOMPARE(spy->at(1).type, ScriptEngineEvent::ContextPush); // SyntaxError constructor
       
  2310         QCOMPARE(spy->at(2).type, ScriptEngineEvent::FunctionEntry); // SyntaxError constructor
       
  2311         QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit); // SyntaxError constructor
       
  2312         QCOMPARE(spy->at(4).type, ScriptEngineEvent::ContextPop); // SyntaxError constructor
       
  2313 
       
  2314         QCOMPARE(spy->at(5).type, ScriptEngineEvent::ExceptionThrow);
       
  2315         QVERIFY(spy->at(5).value.isError());
       
  2316         QCOMPARE(spy->at(5).value.toString(), QString::fromLatin1("SyntaxError: Parse error"));
       
  2317 
       
  2318         QCOMPARE(spy->at(6).type, ScriptEngineEvent::FunctionExit); // evaluate()
       
  2319         QCOMPARE(spy->at(6).scriptId, scriptId);
       
  2320     }
       
  2321 }
       
  2322 
       
  2323 void tst_QScriptEngineAgent::evaluateNullProgram()
       
  2324 {
       
  2325     QScriptEngine eng;
       
  2326     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  2327     (void)eng.evaluate(QScriptProgram());
       
  2328     QCOMPARE(spy->count(), 0);
       
  2329 }
       
  2330 
       
  2331 void tst_QScriptEngineAgent::QTBUG6108()
       
  2332 {
       
  2333     QScriptEngine eng;
       
  2334     ScriptEngineSpy *spy = new ScriptEngineSpy(&eng);
       
  2335     eng.evaluate("eval('a = 1')");
       
  2336     QCOMPARE(spy->count(), 5);
       
  2337 
       
  2338     QCOMPARE(spy->at(0).type, ScriptEngineEvent::ScriptLoad);
       
  2339     QVERIFY(spy->at(0).scriptId != -1);
       
  2340 
       
  2341     QCOMPARE(spy->at(1).type, ScriptEngineEvent::FunctionEntry);
       
  2342     QVERIFY(spy->at(1).scriptId != -1);
       
  2343     QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId);
       
  2344 
       
  2345     QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange);
       
  2346     QVERIFY(spy->at(2).scriptId != -1);
       
  2347     QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId);
       
  2348     QCOMPARE(spy->at(2).lineNumber, 1);
       
  2349 
       
  2350     QCOMPARE(spy->at(3).type, ScriptEngineEvent::FunctionExit);
       
  2351     QVERIFY(spy->at(3).scriptId != -1);
       
  2352     QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId);
       
  2353 
       
  2354     QCOMPARE(spy->at(4).type, ScriptEngineEvent::ScriptUnload);
       
  2355     QCOMPARE(spy->at(4).scriptId, spy->at(0).scriptId);
       
  2356 }
       
  2357 
       
  2358 QTEST_MAIN(tst_QScriptEngineAgent)
       
  2359 #include "tst_qscriptengineagent.moc"