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