tests/auto/qscriptengine/tst_qscriptengine.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 <qscriptengine.h>
       
    46 #include <qscriptengineagent.h>
       
    47 #include <qscriptvalueiterator.h>
       
    48 #include <qgraphicsitem.h>
       
    49 #include <qstandarditemmodel.h>
       
    50 #include <QtCore/qnumeric.h>
       
    51 #include <stdlib.h>
       
    52 
       
    53 Q_DECLARE_METATYPE(QList<int>)
       
    54 Q_DECLARE_METATYPE(QObjectList)
       
    55 
       
    56 //TESTED_CLASS=
       
    57 //TESTED_FILES=
       
    58 
       
    59 #if defined(Q_OS_SYMBIAN)
       
    60 # define STRINGIFY(x) #x
       
    61 # define TOSTRING(x) STRINGIFY(x)
       
    62 # define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID)
       
    63 #endif
       
    64 
       
    65 // The JavaScriptCore GC marks the C stack. To try to ensure that there is
       
    66 // no JSObject* left in stack memory by the compiler, we call this function
       
    67 // to zap some bytes of memory before calling collectGarbage().
       
    68 static void zapSomeStack()
       
    69 {
       
    70     char buf[4096];
       
    71     memset(buf, 0, sizeof(buf));
       
    72 }
       
    73 
       
    74 static void collectGarbage_helper(QScriptEngine &eng)
       
    75 {
       
    76     zapSomeStack();
       
    77     eng.collectGarbage();
       
    78 }
       
    79 
       
    80 class tst_QScriptEngine : public QObject
       
    81 {
       
    82     Q_OBJECT
       
    83 
       
    84 public:
       
    85     tst_QScriptEngine();
       
    86     virtual ~tst_QScriptEngine();
       
    87 
       
    88 private slots:
       
    89     void constructWithParent();
       
    90     void currentContext();
       
    91     void pushPopContext();
       
    92     void getSetDefaultPrototype();
       
    93     void newFunction();
       
    94     void newObject();
       
    95     void newArray();
       
    96     void newVariant();
       
    97     void newRegExp();
       
    98     void newDate();
       
    99     void newQObject();
       
   100     void newQMetaObject();
       
   101     void newActivationObject();
       
   102     void getSetGlobalObject();
       
   103     void globalObjectProperties();
       
   104     void globalObjectGetterSetterProperty();
       
   105     void builtinFunctionNames_data();
       
   106     void builtinFunctionNames();
       
   107     void checkSyntax_data();
       
   108     void checkSyntax();
       
   109     void canEvaluate_data();
       
   110     void canEvaluate();
       
   111     void evaluate_data();
       
   112     void evaluate();
       
   113     void nestedEvaluate();
       
   114     void uncaughtException();
       
   115     void errorMessage_QT679();
       
   116     void valueConversion();
       
   117     void importExtension();
       
   118     void infiniteRecursion();
       
   119     void castWithPrototypeChain();
       
   120     void castWithMultipleInheritance();
       
   121     void collectGarbage();
       
   122     void gcWithNestedDataStructure();
       
   123     void processEventsWhileRunning();
       
   124     void throwErrorFromProcessEvents();
       
   125     void stacktrace();
       
   126     void numberParsing_data();
       
   127     void numberParsing();
       
   128     void automaticSemicolonInsertion();
       
   129     void abortEvaluation();
       
   130     void isEvaluating();
       
   131     void printFunctionWithCustomHandler();
       
   132     void printThrowsException();
       
   133     void errorConstructors();
       
   134     void argumentsProperty();
       
   135     void numberClass();
       
   136     void forInStatement();
       
   137     void functionExpression();
       
   138     void stringObjects();
       
   139     void getterSetterThisObject();
       
   140     void continueInSwitch();
       
   141     void readOnlyPrototypeProperty();
       
   142     void toObject();
       
   143     void reservedWords_data();
       
   144     void reservedWords();
       
   145     void futureReservedWords_data();
       
   146     void futureReservedWords();
       
   147     void throwInsideWithStatement();
       
   148     void getSetAgent();
       
   149     void reentrancy();
       
   150     void incDecNonObjectProperty();
       
   151     void installTranslatorFunctions();
       
   152     void functionScopes();
       
   153     void nativeFunctionScopes();
       
   154 
       
   155     void qRegExpInport_data();
       
   156     void qRegExpInport();
       
   157 };
       
   158 
       
   159 tst_QScriptEngine::tst_QScriptEngine()
       
   160 {
       
   161 }
       
   162 
       
   163 tst_QScriptEngine::~tst_QScriptEngine()
       
   164 {
       
   165 }
       
   166 
       
   167 void tst_QScriptEngine::constructWithParent()
       
   168 {
       
   169     QPointer<QScriptEngine> ptr;
       
   170     {
       
   171         QObject obj;
       
   172         QScriptEngine *engine = new QScriptEngine(&obj);
       
   173         ptr = engine;
       
   174     }
       
   175     QVERIFY(ptr == 0);
       
   176 }
       
   177 
       
   178 void tst_QScriptEngine::currentContext()
       
   179 {
       
   180     QScriptEngine eng;
       
   181     QScriptContext *globalCtx = eng.currentContext();
       
   182     QVERIFY(globalCtx != 0);
       
   183     QVERIFY(globalCtx->parentContext() == 0);
       
   184     QCOMPARE(globalCtx->engine(), &eng);
       
   185     QCOMPARE(globalCtx->argumentCount(), 0);
       
   186     QCOMPARE(globalCtx->backtrace().size(), 1);
       
   187     QVERIFY(!globalCtx->isCalledAsConstructor());
       
   188     QVERIFY(!globalCtx->callee().isValid());
       
   189     QCOMPARE(globalCtx->state(), QScriptContext::NormalState);
       
   190     QVERIFY(globalCtx->thisObject().strictlyEquals(eng.globalObject()));
       
   191     QVERIFY(globalCtx->activationObject().strictlyEquals(eng.globalObject()));
       
   192     QVERIFY(globalCtx->argumentsObject().isObject());
       
   193 }
       
   194 
       
   195 void tst_QScriptEngine::pushPopContext()
       
   196 {
       
   197     QScriptEngine eng;
       
   198     QScriptContext *globalCtx = eng.currentContext();
       
   199     QScriptContext *ctx = eng.pushContext();
       
   200     QVERIFY(ctx != 0);
       
   201     QCOMPARE(ctx->parentContext(), globalCtx);
       
   202     QVERIFY(!ctx->isCalledAsConstructor());
       
   203     QVERIFY(!ctx->callee().isValid());
       
   204     QVERIFY(ctx->thisObject().strictlyEquals(eng.globalObject()));
       
   205     QCOMPARE(ctx->argumentCount(), 0);
       
   206     QCOMPARE(ctx->backtrace().size(), 2);
       
   207     QCOMPARE(ctx->engine(), &eng);
       
   208     QCOMPARE(ctx->state(), QScriptContext::NormalState);
       
   209     QVERIFY(ctx->activationObject().isObject());
       
   210     QVERIFY(ctx->argumentsObject().isObject());
       
   211 
       
   212     QScriptContext *ctx2 = eng.pushContext();
       
   213     QVERIFY(ctx2 != 0);
       
   214     QCOMPARE(ctx2->parentContext(), ctx);
       
   215     QVERIFY(!ctx2->activationObject().strictlyEquals(ctx->activationObject()));
       
   216     QVERIFY(!ctx2->argumentsObject().strictlyEquals(ctx->argumentsObject()));
       
   217 
       
   218     eng.popContext();
       
   219     eng.popContext();
       
   220     QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
       
   221     eng.popContext(); // ignored
       
   222     QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
       
   223     eng.popContext(); // ignored
       
   224 }
       
   225 
       
   226 static QScriptValue myFunction(QScriptContext *, QScriptEngine *eng)
       
   227 {
       
   228     return eng->nullValue();
       
   229 }
       
   230 
       
   231 static QScriptValue myFunctionWithVoidArg(QScriptContext *, QScriptEngine *eng, void *)
       
   232 {
       
   233     return eng->nullValue();
       
   234 }
       
   235 
       
   236 static QScriptValue myThrowingFunction(QScriptContext *ctx, QScriptEngine *)
       
   237 {
       
   238     return ctx->throwError("foo");
       
   239 }
       
   240 
       
   241 void tst_QScriptEngine::newFunction()
       
   242 {
       
   243     QScriptEngine eng;
       
   244     {
       
   245         QScriptValue fun = eng.newFunction(myFunction);
       
   246         QCOMPARE(fun.isValid(), true);
       
   247         QCOMPARE(fun.isFunction(), true);
       
   248         QCOMPARE(fun.isObject(), true);
       
   249         QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
       
   250         // a prototype property is automatically constructed
       
   251         {
       
   252             QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
       
   253             QVERIFY(prot.isObject());
       
   254             QVERIFY(prot.property("constructor").strictlyEquals(fun));
       
   255             QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
       
   256             QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
       
   257         }
       
   258         // prototype should be Function.prototype
       
   259         QCOMPARE(fun.prototype().isValid(), true);
       
   260         QCOMPARE(fun.prototype().isFunction(), true);
       
   261         QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
       
   262 
       
   263         QCOMPARE(fun.call().isNull(), true);
       
   264         QCOMPARE(fun.construct().isObject(), true);
       
   265     }
       
   266 
       
   267     // the overload that takes a void*
       
   268     {
       
   269         QScriptValue fun = eng.newFunction(myFunctionWithVoidArg, (void*)this);
       
   270         QVERIFY(fun.isFunction());
       
   271         QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
       
   272         // a prototype property is automatically constructed
       
   273         {
       
   274             QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
       
   275             QVERIFY(prot.isObject());
       
   276             QVERIFY(prot.property("constructor").strictlyEquals(fun));
       
   277             QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
       
   278             QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
       
   279         }
       
   280         // prototype should be Function.prototype
       
   281         QCOMPARE(fun.prototype().isValid(), true);
       
   282         QCOMPARE(fun.prototype().isFunction(), true);
       
   283         QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
       
   284 
       
   285         QCOMPARE(fun.call().isNull(), true);
       
   286         QCOMPARE(fun.construct().isObject(), true);
       
   287     }
       
   288 
       
   289     // the overload that takes a prototype
       
   290     {
       
   291         QScriptValue proto = eng.newObject();
       
   292         QScriptValue fun = eng.newFunction(myFunction, proto);
       
   293         QCOMPARE(fun.isValid(), true);
       
   294         QCOMPARE(fun.isFunction(), true);
       
   295         QCOMPARE(fun.isObject(), true);
       
   296         // internal prototype should be Function.prototype
       
   297         QCOMPARE(fun.prototype().isValid(), true);
       
   298         QCOMPARE(fun.prototype().isFunction(), true);
       
   299         QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
       
   300         // public prototype should be the one we passed
       
   301         QCOMPARE(fun.property("prototype").strictlyEquals(proto), true);
       
   302         QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
       
   303         QCOMPARE(proto.property("constructor").strictlyEquals(fun), true);
       
   304         QCOMPARE(proto.propertyFlags("constructor"),
       
   305                  QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
       
   306 
       
   307         QCOMPARE(fun.call().isNull(), true);
       
   308         QCOMPARE(fun.construct().isObject(), true);
       
   309     }
       
   310 }
       
   311 
       
   312 void tst_QScriptEngine::newObject()
       
   313 {
       
   314     QScriptEngine eng;
       
   315     QScriptValue object = eng.newObject();
       
   316     QCOMPARE(object.isValid(), true);
       
   317     QCOMPARE(object.isObject(), true);
       
   318     QCOMPARE(object.isFunction(), false);
       
   319     QCOMPARE(object.scriptClass(), (QScriptClass*)0);
       
   320     // prototype should be Object.prototype
       
   321     QCOMPARE(object.prototype().isValid(), true);
       
   322     QCOMPARE(object.prototype().isObject(), true);
       
   323     QCOMPARE(object.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true);
       
   324 }
       
   325 
       
   326 void tst_QScriptEngine::newArray()
       
   327 {
       
   328     QScriptEngine eng;
       
   329     QScriptValue array = eng.newArray();
       
   330     QCOMPARE(array.isValid(), true);
       
   331     QCOMPARE(array.isArray(), true);
       
   332     QCOMPARE(array.isObject(), true);
       
   333     QVERIFY(!array.isFunction());
       
   334     QCOMPARE(array.scriptClass(), (QScriptClass*)0);
       
   335     // prototype should be Array.prototype
       
   336     QCOMPARE(array.prototype().isValid(), true);
       
   337     QCOMPARE(array.prototype().isArray(), true);
       
   338     QCOMPARE(array.prototype().strictlyEquals(eng.evaluate("Array.prototype")), true);
       
   339 
       
   340     // task 218092
       
   341     {
       
   342         QScriptValue ret = eng.evaluate("[].splice(0, 0, 'a')");
       
   343         QVERIFY(ret.isArray());
       
   344         QCOMPARE(ret.property("length").toInt32(), 0);
       
   345     }
       
   346     {
       
   347         QScriptValue ret = eng.evaluate("['a'].splice(0, 1, 'b')");
       
   348         QVERIFY(ret.isArray());
       
   349         QCOMPARE(ret.property("length").toInt32(), 1);
       
   350     }
       
   351     {
       
   352         QScriptValue ret = eng.evaluate("['a', 'b'].splice(0, 1, 'c')");
       
   353         QVERIFY(ret.isArray());
       
   354         QCOMPARE(ret.property("length").toInt32(), 1);
       
   355     }
       
   356     {
       
   357         QScriptValue ret = eng.evaluate("['a', 'b', 'c'].splice(0, 2, 'd')");
       
   358         QVERIFY(ret.isArray());
       
   359         QCOMPARE(ret.property("length").toInt32(), 2);
       
   360     }
       
   361     {
       
   362         QScriptValue ret = eng.evaluate("['a', 'b', 'c'].splice(1, 2, 'd', 'e', 'f')");
       
   363         QVERIFY(ret.isArray());
       
   364         QCOMPARE(ret.property("length").toInt32(), 2);
       
   365     }
       
   366 
       
   367     // task 233836
       
   368     {
       
   369         QScriptValue ret = eng.evaluate("a = new Array(4294967295); a.push('foo')");
       
   370         QVERIFY(ret.isNumber());
       
   371         QCOMPARE(ret.toInt32(), 0);
       
   372         QCOMPARE(eng.evaluate("a[4294967295]").toString(), QString::fromLatin1("foo"));
       
   373     }
       
   374     {
       
   375         QScriptValue ret = eng.newArray(0xFFFFFFFF);
       
   376         QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
       
   377         ret.setProperty(0xFFFFFFFF, 123);
       
   378         QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
       
   379         QVERIFY(ret.property(0xFFFFFFFF).isNumber());
       
   380         QCOMPARE(ret.property(0xFFFFFFFF).toInt32(), 123);
       
   381         ret.setProperty(123, 456);
       
   382         QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
       
   383         QVERIFY(ret.property(123).isNumber());
       
   384         QCOMPARE(ret.property(123).toInt32(), 456);
       
   385     }
       
   386 }
       
   387 
       
   388 void tst_QScriptEngine::newVariant()
       
   389 {
       
   390     QScriptEngine eng;
       
   391     {
       
   392         QScriptValue opaque = eng.newVariant(QVariant());
       
   393         QCOMPARE(opaque.isValid(), true);
       
   394         QCOMPARE(opaque.isVariant(), true);
       
   395         QVERIFY(!opaque.isFunction());
       
   396         QCOMPARE(opaque.isObject(), true);
       
   397         QCOMPARE(opaque.prototype().isValid(), true);
       
   398         QCOMPARE(opaque.prototype().isVariant(), true);
       
   399         QVERIFY(opaque.property("valueOf").call(opaque).isUndefined());
       
   400     }
       
   401     // default prototype should be set automatically
       
   402     {
       
   403         QScriptValue proto = eng.newObject();
       
   404         eng.setDefaultPrototype(qMetaTypeId<QString>(), proto);
       
   405         QScriptValue ret = eng.newVariant(QVariant(QString::fromLatin1("hello")));
       
   406         QVERIFY(ret.isVariant());
       
   407         QCOMPARE(ret.scriptClass(), (QScriptClass*)0);
       
   408         QVERIFY(ret.prototype().strictlyEquals(proto));
       
   409         eng.setDefaultPrototype(qMetaTypeId<QString>(), QScriptValue());
       
   410         QScriptValue ret2 = eng.newVariant(QVariant(QString::fromLatin1("hello")));
       
   411         QVERIFY(ret2.isVariant());
       
   412         QVERIFY(!ret2.prototype().strictlyEquals(proto));
       
   413     }
       
   414     // "promote" plain object to variant
       
   415     {
       
   416         QScriptValue object = eng.newObject();
       
   417         object.setProperty("foo", eng.newObject());
       
   418         object.setProperty("bar", object.property("foo"));
       
   419         QVERIFY(object.property("foo").isObject());
       
   420         QVERIFY(!object.property("foo").isVariant());
       
   421         QScriptValue originalProto = object.property("foo").prototype();
       
   422         QScriptValue ret = eng.newVariant(object.property("foo"), QVariant(123));
       
   423         QVERIFY(ret.isValid());
       
   424         QVERIFY(ret.strictlyEquals(object.property("foo")));
       
   425         QVERIFY(ret.isVariant());
       
   426         QVERIFY(object.property("foo").isVariant());
       
   427         QVERIFY(object.property("bar").isVariant());
       
   428         QCOMPARE(ret.toVariant(), QVariant(123));
       
   429         QVERIFY(ret.prototype().strictlyEquals(originalProto));
       
   430     }
       
   431     // replace value of existing object
       
   432     {
       
   433         QScriptValue object = eng.newVariant(QVariant(123));
       
   434         QScriptValue ret = eng.newVariant(object, QVariant(456));
       
   435         QVERIFY(ret.isValid());
       
   436         QVERIFY(ret.strictlyEquals(object));
       
   437         QVERIFY(ret.isVariant());
       
   438         QCOMPARE(ret.toVariant(), QVariant(456));
       
   439     }
       
   440 
       
   441     // valueOf() and toString()
       
   442     {
       
   443         QScriptValue object = eng.newVariant(QVariant(123));
       
   444         QScriptValue value = object.property("valueOf").call(object);
       
   445         QVERIFY(value.isNumber());
       
   446         QCOMPARE(value.toInt32(), 123);
       
   447         QCOMPARE(object.toString(), QString::fromLatin1("123"));
       
   448         QCOMPARE(object.toVariant().toString(), object.toString());
       
   449     }
       
   450     {
       
   451         QScriptValue object = eng.newVariant(QVariant(QString::fromLatin1("hello")));
       
   452         QScriptValue value = object.property("valueOf").call(object);
       
   453         QVERIFY(value.isString());
       
   454         QCOMPARE(value.toString(), QString::fromLatin1("hello"));
       
   455         QCOMPARE(object.toString(), QString::fromLatin1("hello"));
       
   456         QCOMPARE(object.toVariant().toString(), object.toString());
       
   457     }
       
   458     {
       
   459         QScriptValue object = eng.newVariant(QVariant(false));
       
   460         QScriptValue value = object.property("valueOf").call(object);
       
   461         QVERIFY(value.isBoolean());
       
   462         QCOMPARE(value.toBoolean(), false);
       
   463         QCOMPARE(object.toString(), QString::fromLatin1("false"));
       
   464         QCOMPARE(object.toVariant().toString(), object.toString());
       
   465     }
       
   466     {
       
   467         QScriptValue object = eng.newVariant(QVariant(QPoint(10, 20)));
       
   468         QScriptValue value = object.property("valueOf").call(object);
       
   469         QVERIFY(value.isObject());
       
   470         QVERIFY(value.strictlyEquals(object));
       
   471         QCOMPARE(object.toString(), QString::fromLatin1("QVariant(QPoint)"));
       
   472     }
       
   473 }
       
   474 
       
   475 void tst_QScriptEngine::newRegExp()
       
   476 {
       
   477     QScriptEngine eng;
       
   478     for (int x = 0; x < 2; ++x) {
       
   479         QScriptValue rexp;
       
   480         if (x == 0)
       
   481             rexp = eng.newRegExp("foo", "bar");
       
   482         else
       
   483             rexp = eng.newRegExp(QRegExp("foo"));
       
   484         QCOMPARE(rexp.isValid(), true);
       
   485         QCOMPARE(rexp.isRegExp(), true);
       
   486         QCOMPARE(rexp.isObject(), true);
       
   487         QVERIFY(rexp.isFunction()); // in JSC, RegExp objects are callable
       
   488         // prototype should be RegExp.prototype
       
   489         QCOMPARE(rexp.prototype().isValid(), true);
       
   490         QCOMPARE(rexp.prototype().isObject(), true);
       
   491         QCOMPARE(rexp.prototype().isRegExp(), false);
       
   492         QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
       
   493 
       
   494         QCOMPARE(rexp.toRegExp().pattern(), QRegExp("foo").pattern());
       
   495     }
       
   496     {
       
   497         QScriptValue r = eng.evaluate("/foo/gim");
       
   498         QVERIFY(r.isRegExp());
       
   499         QCOMPARE(r.toString(), QString::fromLatin1("/foo/gim"));
       
   500 
       
   501         QScriptValue rxCtor = eng.globalObject().property("RegExp");
       
   502         QScriptValue r2 = rxCtor.call(QScriptValue(), QScriptValueList() << r);
       
   503         QVERIFY(r2.isRegExp());
       
   504         QVERIFY(r2.strictlyEquals(r));
       
   505 
       
   506         QScriptValue r3 = rxCtor.call(QScriptValue(), QScriptValueList() << r << "gim");
       
   507         QVERIFY(r3.isError());
       
   508         QCOMPARE(r3.toString(), QString::fromLatin1("TypeError: Cannot supply flags when constructing one RegExp from another."));
       
   509 
       
   510         QScriptValue r4 = rxCtor.call(QScriptValue(), QScriptValueList() << "foo" << "gim");
       
   511         QVERIFY(r4.isRegExp());
       
   512 
       
   513         QScriptValue r5 = rxCtor.construct(QScriptValueList() << r);
       
   514         QVERIFY(r5.isRegExp());
       
   515         QCOMPARE(r5.toString(), QString::fromLatin1("/foo/gim"));
       
   516         // In JSC, constructing a RegExp from another produces the same identical object.
       
   517         // This is different from SpiderMonkey and old back-end.
       
   518         QVERIFY(r5.strictlyEquals(r));
       
   519 
       
   520         QScriptValue r6 = rxCtor.construct(QScriptValueList() << "foo" << "bar");
       
   521         QVERIFY(r6.isError());
       
   522         QCOMPARE(r6.toString(), QString::fromLatin1("SyntaxError: Invalid regular expression: invalid regular expression flag"));
       
   523 
       
   524         QScriptValue r7 = eng.evaluate("/foo/gimp");
       
   525         QVERIFY(r7.isError());
       
   526         QCOMPARE(r7.toString(), QString::fromLatin1("SyntaxError: Invalid regular expression: invalid regular expression flag"));
       
   527 
       
   528         QScriptValue r8 = eng.evaluate("/foo/migmigmig");
       
   529         QVERIFY(r8.isRegExp());
       
   530         QCOMPARE(r8.toString(), QString::fromLatin1("/foo/gim"));
       
   531 
       
   532         QScriptValue r9 = rxCtor.construct();
       
   533         QVERIFY(r9.isRegExp());
       
   534         QCOMPARE(r9.toString(), QString::fromLatin1("/(?:)/"));
       
   535 
       
   536         QScriptValue r10 = rxCtor.construct(QScriptValueList() << "" << "gim");
       
   537         QVERIFY(r10.isRegExp());
       
   538         QCOMPARE(r10.toString(), QString::fromLatin1("/(?:)/gim"));
       
   539 
       
   540         QScriptValue r11 = rxCtor.construct(QScriptValueList() << "{1.*}" << "g");
       
   541         QVERIFY(r11.isRegExp());
       
   542         QCOMPARE(r11.toString(), QString::fromLatin1("/{1.*}/g"));
       
   543     }
       
   544 }
       
   545 
       
   546 void tst_QScriptEngine::newDate()
       
   547 {
       
   548     QScriptEngine eng;
       
   549 
       
   550     {
       
   551         QScriptValue date = eng.newDate(0);
       
   552         QCOMPARE(date.isValid(), true);
       
   553         QCOMPARE(date.isDate(), true);
       
   554         QCOMPARE(date.isObject(), true);
       
   555         QVERIFY(!date.isFunction());
       
   556         // prototype should be Date.prototype
       
   557         QCOMPARE(date.prototype().isValid(), true);
       
   558         QCOMPARE(date.prototype().isDate(), true);
       
   559         QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
       
   560     }
       
   561 
       
   562     {
       
   563         QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::LocalTime);
       
   564         QScriptValue date = eng.newDate(dt);
       
   565         QCOMPARE(date.isValid(), true);
       
   566         QCOMPARE(date.isDate(), true);
       
   567         QCOMPARE(date.isObject(), true);
       
   568         // prototype should be Date.prototype
       
   569         QCOMPARE(date.prototype().isValid(), true);
       
   570         QCOMPARE(date.prototype().isDate(), true);
       
   571         QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
       
   572 
       
   573         QCOMPARE(date.toDateTime(), dt);
       
   574     }
       
   575 
       
   576     {
       
   577         QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::UTC);
       
   578         QScriptValue date = eng.newDate(dt);
       
   579         // toDateTime() result should be in local time
       
   580         QCOMPARE(date.toDateTime(), dt.toLocalTime());
       
   581     }
       
   582 
       
   583     // Date.parse() should return NaN when it fails
       
   584     {
       
   585         QScriptValue ret = eng.evaluate("Date.parse()");
       
   586         QVERIFY(ret.isNumber());
       
   587         QVERIFY(qIsNaN(ret.toNumber()));
       
   588     }
       
   589 
       
   590     // Date.parse() should be able to parse the output of Date().toString()
       
   591 #ifndef Q_WS_WIN // TODO: Test and remove this since 169701 has been fixed
       
   592     {
       
   593         QScriptValue ret = eng.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()");
       
   594         QVERIFY(ret.isBoolean());
       
   595         QCOMPARE(ret.toBoolean(), true);
       
   596     }
       
   597 #endif
       
   598 }
       
   599 
       
   600 void tst_QScriptEngine::newQObject()
       
   601 {
       
   602     QScriptEngine eng;
       
   603 
       
   604     {
       
   605         QScriptValue qobject = eng.newQObject(0);
       
   606         QCOMPARE(qobject.isValid(), true);
       
   607         QCOMPARE(qobject.isNull(), true);
       
   608         QCOMPARE(qobject.isObject(), false);
       
   609         QCOMPARE(qobject.toQObject(), (QObject *)0);
       
   610     }
       
   611     {
       
   612         QScriptValue qobject = eng.newQObject(this);
       
   613         QCOMPARE(qobject.isValid(), true);
       
   614         QCOMPARE(qobject.isQObject(), true);
       
   615         QCOMPARE(qobject.isObject(), true);
       
   616         QCOMPARE(qobject.toQObject(), (QObject *)this);
       
   617         QVERIFY(!qobject.isFunction());
       
   618         // prototype should be QObject.prototype
       
   619         QCOMPARE(qobject.prototype().isValid(), true);
       
   620         QCOMPARE(qobject.prototype().isQObject(), true);
       
   621         QCOMPARE(qobject.scriptClass(), (QScriptClass*)0);
       
   622     }
       
   623 
       
   624     // test ownership
       
   625     {
       
   626         QPointer<QObject> ptr = new QObject();
       
   627         QVERIFY(ptr != 0);
       
   628         {
       
   629             QScriptValue v = eng.newQObject(ptr, QScriptEngine::ScriptOwnership);
       
   630         }
       
   631         eng.evaluate("gc()");
       
   632         if (ptr)
       
   633             QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue);
       
   634         QVERIFY(ptr == 0);
       
   635     }
       
   636     {
       
   637         QPointer<QObject> ptr = new QObject();
       
   638         QVERIFY(ptr != 0);
       
   639         {
       
   640             QScriptValue v = eng.newQObject(ptr, QScriptEngine::QtOwnership);
       
   641         }
       
   642         QObject *before = ptr;
       
   643         eng.evaluate("gc()");
       
   644         QVERIFY(ptr == before);
       
   645         delete ptr;
       
   646     }
       
   647     {
       
   648         QObject *parent = new QObject();
       
   649         QObject *child = new QObject(parent);
       
   650         QScriptValue v = eng.newQObject(child, QScriptEngine::QtOwnership);
       
   651         QCOMPARE(v.toQObject(), child);
       
   652         delete parent;
       
   653         QCOMPARE(v.toQObject(), (QObject *)0);
       
   654     }
       
   655     {
       
   656         QPointer<QObject> ptr = new QObject();
       
   657         QVERIFY(ptr != 0);
       
   658         {
       
   659             QScriptValue v = eng.newQObject(ptr, QScriptEngine::AutoOwnership);
       
   660         }
       
   661         eng.evaluate("gc()");
       
   662         // no parent, so it should be like ScriptOwnership
       
   663         if (ptr)
       
   664             QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue);
       
   665         QVERIFY(ptr == 0);
       
   666     }
       
   667     {
       
   668         QObject *parent = new QObject();
       
   669         QPointer<QObject> child = new QObject(parent);
       
   670         QVERIFY(child != 0);
       
   671         {
       
   672             QScriptValue v = eng.newQObject(child, QScriptEngine::AutoOwnership);
       
   673         }
       
   674         eng.evaluate("gc()");
       
   675         // has parent, so it should be like QtOwnership
       
   676         QVERIFY(child != 0);
       
   677         delete parent;
       
   678     }
       
   679 
       
   680     // "promote" plain object to QObject
       
   681     {
       
   682         QScriptValue obj = eng.newObject();
       
   683         QScriptValue originalProto = obj.prototype();
       
   684         QScriptValue ret = eng.newQObject(obj, this);
       
   685         QVERIFY(ret.isValid());
       
   686         QVERIFY(ret.isQObject());
       
   687         QVERIFY(ret.strictlyEquals(obj));
       
   688         QVERIFY(obj.isQObject());
       
   689         QCOMPARE(ret.toQObject(), (QObject *)this);
       
   690         QVERIFY(ret.prototype().strictlyEquals(originalProto));
       
   691         QScriptValue val = ret.property("objectName");
       
   692         QVERIFY(val.isString());
       
   693     }
       
   694     // "promote" variant object to QObject
       
   695     {
       
   696         QScriptValue obj = eng.newVariant(123);
       
   697         QVERIFY(obj.isVariant());
       
   698         QScriptValue originalProto = obj.prototype();
       
   699         QScriptValue ret = eng.newQObject(obj, this);
       
   700         QVERIFY(ret.isQObject());
       
   701         QVERIFY(ret.strictlyEquals(obj));
       
   702         QVERIFY(obj.isQObject());
       
   703         QCOMPARE(ret.toQObject(), (QObject *)this);
       
   704         QVERIFY(ret.prototype().strictlyEquals(originalProto));
       
   705     }
       
   706     // replace QObject* of existing object
       
   707     {
       
   708         QScriptValue object = eng.newVariant(123);
       
   709         QScriptValue originalProto = object.prototype();
       
   710         QObject otherQObject;
       
   711         QScriptValue ret = eng.newQObject(object, &otherQObject);
       
   712         QVERIFY(ret.isValid());
       
   713         QVERIFY(ret.isQObject());
       
   714         QVERIFY(ret.strictlyEquals(object));
       
   715         QCOMPARE(ret.toQObject(), (QObject *)&otherQObject);
       
   716         QVERIFY(ret.prototype().strictlyEquals(originalProto));
       
   717     }
       
   718 
       
   719     // calling newQObject() several times with same object
       
   720     for (int x = 0; x < 2; ++x) {
       
   721         QObject qobj;
       
   722         // the default is to create a new wrapper object
       
   723         QScriptValue obj1 = eng.newQObject(&qobj);
       
   724         QScriptValue obj2 = eng.newQObject(&qobj);
       
   725         QVERIFY(!obj2.strictlyEquals(obj1));
       
   726 
       
   727         QScriptEngine::QObjectWrapOptions opt = 0;
       
   728         bool preferExisting = (x != 0);
       
   729         if (preferExisting)
       
   730             opt |= QScriptEngine::PreferExistingWrapperObject;
       
   731 
       
   732         QScriptValue obj3 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt);
       
   733         QVERIFY(!obj3.strictlyEquals(obj2));
       
   734         QScriptValue obj4 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt);
       
   735         QCOMPARE(obj4.strictlyEquals(obj3), preferExisting);
       
   736 
       
   737         QScriptValue obj5 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt);
       
   738         QVERIFY(!obj5.strictlyEquals(obj4));
       
   739         QScriptValue obj6 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt);
       
   740         QCOMPARE(obj6.strictlyEquals(obj5), preferExisting);
       
   741 
       
   742         QScriptValue obj7 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership,
       
   743                                            QScriptEngine::ExcludeSuperClassMethods | opt);
       
   744         QVERIFY(!obj7.strictlyEquals(obj6));
       
   745         QScriptValue obj8 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership,
       
   746                                            QScriptEngine::ExcludeSuperClassMethods | opt);
       
   747         QCOMPARE(obj8.strictlyEquals(obj7), preferExisting);
       
   748     }
       
   749 
       
   750     // newQObject() should set the default prototype, if one has been registered
       
   751     {
       
   752         QScriptValue oldQObjectProto = eng.defaultPrototype(qMetaTypeId<QObject*>());
       
   753 
       
   754         QScriptValue qobjectProto = eng.newObject();
       
   755         eng.setDefaultPrototype(qMetaTypeId<QObject*>(), qobjectProto);
       
   756         {
       
   757             QScriptValue ret = eng.newQObject(this);
       
   758             QVERIFY(ret.prototype().equals(qobjectProto));
       
   759         }
       
   760         QScriptValue tstProto = eng.newObject();
       
   761         int typeId = qRegisterMetaType<tst_QScriptEngine*>("tst_QScriptEngine*");
       
   762         eng.setDefaultPrototype(typeId, tstProto);
       
   763         {
       
   764             QScriptValue ret = eng.newQObject(this);
       
   765             QVERIFY(ret.prototype().equals(tstProto));
       
   766         }
       
   767 
       
   768         eng.setDefaultPrototype(qMetaTypeId<QObject*>(), oldQObjectProto);
       
   769         eng.setDefaultPrototype(typeId, QScriptValue());
       
   770     }
       
   771 }
       
   772 
       
   773 QT_BEGIN_NAMESPACE
       
   774 Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*)
       
   775 Q_SCRIPT_DECLARE_QMETAOBJECT(QWidget, QWidget*)
       
   776 QT_END_NAMESPACE
       
   777 
       
   778 static QScriptValue myConstructor(QScriptContext *ctx, QScriptEngine *eng)
       
   779 {
       
   780     QScriptValue obj;
       
   781     if (ctx->isCalledAsConstructor()) {
       
   782         obj = ctx->thisObject();
       
   783     } else {
       
   784         obj = eng->newObject();
       
   785         obj.setPrototype(ctx->callee().property("prototype"));
       
   786     }
       
   787     obj.setProperty("isCalledAsConstructor", QScriptValue(eng, ctx->isCalledAsConstructor()));
       
   788     return obj;
       
   789 }
       
   790 
       
   791 void tst_QScriptEngine::newQMetaObject()
       
   792 {
       
   793     QScriptEngine eng;
       
   794 #if 0
       
   795     QScriptValue qclass = eng.newQMetaObject<QObject>();
       
   796     QScriptValue qclass2 = eng.newQMetaObject<QWidget>();
       
   797 #else
       
   798     QScriptValue qclass = qScriptValueFromQMetaObject<QObject>(&eng);
       
   799     QScriptValue qclass2 = qScriptValueFromQMetaObject<QWidget>(&eng);
       
   800 #endif
       
   801     QCOMPARE(qclass.isValid(), true);
       
   802     QCOMPARE(qclass.isQMetaObject(), true);
       
   803     QCOMPARE(qclass.toQMetaObject(), &QObject::staticMetaObject);
       
   804     QCOMPARE(qclass.isFunction(), true);
       
   805     QVERIFY(qclass.property("prototype").isObject());
       
   806 
       
   807     QCOMPARE(qclass2.isValid(), true);
       
   808     QCOMPARE(qclass2.isQMetaObject(), true);
       
   809     QCOMPARE(qclass2.toQMetaObject(), &QWidget::staticMetaObject);
       
   810     QCOMPARE(qclass2.isFunction(), true);
       
   811     QVERIFY(qclass2.property("prototype").isObject());
       
   812 
       
   813     // prototype should be QMetaObject.prototype
       
   814     QCOMPARE(qclass.prototype().isObject(), true);
       
   815     QCOMPARE(qclass2.prototype().isObject(), true);
       
   816 
       
   817     QScriptValue instance = qclass.construct();
       
   818     QCOMPARE(instance.isQObject(), true);
       
   819     QCOMPARE(instance.toQObject()->metaObject(), qclass.toQMetaObject());
       
   820     QVERIFY(instance.instanceOf(qclass));
       
   821 
       
   822     QScriptValue instance2 = qclass2.construct();
       
   823     QCOMPARE(instance2.isQObject(), true);
       
   824     QCOMPARE(instance2.toQObject()->metaObject(), qclass2.toQMetaObject());
       
   825     QVERIFY(instance2.instanceOf(qclass2));
       
   826 
       
   827     QScriptValueList args;
       
   828     args << instance;
       
   829     QScriptValue instance3 = qclass.construct(args);
       
   830     QCOMPARE(instance3.isQObject(), true);
       
   831     QCOMPARE(instance3.toQObject()->parent(), instance.toQObject());
       
   832     QVERIFY(instance3.instanceOf(qclass));
       
   833     args.clear();
       
   834 
       
   835     QPointer<QObject> qpointer1 = instance.toQObject();
       
   836     QPointer<QObject> qpointer2 = instance2.toQObject();
       
   837     QPointer<QObject> qpointer3 = instance3.toQObject();
       
   838 
       
   839     QVERIFY(qpointer1);
       
   840     QVERIFY(qpointer2);
       
   841     QVERIFY(qpointer3);
       
   842 
       
   843     // verify that AutoOwnership is in effect
       
   844     instance = QScriptValue();
       
   845     collectGarbage_helper(eng);
       
   846 
       
   847     QVERIFY(!qpointer1);
       
   848     QVERIFY(qpointer2);
       
   849     QVERIFY(!qpointer3); // was child of instance
       
   850 
       
   851     QVERIFY(instance.toQObject() == 0);
       
   852     QVERIFY(instance3.toQObject() == 0); // was child of instance
       
   853     QVERIFY(instance2.toQObject() != 0);
       
   854     instance2 = QScriptValue();
       
   855     collectGarbage_helper(eng);
       
   856     QVERIFY(instance2.toQObject() == 0);
       
   857 
       
   858     // with custom constructor
       
   859     QScriptValue ctor = eng.newFunction(myConstructor);
       
   860     QScriptValue qclass3 = eng.newQMetaObject(&QObject::staticMetaObject, ctor);
       
   861     QVERIFY(qclass3.property("prototype").equals(ctor.property("prototype")));
       
   862     {
       
   863         QScriptValue ret = qclass3.call();
       
   864         QVERIFY(ret.isObject());
       
   865         QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
       
   866         QVERIFY(!ret.property("isCalledAsConstructor").toBoolean());
       
   867         QVERIFY(ret.instanceOf(qclass3));
       
   868     }
       
   869     {
       
   870         QScriptValue ret = qclass3.construct();
       
   871         QVERIFY(ret.isObject());
       
   872         QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
       
   873         QVERIFY(ret.property("isCalledAsConstructor").toBoolean());
       
   874         QVERIFY(ret.instanceOf(qclass3));
       
   875     }
       
   876 
       
   877     // subclassing
       
   878     qclass2.setProperty("prototype", qclass.construct());
       
   879     QVERIFY(qclass2.construct().instanceOf(qclass));
       
   880 
       
   881     // with meta-constructor
       
   882     QScriptValue qclass4 = eng.newQMetaObject(&QObject::staticMetaObject);
       
   883     {
       
   884         QScriptValue inst = qclass4.construct();
       
   885         QVERIFY(inst.isQObject());
       
   886         QVERIFY(inst.toQObject() != 0);
       
   887         QCOMPARE(inst.toQObject()->parent(), (QObject*)0);
       
   888         QVERIFY(inst.instanceOf(qclass4));
       
   889     }
       
   890     {
       
   891         QScriptValue inst = qclass4.construct(QScriptValueList() << eng.newQObject(this));
       
   892         QVERIFY(inst.isQObject());
       
   893         QVERIFY(inst.toQObject() != 0);
       
   894         QCOMPARE(inst.toQObject()->parent(), (QObject*)this);
       
   895         QVERIFY(inst.instanceOf(qclass4));
       
   896     }
       
   897 }
       
   898 
       
   899 void tst_QScriptEngine::newActivationObject()
       
   900 {
       
   901     QSKIP("internal function not implemented in JSC-based back-end", SkipAll);
       
   902     QScriptEngine eng;
       
   903     QScriptValue act = eng.newActivationObject();
       
   904     QEXPECT_FAIL("", "", Continue);
       
   905     QCOMPARE(act.isValid(), true);
       
   906     QEXPECT_FAIL("", "", Continue);
       
   907     QCOMPARE(act.isObject(), true);
       
   908     QVERIFY(!act.isFunction());
       
   909     QScriptValue v(&eng, 123);
       
   910     act.setProperty("prop", v);
       
   911     QEXPECT_FAIL("", "", Continue);
       
   912     QCOMPARE(act.property("prop").strictlyEquals(v), true);
       
   913     QCOMPARE(act.scope().isValid(), false);
       
   914     QEXPECT_FAIL("", "", Continue);
       
   915     QVERIFY(act.prototype().isNull());
       
   916 }
       
   917 
       
   918 void tst_QScriptEngine::getSetGlobalObject()
       
   919 {
       
   920     QScriptEngine eng;
       
   921     QScriptValue glob = eng.globalObject();
       
   922     QCOMPARE(glob.isValid(), true);
       
   923     QCOMPARE(glob.isObject(), true);
       
   924     QVERIFY(!glob.isFunction());
       
   925     QVERIFY(eng.currentContext()->thisObject().strictlyEquals(glob));
       
   926     QVERIFY(eng.currentContext()->activationObject().strictlyEquals(glob));
       
   927     QCOMPARE(glob.toString(), QString::fromLatin1("[object global]"));
       
   928     // prototype should be Object.prototype
       
   929     QCOMPARE(glob.prototype().isValid(), true);
       
   930     QCOMPARE(glob.prototype().isObject(), true);
       
   931     QCOMPARE(glob.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true);
       
   932 
       
   933     QScriptValue obj = eng.newObject();
       
   934     eng.setGlobalObject(obj);
       
   935     QVERIFY(eng.globalObject().strictlyEquals(obj));
       
   936     QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
       
   937     QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
       
   938     QVERIFY(eng.evaluate("this").strictlyEquals(obj));
       
   939     QCOMPARE(eng.globalObject().toString(), QString::fromLatin1("[object Object]"));
       
   940 
       
   941     glob = QScriptValue(); // kill reference to old global object
       
   942     collectGarbage_helper(eng);
       
   943     obj = eng.newObject();
       
   944     eng.setGlobalObject(obj);
       
   945     QVERIFY(eng.globalObject().strictlyEquals(obj));
       
   946     QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
       
   947     QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
       
   948 
       
   949     collectGarbage_helper(eng);
       
   950     QVERIFY(eng.globalObject().strictlyEquals(obj));
       
   951     QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
       
   952     QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
       
   953 
       
   954     QVERIFY(!obj.property("foo").isValid());
       
   955     eng.evaluate("var foo = 123");
       
   956     {
       
   957         QScriptValue ret = obj.property("foo");
       
   958         QVERIFY(ret.isNumber());
       
   959         QCOMPARE(ret.toInt32(), 123);
       
   960     }
       
   961 
       
   962     QVERIFY(!obj.property("bar").isValid());
       
   963     eng.evaluate("bar = 456");
       
   964     {
       
   965         QScriptValue ret = obj.property("bar");
       
   966         QVERIFY(ret.isNumber());
       
   967         QCOMPARE(ret.toInt32(), 456);
       
   968     }
       
   969 
       
   970     QVERIFY(!obj.property("baz").isValid());
       
   971     eng.evaluate("this['baz'] = 789");
       
   972     {
       
   973         QScriptValue ret = obj.property("baz");
       
   974         QVERIFY(ret.isNumber());
       
   975         QCOMPARE(ret.toInt32(), 789);
       
   976     }
       
   977 
       
   978     {
       
   979         QScriptValue ret = eng.evaluate("(function() { return this; })()");
       
   980         QVERIFY(ret.strictlyEquals(obj));
       
   981     }
       
   982 }
       
   983 
       
   984 static QScriptValue getSetFoo(QScriptContext *ctx, QScriptEngine *)
       
   985 {
       
   986     if (ctx->argumentCount() > 0)
       
   987         ctx->thisObject().setProperty("foo", ctx->argument(0));
       
   988     return ctx->thisObject().property("foo");
       
   989 }
       
   990 
       
   991 void tst_QScriptEngine::globalObjectProperties()
       
   992 {
       
   993     QScriptEngine eng;
       
   994     QScriptValue global = eng.globalObject();
       
   995 
       
   996     QVERIFY(global.property("NaN").isNumber());
       
   997     QVERIFY(qIsNaN(global.property("NaN").toNumber()));
       
   998     QCOMPARE(global.propertyFlags("NaN"), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
       
   999 
       
  1000     QVERIFY(global.property("Infinity").isNumber());
       
  1001     QVERIFY(qIsInf(global.property("Infinity").toNumber()));
       
  1002     QCOMPARE(global.propertyFlags("NaN"), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
       
  1003 
       
  1004     QVERIFY(global.property("undefined").isUndefined());
       
  1005     QCOMPARE(global.propertyFlags("undefined"), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
       
  1006 
       
  1007     QVERIFY(global.property("eval").isFunction());
       
  1008     QCOMPARE(global.propertyFlags("eval"), QScriptValue::SkipInEnumeration);
       
  1009 
       
  1010     QVERIFY(global.property("parseInt").isFunction());
       
  1011     QCOMPARE(global.propertyFlags("parseInt"), QScriptValue::SkipInEnumeration);
       
  1012 
       
  1013     QVERIFY(global.property("parseFloat").isFunction());
       
  1014     QCOMPARE(global.propertyFlags("parseFloat"), QScriptValue::SkipInEnumeration);
       
  1015 
       
  1016     QVERIFY(global.property("isNaN").isFunction());
       
  1017     QCOMPARE(global.propertyFlags("isNaN"), QScriptValue::SkipInEnumeration);
       
  1018 
       
  1019     QVERIFY(global.property("isFinite").isFunction());
       
  1020     QCOMPARE(global.propertyFlags("isFinite"), QScriptValue::SkipInEnumeration);
       
  1021 
       
  1022     QVERIFY(global.property("decodeURI").isFunction());
       
  1023     QCOMPARE(global.propertyFlags("decodeURI"), QScriptValue::SkipInEnumeration);
       
  1024 
       
  1025     QVERIFY(global.property("decodeURIComponent").isFunction());
       
  1026     QCOMPARE(global.propertyFlags("decodeURIComponent"), QScriptValue::SkipInEnumeration);
       
  1027 
       
  1028     QVERIFY(global.property("encodeURI").isFunction());
       
  1029     QCOMPARE(global.propertyFlags("encodeURI"), QScriptValue::SkipInEnumeration);
       
  1030 
       
  1031     QVERIFY(global.property("encodeURIComponent").isFunction());
       
  1032     QCOMPARE(global.propertyFlags("encodeURIComponent"), QScriptValue::SkipInEnumeration);
       
  1033 
       
  1034     QVERIFY(global.property("Object").isFunction());
       
  1035     QCOMPARE(global.propertyFlags("Object"), QScriptValue::SkipInEnumeration);
       
  1036     QVERIFY(global.property("Function").isFunction());
       
  1037     QCOMPARE(global.propertyFlags("Function"), QScriptValue::SkipInEnumeration);
       
  1038     QVERIFY(global.property("Array").isFunction());
       
  1039     QCOMPARE(global.propertyFlags("Array"), QScriptValue::SkipInEnumeration);
       
  1040     QVERIFY(global.property("String").isFunction());
       
  1041     QCOMPARE(global.propertyFlags("String"), QScriptValue::SkipInEnumeration);
       
  1042     QVERIFY(global.property("Boolean").isFunction());
       
  1043     QCOMPARE(global.propertyFlags("Boolean"), QScriptValue::SkipInEnumeration);
       
  1044     QVERIFY(global.property("Number").isFunction());
       
  1045     QCOMPARE(global.propertyFlags("Number"), QScriptValue::SkipInEnumeration);
       
  1046     QVERIFY(global.property("Date").isFunction());
       
  1047     QCOMPARE(global.propertyFlags("Date"), QScriptValue::SkipInEnumeration);
       
  1048     QVERIFY(global.property("RegExp").isFunction());
       
  1049     QCOMPARE(global.propertyFlags("RegExp"), QScriptValue::SkipInEnumeration);
       
  1050     QVERIFY(global.property("Error").isFunction());
       
  1051     QCOMPARE(global.propertyFlags("Error"), QScriptValue::SkipInEnumeration);
       
  1052     QVERIFY(global.property("EvalError").isFunction());
       
  1053     QCOMPARE(global.propertyFlags("EvalError"), QScriptValue::SkipInEnumeration);
       
  1054     QVERIFY(global.property("RangeError").isFunction());
       
  1055     QCOMPARE(global.propertyFlags("RangeError"), QScriptValue::SkipInEnumeration);
       
  1056     QVERIFY(global.property("ReferenceError").isFunction());
       
  1057     QCOMPARE(global.propertyFlags("ReferenceError"), QScriptValue::SkipInEnumeration);
       
  1058     QVERIFY(global.property("SyntaxError").isFunction());
       
  1059     QCOMPARE(global.propertyFlags("SyntaxError"), QScriptValue::SkipInEnumeration);
       
  1060     QVERIFY(global.property("TypeError").isFunction());
       
  1061     QCOMPARE(global.propertyFlags("TypeError"), QScriptValue::SkipInEnumeration);
       
  1062     QVERIFY(global.property("URIError").isFunction());
       
  1063     QCOMPARE(global.propertyFlags("URIError"), QScriptValue::SkipInEnumeration);
       
  1064     QVERIFY(global.property("Math").isObject());
       
  1065     QVERIFY(!global.property("Math").isFunction());
       
  1066     QEXPECT_FAIL("", "[ECMA compliance] JSC sets DontDelete flag for Math object", Continue);
       
  1067     QCOMPARE(global.propertyFlags("Math"), QScriptValue::SkipInEnumeration);
       
  1068 
       
  1069     // enumeration
       
  1070     QSet<QString> expectedNames;
       
  1071     expectedNames
       
  1072         << "isNaN"
       
  1073         << "parseFloat"
       
  1074         << "String"
       
  1075         << "EvalError"
       
  1076         << "URIError"
       
  1077         << "Math"
       
  1078         << "encodeURIComponent"
       
  1079         << "RangeError"
       
  1080         << "eval"
       
  1081         << "isFinite"
       
  1082         << "ReferenceError"
       
  1083         << "Infinity"
       
  1084         << "Function"
       
  1085         << "RegExp"
       
  1086         << "Number"
       
  1087         << "parseInt"
       
  1088         << "Object"
       
  1089         << "decodeURI"
       
  1090         << "TypeError"
       
  1091         << "Boolean"
       
  1092         << "encodeURI"
       
  1093         << "NaN"
       
  1094         << "Error"
       
  1095         << "decodeURIComponent"
       
  1096         << "Date"
       
  1097         << "Array"
       
  1098         << "escape"
       
  1099         << "unescape"
       
  1100         << "SyntaxError"
       
  1101         << "undefined"
       
  1102         // non-standard
       
  1103         << "gc"
       
  1104         << "version"
       
  1105         << "print"
       
  1106         // JavaScriptCore
       
  1107         << "JSON"
       
  1108         ;
       
  1109     QSet<QString> actualNames;
       
  1110     {
       
  1111         QScriptValueIterator it(global);
       
  1112         while (it.hasNext()) {
       
  1113             it.next();
       
  1114             actualNames.insert(it.name());
       
  1115         }
       
  1116     }
       
  1117 
       
  1118     QSet<QString> remainingNames = actualNames;
       
  1119     {
       
  1120         QSet<QString>::const_iterator it;
       
  1121         for (it = expectedNames.constBegin(); it != expectedNames.constEnd(); ++it) {
       
  1122             QString name = *it;
       
  1123             QVERIFY(actualNames.contains(name));
       
  1124             remainingNames.remove(name);
       
  1125         }
       
  1126     }
       
  1127     QVERIFY(remainingNames.isEmpty());
       
  1128 
       
  1129     // create property with no attributes
       
  1130     {
       
  1131         QString name = QString::fromLatin1("foo");
       
  1132         QVERIFY(!global.property(name).isValid());
       
  1133         QScriptValue val(123);
       
  1134         global.setProperty(name, val);
       
  1135         QVERIFY(global.property(name).equals(val));
       
  1136         QVERIFY(global.propertyFlags(name) == 0);
       
  1137         global.setProperty(name, QScriptValue());
       
  1138         QVERIFY(!global.property(name).isValid());
       
  1139     }
       
  1140     // create property with attributes
       
  1141     {
       
  1142         QString name = QString::fromLatin1("bar");
       
  1143         QVERIFY(!global.property(name).isValid());
       
  1144         QScriptValue val(QString::fromLatin1("ciao"));
       
  1145         QScriptValue::PropertyFlags flags = QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration;
       
  1146         global.setProperty(name, val, flags);
       
  1147         QVERIFY(global.property(name).equals(val));
       
  1148         QEXPECT_FAIL("", "custom Global Object properties don't retain attributes", Continue);
       
  1149         QCOMPARE(global.propertyFlags(name), flags);
       
  1150         global.setProperty(name, QScriptValue());
       
  1151         QVERIFY(!global.property(name).isValid());
       
  1152     }
       
  1153 }
       
  1154 
       
  1155 void tst_QScriptEngine::globalObjectGetterSetterProperty()
       
  1156 {
       
  1157     QScriptEngine engine;
       
  1158     QScriptValue global = engine.globalObject();
       
  1159     global.setProperty("bar", engine.newFunction(getSetFoo),
       
  1160                        QScriptValue::PropertySetter | QScriptValue::PropertyGetter);
       
  1161     global.setProperty("foo", 123);
       
  1162     QVERIFY(global.property("bar").equals(global.property("foo")));
       
  1163     QVERIFY(engine.evaluate("bar").equals(global.property("foo")));
       
  1164     global.setProperty("bar", 456);
       
  1165     QVERIFY(global.property("bar").equals(global.property("foo")));
       
  1166 
       
  1167     engine.evaluate("__defineGetter__('baz', function() { return 789; })");
       
  1168     QVERIFY(engine.evaluate("baz").equals(789));
       
  1169     QVERIFY(global.property("baz").equals(789));
       
  1170 }
       
  1171 
       
  1172 void tst_QScriptEngine::builtinFunctionNames_data()
       
  1173 {
       
  1174     QTest::addColumn<QString>("expression");
       
  1175     QTest::addColumn<QString>("expectedName");
       
  1176 
       
  1177     QTest::newRow("print") << QString("print") << QString("print");
       
  1178     QTest::newRow("parseInt") << QString("parseInt") << QString("parseInt");
       
  1179     QTest::newRow("parseFloat") << QString("parseFloat") << QString("parseFloat");
       
  1180     QTest::newRow("isNaN") << QString("isNaN") << QString("isNaN");
       
  1181     QTest::newRow("isFinite") << QString("isFinite") << QString("isFinite");
       
  1182     QTest::newRow("decodeURI") << QString("decodeURI") << QString("decodeURI");
       
  1183     QTest::newRow("decodeURIComponent") << QString("decodeURIComponent") << QString("decodeURIComponent");
       
  1184     QTest::newRow("encodeURI") << QString("encodeURI") << QString("encodeURI");
       
  1185     QTest::newRow("encodeURIComponent") << QString("encodeURIComponent") << QString("encodeURIComponent");
       
  1186     QTest::newRow("escape") << QString("escape") << QString("escape");
       
  1187     QTest::newRow("unescape") << QString("unescape") << QString("unescape");
       
  1188     QTest::newRow("version") << QString("version") << QString("version");
       
  1189     QTest::newRow("gc") << QString("gc") << QString("gc");
       
  1190 
       
  1191     QTest::newRow("Array") << QString("Array") << QString("Array");
       
  1192     QTest::newRow("Array.prototype.toString") << QString("Array.prototype.toString") << QString("toString");
       
  1193     QTest::newRow("Array.prototype.toLocaleString") << QString("Array.prototype.toLocaleString") << QString("toLocaleString");
       
  1194     QTest::newRow("Array.prototype.concat") << QString("Array.prototype.concat") << QString("concat");
       
  1195     QTest::newRow("Array.prototype.join") << QString("Array.prototype.join") << QString("join");
       
  1196     QTest::newRow("Array.prototype.pop") << QString("Array.prototype.pop") << QString("pop");
       
  1197     QTest::newRow("Array.prototype.push") << QString("Array.prototype.push") << QString("push");
       
  1198     QTest::newRow("Array.prototype.reverse") << QString("Array.prototype.reverse") << QString("reverse");
       
  1199     QTest::newRow("Array.prototype.shift") << QString("Array.prototype.shift") << QString("shift");
       
  1200     QTest::newRow("Array.prototype.slice") << QString("Array.prototype.slice") << QString("slice");
       
  1201     QTest::newRow("Array.prototype.sort") << QString("Array.prototype.sort") << QString("sort");
       
  1202     QTest::newRow("Array.prototype.splice") << QString("Array.prototype.splice") << QString("splice");
       
  1203     QTest::newRow("Array.prototype.unshift") << QString("Array.prototype.unshift") << QString("unshift");
       
  1204 
       
  1205     QTest::newRow("Boolean") << QString("Boolean") << QString("Boolean");
       
  1206     QTest::newRow("Boolean.prototype.toString") << QString("Boolean.prototype.toString") << QString("toString");
       
  1207 
       
  1208     QTest::newRow("Date") << QString("Date") << QString("Date");
       
  1209     QTest::newRow("Date.prototype.toString") << QString("Date.prototype.toString") << QString("toString");
       
  1210     QTest::newRow("Date.prototype.toDateString") << QString("Date.prototype.toDateString") << QString("toDateString");
       
  1211     QTest::newRow("Date.prototype.toTimeString") << QString("Date.prototype.toTimeString") << QString("toTimeString");
       
  1212     QTest::newRow("Date.prototype.toLocaleString") << QString("Date.prototype.toLocaleString") << QString("toLocaleString");
       
  1213     QTest::newRow("Date.prototype.toLocaleDateString") << QString("Date.prototype.toLocaleDateString") << QString("toLocaleDateString");
       
  1214     QTest::newRow("Date.prototype.toLocaleTimeString") << QString("Date.prototype.toLocaleTimeString") << QString("toLocaleTimeString");
       
  1215     QTest::newRow("Date.prototype.valueOf") << QString("Date.prototype.valueOf") << QString("valueOf");
       
  1216     QTest::newRow("Date.prototype.getTime") << QString("Date.prototype.getTime") << QString("getTime");
       
  1217     QTest::newRow("Date.prototype.getYear") << QString("Date.prototype.getYear") << QString("getYear");
       
  1218     QTest::newRow("Date.prototype.getFullYear") << QString("Date.prototype.getFullYear") << QString("getFullYear");
       
  1219     QTest::newRow("Date.prototype.getUTCFullYear") << QString("Date.prototype.getUTCFullYear") << QString("getUTCFullYear");
       
  1220     QTest::newRow("Date.prototype.getMonth") << QString("Date.prototype.getMonth") << QString("getMonth");
       
  1221     QTest::newRow("Date.prototype.getUTCMonth") << QString("Date.prototype.getUTCMonth") << QString("getUTCMonth");
       
  1222     QTest::newRow("Date.prototype.getDate") << QString("Date.prototype.getDate") << QString("getDate");
       
  1223     QTest::newRow("Date.prototype.getUTCDate") << QString("Date.prototype.getUTCDate") << QString("getUTCDate");
       
  1224     QTest::newRow("Date.prototype.getDay") << QString("Date.prototype.getDay") << QString("getDay");
       
  1225     QTest::newRow("Date.prototype.getUTCDay") << QString("Date.prototype.getUTCDay") << QString("getUTCDay");
       
  1226     QTest::newRow("Date.prototype.getHours") << QString("Date.prototype.getHours") << QString("getHours");
       
  1227     QTest::newRow("Date.prototype.getUTCHours") << QString("Date.prototype.getUTCHours") << QString("getUTCHours");
       
  1228     QTest::newRow("Date.prototype.getMinutes") << QString("Date.prototype.getMinutes") << QString("getMinutes");
       
  1229     QTest::newRow("Date.prototype.getUTCMinutes") << QString("Date.prototype.getUTCMinutes") << QString("getUTCMinutes");
       
  1230     QTest::newRow("Date.prototype.getSeconds") << QString("Date.prototype.getSeconds") << QString("getSeconds");
       
  1231     QTest::newRow("Date.prototype.getUTCSeconds") << QString("Date.prototype.getUTCSeconds") << QString("getUTCSeconds");
       
  1232     QTest::newRow("Date.prototype.getMilliseconds") << QString("Date.prototype.getMilliseconds") << QString("getMilliseconds");
       
  1233     QTest::newRow("Date.prototype.getUTCMilliseconds") << QString("Date.prototype.getUTCMilliseconds") << QString("getUTCMilliseconds");
       
  1234     QTest::newRow("Date.prototype.getTimezoneOffset") << QString("Date.prototype.getTimezoneOffset") << QString("getTimezoneOffset");
       
  1235     QTest::newRow("Date.prototype.setTime") << QString("Date.prototype.setTime") << QString("setTime");
       
  1236     QTest::newRow("Date.prototype.setMilliseconds") << QString("Date.prototype.setMilliseconds") << QString("setMilliseconds");
       
  1237     QTest::newRow("Date.prototype.setUTCMilliseconds") << QString("Date.prototype.setUTCMilliseconds") << QString("setUTCMilliseconds");
       
  1238     QTest::newRow("Date.prototype.setSeconds") << QString("Date.prototype.setSeconds") << QString("setSeconds");
       
  1239     QTest::newRow("Date.prototype.setUTCSeconds") << QString("Date.prototype.setUTCSeconds") << QString("setUTCSeconds");
       
  1240     QTest::newRow("Date.prototype.setMinutes") << QString("Date.prototype.setMinutes") << QString("setMinutes");
       
  1241     QTest::newRow("Date.prototype.setUTCMinutes") << QString("Date.prototype.setUTCMinutes") << QString("setUTCMinutes");
       
  1242     QTest::newRow("Date.prototype.setHours") << QString("Date.prototype.setHours") << QString("setHours");
       
  1243     QTest::newRow("Date.prototype.setUTCHours") << QString("Date.prototype.setUTCHours") << QString("setUTCHours");
       
  1244     QTest::newRow("Date.prototype.setDate") << QString("Date.prototype.setDate") << QString("setDate");
       
  1245     QTest::newRow("Date.prototype.setUTCDate") << QString("Date.prototype.setUTCDate") << QString("setUTCDate");
       
  1246     QTest::newRow("Date.prototype.setMonth") << QString("Date.prototype.setMonth") << QString("setMonth");
       
  1247     QTest::newRow("Date.prototype.setUTCMonth") << QString("Date.prototype.setUTCMonth") << QString("setUTCMonth");
       
  1248     QTest::newRow("Date.prototype.setYear") << QString("Date.prototype.setYear") << QString("setYear");
       
  1249     QTest::newRow("Date.prototype.setFullYear") << QString("Date.prototype.setFullYear") << QString("setFullYear");
       
  1250     QTest::newRow("Date.prototype.setUTCFullYear") << QString("Date.prototype.setUTCFullYear") << QString("setUTCFullYear");
       
  1251     QTest::newRow("Date.prototype.toUTCString") << QString("Date.prototype.toUTCString") << QString("toUTCString");
       
  1252     QTest::newRow("Date.prototype.toGMTString") << QString("Date.prototype.toGMTString") << QString("toGMTString");
       
  1253 
       
  1254     QTest::newRow("Error") << QString("Error") << QString("Error");
       
  1255 //    QTest::newRow("Error.prototype.backtrace") << QString("Error.prototype.backtrace") << QString("backtrace");
       
  1256     QTest::newRow("Error.prototype.toString") << QString("Error.prototype.toString") << QString("toString");
       
  1257 
       
  1258     QTest::newRow("EvalError") << QString("EvalError") << QString("EvalError");
       
  1259     QTest::newRow("RangeError") << QString("RangeError") << QString("RangeError");
       
  1260     QTest::newRow("ReferenceError") << QString("ReferenceError") << QString("ReferenceError");
       
  1261     QTest::newRow("SyntaxError") << QString("SyntaxError") << QString("SyntaxError");
       
  1262     QTest::newRow("TypeError") << QString("TypeError") << QString("TypeError");
       
  1263     QTest::newRow("URIError") << QString("URIError") << QString("URIError");
       
  1264 
       
  1265     QTest::newRow("Function") << QString("Function") << QString("Function");
       
  1266     QTest::newRow("Function.prototype.toString") << QString("Function.prototype.toString") << QString("toString");
       
  1267     QTest::newRow("Function.prototype.apply") << QString("Function.prototype.apply") << QString("apply");
       
  1268     QTest::newRow("Function.prototype.call") << QString("Function.prototype.call") << QString("call");
       
  1269     QTest::newRow("Function.prototype.connect") << QString("Function.prototype.connect") << QString("connect");
       
  1270     QTest::newRow("Function.prototype.disconnect") << QString("Function.prototype.disconnect") << QString("disconnect");
       
  1271 
       
  1272     QTest::newRow("Math.abs") << QString("Math.abs") << QString("abs");
       
  1273     QTest::newRow("Math.acos") << QString("Math.acos") << QString("acos");
       
  1274     QTest::newRow("Math.asin") << QString("Math.asin") << QString("asin");
       
  1275     QTest::newRow("Math.atan") << QString("Math.atan") << QString("atan");
       
  1276     QTest::newRow("Math.atan2") << QString("Math.atan2") << QString("atan2");
       
  1277     QTest::newRow("Math.ceil") << QString("Math.ceil") << QString("ceil");
       
  1278     QTest::newRow("Math.cos") << QString("Math.cos") << QString("cos");
       
  1279     QTest::newRow("Math.exp") << QString("Math.exp") << QString("exp");
       
  1280     QTest::newRow("Math.floor") << QString("Math.floor") << QString("floor");
       
  1281     QTest::newRow("Math.log") << QString("Math.log") << QString("log");
       
  1282     QTest::newRow("Math.max") << QString("Math.max") << QString("max");
       
  1283     QTest::newRow("Math.min") << QString("Math.min") << QString("min");
       
  1284     QTest::newRow("Math.pow") << QString("Math.pow") << QString("pow");
       
  1285     QTest::newRow("Math.random") << QString("Math.random") << QString("random");
       
  1286     QTest::newRow("Math.round") << QString("Math.round") << QString("round");
       
  1287     QTest::newRow("Math.sin") << QString("Math.sin") << QString("sin");
       
  1288     QTest::newRow("Math.sqrt") << QString("Math.sqrt") << QString("sqrt");
       
  1289     QTest::newRow("Math.tan") << QString("Math.tan") << QString("tan");
       
  1290 
       
  1291     QTest::newRow("Number") << QString("Number") << QString("Number");
       
  1292     QTest::newRow("Number.prototype.toString") << QString("Number.prototype.toString") << QString("toString");
       
  1293     QTest::newRow("Number.prototype.toLocaleString") << QString("Number.prototype.toLocaleString") << QString("toLocaleString");
       
  1294     QTest::newRow("Number.prototype.valueOf") << QString("Number.prototype.valueOf") << QString("valueOf");
       
  1295     QTest::newRow("Number.prototype.toFixed") << QString("Number.prototype.toFixed") << QString("toFixed");
       
  1296     QTest::newRow("Number.prototype.toExponential") << QString("Number.prototype.toExponential") << QString("toExponential");
       
  1297     QTest::newRow("Number.prototype.toPrecision") << QString("Number.prototype.toPrecision") << QString("toPrecision");
       
  1298 
       
  1299     QTest::newRow("Object") << QString("Object") << QString("Object");
       
  1300     QTest::newRow("Object.prototype.toString") << QString("Object.prototype.toString") << QString("toString");
       
  1301     QTest::newRow("Object.prototype.toLocaleString") << QString("Object.prototype.toLocaleString") << QString("toLocaleString");
       
  1302     QTest::newRow("Object.prototype.valueOf") << QString("Object.prototype.valueOf") << QString("valueOf");
       
  1303     QTest::newRow("Object.prototype.hasOwnProperty") << QString("Object.prototype.hasOwnProperty") << QString("hasOwnProperty");
       
  1304     QTest::newRow("Object.prototype.isPrototypeOf") << QString("Object.prototype.isPrototypeOf") << QString("isPrototypeOf");
       
  1305     QTest::newRow("Object.prototype.propertyIsEnumerable") << QString("Object.prototype.propertyIsEnumerable") << QString("propertyIsEnumerable");
       
  1306     QTest::newRow("Object.prototype.__defineGetter__") << QString("Object.prototype.__defineGetter__") << QString("__defineGetter__");
       
  1307     QTest::newRow("Object.prototype.__defineSetter__") << QString("Object.prototype.__defineSetter__") << QString("__defineSetter__");
       
  1308 
       
  1309     QTest::newRow("RegExp") << QString("RegExp") << QString("RegExp");
       
  1310     QTest::newRow("RegExp.prototype.exec") << QString("RegExp.prototype.exec") << QString("exec");
       
  1311     QTest::newRow("RegExp.prototype.test") << QString("RegExp.prototype.test") << QString("test");
       
  1312     QTest::newRow("RegExp.prototype.toString") << QString("RegExp.prototype.toString") << QString("toString");
       
  1313 
       
  1314     QTest::newRow("String") << QString("String") << QString("String");
       
  1315     QTest::newRow("String.prototype.toString") << QString("String.prototype.toString") << QString("toString");
       
  1316     QTest::newRow("String.prototype.valueOf") << QString("String.prototype.valueOf") << QString("valueOf");
       
  1317     QTest::newRow("String.prototype.charAt") << QString("String.prototype.charAt") << QString("charAt");
       
  1318     QTest::newRow("String.prototype.charCodeAt") << QString("String.prototype.charCodeAt") << QString("charCodeAt");
       
  1319     QTest::newRow("String.prototype.concat") << QString("String.prototype.concat") << QString("concat");
       
  1320     QTest::newRow("String.prototype.indexOf") << QString("String.prototype.indexOf") << QString("indexOf");
       
  1321     QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf");
       
  1322     QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare");
       
  1323     QTest::newRow("String.prototype.match") << QString("String.prototype.match") << QString("match");
       
  1324     QTest::newRow("String.prototype.replace") << QString("String.prototype.replace") << QString("replace");
       
  1325     QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search");
       
  1326     QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice");
       
  1327     QTest::newRow("String.prototype.split") << QString("String.prototype.split") << QString("split");
       
  1328     QTest::newRow("String.prototype.substring") << QString("String.prototype.substring") << QString("substring");
       
  1329     QTest::newRow("String.prototype.toLowerCase") << QString("String.prototype.toLowerCase") << QString("toLowerCase");
       
  1330     QTest::newRow("String.prototype.toLocaleLowerCase") << QString("String.prototype.toLocaleLowerCase") << QString("toLocaleLowerCase");
       
  1331     QTest::newRow("String.prototype.toUpperCase") << QString("String.prototype.toUpperCase") << QString("toUpperCase");
       
  1332     QTest::newRow("String.prototype.toLocaleUpperCase") << QString("String.prototype.toLocaleUpperCase") << QString("toLocaleUpperCase");
       
  1333 }
       
  1334 
       
  1335 void tst_QScriptEngine::builtinFunctionNames()
       
  1336 {
       
  1337     QFETCH(QString, expression);
       
  1338     QFETCH(QString, expectedName);
       
  1339     QScriptEngine eng;
       
  1340     QScriptValue ret = eng.evaluate(QString::fromLatin1("%0.name").arg(expression));
       
  1341     QVERIFY(ret.isString());
       
  1342     QCOMPARE(ret.toString(), expectedName);
       
  1343 }
       
  1344 
       
  1345 void tst_QScriptEngine::checkSyntax_data()
       
  1346 {
       
  1347     QTest::addColumn<QString>("code");
       
  1348     QTest::addColumn<int>("expectedState");
       
  1349     QTest::addColumn<int>("errorLineNumber");
       
  1350     QTest::addColumn<int>("errorColumnNumber");
       
  1351     QTest::addColumn<QString>("errorMessage");
       
  1352 
       
  1353     QTest::newRow("0")
       
  1354         << QString("0") << int(QScriptSyntaxCheckResult::Valid)
       
  1355         << -1 << -1 << "";
       
  1356     QTest::newRow("if (")
       
  1357         << QString("if (\n") << int(QScriptSyntaxCheckResult::Intermediate)
       
  1358         << 1 << 4 << "";
       
  1359     QTest::newRow("if else")
       
  1360         << QString("\nif else") << int(QScriptSyntaxCheckResult::Error)
       
  1361         << 2 << 4 << "Expected `('";
       
  1362     QTest::newRow("foo[")
       
  1363         << QString("foo[") << int(QScriptSyntaxCheckResult::Error)
       
  1364         << 1 << 4 << "";
       
  1365     QTest::newRow("foo['bar']")
       
  1366         << QString("foo['bar']") << int(QScriptSyntaxCheckResult::Valid)
       
  1367         << -1 << -1 << "";
       
  1368 
       
  1369     QTest::newRow("/*")
       
  1370         << QString("/*") << int(QScriptSyntaxCheckResult::Intermediate)
       
  1371         << 1 << 1 << "Unclosed comment at end of file";
       
  1372     QTest::newRow("/*\nMy comment")
       
  1373         << QString("/*\nMy comment") << int(QScriptSyntaxCheckResult::Intermediate)
       
  1374         << 1 << 1 << "Unclosed comment at end of file";
       
  1375     QTest::newRow("/*\nMy comment */\nfoo = 10")
       
  1376         << QString("/*\nMy comment */\nfoo = 10") << int(QScriptSyntaxCheckResult::Valid)
       
  1377         << -1 << -1 << "";
       
  1378     QTest::newRow("foo = 10 /*")
       
  1379         << QString("foo = 10 /*") << int(QScriptSyntaxCheckResult::Intermediate)
       
  1380         << -1 << -1 << "";
       
  1381     QTest::newRow("foo = 10; /*")
       
  1382         << QString("foo = 10; /*") << int(QScriptSyntaxCheckResult::Intermediate)
       
  1383         << 1 << 11 << "Expected `end of file'";
       
  1384     QTest::newRow("foo = 10 /* My comment */")
       
  1385         << QString("foo = 10 /* My comment */") << int(QScriptSyntaxCheckResult::Valid)
       
  1386         << -1 << -1 << "";
       
  1387 
       
  1388     QTest::newRow("/=/")
       
  1389         << QString("/=/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
       
  1390     QTest::newRow("/=/g")
       
  1391         << QString("/=/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
       
  1392     QTest::newRow("/a/")
       
  1393         << QString("/a/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
       
  1394     QTest::newRow("/a/g")
       
  1395         << QString("/a/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
       
  1396 }
       
  1397 
       
  1398 void tst_QScriptEngine::checkSyntax()
       
  1399 {
       
  1400     QFETCH(QString, code);
       
  1401     QFETCH(int, expectedState);
       
  1402     QFETCH(int, errorLineNumber);
       
  1403     QFETCH(int, errorColumnNumber);
       
  1404     QFETCH(QString, errorMessage);
       
  1405 
       
  1406     QScriptSyntaxCheckResult result = QScriptEngine::checkSyntax(code);
       
  1407     QCOMPARE(result.state(), QScriptSyntaxCheckResult::State(expectedState));
       
  1408     QCOMPARE(result.errorLineNumber(), errorLineNumber);
       
  1409     QCOMPARE(result.errorColumnNumber(), errorColumnNumber);
       
  1410     QCOMPARE(result.errorMessage(), errorMessage);
       
  1411 
       
  1412     // assignment
       
  1413     {
       
  1414         QScriptSyntaxCheckResult copy = result;
       
  1415         QCOMPARE(copy.state(), result.state());
       
  1416         QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
       
  1417         QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
       
  1418         QCOMPARE(copy.errorMessage(), result.errorMessage());
       
  1419     }
       
  1420     {
       
  1421         QScriptSyntaxCheckResult copy(result);
       
  1422         QCOMPARE(copy.state(), result.state());
       
  1423         QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
       
  1424         QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
       
  1425         QCOMPARE(copy.errorMessage(), result.errorMessage());
       
  1426     }
       
  1427 }
       
  1428 
       
  1429 void tst_QScriptEngine::canEvaluate_data()
       
  1430 {
       
  1431     QTest::addColumn<QString>("code");
       
  1432     QTest::addColumn<bool>("expectSuccess");
       
  1433 
       
  1434     QTest::newRow("") << QString("") << true;
       
  1435     QTest::newRow("0") << QString("0") << true;
       
  1436     QTest::newRow("!") << QString("!\n") << false;
       
  1437     QTest::newRow("if (") << QString("if (\n") << false;
       
  1438     QTest::newRow("if (10) //") << QString("if (10) //\n") << false;
       
  1439     QTest::newRow("a = 1; if (") << QString("a = 1;\nif (\n") << false;
       
  1440     QTest::newRow("./test.js") << QString("./test.js\n") << true;
       
  1441     QTest::newRow("if (0) print(1)") << QString("if (0)\nprint(1)\n") << true;
       
  1442     QTest::newRow("0 = ") << QString("0 = \n") << false;
       
  1443     QTest::newRow("0 = 0") << QString("0 = 0\n") << true;
       
  1444     QTest::newRow("foo[") << QString("foo[") << true; // automatic semicolon will be inserted
       
  1445     QTest::newRow("foo[") << QString("foo[\n") << false;
       
  1446     QTest::newRow("foo['bar']") << QString("foo['bar']") << true;
       
  1447 
       
  1448     QTest::newRow("/*") << QString("/*") << false;
       
  1449     QTest::newRow("/*\nMy comment") << QString("/*\nMy comment") << false;
       
  1450     QTest::newRow("/*\nMy comment */\nfoo = 10") << QString("/*\nMy comment */\nfoo = 10") << true;
       
  1451     QTest::newRow("foo = 10 /*") << QString("foo = 10 /*") << false;
       
  1452     QTest::newRow("foo = 10; /*") << QString("foo = 10; /*") << false;
       
  1453     QTest::newRow("foo = 10 /* My comment */") << QString("foo = 10 /* My comment */") << true;
       
  1454 
       
  1455     QTest::newRow("/=/") << QString("/=/") << true;
       
  1456     QTest::newRow("/=/g") << QString("/=/g") << true;
       
  1457     QTest::newRow("/a/") << QString("/a/") << true;
       
  1458     QTest::newRow("/a/g") << QString("/a/g") << true;
       
  1459 }
       
  1460 
       
  1461 void tst_QScriptEngine::canEvaluate()
       
  1462 {
       
  1463     QFETCH(QString, code);
       
  1464     QFETCH(bool, expectSuccess);
       
  1465 
       
  1466     QScriptEngine eng;
       
  1467     QCOMPARE(eng.canEvaluate(code), expectSuccess);
       
  1468 }
       
  1469 
       
  1470 void tst_QScriptEngine::evaluate_data()
       
  1471 {
       
  1472     QTest::addColumn<QString>("code");
       
  1473     QTest::addColumn<int>("lineNumber");
       
  1474     QTest::addColumn<bool>("expectHadError");
       
  1475     QTest::addColumn<int>("expectErrorLineNumber");
       
  1476 
       
  1477     QTest::newRow("(newline)") << QString("\n") << -1 << false << -1;
       
  1478     QTest::newRow("0 //")   << QString("0 //") << -1 << false << -1;
       
  1479     QTest::newRow("/* */")   << QString("/* */") << -1 << false << -1;
       
  1480     QTest::newRow("//") << QString("//") << -1 << false << -1;
       
  1481     QTest::newRow("(spaces)")  << QString("  ") << -1 << false << -1;
       
  1482     QTest::newRow("(empty)")   << QString("") << -1 << false << -1;
       
  1483     QTest::newRow("0")     << QString("0")       << -1 << false << -1;
       
  1484     QTest::newRow("0=1")   << QString("\n0=1;\n") << -1 << true  << 2;
       
  1485     QTest::newRow("a=1")   << QString("a=1\n")   << -1 << false << -1;
       
  1486     QTest::newRow("a=1;K") << QString("a=1;\nK") << -1 << true  << 2;
       
  1487 
       
  1488     QTest::newRow("f()") << QString("function f()\n"
       
  1489                                     "{\n"
       
  1490                                     "  var a;\n"
       
  1491                                     "  var b=\";\n" // here's the error
       
  1492                                     "}\n"
       
  1493                                     "f();\n")
       
  1494                          << -1 << true << 4;
       
  1495 
       
  1496     QTest::newRow("0")     << QString("0")       << 10 << false << -1;
       
  1497     QTest::newRow("0=1")   << QString("\n\n0=1\n") << 10 << true  << 13;
       
  1498     QTest::newRow("a=1")   << QString("a=1\n")   << 10 << false << -1;
       
  1499     QTest::newRow("a=1;K") << QString("a=1;\n\nK") << 10 << true  << 12;
       
  1500 
       
  1501     QTest::newRow("f()") << QString("function f()\n"
       
  1502                                     "{\n"
       
  1503                                     "  var a;\n"
       
  1504                                     "\n\n"
       
  1505                                     "  var b=\";\n" // here's the error
       
  1506                                     "}\n"
       
  1507                                     "f();\n")
       
  1508                          << 10 << true << 15;
       
  1509     QTest::newRow("functionThatDoesntExist()")
       
  1510         << QString(";\n;\n;\nfunctionThatDoesntExist()")
       
  1511         << -1 << true << 4;
       
  1512     QTest::newRow("for (var p in this) { continue labelThatDoesntExist; }")
       
  1513         << QString("for (var p in this) {\ncontinue labelThatDoesntExist; }")
       
  1514         << 4 << true << 5;
       
  1515     QTest::newRow("duplicateLabel: { duplicateLabel: ; }")
       
  1516         << QString("duplicateLabel: { duplicateLabel: ; }")
       
  1517         << 12 << true << 12;
       
  1518 
       
  1519     QTest::newRow("/=/") << QString("/=/") << -1 << false << -1;
       
  1520     QTest::newRow("/=/g") << QString("/=/g") << -1 << false << -1;
       
  1521     QTest::newRow("/a/") << QString("/a/") << -1 << false << -1;
       
  1522     QTest::newRow("/a/g") << QString("/a/g") << -1 << false << -1;
       
  1523     QTest::newRow("/a/gim") << QString("/a/gim") << -1 << false << -1;
       
  1524     QTest::newRow("/a/gimp") << QString("/a/gimp") << 1 << true << 1;
       
  1525 }
       
  1526 
       
  1527 void tst_QScriptEngine::evaluate()
       
  1528 {
       
  1529     QFETCH(QString, code);
       
  1530     QFETCH(int, lineNumber);
       
  1531     QFETCH(bool, expectHadError);
       
  1532     QFETCH(int, expectErrorLineNumber);
       
  1533 
       
  1534     QScriptEngine eng;
       
  1535     QScriptValue ret;
       
  1536     if (lineNumber != -1)
       
  1537         ret = eng.evaluate(code, /*fileName =*/QString(), lineNumber);
       
  1538     else
       
  1539         ret = eng.evaluate(code);
       
  1540     QCOMPARE(eng.hasUncaughtException(), expectHadError);
       
  1541     QCOMPARE(eng.uncaughtExceptionLineNumber(), expectErrorLineNumber);
       
  1542     if (eng.hasUncaughtException() && ret.isError())
       
  1543         QVERIFY(ret.property("lineNumber").strictlyEquals(QScriptValue(&eng, expectErrorLineNumber)));
       
  1544     else
       
  1545         QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
       
  1546 }
       
  1547 
       
  1548 static QScriptValue eval_nested(QScriptContext *ctx, QScriptEngine *eng)
       
  1549 {
       
  1550     QScriptValue result = eng->newObject();
       
  1551     eng->evaluate("var bar = 'local';");
       
  1552     result.setProperty("thisObjectIdBefore", ctx->thisObject().property("id"));
       
  1553     QScriptValue evaluatedThisObject = eng->evaluate("this");
       
  1554     result.setProperty("thisObjectIdAfter", ctx->thisObject().property("id"));
       
  1555     result.setProperty("evaluatedThisObjectId", evaluatedThisObject.property("id"));
       
  1556     result.setProperty("local_bar", eng->evaluate("bar"));
       
  1557 
       
  1558     return result;
       
  1559 }
       
  1560 
       
  1561 void tst_QScriptEngine::nestedEvaluate()
       
  1562 {
       
  1563     QScriptEngine eng;
       
  1564     QScriptValue fun = eng.newFunction(eval_nested);
       
  1565     eng.globalObject().setProperty("fun", fun);
       
  1566     {
       
  1567         QScriptValue result = eng.evaluate("o = { id:'foo'}; o.fun = fun; o.fun()");
       
  1568         QCOMPARE(result.property("local_bar").toString(), QString("local"));
       
  1569         QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo"));
       
  1570         QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo"));
       
  1571         QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
       
  1572         QScriptValue bar = eng.evaluate("bar");
       
  1573         QVERIFY(bar.isError());
       
  1574         QCOMPARE(bar.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bar"));
       
  1575     }
       
  1576 
       
  1577     {
       
  1578         QScriptValue result = fun.call(eng.evaluate("p = { id:'foo' }") , QScriptValueList() );
       
  1579         QCOMPARE(result.property("local_bar").toString(), QString("local"));
       
  1580         QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo"));
       
  1581         QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo"));
       
  1582         QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
       
  1583         QScriptValue bar = eng.evaluate("bar");
       
  1584         QVERIFY(bar.isError());
       
  1585         QCOMPARE(bar.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bar"));
       
  1586     }
       
  1587 }
       
  1588 
       
  1589 void tst_QScriptEngine::uncaughtException()
       
  1590 {
       
  1591     QScriptEngine eng;
       
  1592     QScriptValue fun = eng.newFunction(myFunction);
       
  1593     QScriptValue throwFun = eng.newFunction(myThrowingFunction);
       
  1594     for (int x = -1; x < 2; ++x) {
       
  1595         {
       
  1596             QScriptValue ret = eng.evaluate("a = 10;\nb = 20;\n0 = 0;\n", /*fileName=*/QString(), /*lineNumber=*/x);
       
  1597             QVERIFY(eng.hasUncaughtException());
       
  1598             QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2);
       
  1599             QVERIFY(eng.uncaughtException().strictlyEquals(ret));
       
  1600             (void)ret.toString();
       
  1601             QVERIFY(eng.hasUncaughtException());
       
  1602             QVERIFY(eng.uncaughtException().strictlyEquals(ret));
       
  1603             QVERIFY(fun.call().isNull());
       
  1604             QVERIFY(eng.hasUncaughtException());
       
  1605             QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2);
       
  1606             QVERIFY(eng.uncaughtException().strictlyEquals(ret));
       
  1607             eng.clearExceptions();
       
  1608             QVERIFY(!eng.hasUncaughtException());
       
  1609             QCOMPARE(eng.uncaughtExceptionLineNumber(), -1);
       
  1610             QVERIFY(!eng.uncaughtException().isValid());
       
  1611 
       
  1612             eng.evaluate("2 = 3");
       
  1613             QVERIFY(eng.hasUncaughtException());
       
  1614             QScriptValue ret2 = throwFun.call();
       
  1615             QVERIFY(ret2.isError());
       
  1616             QVERIFY(eng.hasUncaughtException());
       
  1617             QVERIFY(eng.uncaughtException().strictlyEquals(ret2));
       
  1618             QCOMPARE(eng.uncaughtExceptionLineNumber(), 0);
       
  1619             eng.clearExceptions();
       
  1620             QVERIFY(!eng.hasUncaughtException());
       
  1621             eng.evaluate("1 + 2");
       
  1622             QVERIFY(!eng.hasUncaughtException());
       
  1623         }
       
  1624         {
       
  1625             QScriptValue ret = eng.evaluate("a = 10");
       
  1626             QVERIFY(!eng.hasUncaughtException());
       
  1627             QVERIFY(!eng.uncaughtException().isValid());
       
  1628         }
       
  1629         {
       
  1630             QScriptValue ret = eng.evaluate("1 = 2");
       
  1631             QVERIFY(eng.hasUncaughtException());
       
  1632             eng.clearExceptions();
       
  1633             QVERIFY(!eng.hasUncaughtException());
       
  1634         }
       
  1635         {
       
  1636             eng.globalObject().setProperty("throwFun", throwFun);
       
  1637             eng.evaluate("1;\nthrowFun();");
       
  1638             QVERIFY(eng.hasUncaughtException());
       
  1639             QCOMPARE(eng.uncaughtExceptionLineNumber(), 2);
       
  1640             eng.clearExceptions();
       
  1641             QVERIFY(!eng.hasUncaughtException());
       
  1642         }
       
  1643     }
       
  1644 }
       
  1645 
       
  1646 void tst_QScriptEngine::errorMessage_QT679()
       
  1647 {
       
  1648     QScriptEngine engine;
       
  1649     engine.globalObject().setProperty("foo", 15);
       
  1650     QScriptValue error = engine.evaluate("'hello world';\nfoo.bar.blah");
       
  1651     QVERIFY(error.isError());
       
  1652     QCOMPARE(error.toString(), QString::fromLatin1("TypeError: Result of expression 'foo.bar' [undefined] is not an object."));
       
  1653 }
       
  1654 
       
  1655 struct Foo {
       
  1656 public:
       
  1657     int x, y;
       
  1658     Foo() : x(-1), y(-1) { }
       
  1659 };
       
  1660 
       
  1661 Q_DECLARE_METATYPE(Foo)
       
  1662 Q_DECLARE_METATYPE(Foo*)
       
  1663 
       
  1664 void tst_QScriptEngine::getSetDefaultPrototype()
       
  1665 {
       
  1666     QScriptEngine eng;
       
  1667     {
       
  1668         QScriptValue object = eng.newObject();
       
  1669         QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
       
  1670         eng.setDefaultPrototype(qMetaTypeId<int>(), object);
       
  1671         QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).strictlyEquals(object), true);
       
  1672         QScriptValue value = eng.newVariant(int(123));
       
  1673         QCOMPARE(value.prototype().isObject(), true);
       
  1674         QCOMPARE(value.prototype().strictlyEquals(object), true);
       
  1675 
       
  1676         eng.setDefaultPrototype(qMetaTypeId<int>(), QScriptValue());
       
  1677         QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
       
  1678         QScriptValue value2 = eng.newVariant(int(123));
       
  1679         QCOMPARE(value2.prototype().strictlyEquals(object), false);
       
  1680     }
       
  1681     {
       
  1682         QScriptValue object = eng.newObject();
       
  1683         QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
       
  1684         eng.setDefaultPrototype(qMetaTypeId<Foo>(), object);
       
  1685         QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(object), true);
       
  1686         QScriptValue value = eng.newVariant(qVariantFromValue(Foo()));
       
  1687         QCOMPARE(value.prototype().isObject(), true);
       
  1688         QCOMPARE(value.prototype().strictlyEquals(object), true);
       
  1689 
       
  1690         eng.setDefaultPrototype(qMetaTypeId<Foo>(), QScriptValue());
       
  1691         QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
       
  1692         QScriptValue value2 = eng.newVariant(qVariantFromValue(Foo()));
       
  1693         QCOMPARE(value2.prototype().strictlyEquals(object), false);
       
  1694     }
       
  1695 }
       
  1696 
       
  1697 static QScriptValue fooToScriptValue(QScriptEngine *eng, const Foo &foo)
       
  1698 {
       
  1699     QScriptValue obj = eng->newObject();
       
  1700     obj.setProperty("x", QScriptValue(eng, foo.x));
       
  1701     obj.setProperty("y", QScriptValue(eng, foo.y));
       
  1702     return obj;
       
  1703 }
       
  1704 
       
  1705 static void fooFromScriptValue(const QScriptValue &value, Foo &foo)
       
  1706 {
       
  1707     foo.x = value.property("x").toInt32();
       
  1708     foo.y = value.property("y").toInt32();
       
  1709 }
       
  1710 
       
  1711 static QScriptValue fooToScriptValueV2(QScriptEngine *eng, const Foo &foo)
       
  1712 {
       
  1713     return QScriptValue(eng, foo.x);
       
  1714 }
       
  1715 
       
  1716 static void fooFromScriptValueV2(const QScriptValue &value, Foo &foo)
       
  1717 {
       
  1718     foo.x = value.toInt32();
       
  1719 }
       
  1720 
       
  1721 Q_DECLARE_METATYPE(QLinkedList<QString>)
       
  1722 Q_DECLARE_METATYPE(QList<Foo>)
       
  1723 Q_DECLARE_METATYPE(QVector<QChar>)
       
  1724 Q_DECLARE_METATYPE(QStack<int>)
       
  1725 Q_DECLARE_METATYPE(QQueue<char>)
       
  1726 Q_DECLARE_METATYPE(QLinkedList<QStack<int> >)
       
  1727 
       
  1728 void tst_QScriptEngine::valueConversion()
       
  1729 {
       
  1730     QScriptEngine eng;
       
  1731     {
       
  1732         QScriptValue num = qScriptValueFromValue(&eng, 123);
       
  1733         QCOMPARE(num.isNumber(), true);
       
  1734         QCOMPARE(num.strictlyEquals(QScriptValue(&eng, 123)), true);
       
  1735 
       
  1736         int inum = qScriptValueToValue<int>(num);
       
  1737         QCOMPARE(inum, 123);
       
  1738 
       
  1739         QString snum = qScriptValueToValue<QString>(num);
       
  1740         QCOMPARE(snum, QLatin1String("123"));
       
  1741     }
       
  1742 #ifndef QT_NO_MEMBER_TEMPLATES
       
  1743     {
       
  1744         QScriptValue num = eng.toScriptValue(123);
       
  1745         QCOMPARE(num.isNumber(), true);
       
  1746         QCOMPARE(num.strictlyEquals(QScriptValue(&eng, 123)), true);
       
  1747 
       
  1748         int inum = eng.fromScriptValue<int>(num);
       
  1749         QCOMPARE(inum, 123);
       
  1750 
       
  1751         QString snum = eng.fromScriptValue<QString>(num);
       
  1752         QCOMPARE(snum, QLatin1String("123"));
       
  1753     }
       
  1754 #endif
       
  1755     {
       
  1756         QScriptValue num(&eng, 123);
       
  1757         QCOMPARE(qScriptValueToValue<char>(num), char(123));
       
  1758         QCOMPARE(qScriptValueToValue<unsigned char>(num), (unsigned char)(123));
       
  1759         QCOMPARE(qScriptValueToValue<short>(num), short(123));
       
  1760         QCOMPARE(qScriptValueToValue<unsigned short>(num), (unsigned short)(123));
       
  1761         QCOMPARE(qScriptValueToValue<float>(num), float(123));
       
  1762         QCOMPARE(qScriptValueToValue<double>(num), double(123));
       
  1763         QCOMPARE(qScriptValueToValue<qlonglong>(num), qlonglong(123));
       
  1764         QCOMPARE(qScriptValueToValue<qulonglong>(num), qulonglong(123));
       
  1765     }
       
  1766     {
       
  1767         QScriptValue num(123);
       
  1768         QCOMPARE(qScriptValueToValue<char>(num), char(123));
       
  1769         QCOMPARE(qScriptValueToValue<unsigned char>(num), (unsigned char)(123));
       
  1770         QCOMPARE(qScriptValueToValue<short>(num), short(123));
       
  1771         QCOMPARE(qScriptValueToValue<unsigned short>(num), (unsigned short)(123));
       
  1772         QCOMPARE(qScriptValueToValue<float>(num), float(123));
       
  1773         QCOMPARE(qScriptValueToValue<double>(num), double(123));
       
  1774         QCOMPARE(qScriptValueToValue<qlonglong>(num), qlonglong(123));
       
  1775         QCOMPARE(qScriptValueToValue<qulonglong>(num), qulonglong(123));
       
  1776     }
       
  1777 
       
  1778     {
       
  1779         QScriptValue num = qScriptValueFromValue(&eng, Q_INT64_C(0x100000000));
       
  1780         QCOMPARE(qScriptValueToValue<qlonglong>(num), Q_INT64_C(0x100000000));
       
  1781         QCOMPARE(qScriptValueToValue<qulonglong>(num), Q_UINT64_C(0x100000000));
       
  1782     }
       
  1783 
       
  1784     {
       
  1785         QChar c = QLatin1Char('c');
       
  1786         QScriptValue str = QScriptValue(&eng, "ciao");
       
  1787         QCOMPARE(qScriptValueToValue<QChar>(str), c);
       
  1788         QScriptValue code = QScriptValue(&eng, c.unicode());
       
  1789         QCOMPARE(qScriptValueToValue<QChar>(code), c);
       
  1790         QCOMPARE(qScriptValueToValue<QChar>(qScriptValueFromValue(&eng, c)), c);
       
  1791     }
       
  1792 
       
  1793     {
       
  1794         // a type that we don't have built-in conversion of
       
  1795         // (it's stored as a variant)
       
  1796         QTime tm(1, 2, 3, 4);
       
  1797         QScriptValue val = qScriptValueFromValue(&eng, tm);
       
  1798         QCOMPARE(qScriptValueToValue<QTime>(val), tm);
       
  1799     }
       
  1800 
       
  1801     {
       
  1802         Foo foo;
       
  1803         foo.x = 12;
       
  1804         foo.y = 34;
       
  1805         QScriptValue fooVal = qScriptValueFromValue(&eng, foo);
       
  1806         QCOMPARE(fooVal.isVariant(), true);
       
  1807 
       
  1808         Foo foo2 = qScriptValueToValue<Foo>(fooVal);
       
  1809         QCOMPARE(foo2.x, foo.x);
       
  1810         QCOMPARE(foo2.y, foo.y);
       
  1811     }
       
  1812 
       
  1813     qScriptRegisterMetaType<Foo>(&eng, fooToScriptValue, fooFromScriptValue);
       
  1814 
       
  1815     {
       
  1816         Foo foo;
       
  1817         foo.x = 12;
       
  1818         foo.y = 34;
       
  1819         QScriptValue fooVal = qScriptValueFromValue(&eng, foo);
       
  1820         QCOMPARE(fooVal.isObject(), true);
       
  1821         QVERIFY(fooVal.prototype().strictlyEquals(eng.evaluate("Object.prototype")));
       
  1822         QCOMPARE(fooVal.property("x").strictlyEquals(QScriptValue(&eng, 12)), true);
       
  1823         QCOMPARE(fooVal.property("y").strictlyEquals(QScriptValue(&eng, 34)), true);
       
  1824         fooVal.setProperty("x", QScriptValue(&eng, 56));
       
  1825         fooVal.setProperty("y", QScriptValue(&eng, 78));
       
  1826 
       
  1827         Foo foo2 = qScriptValueToValue<Foo>(fooVal);
       
  1828         QCOMPARE(foo2.x, 56);
       
  1829         QCOMPARE(foo2.y, 78);
       
  1830 
       
  1831         QScriptValue fooProto = eng.newObject();
       
  1832         eng.setDefaultPrototype(qMetaTypeId<Foo>(), fooProto);
       
  1833         QScriptValue fooVal2 = qScriptValueFromValue(&eng, foo2);
       
  1834         QVERIFY(fooVal2.prototype().strictlyEquals(fooProto));
       
  1835         QVERIFY(fooVal2.property("x").strictlyEquals(QScriptValue(&eng, 56)));
       
  1836         QVERIFY(fooVal2.property("y").strictlyEquals(QScriptValue(&eng, 78)));
       
  1837     }
       
  1838 
       
  1839     qScriptRegisterSequenceMetaType<QLinkedList<QString> >(&eng);
       
  1840 
       
  1841     {
       
  1842         QLinkedList<QString> lst;
       
  1843         lst << QLatin1String("foo") << QLatin1String("bar");
       
  1844         QScriptValue lstVal = qScriptValueFromValue(&eng, lst);
       
  1845         QCOMPARE(lstVal.isArray(), true);
       
  1846         QCOMPARE(lstVal.property("length").toInt32(), 2);
       
  1847         QCOMPARE(lstVal.property("0").isString(), true);
       
  1848         QCOMPARE(lstVal.property("0").toString(), QLatin1String("foo"));
       
  1849         QCOMPARE(lstVal.property("1").isString(), true);
       
  1850         QCOMPARE(lstVal.property("1").toString(), QLatin1String("bar"));
       
  1851     }
       
  1852 
       
  1853     qScriptRegisterSequenceMetaType<QList<Foo> >(&eng);
       
  1854     qScriptRegisterSequenceMetaType<QStack<int> >(&eng);
       
  1855     qScriptRegisterSequenceMetaType<QVector<QChar> >(&eng);
       
  1856     qScriptRegisterSequenceMetaType<QQueue<char> >(&eng);
       
  1857     qScriptRegisterSequenceMetaType<QLinkedList<QStack<int> > >(&eng);
       
  1858 
       
  1859     {
       
  1860         QLinkedList<QStack<int> > lst;
       
  1861         QStack<int> first; first << 13 << 49; lst << first;
       
  1862         QStack<int> second; second << 99999;lst << second;
       
  1863         QScriptValue lstVal = qScriptValueFromValue(&eng, lst);
       
  1864         QCOMPARE(lstVal.isArray(), true);
       
  1865         QCOMPARE(lstVal.property("length").toInt32(), 2);
       
  1866         QCOMPARE(lstVal.property("0").isArray(), true);
       
  1867         QCOMPARE(lstVal.property("0").property("length").toInt32(), 2);
       
  1868         QCOMPARE(lstVal.property("0").property("0").toInt32(), first.at(0));
       
  1869         QCOMPARE(lstVal.property("0").property("1").toInt32(), first.at(1));
       
  1870         QCOMPARE(lstVal.property("1").isArray(), true);
       
  1871         QCOMPARE(lstVal.property("1").property("length").toInt32(), 1);
       
  1872         QCOMPARE(lstVal.property("1").property("0").toInt32(), second.at(0));
       
  1873         QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("0")), first);
       
  1874         QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("1")), second);
       
  1875         QCOMPARE(qscriptvalue_cast<QLinkedList<QStack<int> > >(lstVal), lst);
       
  1876     }
       
  1877 
       
  1878     // pointers
       
  1879     {
       
  1880         Foo foo;
       
  1881         {
       
  1882             QScriptValue v = qScriptValueFromValue(&eng, &foo);
       
  1883             Foo *pfoo = qscriptvalue_cast<Foo*>(v);
       
  1884             QCOMPARE(pfoo, &foo);
       
  1885         }
       
  1886         {
       
  1887             Foo *pfoo = 0;
       
  1888             QScriptValue v = qScriptValueFromValue(&eng, pfoo);
       
  1889             QCOMPARE(v.isNull(), true);
       
  1890             QVERIFY(qscriptvalue_cast<Foo*>(v) == 0);
       
  1891         }
       
  1892     }
       
  1893 
       
  1894     // QList<int> and QObjectList should be converted from/to arrays by default
       
  1895     {
       
  1896         QList<int> lst;
       
  1897         lst << 1 << 2 << 3;
       
  1898         QScriptValue val = qScriptValueFromValue(&eng, lst);
       
  1899         QVERIFY(val.isArray());
       
  1900         QCOMPARE(val.property("length").toInt32(), lst.size());
       
  1901         QCOMPARE(val.property(0).toInt32(), lst.at(0));
       
  1902         QCOMPARE(val.property(1).toInt32(), lst.at(1));
       
  1903         QCOMPARE(val.property(2).toInt32(), lst.at(2));
       
  1904 
       
  1905         QCOMPARE(qscriptvalue_cast<QList<int> >(val), lst);
       
  1906     }
       
  1907     {
       
  1908         QObjectList lst;
       
  1909         lst << this;
       
  1910         QScriptValue val = qScriptValueFromValue(&eng, lst);
       
  1911         QVERIFY(val.isArray());
       
  1912         QCOMPARE(val.property("length").toInt32(), lst.size());
       
  1913         QCOMPARE(val.property(0).toQObject(), (QObject *)this);
       
  1914 
       
  1915         QCOMPARE(qscriptvalue_cast<QObjectList>(val), lst);
       
  1916     }
       
  1917 
       
  1918     // qScriptValueFromValue() should be "smart" when the argument is a QVariant
       
  1919     {
       
  1920         QScriptValue val = qScriptValueFromValue(&eng, QVariant());
       
  1921         QVERIFY(!val.isVariant());
       
  1922         QVERIFY(val.isUndefined());
       
  1923     }
       
  1924     {
       
  1925         QScriptValue val = qScriptValueFromValue(&eng, QVariant(true));
       
  1926         QVERIFY(!val.isVariant());
       
  1927         QVERIFY(val.isBoolean());
       
  1928         QCOMPARE(val.toBoolean(), true);
       
  1929     }
       
  1930     {
       
  1931         QScriptValue val = qScriptValueFromValue(&eng, QVariant(int(123)));
       
  1932         QVERIFY(!val.isVariant());
       
  1933         QVERIFY(val.isNumber());
       
  1934         QCOMPARE(val.toNumber(), qsreal(123));
       
  1935     }
       
  1936     {
       
  1937         QScriptValue val = qScriptValueFromValue(&eng, QVariant(qsreal(1.25)));
       
  1938         QVERIFY(!val.isVariant());
       
  1939         QVERIFY(val.isNumber());
       
  1940         QCOMPARE(val.toNumber(), qsreal(1.25));
       
  1941     }
       
  1942     {
       
  1943         QString str = QString::fromLatin1("ciao");
       
  1944         QScriptValue val = qScriptValueFromValue(&eng, QVariant(str));
       
  1945         QVERIFY(!val.isVariant());
       
  1946         QVERIFY(val.isString());
       
  1947         QCOMPARE(val.toString(), str);
       
  1948     }
       
  1949     {
       
  1950         QScriptValue val = qScriptValueFromValue(&eng, qVariantFromValue((QObject*)this));
       
  1951         QVERIFY(!val.isVariant());
       
  1952         QVERIFY(val.isQObject());
       
  1953         QCOMPARE(val.toQObject(), (QObject*)this);
       
  1954     }
       
  1955     {
       
  1956         QVariant var = qVariantFromValue(QPoint(123, 456));
       
  1957         QScriptValue val = qScriptValueFromValue(&eng, var);
       
  1958         QVERIFY(val.isVariant());
       
  1959         QCOMPARE(val.toVariant(), var);
       
  1960     }
       
  1961 
       
  1962     // task 248802
       
  1963     qScriptRegisterMetaType<Foo>(&eng, fooToScriptValueV2, fooFromScriptValueV2);
       
  1964     {
       
  1965         QScriptValue num(&eng, 123);
       
  1966         Foo foo = qScriptValueToValue<Foo>(num);
       
  1967         QCOMPARE(foo.x, 123);
       
  1968     }
       
  1969     {
       
  1970         QScriptValue num(123);
       
  1971         Foo foo = qScriptValueToValue<Foo>(num);
       
  1972         QCOMPARE(foo.x, -1);
       
  1973     }
       
  1974     {
       
  1975         QScriptValue str(&eng, "123");
       
  1976         Foo foo = qScriptValueToValue<Foo>(str);
       
  1977         QCOMPARE(foo.x, 123);
       
  1978     }
       
  1979 
       
  1980     // more built-in types
       
  1981     {
       
  1982         QScriptValue val = qScriptValueFromValue(&eng, uint(123));
       
  1983         QVERIFY(val.isNumber());
       
  1984         QCOMPARE(val.toInt32(), 123);
       
  1985     }
       
  1986     {
       
  1987         QScriptValue val = qScriptValueFromValue(&eng, qulonglong(123));
       
  1988         QVERIFY(val.isNumber());
       
  1989         QCOMPARE(val.toInt32(), 123);
       
  1990     }
       
  1991     {
       
  1992         QScriptValue val = qScriptValueFromValue(&eng, float(123));
       
  1993         QVERIFY(val.isNumber());
       
  1994         QCOMPARE(val.toInt32(), 123);
       
  1995     }
       
  1996     {
       
  1997         QScriptValue val = qScriptValueFromValue(&eng, short(123));
       
  1998         QVERIFY(val.isNumber());
       
  1999         QCOMPARE(val.toInt32(), 123);
       
  2000     }
       
  2001     {
       
  2002         QScriptValue val = qScriptValueFromValue(&eng, ushort(123));
       
  2003         QVERIFY(val.isNumber());
       
  2004         QCOMPARE(val.toInt32(), 123);
       
  2005     }
       
  2006     {
       
  2007         QScriptValue val = qScriptValueFromValue(&eng, char(123));
       
  2008         QVERIFY(val.isNumber());
       
  2009         QCOMPARE(val.toInt32(), 123);
       
  2010     }
       
  2011     {
       
  2012         QScriptValue val = qScriptValueFromValue(&eng, uchar(123));
       
  2013         QVERIFY(val.isNumber());
       
  2014         QCOMPARE(val.toInt32(), 123);
       
  2015     }
       
  2016     {
       
  2017         QDateTime in = QDateTime::currentDateTime();
       
  2018         QScriptValue val = qScriptValueFromValue(&eng, in);
       
  2019         QVERIFY(val.isDate());
       
  2020         QCOMPARE(val.toDateTime(), in);
       
  2021     }
       
  2022     {
       
  2023         QDate in = QDate::currentDate();
       
  2024         QScriptValue val = qScriptValueFromValue(&eng, in);
       
  2025         QVERIFY(val.isDate());
       
  2026         QCOMPARE(val.toDateTime().date(), in);
       
  2027     }
       
  2028     {
       
  2029         QRegExp in = QRegExp("foo");
       
  2030         QScriptValue val = qScriptValueFromValue(&eng, in);
       
  2031         QVERIFY(val.isRegExp());
       
  2032         QRegExp out = val.toRegExp();
       
  2033         QEXPECT_FAIL("", "JSC-based back-end doesn't preserve QRegExp::patternSyntax (always uses RegExp2)", Continue);
       
  2034         QCOMPARE(out.patternSyntax(), in.patternSyntax());
       
  2035         QCOMPARE(out.pattern(), in.pattern());
       
  2036         QCOMPARE(out.caseSensitivity(), in.caseSensitivity());
       
  2037         QCOMPARE(out.isMinimal(), in.isMinimal());
       
  2038     }
       
  2039     {
       
  2040         QRegExp in = QRegExp("foo", Qt::CaseSensitive, QRegExp::RegExp2);
       
  2041         QScriptValue val = qScriptValueFromValue(&eng, in);
       
  2042         QVERIFY(val.isRegExp());
       
  2043         QCOMPARE(val.toRegExp(), in);
       
  2044     }
       
  2045     {
       
  2046         QRegExp in = QRegExp("foo");
       
  2047         in.setMinimal(true);
       
  2048         QScriptValue val = qScriptValueFromValue(&eng, in);
       
  2049         QVERIFY(val.isRegExp());
       
  2050         QEXPECT_FAIL("", "JSC-based back-end doesn't preserve QRegExp::minimal (always false)", Continue);
       
  2051         QCOMPARE(val.toRegExp().isMinimal(), in.isMinimal());
       
  2052     }
       
  2053 }
       
  2054 
       
  2055 static QScriptValue __import__(QScriptContext *ctx, QScriptEngine *eng)
       
  2056 {
       
  2057     return eng->importExtension(ctx->argument(0).toString());
       
  2058 }
       
  2059 
       
  2060 void tst_QScriptEngine::importExtension()
       
  2061 {
       
  2062     QStringList libPaths = QCoreApplication::instance()->libraryPaths();
       
  2063     QCoreApplication::instance()->setLibraryPaths(QStringList() << SRCDIR);
       
  2064 
       
  2065     QStringList availableExtensions;
       
  2066     {
       
  2067         QScriptEngine eng;
       
  2068         QVERIFY(eng.importedExtensions().isEmpty());
       
  2069         QStringList ret = eng.availableExtensions();
       
  2070         QCOMPARE(ret.size(), 4);
       
  2071         QCOMPARE(ret.at(0), QString::fromLatin1("com"));
       
  2072         QCOMPARE(ret.at(1), QString::fromLatin1("com.trolltech"));
       
  2073         QCOMPARE(ret.at(2), QString::fromLatin1("com.trolltech.recursive"));
       
  2074         QCOMPARE(ret.at(3), QString::fromLatin1("com.trolltech.syntaxerror"));
       
  2075         availableExtensions = ret;
       
  2076     }
       
  2077 
       
  2078     // try to import something that doesn't exist
       
  2079     {
       
  2080         QScriptEngine eng;
       
  2081         QScriptValue ret = eng.importExtension("this.extension.does.not.exist");
       
  2082         QCOMPARE(eng.hasUncaughtException(), true);
       
  2083         QCOMPARE(ret.isError(), true);
       
  2084         QCOMPARE(ret.toString(), QString::fromLatin1("Error: Unable to import this.extension.does.not.exist: no such extension"));
       
  2085     }
       
  2086 
       
  2087     {
       
  2088         QScriptEngine eng;
       
  2089         for (int x = 0; x < 2; ++x) {
       
  2090             QCOMPARE(eng.globalObject().property("com").isValid(), x == 1);
       
  2091             QScriptValue ret = eng.importExtension("com.trolltech");
       
  2092             QCOMPARE(eng.hasUncaughtException(), false);
       
  2093             QCOMPARE(ret.isUndefined(), true);
       
  2094 
       
  2095             QScriptValue com = eng.globalObject().property("com");
       
  2096             QCOMPARE(com.isObject(), true);
       
  2097             QCOMPARE(com.property("wasDefinedAlready")
       
  2098                      .strictlyEquals(QScriptValue(&eng, false)), true);
       
  2099             QCOMPARE(com.property("name")
       
  2100                      .strictlyEquals(QScriptValue(&eng, "com")), true);
       
  2101             QCOMPARE(com.property("level")
       
  2102                      .strictlyEquals(QScriptValue(&eng, 1)), true);
       
  2103             QVERIFY(com.property("originalPostInit").isUndefined());
       
  2104             QVERIFY(com.property("postInitCallCount").strictlyEquals(1));
       
  2105 
       
  2106             QScriptValue trolltech = com.property("trolltech");
       
  2107             QCOMPARE(trolltech.isObject(), true);
       
  2108             QCOMPARE(trolltech.property("wasDefinedAlready")
       
  2109                      .strictlyEquals(QScriptValue(&eng, false)), true);
       
  2110             QCOMPARE(trolltech.property("name")
       
  2111                      .strictlyEquals(QScriptValue(&eng, "com.trolltech")), true);
       
  2112             QCOMPARE(trolltech.property("level")
       
  2113                      .strictlyEquals(QScriptValue(&eng, 2)), true);
       
  2114             QVERIFY(trolltech.property("originalPostInit").isUndefined());
       
  2115             QVERIFY(trolltech.property("postInitCallCount").strictlyEquals(1));
       
  2116         }
       
  2117         QStringList imp = eng.importedExtensions();
       
  2118         QCOMPARE(imp.size(), 2);
       
  2119         QCOMPARE(imp.at(0), QString::fromLatin1("com"));
       
  2120         QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
       
  2121         QCOMPARE(eng.availableExtensions(), availableExtensions);
       
  2122     }
       
  2123 
       
  2124     // recursive import should throw an error
       
  2125     {
       
  2126         QScriptEngine eng;
       
  2127         QVERIFY(eng.importedExtensions().isEmpty());
       
  2128         eng.globalObject().setProperty("__import__", eng.newFunction(__import__));
       
  2129         QScriptValue ret = eng.importExtension("com.trolltech.recursive");
       
  2130         QCOMPARE(eng.hasUncaughtException(), true);
       
  2131         QVERIFY(ret.isError());
       
  2132         QCOMPARE(ret.toString(), QString::fromLatin1("Error: recursive import of com.trolltech.recursive"));
       
  2133         QStringList imp = eng.importedExtensions();
       
  2134         QCOMPARE(imp.size(), 2);
       
  2135         QCOMPARE(imp.at(0), QString::fromLatin1("com"));
       
  2136         QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
       
  2137         QCOMPARE(eng.availableExtensions(), availableExtensions);
       
  2138     }
       
  2139 
       
  2140     {
       
  2141         QScriptEngine eng;
       
  2142         eng.globalObject().setProperty("__import__", eng.newFunction(__import__));
       
  2143         for (int x = 0; x < 2; ++x) {
       
  2144             if (x == 0)
       
  2145                 QVERIFY(eng.importedExtensions().isEmpty());
       
  2146             QScriptValue ret = eng.importExtension("com.trolltech.syntaxerror");
       
  2147             QVERIFY(eng.hasUncaughtException());
       
  2148             QEXPECT_FAIL("", "JSC throws syntax error eagerly", Continue);
       
  2149             QCOMPARE(eng.uncaughtExceptionLineNumber(), 4);
       
  2150             QVERIFY(ret.isError());
       
  2151             QCOMPARE(ret.property("message").toString(), QLatin1String("Parse error"));
       
  2152         }
       
  2153         QStringList imp = eng.importedExtensions();
       
  2154         QCOMPARE(imp.size(), 2);
       
  2155         QCOMPARE(imp.at(0), QString::fromLatin1("com"));
       
  2156         QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
       
  2157         QCOMPARE(eng.availableExtensions(), availableExtensions);
       
  2158     }
       
  2159 
       
  2160     QCoreApplication::instance()->setLibraryPaths(libPaths);
       
  2161 }
       
  2162 
       
  2163 static QScriptValue recurse(QScriptContext *ctx, QScriptEngine *eng)
       
  2164 {
       
  2165     Q_UNUSED(eng);
       
  2166     return ctx->callee().call();
       
  2167 }
       
  2168 
       
  2169 static QScriptValue recurse2(QScriptContext *ctx, QScriptEngine *eng)
       
  2170 {
       
  2171     Q_UNUSED(eng);
       
  2172     return ctx->callee().construct();
       
  2173 }
       
  2174 
       
  2175 void tst_QScriptEngine::infiniteRecursion()
       
  2176 {
       
  2177     const QString stackOverflowError = QString::fromLatin1("RangeError: Maximum call stack size exceeded.");
       
  2178     QScriptEngine eng;
       
  2179     {
       
  2180         QScriptValue ret = eng.evaluate("function foo() { foo(); }; foo();");
       
  2181         QCOMPARE(ret.isError(), true);
       
  2182         QCOMPARE(ret.toString(), stackOverflowError);
       
  2183     }
       
  2184 #if 0 //The native C++ stack overflow before the JS stack
       
  2185     {
       
  2186         QScriptValue fun = eng.newFunction(recurse);
       
  2187         QScriptValue ret = fun.call();
       
  2188         QCOMPARE(ret.isError(), true);
       
  2189         QCOMPARE(ret.toString(), stackOverflowError);
       
  2190     }
       
  2191     {
       
  2192         QScriptValue fun = eng.newFunction(recurse2);
       
  2193         QScriptValue ret = fun.construct();
       
  2194         QCOMPARE(ret.isError(), true);
       
  2195         QCOMPARE(ret.toString(), stackOverflowError);
       
  2196     }
       
  2197 #endif
       
  2198 }
       
  2199 
       
  2200 struct Bar {
       
  2201     int a;
       
  2202 };
       
  2203 
       
  2204 struct Baz : public Bar {
       
  2205     int b;
       
  2206 };
       
  2207 
       
  2208 Q_DECLARE_METATYPE(Bar*)
       
  2209 Q_DECLARE_METATYPE(Baz*)
       
  2210 
       
  2211 Q_DECLARE_METATYPE(QGradient)
       
  2212 Q_DECLARE_METATYPE(QGradient*)
       
  2213 Q_DECLARE_METATYPE(QLinearGradient)
       
  2214 
       
  2215 class Zoo : public QObject
       
  2216 {
       
  2217     Q_OBJECT
       
  2218 public:
       
  2219     Zoo() { }
       
  2220 public slots:
       
  2221     Baz *toBaz(Bar *b) { return reinterpret_cast<Baz*>(b); }
       
  2222 };
       
  2223 
       
  2224 void tst_QScriptEngine::castWithPrototypeChain()
       
  2225 {
       
  2226     QScriptEngine eng;
       
  2227     Bar bar;
       
  2228     Baz baz;
       
  2229     QScriptValue barProto = qScriptValueFromValue(&eng, &bar);
       
  2230     QScriptValue bazProto = qScriptValueFromValue(&eng, &baz);
       
  2231     eng.setDefaultPrototype(qMetaTypeId<Bar*>(), barProto);
       
  2232     eng.setDefaultPrototype(qMetaTypeId<Baz*>(), bazProto);
       
  2233 
       
  2234     Baz baz2;
       
  2235     baz2.a = 123;
       
  2236     baz2.b = 456;
       
  2237     QScriptValue baz2Value = qScriptValueFromValue(&eng, &baz2);
       
  2238     {
       
  2239         Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
       
  2240         QVERIFY(pbaz != 0);
       
  2241         QCOMPARE(pbaz->b, baz2.b);
       
  2242 
       
  2243         Zoo zoo;
       
  2244         QScriptValue scriptZoo = eng.newQObject(&zoo);
       
  2245         QScriptValue toBaz = scriptZoo.property("toBaz");
       
  2246         QVERIFY(toBaz.isFunction());
       
  2247 
       
  2248         // no relation between Bar and Baz's proto --> casting fails
       
  2249         {
       
  2250             Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
       
  2251             QVERIFY(pbar == 0);
       
  2252         }
       
  2253 
       
  2254         {
       
  2255             QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value);
       
  2256             QVERIFY(ret.isError());
       
  2257             QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to toBaz(); candidates were\n    toBaz(Bar*)"));
       
  2258         }
       
  2259 
       
  2260         // establish chain -- now casting should work
       
  2261         bazProto.setPrototype(barProto);
       
  2262 
       
  2263         {
       
  2264             Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
       
  2265             QVERIFY(pbar != 0);
       
  2266             QCOMPARE(pbar->a, baz2.a);
       
  2267         }
       
  2268 
       
  2269         {
       
  2270             QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value);
       
  2271             QVERIFY(!ret.isError());
       
  2272             QCOMPARE(qscriptvalue_cast<Baz*>(ret), pbaz);
       
  2273         }
       
  2274     }
       
  2275 
       
  2276     bazProto.setPrototype(barProto.prototype()); // kill chain
       
  2277     {
       
  2278         Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
       
  2279         QVERIFY(pbaz != 0);
       
  2280         // should not work anymore
       
  2281         Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
       
  2282         QVERIFY(pbar == 0);
       
  2283     }
       
  2284 
       
  2285     bazProto.setPrototype(eng.newQObject(this));
       
  2286     {
       
  2287         Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
       
  2288         QVERIFY(pbaz != 0);
       
  2289         // should not work now either
       
  2290         Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
       
  2291         QVERIFY(pbar == 0);
       
  2292     }
       
  2293 
       
  2294     {
       
  2295         QScriptValue b = qScriptValueFromValue(&eng, QBrush());
       
  2296         b.setPrototype(barProto);
       
  2297         // this shows that a "wrong" cast is possible, if you
       
  2298         // don't play by the rules (the pointer is actually a QBrush*)...
       
  2299         Bar *pbar = qscriptvalue_cast<Bar*>(b);
       
  2300         QVERIFY(pbar != 0);
       
  2301     }
       
  2302 
       
  2303     {
       
  2304         QScriptValue gradientProto = qScriptValueFromValue(&eng, QGradient());
       
  2305         QScriptValue linearGradientProto = qScriptValueFromValue(&eng, QLinearGradient());
       
  2306         linearGradientProto.setPrototype(gradientProto);
       
  2307         QLinearGradient lg(10, 20, 30, 40);
       
  2308         QScriptValue linearGradient = qScriptValueFromValue(&eng, lg);
       
  2309         {
       
  2310             QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient);
       
  2311             QVERIFY(pgrad == 0);
       
  2312         }
       
  2313         linearGradient.setPrototype(linearGradientProto);
       
  2314         {
       
  2315             QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient);
       
  2316             QVERIFY(pgrad != 0);
       
  2317             QCOMPARE(pgrad->type(), QGradient::LinearGradient);
       
  2318             QLinearGradient *plingrad = static_cast<QLinearGradient*>(pgrad);
       
  2319             QCOMPARE(plingrad->start(), lg.start());
       
  2320             QCOMPARE(plingrad->finalStop(), lg.finalStop());
       
  2321         }
       
  2322     }
       
  2323 }
       
  2324 
       
  2325 class Klazz : public QWidget,
       
  2326               public QStandardItem,
       
  2327               public QGraphicsItem
       
  2328 {
       
  2329     Q_OBJECT
       
  2330 public:
       
  2331     Klazz(QWidget *parent = 0) : QWidget(parent) { }
       
  2332     virtual QRectF boundingRect() const { return QRectF(); }
       
  2333     virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { }
       
  2334 };
       
  2335 
       
  2336 Q_DECLARE_METATYPE(Klazz*)
       
  2337 Q_DECLARE_METATYPE(QStandardItem*)
       
  2338 
       
  2339 void tst_QScriptEngine::castWithMultipleInheritance()
       
  2340 {
       
  2341     QScriptEngine eng;
       
  2342     Klazz klz;
       
  2343     QScriptValue v = eng.newQObject(&klz);
       
  2344 
       
  2345     QCOMPARE(qscriptvalue_cast<Klazz*>(v), &klz);
       
  2346     QCOMPARE(qscriptvalue_cast<QWidget*>(v), (QWidget *)&klz);
       
  2347     QCOMPARE(qscriptvalue_cast<QObject*>(v), (QObject *)&klz);
       
  2348     QCOMPARE(qscriptvalue_cast<QStandardItem*>(v), (QStandardItem *)&klz);
       
  2349     QCOMPARE(qscriptvalue_cast<QGraphicsItem*>(v), (QGraphicsItem *)&klz);
       
  2350 }
       
  2351 
       
  2352 void tst_QScriptEngine::collectGarbage()
       
  2353 {
       
  2354     QScriptEngine eng;
       
  2355     eng.evaluate("a = new Object(); a = new Object(); a = new Object()");
       
  2356     QScriptValue a = eng.newObject();
       
  2357     a = eng.newObject();
       
  2358     a = eng.newObject();
       
  2359     QPointer<QObject> ptr = new QObject();
       
  2360     QVERIFY(ptr != 0);
       
  2361     (void)eng.newQObject(ptr, QScriptEngine::ScriptOwnership);
       
  2362     collectGarbage_helper(eng);
       
  2363     QVERIFY(ptr == 0);
       
  2364 }
       
  2365 
       
  2366 void tst_QScriptEngine::gcWithNestedDataStructure()
       
  2367 {
       
  2368     QScriptEngine eng;
       
  2369     eng.evaluate(
       
  2370         "function makeList(size)"
       
  2371         "{"
       
  2372         "  var head = { };"
       
  2373         "  var l = head;"
       
  2374         "  for (var i = 0; i < size; ++i) {"
       
  2375         "    l.data = i + \"\";"
       
  2376         "    l.next = { }; l = l.next;"
       
  2377         "  }"
       
  2378         "  l.next = null;"
       
  2379         "  return head;"
       
  2380         "}");
       
  2381     QCOMPARE(eng.hasUncaughtException(), false);
       
  2382     const int size = 200;
       
  2383     QScriptValue head = eng.evaluate(QString::fromLatin1("makeList(%0)").arg(size));
       
  2384     QCOMPARE(eng.hasUncaughtException(), false);
       
  2385     for (int x = 0; x < 2; ++x) {
       
  2386         if (x == 1)
       
  2387             eng.evaluate("gc()");
       
  2388         QScriptValue l = head;
       
  2389         for (int i = 0; i < 200; ++i) {
       
  2390             QCOMPARE(l.property("data").toString(), QString::number(i));
       
  2391             l = l.property("next");
       
  2392         }
       
  2393     }
       
  2394 }
       
  2395 
       
  2396 class EventReceiver : public QObject
       
  2397 {
       
  2398 public:
       
  2399     EventReceiver() {
       
  2400         received = false;
       
  2401     }
       
  2402 
       
  2403     bool event(QEvent *e) {
       
  2404         received |= (e->type() == QEvent::User + 1);
       
  2405         return QObject::event(e);
       
  2406     }
       
  2407 
       
  2408     bool received;
       
  2409 };
       
  2410 
       
  2411 void tst_QScriptEngine::processEventsWhileRunning()
       
  2412 {
       
  2413     for (int x = 0; x < 2; ++x) {
       
  2414         QScriptEngine eng;
       
  2415         if (x == 0)
       
  2416             eng.pushContext();
       
  2417 
       
  2418         QString script = QString::fromLatin1(
       
  2419             "var end = Number(new Date()) + 2000;"
       
  2420             "var x = 0;"
       
  2421             "while (Number(new Date()) < end) {"
       
  2422             "    ++x;"
       
  2423             "}");
       
  2424 
       
  2425         EventReceiver receiver;
       
  2426         QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
       
  2427 
       
  2428         eng.evaluate(script);
       
  2429         QVERIFY(!eng.hasUncaughtException());
       
  2430         QVERIFY(!receiver.received);
       
  2431 
       
  2432         QCOMPARE(eng.processEventsInterval(), -1);
       
  2433         eng.setProcessEventsInterval(100);
       
  2434         eng.evaluate(script);
       
  2435         QVERIFY(!eng.hasUncaughtException());
       
  2436         QVERIFY(receiver.received);
       
  2437 
       
  2438         if (x == 0)
       
  2439             eng.popContext();
       
  2440     }
       
  2441 }
       
  2442 
       
  2443 class EventReceiver2 : public QObject
       
  2444 {
       
  2445 public:
       
  2446     EventReceiver2(QScriptEngine *eng) {
       
  2447         engine = eng;
       
  2448     }
       
  2449 
       
  2450     bool event(QEvent *e) {
       
  2451         if (e->type() == QEvent::User + 1) {
       
  2452             engine->currentContext()->throwError("Killed");
       
  2453         }
       
  2454         return QObject::event(e);
       
  2455     }
       
  2456 
       
  2457     QScriptEngine *engine;
       
  2458 };
       
  2459 
       
  2460 void tst_QScriptEngine::throwErrorFromProcessEvents()
       
  2461 {
       
  2462     QScriptEngine eng;
       
  2463 
       
  2464     EventReceiver2 receiver(&eng);
       
  2465     QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
       
  2466 
       
  2467     eng.setProcessEventsInterval(100);
       
  2468     QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }"));
       
  2469     QVERIFY(ret.isError());
       
  2470     QCOMPARE(ret.toString(), QString::fromLatin1("Error: Killed"));
       
  2471 }
       
  2472 
       
  2473 void tst_QScriptEngine::stacktrace()
       
  2474 {
       
  2475     QString script = QString::fromLatin1(
       
  2476         "function foo(counter) {\n"
       
  2477         "    switch (counter) {\n"
       
  2478         "        case 0: foo(counter+1); break;\n"
       
  2479         "        case 1: foo(counter+1); break;\n"
       
  2480         "        case 2: foo(counter+1); break;\n"
       
  2481         "        case 3: foo(counter+1); break;\n"
       
  2482         "        case 4: foo(counter+1); break;\n"
       
  2483         "        default:\n"
       
  2484         "        throw new Error('blah');\n"
       
  2485         "    }\n"
       
  2486         "}\n"
       
  2487         "foo(0);");
       
  2488 
       
  2489     const QString fileName("testfile");
       
  2490 
       
  2491     QStringList backtrace;
       
  2492     backtrace << "foo(5)@testfile:9"
       
  2493               << "foo(4)@testfile:7"
       
  2494               << "foo(3)@testfile:6"
       
  2495               << "foo(2)@testfile:5"
       
  2496               << "foo(1)@testfile:4"
       
  2497               << "foo(0)@testfile:3"
       
  2498               << "<global>()@testfile:12";
       
  2499 
       
  2500     QScriptEngine eng;
       
  2501     QScriptValue result = eng.evaluate(script, fileName);
       
  2502     QVERIFY(eng.hasUncaughtException());
       
  2503     QVERIFY(result.isError());
       
  2504 
       
  2505     QEXPECT_FAIL("", "", Abort);
       
  2506     QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
       
  2507     QVERIFY(eng.hasUncaughtException());
       
  2508     QVERIFY(result.strictlyEquals(eng.uncaughtException()));
       
  2509 
       
  2510     QCOMPARE(result.property("fileName").toString(), fileName);
       
  2511     QCOMPARE(result.property("lineNumber").toInt32(), 9);
       
  2512 
       
  2513     QScriptValue stack = result.property("stack");
       
  2514     QVERIFY(stack.isArray());
       
  2515 
       
  2516     QCOMPARE(stack.property("length").toInt32(), 7);
       
  2517 
       
  2518     QScriptValueIterator it(stack);
       
  2519     int counter = 5;
       
  2520     while (it.hasNext()) {
       
  2521         it.next();
       
  2522         QScriptValue obj = it.value();
       
  2523         QScriptValue frame = obj.property("frame");
       
  2524 
       
  2525         QCOMPARE(obj.property("fileName").toString(), fileName);
       
  2526         if (counter >= 0) {
       
  2527             QScriptValue callee = frame.property("arguments").property("callee");
       
  2528             QVERIFY(callee.strictlyEquals(eng.globalObject().property("foo")));
       
  2529             QCOMPARE(obj.property("functionName").toString(), QString("foo"));
       
  2530             int line = obj.property("lineNumber").toInt32();
       
  2531             if (counter == 5)
       
  2532                 QCOMPARE(line, 9);
       
  2533             else
       
  2534                 QCOMPARE(line, 3 + counter);
       
  2535         } else {
       
  2536             QVERIFY(frame.strictlyEquals(eng.globalObject()));
       
  2537             QVERIFY(obj.property("functionName").toString().isEmpty());
       
  2538         }
       
  2539 
       
  2540         --counter;
       
  2541     }
       
  2542 
       
  2543     {
       
  2544         QScriptValue bt = result.property("backtrace").call(result);
       
  2545         QCOMPARE(qscriptvalue_cast<QStringList>(bt), backtrace);
       
  2546     }
       
  2547 
       
  2548     // throw something that isn't an Error object
       
  2549     eng.clearExceptions();
       
  2550     QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
       
  2551     QString script2 = QString::fromLatin1(
       
  2552         "function foo(counter) {\n"
       
  2553         "    switch (counter) {\n"
       
  2554         "        case 0: foo(counter+1); break;\n"
       
  2555         "        case 1: foo(counter+1); break;\n"
       
  2556         "        case 2: foo(counter+1); break;\n"
       
  2557         "        case 3: foo(counter+1); break;\n"
       
  2558         "        case 4: foo(counter+1); break;\n"
       
  2559         "        default:\n"
       
  2560         "        throw 'just a string';\n"
       
  2561         "    }\n"
       
  2562         "}\n"
       
  2563         "foo(0);");
       
  2564 
       
  2565     QScriptValue result2 = eng.evaluate(script2, fileName);
       
  2566     QVERIFY(eng.hasUncaughtException());
       
  2567     QVERIFY(!result2.isError());
       
  2568     QVERIFY(result2.isString());
       
  2569 
       
  2570     QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
       
  2571     QVERIFY(eng.hasUncaughtException());
       
  2572 
       
  2573     eng.clearExceptions();
       
  2574     QVERIFY(!eng.hasUncaughtException());
       
  2575     QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
       
  2576 }
       
  2577 
       
  2578 void tst_QScriptEngine::numberParsing_data()
       
  2579 {
       
  2580     QTest::addColumn<QString>("string");
       
  2581     QTest::addColumn<qsreal>("expect");
       
  2582 
       
  2583     QTest::newRow("decimal 0") << QString("0") << qsreal(0);
       
  2584     QTest::newRow("octal 0") << QString("00") << qsreal(00);
       
  2585     QTest::newRow("hex 0") << QString("0x0") << qsreal(0x0);
       
  2586     QTest::newRow("decimal 100") << QString("100") << qsreal(100);
       
  2587     QTest::newRow("hex 100") << QString("0x100") << qsreal(0x100);
       
  2588     QTest::newRow("octal 100") << QString("0100") << qsreal(0100);
       
  2589     QTest::newRow("decimal 4G") << QString("4294967296") << qsreal(Q_UINT64_C(4294967296));
       
  2590     QTest::newRow("hex 4G") << QString("0x100000000") << qsreal(Q_UINT64_C(0x100000000));
       
  2591     QTest::newRow("octal 4G") << QString("040000000000") << qsreal(Q_UINT64_C(040000000000));
       
  2592     QTest::newRow("0.5") << QString("0.5") << qsreal(0.5);
       
  2593     QTest::newRow("1.5") << QString("1.5") << qsreal(1.5);
       
  2594     QTest::newRow("1e2") << QString("1e2") << qsreal(100);
       
  2595 }
       
  2596 
       
  2597 void tst_QScriptEngine::numberParsing()
       
  2598 {
       
  2599     QFETCH(QString, string);
       
  2600     QFETCH(qsreal, expect);
       
  2601 
       
  2602     QScriptEngine eng;
       
  2603     QScriptValue ret = eng.evaluate(string);
       
  2604     QVERIFY(ret.isNumber());
       
  2605     qsreal actual = ret.toNumber();
       
  2606     QCOMPARE(actual, expect);
       
  2607 }
       
  2608 
       
  2609 // see ECMA-262, section 7.9
       
  2610 void tst_QScriptEngine::automaticSemicolonInsertion()
       
  2611 {
       
  2612     QScriptEngine eng;
       
  2613     {
       
  2614         QScriptValue ret = eng.evaluate("{ 1 2 } 3");
       
  2615         QVERIFY(ret.isError());
       
  2616         QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
       
  2617     }
       
  2618     {
       
  2619         QScriptValue ret = eng.evaluate("{ 1\n2 } 3");
       
  2620         QVERIFY(ret.isNumber());
       
  2621         QCOMPARE(ret.toInt32(), 3);
       
  2622     }
       
  2623     {
       
  2624         QScriptValue ret = eng.evaluate("for (a; b\n)");
       
  2625         QVERIFY(ret.isError());
       
  2626         QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
       
  2627     }
       
  2628     {
       
  2629         QScriptValue ret = eng.evaluate("(function() { return\n1 + 2 })()");
       
  2630         QVERIFY(ret.isUndefined());
       
  2631     }
       
  2632     {
       
  2633         eng.evaluate("c = 2; b = 1");
       
  2634         QScriptValue ret = eng.evaluate("a = b\n++c");
       
  2635         QVERIFY(ret.isNumber());
       
  2636         QCOMPARE(ret.toInt32(), 3);
       
  2637     }
       
  2638     {
       
  2639         QScriptValue ret = eng.evaluate("if (a > b)\nelse c = d");
       
  2640         QVERIFY(ret.isError());
       
  2641         QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
       
  2642     }
       
  2643     {
       
  2644         eng.evaluate("function c() { return { foo: function() { return 5; } } }");
       
  2645         eng.evaluate("b = 1; d = 2; e = 3");
       
  2646         QScriptValue ret = eng.evaluate("a = b + c\n(d + e).foo()");
       
  2647         QVERIFY(ret.isNumber());
       
  2648         QCOMPARE(ret.toInt32(), 6);
       
  2649     }
       
  2650     {
       
  2651         QScriptValue ret = eng.evaluate("throw\n1");
       
  2652         QVERIFY(ret.isError());
       
  2653         QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
       
  2654     }
       
  2655     {
       
  2656         QScriptValue ret = eng.evaluate("a = Number(1)\n++a");
       
  2657         QVERIFY(ret.isNumber());
       
  2658         QCOMPARE(ret.toInt32(), 2);
       
  2659     }
       
  2660 
       
  2661     // "a semicolon is never inserted automatically if the semicolon
       
  2662     // would then be parsed as an empty statement"
       
  2663     {
       
  2664         eng.evaluate("a = 123");
       
  2665         QScriptValue ret = eng.evaluate("if (0)\n ++a; a");
       
  2666         QVERIFY(ret.isNumber());
       
  2667         QCOMPARE(ret.toInt32(), 123);
       
  2668     }
       
  2669     {
       
  2670         eng.evaluate("a = 123");
       
  2671         QScriptValue ret = eng.evaluate("if (0)\n --a; a");
       
  2672         QVERIFY(ret.isNumber());
       
  2673         QCOMPARE(ret.toInt32(), 123);
       
  2674     }
       
  2675     {
       
  2676         eng.evaluate("a = 123");
       
  2677         QScriptValue ret = eng.evaluate("if ((0))\n ++a; a");
       
  2678         QVERIFY(ret.isNumber());
       
  2679         QCOMPARE(ret.toInt32(), 123);
       
  2680     }
       
  2681     {
       
  2682         eng.evaluate("a = 123");
       
  2683         QScriptValue ret = eng.evaluate("if ((0))\n --a; a");
       
  2684         QVERIFY(ret.isNumber());
       
  2685         QCOMPARE(ret.toInt32(), 123);
       
  2686     }
       
  2687     {
       
  2688         eng.evaluate("a = 123");
       
  2689         QScriptValue ret = eng.evaluate("if (0\n)\n ++a; a");
       
  2690         QVERIFY(ret.isNumber());
       
  2691         QCOMPARE(ret.toInt32(), 123);
       
  2692     }
       
  2693     {
       
  2694         eng.evaluate("a = 123");
       
  2695         QScriptValue ret = eng.evaluate("if (0\n ++a; a");
       
  2696         QVERIFY(ret.isError());
       
  2697     }
       
  2698     {
       
  2699         eng.evaluate("a = 123");
       
  2700         QScriptValue ret = eng.evaluate("if (0))\n ++a; a");
       
  2701         QVERIFY(ret.isError());
       
  2702     }
       
  2703     {
       
  2704         QScriptValue ret = eng.evaluate("n = 0; for (i = 0; i < 10; ++i)\n ++n; n");
       
  2705         QVERIFY(ret.isNumber());
       
  2706         QCOMPARE(ret.toInt32(), 10);
       
  2707     }
       
  2708     {
       
  2709         QScriptValue ret = eng.evaluate("n = 30; for (i = 0; i < 10; ++i)\n --n; n");
       
  2710         QVERIFY(ret.isNumber());
       
  2711         QCOMPARE(ret.toInt32(), 20);
       
  2712     }
       
  2713     {
       
  2714         QScriptValue ret = eng.evaluate("n = 0; for (var i = 0; i < 10; ++i)\n ++n; n");
       
  2715         QVERIFY(ret.isNumber());
       
  2716         QCOMPARE(ret.toInt32(), 10);
       
  2717     }
       
  2718     {
       
  2719         QScriptValue ret = eng.evaluate("n = 30; for (var i = 0; i < 10; ++i)\n --n; n");
       
  2720         QVERIFY(ret.isNumber());
       
  2721         QCOMPARE(ret.toInt32(), 20);
       
  2722     }
       
  2723     {
       
  2724         QScriptValue ret = eng.evaluate("n = 0; i = 0; while (i++ < 10)\n ++n; n");
       
  2725         QVERIFY(ret.isNumber());
       
  2726         QCOMPARE(ret.toInt32(), 10);
       
  2727     }
       
  2728     {
       
  2729         QScriptValue ret = eng.evaluate("n = 30; i = 0; while (i++ < 10)\n --n; n");
       
  2730         QVERIFY(ret.isNumber());
       
  2731         QCOMPARE(ret.toInt32(), 20);
       
  2732     }
       
  2733     {
       
  2734         QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (i in o)\n ++n; n");
       
  2735         QVERIFY(ret.isNumber());
       
  2736         QCOMPARE(ret.toInt32(), 3);
       
  2737     }
       
  2738     {
       
  2739         QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (i in o)\n --n; n");
       
  2740         QVERIFY(ret.isNumber());
       
  2741         QCOMPARE(ret.toInt32(), 6);
       
  2742     }
       
  2743     {
       
  2744         QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (var i in o)\n ++n; n");
       
  2745         QVERIFY(ret.isNumber());
       
  2746         QCOMPARE(ret.toInt32(), 3);
       
  2747     }
       
  2748     {
       
  2749         QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (var i in o)\n --n; n");
       
  2750         QVERIFY(ret.isNumber());
       
  2751         QCOMPARE(ret.toInt32(), 6);
       
  2752     }
       
  2753     {
       
  2754         QScriptValue ret = eng.evaluate("o = { n: 3 }; n = 5; with (o)\n ++n; n");
       
  2755         QVERIFY(ret.isNumber());
       
  2756         QCOMPARE(ret.toInt32(), 5);
       
  2757     }
       
  2758     {
       
  2759         QScriptValue ret = eng.evaluate("o = { n: 3 }; n = 10; with (o)\n --n; n");
       
  2760         QVERIFY(ret.isNumber());
       
  2761         QCOMPARE(ret.toInt32(), 10);
       
  2762     }
       
  2763     {
       
  2764         QScriptValue ret = eng.evaluate("n = 5; i = 0; do\n ++n; while (++i < 10); n");
       
  2765         QVERIFY(ret.isNumber());
       
  2766         QCOMPARE(ret.toInt32(), 15);
       
  2767     }
       
  2768     {
       
  2769         QScriptValue ret = eng.evaluate("n = 20; i = 0; do\n --n; while (++i < 10); n");
       
  2770         QVERIFY(ret.isNumber());
       
  2771         QCOMPARE(ret.toInt32(), 10);
       
  2772     }
       
  2773 
       
  2774     {
       
  2775         QScriptValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n++n; n");
       
  2776         QVERIFY(ret.isNumber());
       
  2777         QCOMPARE(ret.toInt32(), 2);
       
  2778     }
       
  2779     {
       
  2780         QScriptValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n--n; n");
       
  2781         QVERIFY(ret.isNumber());
       
  2782         QCOMPARE(ret.toInt32(), 0);
       
  2783     }
       
  2784 
       
  2785     {
       
  2786         QScriptValue ret = eng.evaluate("if (0)");
       
  2787         QVERIFY(ret.isError());
       
  2788     }
       
  2789     {
       
  2790         QScriptValue ret = eng.evaluate("while (0)");
       
  2791         QVERIFY(ret.isError());
       
  2792     }
       
  2793     {
       
  2794         QScriptValue ret = eng.evaluate("for (;;)");
       
  2795         QVERIFY(ret.isError());
       
  2796     }
       
  2797     {
       
  2798         QScriptValue ret = eng.evaluate("for (p in this)");
       
  2799         QVERIFY(ret.isError());
       
  2800     }
       
  2801     {
       
  2802         QScriptValue ret = eng.evaluate("with (this)");
       
  2803         QVERIFY(ret.isError());
       
  2804     }
       
  2805     {
       
  2806         QScriptValue ret = eng.evaluate("do");
       
  2807         QVERIFY(ret.isError());
       
  2808     }
       
  2809 }
       
  2810 
       
  2811 class EventReceiver3 : public QObject
       
  2812 {
       
  2813 public:
       
  2814     enum AbortionResult {
       
  2815         None = 0,
       
  2816         String = 1,
       
  2817         Error = 2
       
  2818     };
       
  2819 
       
  2820     EventReceiver3(QScriptEngine *eng) {
       
  2821         engine = eng;
       
  2822         resultType = None;
       
  2823     }
       
  2824 
       
  2825     bool event(QEvent *e) {
       
  2826         if (e->type() == QEvent::User + 1) {
       
  2827             switch (resultType) {
       
  2828             case None:
       
  2829                 engine->abortEvaluation();
       
  2830                 break;
       
  2831             case String:
       
  2832                 engine->abortEvaluation(QScriptValue(engine, QString::fromLatin1("Aborted")));
       
  2833                 break;
       
  2834             case Error:
       
  2835                 engine->abortEvaluation(engine->currentContext()->throwError("AbortedWithError"));
       
  2836                 break;
       
  2837             }
       
  2838         }
       
  2839         return QObject::event(e);
       
  2840     }
       
  2841 
       
  2842     AbortionResult resultType;
       
  2843     QScriptEngine *engine;
       
  2844 };
       
  2845 
       
  2846 static QScriptValue myFunctionAbortingEvaluation(QScriptContext *, QScriptEngine *eng)
       
  2847 {
       
  2848     eng->abortEvaluation();
       
  2849     return eng->nullValue(); // should be ignored
       
  2850 }
       
  2851 
       
  2852 void tst_QScriptEngine::abortEvaluation()
       
  2853 {
       
  2854     QScriptEngine eng;
       
  2855 
       
  2856     eng.abortEvaluation();
       
  2857     QVERIFY(!eng.hasUncaughtException());
       
  2858 
       
  2859     eng.abortEvaluation(123);
       
  2860     {
       
  2861         QScriptValue ret = eng.evaluate("'ciao'");
       
  2862         QVERIFY(ret.isString());
       
  2863         QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
       
  2864     }
       
  2865 
       
  2866     EventReceiver3 receiver(&eng);
       
  2867 
       
  2868     eng.setProcessEventsInterval(100);
       
  2869     for (int x = 0; x < 3; ++x) {
       
  2870         QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
       
  2871         receiver.resultType = EventReceiver3::AbortionResult(x);
       
  2872         QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }"));
       
  2873         switch (receiver.resultType) {
       
  2874         case EventReceiver3::None:
       
  2875             QVERIFY(!eng.hasUncaughtException());
       
  2876             QVERIFY(!ret.isValid());
       
  2877             break;
       
  2878         case EventReceiver3::String:
       
  2879             QVERIFY(!eng.hasUncaughtException());
       
  2880             QVERIFY(ret.isString());
       
  2881             QCOMPARE(ret.toString(), QString::fromLatin1("Aborted"));
       
  2882             break;
       
  2883         case EventReceiver3::Error:
       
  2884             QVERIFY(eng.hasUncaughtException());
       
  2885             QVERIFY(ret.isError());
       
  2886             QCOMPARE(ret.toString(), QString::fromLatin1("Error: AbortedWithError"));
       
  2887             break;
       
  2888         }
       
  2889     }
       
  2890 
       
  2891     // scripts cannot intercept the abortion with try/catch
       
  2892     for (int y = 0; y < 3; ++y) {
       
  2893         QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
       
  2894         receiver.resultType = EventReceiver3::AbortionResult(y);
       
  2895         QScriptValue ret = eng.evaluate(QString::fromLatin1(
       
  2896                                             "while (1) {\n"
       
  2897                                             "  try {\n"
       
  2898                                             "    (function() { while (1) { } })();\n"
       
  2899                                             "  } catch (e) {\n"
       
  2900                                             "    ;\n"
       
  2901                                             "  }\n"
       
  2902                                             "}"));
       
  2903         switch (receiver.resultType) {
       
  2904         case EventReceiver3::None:
       
  2905             QVERIFY(!eng.hasUncaughtException());
       
  2906             QVERIFY(!ret.isValid());
       
  2907             break;
       
  2908         case EventReceiver3::String:
       
  2909             QVERIFY(!eng.hasUncaughtException());
       
  2910             QVERIFY(ret.isString());
       
  2911             QCOMPARE(ret.toString(), QString::fromLatin1("Aborted"));
       
  2912             break;
       
  2913         case EventReceiver3::Error:
       
  2914             QVERIFY(eng.hasUncaughtException());
       
  2915             QVERIFY(ret.isError());
       
  2916             break;
       
  2917         }
       
  2918     }
       
  2919 
       
  2920     {
       
  2921         QScriptValue fun = eng.newFunction(myFunctionAbortingEvaluation);
       
  2922         eng.globalObject().setProperty("myFunctionAbortingEvaluation", fun);
       
  2923         QScriptValue ret = eng.evaluate("myFunctionAbortingEvaluation()");
       
  2924         QVERIFY(!ret.isValid());
       
  2925     }
       
  2926 }
       
  2927 
       
  2928 static QScriptValue myFunctionReturningIsEvaluating(QScriptContext *, QScriptEngine *eng)
       
  2929 {
       
  2930     return QScriptValue(eng, eng->isEvaluating());
       
  2931 }
       
  2932 
       
  2933 class EventReceiver4 : public QObject
       
  2934 {
       
  2935 public:
       
  2936     EventReceiver4(QScriptEngine *eng) {
       
  2937         engine = eng;
       
  2938         wasEvaluating = false;
       
  2939     }
       
  2940 
       
  2941     bool event(QEvent *e) {
       
  2942         if (e->type() == QEvent::User + 1) {
       
  2943             wasEvaluating = engine->isEvaluating();
       
  2944         }
       
  2945         return QObject::event(e);
       
  2946     }
       
  2947 
       
  2948     QScriptEngine *engine;
       
  2949     bool wasEvaluating;
       
  2950 };
       
  2951 
       
  2952 void tst_QScriptEngine::isEvaluating()
       
  2953 {
       
  2954     QScriptEngine eng;
       
  2955 
       
  2956     QVERIFY(!eng.isEvaluating());
       
  2957 
       
  2958     eng.evaluate("");
       
  2959     QVERIFY(!eng.isEvaluating());
       
  2960     eng.evaluate("123");
       
  2961     QVERIFY(!eng.isEvaluating());
       
  2962     eng.evaluate("0 = 0");
       
  2963     QVERIFY(!eng.isEvaluating());
       
  2964 
       
  2965     {
       
  2966         QScriptValue fun = eng.newFunction(myFunctionReturningIsEvaluating);
       
  2967         eng.globalObject().setProperty("myFunctionReturningIsEvaluating", fun);
       
  2968         QScriptValue ret = eng.evaluate("myFunctionReturningIsEvaluating()");
       
  2969         QVERIFY(ret.isBoolean());
       
  2970         QVERIFY(ret.toBoolean());
       
  2971     }
       
  2972 
       
  2973     {
       
  2974         EventReceiver4 receiver(&eng);
       
  2975         QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
       
  2976 
       
  2977         QString script = QString::fromLatin1(
       
  2978             "var end = Number(new Date()) + 1000;"
       
  2979             "var x = 0;"
       
  2980             "while (Number(new Date()) < end) {"
       
  2981             "    ++x;"
       
  2982             "}");
       
  2983 
       
  2984         eng.setProcessEventsInterval(100);
       
  2985         eng.evaluate(script);
       
  2986         QVERIFY(receiver.wasEvaluating);
       
  2987     }
       
  2988 }
       
  2989 
       
  2990 static QtMsgType theMessageType;
       
  2991 static QString theMessage;
       
  2992 
       
  2993 static void myMsgHandler(QtMsgType type, const char *msg)
       
  2994 {
       
  2995     theMessageType = type;
       
  2996     theMessage = QString::fromLatin1(msg);
       
  2997 }
       
  2998 
       
  2999 void tst_QScriptEngine::printFunctionWithCustomHandler()
       
  3000 {
       
  3001     QScriptEngine eng;
       
  3002     QtMsgHandler oldHandler = qInstallMsgHandler(myMsgHandler);
       
  3003     QVERIFY(eng.globalObject().property("print").isFunction());
       
  3004     theMessageType = QtSystemMsg;
       
  3005     QVERIFY(theMessage.isEmpty());
       
  3006     QVERIFY(eng.evaluate("print('test')").isUndefined());
       
  3007     QCOMPARE(theMessageType, QtDebugMsg);
       
  3008     QCOMPARE(theMessage, QString::fromLatin1("test"));
       
  3009     theMessageType = QtSystemMsg;
       
  3010     theMessage.clear();
       
  3011     QVERIFY(eng.evaluate("print(3, true, 'little pigs')").isUndefined());
       
  3012     QCOMPARE(theMessageType, QtDebugMsg);
       
  3013     QCOMPARE(theMessage, QString::fromLatin1("3 true little pigs"));
       
  3014     qInstallMsgHandler(oldHandler);
       
  3015 }
       
  3016 
       
  3017 void tst_QScriptEngine::printThrowsException()
       
  3018 {
       
  3019     QScriptEngine eng;
       
  3020     QScriptValue ret = eng.evaluate("print({ toString: function() { throw 'foo'; } });");
       
  3021     QVERIFY(eng.hasUncaughtException());
       
  3022     QVERIFY(ret.strictlyEquals(QScriptValue(&eng, QLatin1String("foo"))));
       
  3023 }
       
  3024 
       
  3025 void tst_QScriptEngine::errorConstructors()
       
  3026 {
       
  3027     QScriptEngine eng;
       
  3028     QStringList prefixes;
       
  3029     prefixes << "" << "Eval" << "Range" << "Reference" << "Syntax" << "Type" << "URI";
       
  3030     for (int x = 0; x < 3; ++x) {
       
  3031         for (int i = 0; i < prefixes.size(); ++i) {
       
  3032             QString name = prefixes.at(i) + QLatin1String("Error");
       
  3033             QString code = QString(i+1, QLatin1Char('\n'));
       
  3034             if (x == 0)
       
  3035                 code += QLatin1String("throw ");
       
  3036             else if (x == 1)
       
  3037                 code += QLatin1String("new ");
       
  3038             code += name + QLatin1String("()");
       
  3039             QScriptValue ret = eng.evaluate(code);
       
  3040             QVERIFY(ret.isError());
       
  3041             QCOMPARE(eng.hasUncaughtException(), x == 0);
       
  3042             eng.clearExceptions();
       
  3043             QVERIFY(ret.toString().startsWith(name));
       
  3044             if (x != 0)
       
  3045                 QEXPECT_FAIL("", "JSC doesn't assign lineNumber when errors are not thrown", Continue);
       
  3046             QCOMPARE(ret.property("lineNumber").toInt32(), i+2);
       
  3047         }
       
  3048     }
       
  3049 }
       
  3050 
       
  3051 static QScriptValue argumentsProperty_fun(QScriptContext *, QScriptEngine *eng)
       
  3052 {
       
  3053     eng->evaluate("var a = arguments[0];");
       
  3054     eng->evaluate("arguments[0] = 200;");
       
  3055     return eng->evaluate("a + arguments[0]");
       
  3056 }
       
  3057 
       
  3058 
       
  3059 void tst_QScriptEngine::argumentsProperty()
       
  3060 {
       
  3061     {
       
  3062         QScriptEngine eng;
       
  3063         QEXPECT_FAIL("", "", Continue);
       
  3064         QVERIFY(eng.evaluate("arguments").isUndefined());
       
  3065         eng.evaluate("arguments = 10");
       
  3066         QScriptValue ret = eng.evaluate("arguments");
       
  3067         QVERIFY(ret.isNumber());
       
  3068         QCOMPARE(ret.toInt32(), 10);
       
  3069         QEXPECT_FAIL("", "", Continue);
       
  3070         QVERIFY(!eng.evaluate("delete arguments").toBoolean());
       
  3071     }
       
  3072     {
       
  3073         QScriptEngine eng;
       
  3074         eng.evaluate("o = { arguments: 123 }");
       
  3075         QScriptValue ret = eng.evaluate("with (o) { arguments; }");
       
  3076         QVERIFY(ret.isNumber());
       
  3077         QCOMPARE(ret.toInt32(), 123);
       
  3078     }
       
  3079     {
       
  3080         QScriptEngine eng;
       
  3081         QScriptValue ret = eng.evaluate("(function() { arguments = 456; return arguments; })()");
       
  3082         QVERIFY(ret.isNumber());
       
  3083         QCOMPARE(ret.toInt32(), 456);
       
  3084         QEXPECT_FAIL("", "", Continue);
       
  3085         QVERIFY(eng.evaluate("arguments").isUndefined());
       
  3086     }
       
  3087 
       
  3088     {
       
  3089         QScriptEngine eng;
       
  3090         QScriptValue fun = eng.newFunction(argumentsProperty_fun);
       
  3091         eng.globalObject().setProperty("fun", eng.newFunction(argumentsProperty_fun));
       
  3092         QScriptValue result = eng.evaluate("fun(18)");
       
  3093         QVERIFY(result.isNumber());
       
  3094         QCOMPARE(result.toInt32(), 218);
       
  3095     }
       
  3096 }
       
  3097 
       
  3098 void tst_QScriptEngine::numberClass()
       
  3099 {
       
  3100     QScriptEngine eng;
       
  3101 
       
  3102     QScriptValue ctor = eng.globalObject().property("Number");
       
  3103     QVERIFY(ctor.property("length").isNumber());
       
  3104     QCOMPARE(ctor.property("length").toNumber(), qsreal(1));
       
  3105     QScriptValue proto = ctor.property("prototype");
       
  3106     QVERIFY(proto.isObject());
       
  3107     {
       
  3108         QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration
       
  3109                                             | QScriptValue::Undeletable
       
  3110                                             | QScriptValue::ReadOnly;
       
  3111         QCOMPARE(ctor.propertyFlags("prototype"), flags);
       
  3112         QVERIFY(ctor.property("MAX_VALUE").isNumber());
       
  3113         QCOMPARE(ctor.propertyFlags("MAX_VALUE"), flags);
       
  3114         QVERIFY(ctor.property("MIN_VALUE").isNumber());
       
  3115         QCOMPARE(ctor.propertyFlags("MIN_VALUE"), flags);
       
  3116         QVERIFY(ctor.property("NaN").isNumber());
       
  3117         QCOMPARE(ctor.propertyFlags("NaN"), flags);
       
  3118         QVERIFY(ctor.property("NEGATIVE_INFINITY").isNumber());
       
  3119         QCOMPARE(ctor.propertyFlags("NEGATIVE_INFINITY"), flags);
       
  3120         QVERIFY(ctor.property("POSITIVE_INFINITY").isNumber());
       
  3121         QCOMPARE(ctor.propertyFlags("POSITIVE_INFINITY"), flags);
       
  3122     }
       
  3123     QVERIFY(proto.instanceOf(eng.globalObject().property("Object")));
       
  3124     QCOMPARE(proto.toNumber(), qsreal(0));
       
  3125     QVERIFY(proto.property("constructor").strictlyEquals(ctor));
       
  3126 
       
  3127     {
       
  3128         QScriptValue ret = eng.evaluate("Number()");
       
  3129         QVERIFY(ret.isNumber());
       
  3130         QCOMPARE(ret.toNumber(), qsreal(0));
       
  3131     }
       
  3132     {
       
  3133         QScriptValue ret = eng.evaluate("Number(123)");
       
  3134         QVERIFY(ret.isNumber());
       
  3135         QCOMPARE(ret.toNumber(), qsreal(123));
       
  3136     }
       
  3137     {
       
  3138         QScriptValue ret = eng.evaluate("Number('456')");
       
  3139         QVERIFY(ret.isNumber());
       
  3140         QCOMPARE(ret.toNumber(), qsreal(456));
       
  3141     }
       
  3142     {
       
  3143         QScriptValue ret = eng.evaluate("new Number()");
       
  3144         QVERIFY(!ret.isNumber());
       
  3145         QVERIFY(ret.isObject());
       
  3146         QCOMPARE(ret.toNumber(), qsreal(0));
       
  3147     }
       
  3148     {
       
  3149         QScriptValue ret = eng.evaluate("new Number(123)");
       
  3150         QVERIFY(!ret.isNumber());
       
  3151         QVERIFY(ret.isObject());
       
  3152         QCOMPARE(ret.toNumber(), qsreal(123));
       
  3153     }
       
  3154     {
       
  3155         QScriptValue ret = eng.evaluate("new Number('456')");
       
  3156         QVERIFY(!ret.isNumber());
       
  3157         QVERIFY(ret.isObject());
       
  3158         QCOMPARE(ret.toNumber(), qsreal(456));
       
  3159     }
       
  3160 
       
  3161     QVERIFY(proto.property("toString").isFunction());
       
  3162     {
       
  3163         QScriptValue ret = eng.evaluate("new Number(123).toString()");
       
  3164         QVERIFY(ret.isString());
       
  3165         QCOMPARE(ret.toString(), QString::fromLatin1("123"));
       
  3166     }
       
  3167     {
       
  3168         QScriptValue ret = eng.evaluate("new Number(123).toString(8)");
       
  3169         QVERIFY(ret.isString());
       
  3170         QCOMPARE(ret.toString(), QString::fromLatin1("173"));
       
  3171     }
       
  3172     {
       
  3173         QScriptValue ret = eng.evaluate("new Number(123).toString(16)");
       
  3174         QVERIFY(ret.isString());
       
  3175         QCOMPARE(ret.toString(), QString::fromLatin1("7b"));
       
  3176     }
       
  3177     QVERIFY(proto.property("toLocaleString").isFunction());
       
  3178     {
       
  3179         QScriptValue ret = eng.evaluate("new Number(123).toLocaleString()");
       
  3180         QVERIFY(ret.isString());
       
  3181         QCOMPARE(ret.toString(), QString::fromLatin1("123"));
       
  3182     }
       
  3183     QVERIFY(proto.property("valueOf").isFunction());
       
  3184     {
       
  3185         QScriptValue ret = eng.evaluate("new Number(123).valueOf()");
       
  3186         QVERIFY(ret.isNumber());
       
  3187         QCOMPARE(ret.toNumber(), qsreal(123));
       
  3188     }
       
  3189     QVERIFY(proto.property("toExponential").isFunction());
       
  3190     {
       
  3191         QScriptValue ret = eng.evaluate("new Number(123).toExponential()");
       
  3192         QVERIFY(ret.isString());
       
  3193         QCOMPARE(ret.toString(), QString::fromLatin1("1.23e+2"));
       
  3194     }
       
  3195     QVERIFY(proto.property("toFixed").isFunction());
       
  3196     {
       
  3197         QScriptValue ret = eng.evaluate("new Number(123).toFixed()");
       
  3198         QVERIFY(ret.isString());
       
  3199         QCOMPARE(ret.toString(), QString::fromLatin1("123"));
       
  3200     }
       
  3201     QVERIFY(proto.property("toPrecision").isFunction());
       
  3202     {
       
  3203         QScriptValue ret = eng.evaluate("new Number(123).toPrecision()");
       
  3204         QVERIFY(ret.isString());
       
  3205         QCOMPARE(ret.toString(), QString::fromLatin1("123"));
       
  3206     }
       
  3207 }
       
  3208 
       
  3209 void tst_QScriptEngine::forInStatement()
       
  3210 {
       
  3211     QScriptEngine eng;
       
  3212     {
       
  3213         QScriptValue ret = eng.evaluate("o = { }; r = []; for (var p in o) r[r.length] = p; r");
       
  3214         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3215         QVERIFY(lst.isEmpty());
       
  3216     }
       
  3217     {
       
  3218         QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];"
       
  3219                                         "for (var p in o) r[r.length] = p; r");
       
  3220         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3221         QCOMPARE(lst.size(), 1);
       
  3222         QCOMPARE(lst.at(0), QString::fromLatin1("p"));
       
  3223     }
       
  3224     {
       
  3225         QScriptValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];"
       
  3226                                         "for (var p in o) r[r.length] = p; r");
       
  3227         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3228         QCOMPARE(lst.size(), 2);
       
  3229         QCOMPARE(lst.at(0), QString::fromLatin1("p"));
       
  3230         QCOMPARE(lst.at(1), QString::fromLatin1("q"));
       
  3231     }
       
  3232 
       
  3233     // properties in prototype
       
  3234     {
       
  3235         QScriptValue ret = eng.evaluate("o = { }; o.__proto__ = { p: 123 }; r = [];"
       
  3236                                         "for (var p in o) r[r.length] = p; r");
       
  3237         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3238         QCOMPARE(lst.size(), 1);
       
  3239         QCOMPARE(lst.at(0), QString::fromLatin1("p"));
       
  3240     }
       
  3241     {
       
  3242         QScriptValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { q: 456 }; r = [];"
       
  3243                                         "for (var p in o) r[r.length] = p; r");
       
  3244         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3245         QCOMPARE(lst.size(), 2);
       
  3246         QCOMPARE(lst.at(0), QString::fromLatin1("p"));
       
  3247         QCOMPARE(lst.at(1), QString::fromLatin1("q"));
       
  3248     }
       
  3249     {
       
  3250         // shadowed property
       
  3251         QScriptValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { p: 456 }; r = [];"
       
  3252                                         "for (var p in o) r[r.length] = p; r");
       
  3253         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3254         QCOMPARE(lst.size(), 1);
       
  3255         QCOMPARE(lst.at(0), QString::fromLatin1("p"));
       
  3256     }
       
  3257 
       
  3258     // deleting property during enumeration
       
  3259     {
       
  3260         QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];"
       
  3261                                         "for (var p in o) { r[r.length] = p; delete r[p]; } r");
       
  3262         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3263         QCOMPARE(lst.size(), 1);
       
  3264         QCOMPARE(lst.at(0), QString::fromLatin1("p"));
       
  3265     }
       
  3266     {
       
  3267         QScriptValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];"
       
  3268                                         "for (var p in o) { r[r.length] = p; delete o.q; } r");
       
  3269         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3270         QCOMPARE(lst.size(), 1);
       
  3271         QCOMPARE(lst.at(0), QString::fromLatin1("p"));
       
  3272     }
       
  3273 
       
  3274     // adding property during enumeration
       
  3275     {
       
  3276         QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];"
       
  3277                                         "for (var p in o) { r[r.length] = p; o.q = 456; } r");
       
  3278         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3279         QCOMPARE(lst.size(), 1);
       
  3280         QCOMPARE(lst.at(0), QString::fromLatin1("p"));
       
  3281     }
       
  3282 
       
  3283     // arrays
       
  3284     {
       
  3285         QScriptValue ret = eng.evaluate("a = [123, 456]; r = [];"
       
  3286                                         "for (var p in a) r[r.length] = p; r");
       
  3287         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3288         QCOMPARE(lst.size(), 2);
       
  3289         QCOMPARE(lst.at(0), QString::fromLatin1("0"));
       
  3290         QCOMPARE(lst.at(1), QString::fromLatin1("1"));
       
  3291     }
       
  3292     {
       
  3293         QScriptValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar'; r = [];"
       
  3294                                         "for (var p in a) r[r.length] = p; r");
       
  3295         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3296         QCOMPARE(lst.size(), 3);
       
  3297         QCOMPARE(lst.at(0), QString::fromLatin1("0"));
       
  3298         QCOMPARE(lst.at(1), QString::fromLatin1("1"));
       
  3299         QCOMPARE(lst.at(2), QString::fromLatin1("foo"));
       
  3300     }
       
  3301     {
       
  3302         QScriptValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar';"
       
  3303                                         "b = [111, 222, 333]; b.bar = 'baz';"
       
  3304                                         "a.__proto__ = b; r = [];"
       
  3305                                         "for (var p in a) r[r.length] = p; r");
       
  3306         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3307         QCOMPARE(lst.size(), 5);
       
  3308         QCOMPARE(lst.at(0), QString::fromLatin1("0"));
       
  3309         QCOMPARE(lst.at(1), QString::fromLatin1("1"));
       
  3310         QCOMPARE(lst.at(2), QString::fromLatin1("foo"));
       
  3311         QCOMPARE(lst.at(3), QString::fromLatin1("2"));
       
  3312         QCOMPARE(lst.at(4), QString::fromLatin1("bar"));
       
  3313     }
       
  3314 
       
  3315     // null and undefined
       
  3316     // according to the spec, we should throw an exception; however, for
       
  3317     // compability with the real world, we don't
       
  3318     {
       
  3319         QScriptValue ret = eng.evaluate("r = true; for (var p in undefined) r = false; r");
       
  3320         QVERIFY(ret.isBool());
       
  3321         QVERIFY(ret.toBool());
       
  3322     }
       
  3323     {
       
  3324         QScriptValue ret = eng.evaluate("r = true; for (var p in null) r = false; r");
       
  3325         QVERIFY(ret.isBool());
       
  3326         QVERIFY(ret.toBool());
       
  3327     }
       
  3328 }
       
  3329 
       
  3330 void tst_QScriptEngine::functionExpression()
       
  3331 {
       
  3332     // task 175679
       
  3333     QScriptEngine eng;
       
  3334     QVERIFY(!eng.globalObject().property("bar").isValid());
       
  3335     eng.evaluate("function foo(arg) {\n"
       
  3336                  "  if (arg == 'bar')\n"
       
  3337                  "    function bar() { return 'bar'; }\n"
       
  3338                  "  else\n"
       
  3339                  "    function baz() { return 'baz'; }\n"
       
  3340                  "  return (arg == 'bar') ? bar : baz;\n"
       
  3341                  "}");
       
  3342     QVERIFY(!eng.globalObject().property("bar").isValid());
       
  3343     QVERIFY(!eng.globalObject().property("baz").isValid());
       
  3344     QVERIFY(eng.evaluate("foo").isFunction());
       
  3345     {
       
  3346         QScriptValue ret = eng.evaluate("foo('bar')");
       
  3347         QVERIFY(ret.isFunction());
       
  3348         QScriptValue ret2 = ret.call(QScriptValue());
       
  3349         QCOMPARE(ret2.toString(), QString::fromLatin1("bar"));
       
  3350         QVERIFY(!eng.globalObject().property("bar").isValid());
       
  3351         QVERIFY(!eng.globalObject().property("baz").isValid());
       
  3352     }
       
  3353     {
       
  3354         QScriptValue ret = eng.evaluate("foo('baz')");
       
  3355         QVERIFY(ret.isFunction());
       
  3356         QScriptValue ret2 = ret.call(QScriptValue());
       
  3357         QCOMPARE(ret2.toString(), QString::fromLatin1("baz"));
       
  3358         QVERIFY(!eng.globalObject().property("bar").isValid());
       
  3359         QVERIFY(!eng.globalObject().property("baz").isValid());
       
  3360     }
       
  3361 }
       
  3362 
       
  3363 void tst_QScriptEngine::stringObjects()
       
  3364 {
       
  3365     QScriptEngine eng;
       
  3366     QString str("ciao");
       
  3367     // in C++
       
  3368     {
       
  3369         QScriptValue obj = QScriptValue(&eng, str).toObject();
       
  3370         QCOMPARE(obj.property("length").toInt32(), str.length());
       
  3371         QCOMPARE(obj.propertyFlags("length"), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly));
       
  3372         for (int i = 0; i < str.length(); ++i) {
       
  3373             QString pname = QString::number(i);
       
  3374             QVERIFY(obj.property(pname).isString());
       
  3375             QCOMPARE(obj.property(pname).toString(), QString(str.at(i)));
       
  3376             QCOMPARE(obj.propertyFlags(pname), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::ReadOnly));
       
  3377             obj.setProperty(pname, QScriptValue());
       
  3378             obj.setProperty(pname, QScriptValue(&eng, 123));
       
  3379             QVERIFY(obj.property(pname).isString());
       
  3380             QCOMPARE(obj.property(pname).toString(), QString(str.at(i)));
       
  3381         }
       
  3382         QVERIFY(!obj.property("-1").isValid());
       
  3383         QVERIFY(!obj.property(QString::number(str.length())).isValid());
       
  3384 
       
  3385         QScriptValue val(&eng, 123);
       
  3386         obj.setProperty("-1", val);
       
  3387         QVERIFY(obj.property("-1").strictlyEquals(val));
       
  3388         obj.setProperty("100", val);
       
  3389         QVERIFY(obj.property("100").strictlyEquals(val));
       
  3390     }
       
  3391 
       
  3392     // in script
       
  3393     {
       
  3394         QScriptValue ret = eng.evaluate("s = new String('ciao'); r = []; for (var p in s) r.push(p); r");
       
  3395         QVERIFY(ret.isArray());
       
  3396         QStringList lst = qscriptvalue_cast<QStringList>(ret);
       
  3397         QCOMPARE(lst.size(), str.length());
       
  3398         for (int i = 0; i < str.length(); ++i)
       
  3399             QCOMPARE(lst.at(i), QString::number(i));
       
  3400 
       
  3401         QScriptValue ret2 = eng.evaluate("s[0] = 123; s[0]");
       
  3402         QVERIFY(ret2.isString());
       
  3403         QCOMPARE(ret2.toString().length(), 1);
       
  3404         QCOMPARE(ret2.toString().at(0), str.at(0));
       
  3405 
       
  3406         QScriptValue ret3 = eng.evaluate("s[-1] = 123; s[-1]");
       
  3407         QVERIFY(ret3.isNumber());
       
  3408         QCOMPARE(ret3.toInt32(), 123);
       
  3409 
       
  3410         QScriptValue ret4 = eng.evaluate("s[s.length] = 456; s[s.length]");
       
  3411         QVERIFY(ret4.isNumber());
       
  3412         QCOMPARE(ret4.toInt32(), 456);
       
  3413 
       
  3414         QScriptValue ret5 = eng.evaluate("delete s[0]");
       
  3415         QVERIFY(ret5.isBoolean());
       
  3416         QVERIFY(!ret5.toBoolean());
       
  3417 
       
  3418         QScriptValue ret6 = eng.evaluate("delete s[-1]");
       
  3419         QVERIFY(ret6.isBoolean());
       
  3420         QVERIFY(ret6.toBoolean());
       
  3421 
       
  3422         QScriptValue ret7 = eng.evaluate("delete s[s.length]");
       
  3423         QVERIFY(ret7.isBoolean());
       
  3424         QVERIFY(ret7.toBoolean());
       
  3425     }
       
  3426 
       
  3427     // task 212440
       
  3428     {
       
  3429         QScriptValue ret = eng.evaluate("replace_args = []; \"a a a\".replace(/(a)/g, function() { replace_args.push(arguments); }); replace_args");
       
  3430         QVERIFY(ret.isArray());
       
  3431         int len = ret.property("length").toInt32();
       
  3432         QCOMPARE(len, 3);
       
  3433         for (int i = 0; i < len; ++i) {
       
  3434             QScriptValue args = ret.property(i);
       
  3435             QCOMPARE(args.property("length").toInt32(), 4);
       
  3436             QCOMPARE(args.property(0).toString(), QString::fromLatin1("a")); // matched string
       
  3437             QCOMPARE(args.property(1).toString(), QString::fromLatin1("a")); // capture
       
  3438             QVERIFY(args.property(2).isNumber());
       
  3439             QCOMPARE(args.property(2).toInt32(), i*2); // index of match
       
  3440             QCOMPARE(args.property(3).toString(), QString::fromLatin1("a a a"));
       
  3441         }
       
  3442     }
       
  3443     // task 212501
       
  3444     {
       
  3445         QScriptValue ret = eng.evaluate("\"foo\".replace(/a/g, function() {})");
       
  3446         QVERIFY(ret.isString());
       
  3447         QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
       
  3448     }
       
  3449 }
       
  3450 
       
  3451 void tst_QScriptEngine::getterSetterThisObject()
       
  3452 {
       
  3453     // Global Object
       
  3454     {
       
  3455         QScriptEngine eng;
       
  3456         // read
       
  3457         eng.evaluate("__defineGetter__('x', function() { return this; });");
       
  3458         {
       
  3459             QScriptValue ret = eng.evaluate("x");
       
  3460             QVERIFY(ret.equals(eng.globalObject()));
       
  3461         }
       
  3462         {
       
  3463             QScriptValue ret = eng.evaluate("(function() { return x; })()");
       
  3464             QVERIFY(ret.equals(eng.globalObject()));
       
  3465         }
       
  3466         {
       
  3467             QScriptValue ret = eng.evaluate("with (this) x");
       
  3468             QVERIFY(ret.equals(eng.globalObject()));
       
  3469         }
       
  3470         {
       
  3471             QScriptValue ret = eng.evaluate("with ({}) x");
       
  3472             QVERIFY(ret.equals(eng.globalObject()));
       
  3473         }
       
  3474         {
       
  3475             QScriptValue ret = eng.evaluate("(function() { with ({}) return x; })()");
       
  3476             QVERIFY(ret.equals(eng.globalObject()));
       
  3477         }
       
  3478         // write
       
  3479         eng.evaluate("__defineSetter__('x', function() { return this; });");
       
  3480         {
       
  3481             QScriptValue ret = eng.evaluate("x = 'foo'");
       
  3482             // SpiderMonkey says setter return value, JSC says RHS.
       
  3483             QVERIFY(ret.isString());
       
  3484             QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
       
  3485         }
       
  3486         {
       
  3487             QScriptValue ret = eng.evaluate("(function() { return x = 'foo'; })()");
       
  3488             // SpiderMonkey says setter return value, JSC says RHS.
       
  3489             QVERIFY(ret.isString());
       
  3490             QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
       
  3491         }
       
  3492         {
       
  3493             QScriptValue ret = eng.evaluate("with (this) x = 'foo'");
       
  3494             // SpiderMonkey says setter return value, JSC says RHS.
       
  3495             QVERIFY(ret.isString());
       
  3496             QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
       
  3497         }
       
  3498         {
       
  3499             QScriptValue ret = eng.evaluate("with ({}) x = 'foo'");
       
  3500             // SpiderMonkey says setter return value, JSC says RHS.
       
  3501             QVERIFY(ret.isString());
       
  3502             QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
       
  3503         }
       
  3504         {
       
  3505             QScriptValue ret = eng.evaluate("(function() { with ({}) return x = 'foo'; })()");
       
  3506             // SpiderMonkey says setter return value, JSC says RHS.
       
  3507             QVERIFY(ret.isString());
       
  3508             QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
       
  3509         }
       
  3510     }
       
  3511 
       
  3512     // other object
       
  3513     {
       
  3514         QScriptEngine eng;
       
  3515         eng.evaluate("o = {}");
       
  3516         // read
       
  3517         eng.evaluate("o.__defineGetter__('x', function() { return this; })");
       
  3518         QVERIFY(eng.evaluate("o.x === o").toBoolean());
       
  3519         QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o")));
       
  3520         QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean());
       
  3521         eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o"));
       
  3522         // write
       
  3523         eng.evaluate("o.__defineSetter__('x', function() { return this; });");
       
  3524         // SpiderMonkey says setter return value, JSC says RHS.
       
  3525         QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean());
       
  3526         QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo"));
       
  3527         QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo"));
       
  3528     }
       
  3529 
       
  3530     // getter+setter in prototype chain
       
  3531     {
       
  3532         QScriptEngine eng;
       
  3533         eng.evaluate("o = {}; p = {}; o.__proto__ = p");
       
  3534         // read
       
  3535         eng.evaluate("p.__defineGetter__('x', function() { return this; })");
       
  3536         QVERIFY(eng.evaluate("o.x === o").toBoolean());
       
  3537         QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o")));
       
  3538         QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean());
       
  3539         eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o"));
       
  3540         eng.evaluate("with (q) with (o) x").equals(eng.evaluate("o"));
       
  3541         // write
       
  3542         eng.evaluate("o.__defineSetter__('x', function() { return this; });");
       
  3543         // SpiderMonkey says setter return value, JSC says RHS.
       
  3544         QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean());
       
  3545         QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo"));
       
  3546         QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo"));
       
  3547     }
       
  3548 
       
  3549     // getter+setter in activation
       
  3550     {
       
  3551         QScriptEngine eng;
       
  3552         QScriptContext *ctx = eng.pushContext();
       
  3553         QVERIFY(ctx != 0);
       
  3554         QScriptValue act = ctx->activationObject();
       
  3555         act.setProperty("act", act);
       
  3556         // read
       
  3557         eng.evaluate("act.__defineGetter__('x', function() { return this; })");
       
  3558         QVERIFY(eng.evaluate("x === act").toBoolean());
       
  3559         QEXPECT_FAIL("", "Exotic overload (don't care for now)", Continue);
       
  3560         QVERIFY(eng.evaluate("with (act) x").equals("foo"));
       
  3561         QVERIFY(eng.evaluate("(function() { with (act) return x; })() === act").toBoolean());
       
  3562         eng.evaluate("q = {}; with (act) with (q) x").equals(eng.evaluate("act"));
       
  3563         eng.evaluate("with (q) with (act) x").equals(eng.evaluate("act"));
       
  3564         // write
       
  3565         eng.evaluate("act.__defineSetter__('x', function() { return this; });");
       
  3566         QVERIFY(eng.evaluate("(x = 'foo') === 'foo'").toBoolean());
       
  3567         QVERIFY(eng.evaluate("with (act) x = 'foo'").equals("foo"));
       
  3568         QVERIFY(eng.evaluate("with (act) with (q) x = 'foo'").equals("foo"));
       
  3569         eng.popContext();
       
  3570     }
       
  3571 }
       
  3572 
       
  3573 void tst_QScriptEngine::continueInSwitch()
       
  3574 {
       
  3575     QScriptEngine eng;
       
  3576     // switch - continue
       
  3577     {
       
  3578         QScriptValue ret = eng.evaluate("switch (1) { default: continue; }");
       
  3579         QVERIFY(ret.isError());
       
  3580     }
       
  3581     // for - switch - case - continue
       
  3582     {
       
  3583         QScriptValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
       
  3584                                         "  switch (i) {\n"
       
  3585                                         "    case 1: ++j; continue;\n"
       
  3586                                         "    case 100: ++j; continue;\n"
       
  3587                                         "    case 1000: ++j; continue;\n"
       
  3588                                         "  }\n"
       
  3589                                         "}; j");
       
  3590         QVERIFY(ret.isNumber());
       
  3591         QCOMPARE(ret.toInt32(), 3);
       
  3592     }
       
  3593     // for - switch - case - default - continue
       
  3594     {
       
  3595         QScriptValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
       
  3596                                         "  switch (i) {\n"
       
  3597                                         "    case 1: ++j; continue;\n"
       
  3598                                         "    case 100: ++j; continue;\n"
       
  3599                                         "    case 1000: ++j; continue;\n"
       
  3600                                         "    default: if (i < 50000) break; else continue;\n"
       
  3601                                         "  }\n"
       
  3602                                         "}; j");
       
  3603         QVERIFY(ret.isNumber());
       
  3604         QCOMPARE(ret.toInt32(), 3);
       
  3605     }
       
  3606     // switch - for - continue
       
  3607     {
       
  3608         QScriptValue ret = eng.evaluate("j = 123; switch (j) {\n"
       
  3609                                         "  case 123:\n"
       
  3610                                         "  for (i = 0; i < 100000; ++i) {\n"
       
  3611                                         "    continue;\n"
       
  3612                                         "  }\n"
       
  3613                                         "}; i\n");
       
  3614         QVERIFY(ret.isNumber());
       
  3615         QCOMPARE(ret.toInt32(), 100000);
       
  3616     }
       
  3617     // switch - switch - continue
       
  3618     {
       
  3619         QScriptValue ret = eng.evaluate("i = 1; switch (i) { default: switch (i) { case 1: continue; } }");
       
  3620         QVERIFY(ret.isError());
       
  3621     }
       
  3622     // for - switch - switch - continue
       
  3623     {
       
  3624         QScriptValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
       
  3625                                         "  switch (i) {\n"
       
  3626                                         "    case 1:\n"
       
  3627                                         "    switch (i) {\n"
       
  3628                                         "      case 1: ++j; continue;\n"
       
  3629                                         "    }\n"
       
  3630                                         "  }\n"
       
  3631                                         "}; j");
       
  3632         QVERIFY(ret.isNumber());
       
  3633         QCOMPARE(ret.toInt32(), 1);
       
  3634     }
       
  3635     // switch - for - switch - continue
       
  3636     {
       
  3637         QScriptValue ret = eng.evaluate("j = 123; switch (j) {\n"
       
  3638                                         "  case 123:\n"
       
  3639                                         "  for (i = 0; i < 100000; ++i) {\n"
       
  3640                                         "    switch (i) {\n"
       
  3641                                         "      case 1:\n"
       
  3642                                         "      ++j; continue;\n"
       
  3643                                         "    }\n"
       
  3644                                         "  }\n"
       
  3645                                         "}; i\n");
       
  3646         QVERIFY(ret.isNumber());
       
  3647         QCOMPARE(ret.toInt32(), 100000);
       
  3648     }
       
  3649 }
       
  3650 
       
  3651 void tst_QScriptEngine::readOnlyPrototypeProperty()
       
  3652 {
       
  3653     QSKIP("JSC semantics differ from old back-end and SpiderMonkey", SkipAll);
       
  3654     QScriptEngine eng;
       
  3655     QCOMPARE(eng.evaluate("o = {}; o.__proto__ = parseInt; o.length").toInt32(), 2);
       
  3656     QCOMPARE(eng.evaluate("o.length = 4; o.length").toInt32(), 2);
       
  3657     QVERIFY(!eng.evaluate("o.hasOwnProperty('length')").toBoolean());
       
  3658     QCOMPARE(eng.evaluate("o.length *= 2; o.length").toInt32(), 2);
       
  3659     QCOMPARE(eng.evaluate("o.length /= 2; o.length").toInt32(), 2);
       
  3660     QCOMPARE(eng.evaluate("o.length %= 2; o.length").toInt32(), 2);
       
  3661     QCOMPARE(eng.evaluate("o.length += 2; o.length").toInt32(), 2);
       
  3662     QCOMPARE(eng.evaluate("o.length -= 2; o.length").toInt32(), 2);
       
  3663     QCOMPARE(eng.evaluate("o.length <<= 2; o.length").toInt32(), 2);
       
  3664     QCOMPARE(eng.evaluate("o.length >>= 2; o.length").toInt32(), 2);
       
  3665     QCOMPARE(eng.evaluate("o.length >>>= 2; o.length").toInt32(), 2);
       
  3666     QCOMPARE(eng.evaluate("o.length &= 0; o.length").toInt32(), 2);
       
  3667     QCOMPARE(eng.evaluate("o.length ^= 255; o.length").toInt32(), 2);
       
  3668     QCOMPARE(eng.evaluate("o.length |= 255; o.length").toInt32(), 2);
       
  3669 
       
  3670     {
       
  3671         QScriptValue ret = eng.evaluate("o.__defineGetter__('length', function() {})");
       
  3672         QVERIFY(ret.isError());
       
  3673         QCOMPARE(ret.toString(), QString::fromLatin1("Error: cannot redefine read-only property"));
       
  3674     }
       
  3675     {
       
  3676         QScriptValue ret = eng.evaluate("o.__defineSetter__('length', function() {})");
       
  3677         QVERIFY(ret.isError());
       
  3678         QCOMPARE(ret.toString(), QString::fromLatin1("Error: cannot redefine read-only property"));
       
  3679     }
       
  3680 }
       
  3681 
       
  3682 void tst_QScriptEngine::toObject()
       
  3683 {
       
  3684     QScriptEngine eng;
       
  3685 
       
  3686     QVERIFY(!eng.toObject(eng.undefinedValue()).isValid());
       
  3687 
       
  3688     QVERIFY(!eng.toObject(eng.nullValue()).isValid());
       
  3689 
       
  3690     QScriptValue falskt(false);
       
  3691     {
       
  3692         QScriptValue tmp = eng.toObject(falskt);
       
  3693         QVERIFY(tmp.isObject());
       
  3694         QCOMPARE(tmp.toNumber(), falskt.toNumber());
       
  3695     }
       
  3696 
       
  3697     QScriptValue sant(true);
       
  3698     {
       
  3699         QScriptValue tmp = eng.toObject(sant);
       
  3700         QVERIFY(tmp.isObject());
       
  3701         QCOMPARE(tmp.toNumber(), sant.toNumber());
       
  3702     }
       
  3703 
       
  3704     QScriptValue number(123.0);
       
  3705     {
       
  3706         QScriptValue tmp = eng.toObject(number);
       
  3707         QVERIFY(tmp.isObject());
       
  3708         QCOMPARE(tmp.toNumber(), number.toNumber());
       
  3709     }
       
  3710 
       
  3711     QScriptValue str = QScriptValue(&eng, QString("ciao"));
       
  3712     {
       
  3713         QScriptValue tmp = eng.toObject(str);
       
  3714         QVERIFY(tmp.isObject());
       
  3715         QCOMPARE(tmp.toString(), str.toString());
       
  3716     }
       
  3717 
       
  3718     QScriptValue object = eng.newObject();
       
  3719     {
       
  3720         QScriptValue tmp = eng.toObject(object);
       
  3721         QVERIFY(tmp.isObject());
       
  3722         QVERIFY(tmp.strictlyEquals(object));
       
  3723     }
       
  3724 
       
  3725     QScriptValue qobject = eng.newQObject(this);
       
  3726     QVERIFY(eng.toObject(qobject).strictlyEquals(qobject));
       
  3727 
       
  3728     QVERIFY(!eng.toObject(QScriptValue()).isValid());
       
  3729 }
       
  3730 
       
  3731 void tst_QScriptEngine::reservedWords_data()
       
  3732 {
       
  3733     QTest::addColumn<QString>("word");
       
  3734     QTest::newRow("break") << QString("break");
       
  3735     QTest::newRow("case") << QString("case");
       
  3736     QTest::newRow("catch") << QString("catch");
       
  3737     QTest::newRow("continue") << QString("continue");
       
  3738     QTest::newRow("default") << QString("default");
       
  3739     QTest::newRow("delete") << QString("delete");
       
  3740     QTest::newRow("do") << QString("do");
       
  3741     QTest::newRow("else") << QString("else");
       
  3742     QTest::newRow("false") << QString("false");
       
  3743     QTest::newRow("finally") << QString("finally");
       
  3744     QTest::newRow("for") << QString("for");
       
  3745     QTest::newRow("function") << QString("function");
       
  3746     QTest::newRow("if") << QString("if");
       
  3747     QTest::newRow("in") << QString("in");
       
  3748     QTest::newRow("instanceof") << QString("instanceof");
       
  3749     QTest::newRow("new") << QString("new");
       
  3750     QTest::newRow("null") << QString("null");
       
  3751     QTest::newRow("return") << QString("return");
       
  3752     QTest::newRow("switch") << QString("switch");
       
  3753     QTest::newRow("this") << QString("this");
       
  3754     QTest::newRow("throw") << QString("throw");
       
  3755     QTest::newRow("true") << QString("true");
       
  3756     QTest::newRow("try") << QString("try");
       
  3757     QTest::newRow("typeof") << QString("typeof");
       
  3758     QTest::newRow("var") << QString("var");
       
  3759     QTest::newRow("void") << QString("void");
       
  3760     QTest::newRow("while") << QString("while");
       
  3761     QTest::newRow("with") << QString("with");
       
  3762 }
       
  3763 
       
  3764 void tst_QScriptEngine::reservedWords()
       
  3765 {
       
  3766     QFETCH(QString, word);
       
  3767     {
       
  3768         QScriptEngine eng;
       
  3769         QScriptValue ret = eng.evaluate(word + " = 123");
       
  3770         QVERIFY(ret.isError());
       
  3771         QString str = ret.toString();
       
  3772         QVERIFY(str.startsWith("SyntaxError") || str.startsWith("ReferenceError"));
       
  3773     }
       
  3774     {
       
  3775         QScriptEngine eng;
       
  3776         QScriptValue ret = eng.evaluate("var " + word + " = 123");
       
  3777         QVERIFY(ret.isError());
       
  3778         QVERIFY(ret.toString().startsWith("SyntaxError"));
       
  3779     }
       
  3780     {
       
  3781         QScriptEngine eng;
       
  3782         QScriptValue ret = eng.evaluate("o = {}; o." + word + " = 123");
       
  3783         // in the old back-end and in SpiderMonkey this is allowed, but not in JSC
       
  3784         QVERIFY(ret.isError());
       
  3785         QVERIFY(ret.toString().startsWith("SyntaxError"));
       
  3786     }
       
  3787     {
       
  3788         QScriptEngine eng;
       
  3789         QScriptValue ret = eng.evaluate("o = { " + word + ": 123 }");
       
  3790         // in the old back-end and in SpiderMonkey this is allowed, but not in JSC
       
  3791         QVERIFY(ret.isError());
       
  3792         QVERIFY(ret.toString().startsWith("SyntaxError"));
       
  3793     }
       
  3794     {
       
  3795         // SpiderMonkey allows this, but we don't
       
  3796         QScriptEngine eng;
       
  3797         QScriptValue ret = eng.evaluate("function " + word + "() {}");
       
  3798         QVERIFY(ret.isError());
       
  3799         QVERIFY(ret.toString().startsWith("SyntaxError"));
       
  3800     }
       
  3801 }
       
  3802 
       
  3803 void tst_QScriptEngine::futureReservedWords_data()
       
  3804 {
       
  3805     QTest::addColumn<QString>("word");
       
  3806     QTest::addColumn<bool>("allowed");
       
  3807     QTest::newRow("abstract") << QString("abstract") << true;
       
  3808     QTest::newRow("boolean") << QString("boolean") << true;
       
  3809     QTest::newRow("byte") << QString("byte") << true;
       
  3810     QTest::newRow("char") << QString("char") << true;
       
  3811     QTest::newRow("class") << QString("class") << false;
       
  3812     QTest::newRow("const") << QString("const") << false;
       
  3813     QTest::newRow("debugger") << QString("debugger") << false;
       
  3814     QTest::newRow("double") << QString("double") << true;
       
  3815     QTest::newRow("enum") << QString("enum") << false;
       
  3816     QTest::newRow("export") << QString("export") << false;
       
  3817     QTest::newRow("extends") << QString("extends") << false;
       
  3818     QTest::newRow("final") << QString("final") << true;
       
  3819     QTest::newRow("float") << QString("float") << true;
       
  3820     QTest::newRow("goto") << QString("goto") << true;
       
  3821     QTest::newRow("implements") << QString("implements") << true;
       
  3822     QTest::newRow("import") << QString("import") << false;
       
  3823     QTest::newRow("int") << QString("int") << true;
       
  3824     QTest::newRow("interface") << QString("interface") << true;
       
  3825     QTest::newRow("long") << QString("long") << true;
       
  3826     QTest::newRow("native") << QString("native") << true;
       
  3827     QTest::newRow("package") << QString("package") << true;
       
  3828     QTest::newRow("private") << QString("private") << true;
       
  3829     QTest::newRow("protected") << QString("protected") << true;
       
  3830     QTest::newRow("public") << QString("public") << true;
       
  3831     QTest::newRow("short") << QString("short") << true;
       
  3832     QTest::newRow("static") << QString("static") << true;
       
  3833     QTest::newRow("super") << QString("super") << false;
       
  3834     QTest::newRow("synchronized") << QString("synchronized") << true;
       
  3835     QTest::newRow("throws") << QString("throws") << true;
       
  3836     QTest::newRow("transient") << QString("transient") << true;
       
  3837     QTest::newRow("volatile") << QString("volatile") << true;
       
  3838 }
       
  3839 
       
  3840 void tst_QScriptEngine::futureReservedWords()
       
  3841 {
       
  3842     QFETCH(QString, word);
       
  3843     QFETCH(bool, allowed);
       
  3844     {
       
  3845         QScriptEngine eng;
       
  3846         QScriptValue ret = eng.evaluate(word + " = 123");
       
  3847         QCOMPARE(!ret.isError(), allowed);
       
  3848     }
       
  3849     {
       
  3850         QScriptEngine eng;
       
  3851         QScriptValue ret = eng.evaluate("var " + word + " = 123");
       
  3852         QCOMPARE(!ret.isError(), allowed);
       
  3853     }
       
  3854     {
       
  3855         // this should probably be allowed (see task 162567)
       
  3856         QScriptEngine eng;
       
  3857         QScriptValue ret = eng.evaluate("o = {}; o." + word + " = 123");
       
  3858         QCOMPARE(ret.isNumber(), allowed);
       
  3859         QCOMPARE(!ret.isError(), allowed);
       
  3860     }
       
  3861     {
       
  3862         // this should probably be allowed (see task 162567)
       
  3863         QScriptEngine eng;
       
  3864         QScriptValue ret = eng.evaluate("o = { " + word + ": 123 }");
       
  3865         QCOMPARE(!ret.isError(), allowed);
       
  3866     }
       
  3867 }
       
  3868 
       
  3869 void tst_QScriptEngine::throwInsideWithStatement()
       
  3870 {
       
  3871     // task 209988
       
  3872     QScriptEngine eng;
       
  3873     {
       
  3874         QScriptValue ret = eng.evaluate(
       
  3875             "try {"
       
  3876             "  o = { bad : \"bug\" };"
       
  3877             "  with (o) {"
       
  3878             "    throw 123;"
       
  3879             "  }"
       
  3880             "} catch (e) {"
       
  3881             "  bad;"
       
  3882             "}");
       
  3883         QVERIFY(ret.isError());
       
  3884         QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bad"));
       
  3885     }
       
  3886     {
       
  3887         QScriptValue ret = eng.evaluate(
       
  3888             "try {"
       
  3889             "  o = { bad : \"bug\" };"
       
  3890             "  with (o) {"
       
  3891             "    throw 123;"
       
  3892             "  }"
       
  3893             "} finally {"
       
  3894             "  bad;"
       
  3895             "}");
       
  3896         QVERIFY(ret.isError());
       
  3897         QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bad"));
       
  3898     }
       
  3899     {
       
  3900         eng.clearExceptions();
       
  3901         QScriptValue ret = eng.evaluate(
       
  3902             "o = { bug : \"no bug\" };"
       
  3903             "with (o) {"
       
  3904             "  try {"
       
  3905             "    throw 123;"
       
  3906             "  } finally {"
       
  3907             "    bug;"
       
  3908             "  }"
       
  3909             "}");
       
  3910         QVERIFY(ret.isNumber());
       
  3911         QCOMPARE(ret.toInt32(), 123);
       
  3912         QVERIFY(eng.hasUncaughtException());
       
  3913     }
       
  3914     {
       
  3915         eng.clearExceptions();
       
  3916         QScriptValue ret = eng.evaluate(
       
  3917             "o = { bug : \"no bug\" };"
       
  3918             "with (o) {"
       
  3919             "    throw 123;"
       
  3920             "}");
       
  3921         QVERIFY(ret.isNumber());
       
  3922         QScriptValue ret2 = eng.evaluate("bug");
       
  3923         QVERIFY(ret2.isError());
       
  3924         QCOMPARE(ret2.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bug"));
       
  3925     }
       
  3926 }
       
  3927 
       
  3928 class TestAgent : public QScriptEngineAgent
       
  3929 {
       
  3930 public:
       
  3931     TestAgent(QScriptEngine *engine) : QScriptEngineAgent(engine) {}
       
  3932 };
       
  3933 
       
  3934 void tst_QScriptEngine::getSetAgent()
       
  3935 {
       
  3936     // case 1: engine deleted before agent --> agent deleted too
       
  3937     {
       
  3938         QScriptEngine *eng = new QScriptEngine;
       
  3939         QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
       
  3940         TestAgent *agent = new TestAgent(eng);
       
  3941         eng->setAgent(agent);
       
  3942         QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
       
  3943         eng->setAgent(0); // the engine maintains ownership of the old agent
       
  3944         QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
       
  3945         delete eng;
       
  3946     }
       
  3947     // case 2: agent deleted before engine --> engine's agent should become 0
       
  3948     {
       
  3949         QScriptEngine *eng = new QScriptEngine;
       
  3950         TestAgent *agent = new TestAgent(eng);
       
  3951         eng->setAgent(agent);
       
  3952         QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
       
  3953         delete agent;
       
  3954         QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
       
  3955         eng->evaluate("(function(){ return 123; })()");
       
  3956         delete eng;
       
  3957     }
       
  3958     {
       
  3959         QScriptEngine eng;
       
  3960         QScriptEngine eng2;
       
  3961         TestAgent *agent = new TestAgent(&eng);
       
  3962         QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::setAgent(): cannot set agent belonging to different engine");
       
  3963         eng2.setAgent(agent);
       
  3964         QCOMPARE(eng2.agent(), (QScriptEngineAgent*)0);
       
  3965     }
       
  3966 }
       
  3967 
       
  3968 void tst_QScriptEngine::reentrancy()
       
  3969 {
       
  3970     {
       
  3971         QScriptEngine eng1;
       
  3972         QScriptEngine eng2;
       
  3973         QScriptString s1 = eng1.toStringHandle("foo");
       
  3974         QScriptString s2 = eng2.toStringHandle("foo");
       
  3975         QVERIFY(s1 != s2);
       
  3976     }
       
  3977     {
       
  3978         QScriptEngine eng1;
       
  3979         QScriptEngine eng2;
       
  3980         eng1.setProcessEventsInterval(123);
       
  3981         QCOMPARE(eng2.processEventsInterval(), -1);
       
  3982         eng2.setProcessEventsInterval(456);
       
  3983         QCOMPARE(eng1.processEventsInterval(), 123);
       
  3984     }
       
  3985     {
       
  3986         QScriptEngine eng1;
       
  3987         QScriptEngine eng2;
       
  3988         qScriptRegisterMetaType<Foo>(&eng1, fooToScriptValue, fooFromScriptValue);
       
  3989         Foo foo;
       
  3990         foo.x = 12;
       
  3991         foo.y = 34;
       
  3992         {
       
  3993             QScriptValue fooVal = qScriptValueFromValue(&eng1, foo);
       
  3994             QVERIFY(fooVal.isObject());
       
  3995             QVERIFY(!fooVal.isVariant());
       
  3996             QCOMPARE(fooVal.property("x").toInt32(), 12);
       
  3997             QCOMPARE(fooVal.property("y").toInt32(), 34);
       
  3998             fooVal.setProperty("x", 56);
       
  3999             fooVal.setProperty("y", 78);
       
  4000 
       
  4001             Foo foo2 = qScriptValueToValue<Foo>(fooVal);
       
  4002             QCOMPARE(foo2.x, 56);
       
  4003             QCOMPARE(foo2.y, 78);
       
  4004         }
       
  4005         {
       
  4006             QScriptValue fooVal = qScriptValueFromValue(&eng2, foo);
       
  4007             QVERIFY(fooVal.isVariant());
       
  4008 
       
  4009             Foo foo2 = qScriptValueToValue<Foo>(fooVal);
       
  4010             QCOMPARE(foo2.x, 12);
       
  4011             QCOMPARE(foo2.y, 34);
       
  4012         }
       
  4013         QVERIFY(!eng1.defaultPrototype(qMetaTypeId<Foo>()).isValid());
       
  4014         QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
       
  4015         QScriptValue proto1 = eng1.newObject();
       
  4016         eng1.setDefaultPrototype(qMetaTypeId<Foo>(), proto1);
       
  4017         QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
       
  4018         QScriptValue proto2 = eng2.newObject();
       
  4019         eng2.setDefaultPrototype(qMetaTypeId<Foo>(), proto2);
       
  4020         QVERIFY(eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
       
  4021         QVERIFY(eng1.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(proto1));
       
  4022     }
       
  4023     {
       
  4024         QScriptEngine eng1;
       
  4025         QScriptEngine eng2;
       
  4026         QVERIFY(!eng2.globalObject().property("a").isValid());
       
  4027         eng1.evaluate("a = 10");
       
  4028         QVERIFY(eng1.globalObject().property("a").isNumber());
       
  4029         QVERIFY(!eng2.globalObject().property("a").isValid());
       
  4030         eng2.evaluate("a = 20");
       
  4031         QVERIFY(eng2.globalObject().property("a").isNumber());
       
  4032         QCOMPARE(eng1.globalObject().property("a").toInt32(), 10);
       
  4033     }
       
  4034     // weird bug with JSC backend
       
  4035     {
       
  4036         QScriptEngine eng;
       
  4037         QCOMPARE(eng.evaluate("Array()").toString(), QString());
       
  4038         eng.evaluate("Array.prototype.toString");
       
  4039         QCOMPARE(eng.evaluate("Array()").toString(), QString());
       
  4040     }
       
  4041     {
       
  4042         QScriptEngine eng;
       
  4043         QCOMPARE(eng.evaluate("Array()").toString(), QString());
       
  4044     }
       
  4045 }
       
  4046 
       
  4047 void tst_QScriptEngine:: incDecNonObjectProperty()
       
  4048 {
       
  4049     QScriptEngine eng;
       
  4050     {
       
  4051         QScriptValue ret = eng.evaluate("var a; a.n++");
       
  4052         QVERIFY(ret.isError());
       
  4053         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [undefined] is not an object."));
       
  4054     }
       
  4055     {
       
  4056         QScriptValue ret = eng.evaluate("var a; a.n--");
       
  4057         QVERIFY(ret.isError());
       
  4058         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [undefined] is not an object."));
       
  4059     }
       
  4060     {
       
  4061         QScriptValue ret = eng.evaluate("var a = null; a.n++");
       
  4062         QVERIFY(ret.isError());
       
  4063         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
       
  4064     }
       
  4065     {
       
  4066         QScriptValue ret = eng.evaluate("var a = null; a.n--");
       
  4067         QVERIFY(ret.isError());
       
  4068         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
       
  4069     }
       
  4070     {
       
  4071         QScriptValue ret = eng.evaluate("var a; ++a.n");
       
  4072         QVERIFY(ret.isError());
       
  4073         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
       
  4074     }
       
  4075     {
       
  4076         QScriptValue ret = eng.evaluate("var a; --a.n");
       
  4077         QVERIFY(ret.isError());
       
  4078         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
       
  4079     }
       
  4080     {
       
  4081         QScriptValue ret = eng.evaluate("var a; a.n += 1");
       
  4082         QVERIFY(ret.isError());
       
  4083         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
       
  4084     }
       
  4085     {
       
  4086         QScriptValue ret = eng.evaluate("var a; a.n -= 1");
       
  4087         QVERIFY(ret.isError());
       
  4088         QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
       
  4089     }
       
  4090     {
       
  4091         QScriptValue ret = eng.evaluate("var a = 'ciao'; a.length++");
       
  4092         QVERIFY(ret.isNumber());
       
  4093         QCOMPARE(ret.toInt32(), 4);
       
  4094     }
       
  4095     {
       
  4096         QScriptValue ret = eng.evaluate("var a = 'ciao'; a.length--");
       
  4097         QVERIFY(ret.isNumber());
       
  4098         QCOMPARE(ret.toInt32(), 4);
       
  4099     }
       
  4100     {
       
  4101         QScriptValue ret = eng.evaluate("var a = 'ciao'; ++a.length");
       
  4102         QVERIFY(ret.isNumber());
       
  4103         QCOMPARE(ret.toInt32(), 5);
       
  4104     }
       
  4105     {
       
  4106         QScriptValue ret = eng.evaluate("var a = 'ciao'; --a.length");
       
  4107         QVERIFY(ret.isNumber());
       
  4108         QCOMPARE(ret.toInt32(), 3);
       
  4109     }
       
  4110 }
       
  4111 
       
  4112 void tst_QScriptEngine::installTranslatorFunctions()
       
  4113 {
       
  4114     QScriptEngine eng;
       
  4115     QScriptValue global = eng.globalObject();
       
  4116     QVERIFY(!global.property("qsTranslate").isValid());
       
  4117     QVERIFY(!global.property("QT_TRANSLATE_NOOP").isValid());
       
  4118     QVERIFY(!global.property("qsTr").isValid());
       
  4119     QVERIFY(!global.property("QT_TR_NOOP").isValid());
       
  4120     QVERIFY(!global.property("String").property("prototype").property("arg").isValid());
       
  4121 
       
  4122     eng.installTranslatorFunctions();
       
  4123     QVERIFY(global.property("qsTranslate").isFunction());
       
  4124     QVERIFY(global.property("QT_TRANSLATE_NOOP").isFunction());
       
  4125     QVERIFY(global.property("qsTr").isFunction());
       
  4126     QVERIFY(global.property("QT_TR_NOOP").isFunction());
       
  4127     QVERIFY(global.property("String").property("prototype").property("arg").isFunction());
       
  4128 
       
  4129     {
       
  4130         QScriptValue ret = eng.evaluate("qsTr('foo')");
       
  4131         QVERIFY(ret.isString());
       
  4132         QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
       
  4133     }
       
  4134     {
       
  4135         QScriptValue ret = eng.evaluate("qsTranslate('foo', 'bar')");
       
  4136         QVERIFY(ret.isString());
       
  4137         QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
       
  4138     }
       
  4139     {
       
  4140         QScriptValue ret = eng.evaluate("QT_TR_NOOP('foo')");
       
  4141         QVERIFY(ret.isString());
       
  4142         QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
       
  4143     }
       
  4144     {
       
  4145         QScriptValue ret = eng.evaluate("QT_TRANSLATE_NOOP('foo', 'bar')");
       
  4146         QVERIFY(ret.isString());
       
  4147         QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
       
  4148     }
       
  4149     {
       
  4150         QScriptValue ret = eng.evaluate("'foo%0'.arg('bar')");
       
  4151         QVERIFY(ret.isString());
       
  4152         QCOMPARE(ret.toString(), QString::fromLatin1("foobar"));
       
  4153     }
       
  4154 }
       
  4155 
       
  4156 void tst_QScriptEngine::functionScopes()
       
  4157 {
       
  4158     QScriptEngine eng;
       
  4159     {
       
  4160         // top-level functions have only the global object in their scope
       
  4161         QScriptValue fun = eng.evaluate("(function() {})");
       
  4162         QVERIFY(fun.isFunction());
       
  4163         QEXPECT_FAIL("", "Function scope proxying is not implemented", Abort);
       
  4164         QVERIFY(fun.scope().isObject());
       
  4165         QVERIFY(fun.scope().strictlyEquals(eng.globalObject()));
       
  4166         QVERIFY(!eng.globalObject().scope().isValid());
       
  4167     }
       
  4168     {
       
  4169         QScriptValue fun = eng.globalObject().property("Object");
       
  4170         QVERIFY(fun.isFunction());
       
  4171         // native built-in functions don't have scope
       
  4172         QVERIFY(!fun.scope().isValid());
       
  4173     }
       
  4174     {
       
  4175         // closure
       
  4176         QScriptValue fun = eng.evaluate("(function(arg) { var foo = arg; return function() { return foo; }; })(123)");
       
  4177         QVERIFY(fun.isFunction());
       
  4178         {
       
  4179             QScriptValue ret = fun.call();
       
  4180             QVERIFY(ret.isNumber());
       
  4181             QCOMPARE(ret.toInt32(), 123);
       
  4182         }
       
  4183         QScriptValue scope = fun.scope();
       
  4184         QVERIFY(scope.isObject());
       
  4185         {
       
  4186             QScriptValue ret = scope.property("foo");
       
  4187             QVERIFY(ret.isNumber());
       
  4188             QCOMPARE(ret.toInt32(), 123);
       
  4189             QCOMPARE(scope.propertyFlags("foo"), QScriptValue::Undeletable);
       
  4190         }
       
  4191         {
       
  4192             QScriptValue ret = scope.property("arg");
       
  4193             QVERIFY(ret.isNumber());
       
  4194             QCOMPARE(ret.toInt32(), 123);
       
  4195             QCOMPARE(scope.propertyFlags("arg"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
       
  4196         }
       
  4197 
       
  4198         scope.setProperty("foo", 456);
       
  4199         {
       
  4200             QScriptValue ret = fun.call();
       
  4201             QVERIFY(ret.isNumber());
       
  4202             QCOMPARE(ret.toInt32(), 456);
       
  4203         }
       
  4204 
       
  4205         scope = scope.scope();
       
  4206         QVERIFY(scope.isObject());
       
  4207         QVERIFY(scope.strictlyEquals(eng.globalObject()));
       
  4208     }
       
  4209 }
       
  4210 
       
  4211 static QScriptValue counter_inner(QScriptContext *ctx, QScriptEngine *)
       
  4212 {
       
  4213      QScriptValue outerAct = ctx->callee().scope();
       
  4214      double count = outerAct.property("count").toNumber();
       
  4215      outerAct.setProperty("count", count+1);
       
  4216      return count;
       
  4217 }
       
  4218 
       
  4219 static QScriptValue counter(QScriptContext *ctx, QScriptEngine *eng)
       
  4220 {
       
  4221      QScriptValue act = ctx->activationObject();
       
  4222      act.setProperty("count", ctx->argument(0).toInt32());
       
  4223      QScriptValue result = eng->newFunction(counter_inner);
       
  4224      result.setScope(act);
       
  4225      return result;
       
  4226 }
       
  4227 
       
  4228 static QScriptValue counter_hybrid(QScriptContext *ctx, QScriptEngine *eng)
       
  4229 {
       
  4230      QScriptValue act = ctx->activationObject();
       
  4231      act.setProperty("count", ctx->argument(0).toInt32());
       
  4232      return eng->evaluate("(function() { return count++; })");
       
  4233 }
       
  4234 
       
  4235 void tst_QScriptEngine::nativeFunctionScopes()
       
  4236 {
       
  4237     QScriptEngine eng;
       
  4238     {
       
  4239         QScriptValue fun = eng.newFunction(counter);
       
  4240         QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123);
       
  4241         QVERIFY(cnt.isFunction());
       
  4242         {
       
  4243             QScriptValue ret = cnt.call();
       
  4244             QVERIFY(ret.isNumber());
       
  4245             QCOMPARE(ret.toInt32(), 123);
       
  4246         }
       
  4247     }
       
  4248     {
       
  4249         QScriptValue fun = eng.newFunction(counter_hybrid);
       
  4250         QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123);
       
  4251         QVERIFY(cnt.isFunction());
       
  4252         {
       
  4253             QScriptValue ret = cnt.call();
       
  4254             QVERIFY(ret.isNumber());
       
  4255             QCOMPARE(ret.toInt32(), 123);
       
  4256         }
       
  4257     }
       
  4258 
       
  4259     //from http://doc.trolltech.com/latest/qtscript.html#nested-functions-and-the-scope-chain
       
  4260     {
       
  4261         QScriptEngine eng;
       
  4262         eng.evaluate("function counter() { var count = 0; return function() { return count++; } }\n"
       
  4263                      "var c1 = counter();  var c2 = counter(); ");
       
  4264         QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
       
  4265         QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
       
  4266         QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
       
  4267         QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
       
  4268         QVERIFY(!eng.hasUncaughtException());
       
  4269     }
       
  4270     {
       
  4271         QScriptEngine eng;
       
  4272         eng.globalObject().setProperty("counter", eng.newFunction(counter));
       
  4273         eng.evaluate("var c1 = counter();  var c2 = counter(); ");
       
  4274         QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
       
  4275         QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
       
  4276         QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
       
  4277         QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
       
  4278         QVERIFY(!eng.hasUncaughtException());
       
  4279     }
       
  4280     {
       
  4281         QScriptEngine eng;
       
  4282         eng.globalObject().setProperty("counter", eng.newFunction(counter_hybrid));
       
  4283         eng.evaluate("var c1 = counter();  var c2 = counter(); ");
       
  4284         QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
       
  4285         QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
       
  4286         QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
       
  4287         QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
       
  4288         QVERIFY(!eng.hasUncaughtException());
       
  4289     }
       
  4290 }
       
  4291 
       
  4292 static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; }
       
  4293 
       
  4294 void tst_QScriptEngine::qRegExpInport_data()
       
  4295 {
       
  4296     QTest::addColumn<QRegExp>("rx");
       
  4297     QTest::addColumn<QString>("string");
       
  4298     QTest::addColumn<QString>("matched");
       
  4299 
       
  4300     QTest::newRow("normal")  << QRegExp("(test|foo)") << "test _ foo _ test _ Foo";
       
  4301     QTest::newRow("normal2")  << QRegExp("(Test|Foo)") << "test _ foo _ test _ Foo";
       
  4302     QTest::newRow("case insensitive)")  << QRegExp("(test|foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo";
       
  4303     QTest::newRow("case insensitive2)")  << QRegExp("(Test|Foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo";
       
  4304     QTest::newRow("b(a*)(b*)")  << QRegExp("b(a*)(b*)", Qt::CaseInsensitive) << "aaabbBbaAabaAaababaaabbaaab";
       
  4305     QTest::newRow("greedy")  << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp2) << "aaaabaaba";
       
  4306     // this one will fail because we do not support the QRegExp::RegExp in JSC
       
  4307     //QTest::newRow("not_greedy")  << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp) << "aaaabaaba";
       
  4308     QTest::newRow("willcard")  << QRegExp("*.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "file.txt";
       
  4309     QTest::newRow("willcard 2")  << QRegExp("a?b.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "ab.txt abb.rtc acb.txt";
       
  4310     QTest::newRow("slash")  << QRegExp("g/.*/s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string/string/string";
       
  4311     QTest::newRow("slash2")  << QRegExp("g / .* / s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string / string / string";
       
  4312     QTest::newRow("fixed")  << QRegExp("a*aa.a(ba)*a\\ba", Qt::CaseInsensitive, QRegExp::FixedString) << "aa*aa.a(ba)*a\\ba";
       
  4313     QTest::newRow("fixed insensitive")  << QRegExp("A*A", Qt::CaseInsensitive, QRegExp::FixedString) << "a*A A*a A*A a*a";
       
  4314     QTest::newRow("fixed sensitive")  << QRegExp("A*A", Qt::CaseSensitive, QRegExp::FixedString) << "a*A A*a A*A a*a";
       
  4315     QTest::newRow("html")  << QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2) << "<b>bold</b><i>italic</i><b>bold</b>";
       
  4316     QTest::newRow("html minimal")  << minimal(QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2)) << "<b>bold</b><i>italic</i><b>bold</b>";
       
  4317     QTest::newRow("aaa")  << QRegExp("a{2,5}") << "aAaAaaaaaAa";
       
  4318     QTest::newRow("aaa minimal")  << minimal(QRegExp("a{2,5}")) << "aAaAaaaaaAa";
       
  4319     QTest::newRow("minimal")  << minimal(QRegExp(".*\\} [*8]")) << "}?} ?} *";
       
  4320 }
       
  4321 
       
  4322 void tst_QScriptEngine::qRegExpInport()
       
  4323 {
       
  4324     QFETCH(QRegExp, rx);
       
  4325     QFETCH(QString, string);
       
  4326 
       
  4327     QScriptEngine eng;
       
  4328     QScriptValue rexp;
       
  4329     rexp = eng.newRegExp(rx);
       
  4330 
       
  4331     QCOMPARE(rexp.isValid(), true);
       
  4332     QCOMPARE(rexp.isRegExp(), true);
       
  4333     QVERIFY(rexp.isFunction());
       
  4334 
       
  4335     QScriptValue func = eng.evaluate("(function(string, regexp) { return string.match(regexp); })");
       
  4336     QScriptValue result = func.call(QScriptValue(),  QScriptValueList() << string << rexp);
       
  4337 
       
  4338     rx.indexIn(string);
       
  4339     for (int i = 0; i <= rx.numCaptures(); i++)  {
       
  4340         QCOMPARE(result.property(i).toString(), rx.cap(i));
       
  4341     }
       
  4342 }
       
  4343 
       
  4344 QTEST_MAIN(tst_QScriptEngine)
       
  4345 #include "tst_qscriptengine.moc"