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