tests/auto/qscriptengine/tst_qscriptengine.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
    42 
    42 
    43 #include <QtTest/QtTest>
    43 #include <QtTest/QtTest>
    44 
    44 
    45 #include <qscriptengine.h>
    45 #include <qscriptengine.h>
    46 #include <qscriptengineagent.h>
    46 #include <qscriptengineagent.h>
       
    47 #include <qscriptprogram.h>
    47 #include <qscriptvalueiterator.h>
    48 #include <qscriptvalueiterator.h>
    48 #include <qgraphicsitem.h>
    49 #include <qgraphicsitem.h>
    49 #include <qstandarditemmodel.h>
    50 #include <qstandarditemmodel.h>
    50 #include <QtCore/qnumeric.h>
    51 #include <QtCore/qnumeric.h>
    51 #include <stdlib.h>
    52 #include <stdlib.h>
    52 
    53 
    53 Q_DECLARE_METATYPE(QList<int>)
    54 Q_DECLARE_METATYPE(QList<int>)
    54 Q_DECLARE_METATYPE(QObjectList)
    55 Q_DECLARE_METATYPE(QObjectList)
       
    56 Q_DECLARE_METATYPE(QScriptProgram)
    55 
    57 
    56 //TESTED_CLASS=
    58 //TESTED_CLASS=
    57 //TESTED_FILES=
    59 //TESTED_FILES=
    58 
    60 
    59 #if defined(Q_OS_SYMBIAN)
    61 #if defined(Q_OS_SYMBIAN)
   149     void reentrancy();
   151     void reentrancy();
   150     void incDecNonObjectProperty();
   152     void incDecNonObjectProperty();
   151     void installTranslatorFunctions();
   153     void installTranslatorFunctions();
   152     void functionScopes();
   154     void functionScopes();
   153     void nativeFunctionScopes();
   155     void nativeFunctionScopes();
       
   156     void evaluateProgram();
       
   157     void collectGarbageAfterConnect();
   154 
   158 
   155     void qRegExpInport_data();
   159     void qRegExpInport_data();
   156     void qRegExpInport();
   160     void qRegExpInport();
   157 };
   161 };
   158 
   162 
  1143         QVERIFY(!global.property(name).isValid());
  1147         QVERIFY(!global.property(name).isValid());
  1144         QScriptValue val(QString::fromLatin1("ciao"));
  1148         QScriptValue val(QString::fromLatin1("ciao"));
  1145         QScriptValue::PropertyFlags flags = QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration;
  1149         QScriptValue::PropertyFlags flags = QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration;
  1146         global.setProperty(name, val, flags);
  1150         global.setProperty(name, val, flags);
  1147         QVERIFY(global.property(name).equals(val));
  1151         QVERIFY(global.property(name).equals(val));
  1148         QEXPECT_FAIL("", "custom Global Object properties don't retain attributes", Continue);
  1152         QEXPECT_FAIL("", "QTBUG-6134: custom Global Object properties don't retain attributes", Continue);
  1149         QCOMPARE(global.propertyFlags(name), flags);
  1153         QCOMPARE(global.propertyFlags(name), flags);
  1150         global.setProperty(name, QScriptValue());
  1154         global.setProperty(name, QScriptValue());
  1151         QVERIFY(!global.property(name).isValid());
  1155         QVERIFY(!global.property(name).isValid());
  1152     }
  1156     }
  1153 }
  1157 }
  2028     {
  2032     {
  2029         QRegExp in = QRegExp("foo");
  2033         QRegExp in = QRegExp("foo");
  2030         QScriptValue val = qScriptValueFromValue(&eng, in);
  2034         QScriptValue val = qScriptValueFromValue(&eng, in);
  2031         QVERIFY(val.isRegExp());
  2035         QVERIFY(val.isRegExp());
  2032         QRegExp out = val.toRegExp();
  2036         QRegExp out = val.toRegExp();
  2033         QEXPECT_FAIL("", "JSC-based back-end doesn't preserve QRegExp::patternSyntax (always uses RegExp2)", Continue);
  2037         QEXPECT_FAIL("", "QTBUG-6136: JSC-based back-end doesn't preserve QRegExp::patternSyntax (always uses RegExp2)", Continue);
  2034         QCOMPARE(out.patternSyntax(), in.patternSyntax());
  2038         QCOMPARE(out.patternSyntax(), in.patternSyntax());
  2035         QCOMPARE(out.pattern(), in.pattern());
  2039         QCOMPARE(out.pattern(), in.pattern());
  2036         QCOMPARE(out.caseSensitivity(), in.caseSensitivity());
  2040         QCOMPARE(out.caseSensitivity(), in.caseSensitivity());
  2037         QCOMPARE(out.isMinimal(), in.isMinimal());
  2041         QCOMPARE(out.isMinimal(), in.isMinimal());
  2038     }
  2042     }
  2045     {
  2049     {
  2046         QRegExp in = QRegExp("foo");
  2050         QRegExp in = QRegExp("foo");
  2047         in.setMinimal(true);
  2051         in.setMinimal(true);
  2048         QScriptValue val = qScriptValueFromValue(&eng, in);
  2052         QScriptValue val = qScriptValueFromValue(&eng, in);
  2049         QVERIFY(val.isRegExp());
  2053         QVERIFY(val.isRegExp());
  2050         QEXPECT_FAIL("", "JSC-based back-end doesn't preserve QRegExp::minimal (always false)", Continue);
  2054         QEXPECT_FAIL("", "QTBUG-6136: JSC-based back-end doesn't preserve QRegExp::minimal (always false)", Continue);
  2051         QCOMPARE(val.toRegExp().isMinimal(), in.isMinimal());
  2055         QCOMPARE(val.toRegExp().isMinimal(), in.isMinimal());
  2052     }
  2056     }
  2053 }
  2057 }
  2054 
  2058 
  2055 static QScriptValue __import__(QScriptContext *ctx, QScriptEngine *eng)
  2059 static QScriptValue __import__(QScriptContext *ctx, QScriptEngine *eng)
  2500     QScriptEngine eng;
  2504     QScriptEngine eng;
  2501     QScriptValue result = eng.evaluate(script, fileName);
  2505     QScriptValue result = eng.evaluate(script, fileName);
  2502     QVERIFY(eng.hasUncaughtException());
  2506     QVERIFY(eng.hasUncaughtException());
  2503     QVERIFY(result.isError());
  2507     QVERIFY(result.isError());
  2504 
  2508 
  2505     QEXPECT_FAIL("", "", Abort);
  2509     QEXPECT_FAIL("", "QTBUG-6139: uncaughtExceptionBacktrace() doesn't give the full backtrace", Abort);
  2506     QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
  2510     QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
  2507     QVERIFY(eng.hasUncaughtException());
  2511     QVERIFY(eng.hasUncaughtException());
  2508     QVERIFY(result.strictlyEquals(eng.uncaughtException()));
  2512     QVERIFY(result.strictlyEquals(eng.uncaughtException()));
  2509 
  2513 
  2510     QCOMPARE(result.property("fileName").toString(), fileName);
  2514     QCOMPARE(result.property("fileName").toString(), fileName);
  3040             QVERIFY(ret.isError());
  3044             QVERIFY(ret.isError());
  3041             QCOMPARE(eng.hasUncaughtException(), x == 0);
  3045             QCOMPARE(eng.hasUncaughtException(), x == 0);
  3042             eng.clearExceptions();
  3046             eng.clearExceptions();
  3043             QVERIFY(ret.toString().startsWith(name));
  3047             QVERIFY(ret.toString().startsWith(name));
  3044             if (x != 0)
  3048             if (x != 0)
  3045                 QEXPECT_FAIL("", "JSC doesn't assign lineNumber when errors are not thrown", Continue);
  3049                 QEXPECT_FAIL("", "QTBUG-6138: JSC doesn't assign lineNumber when errors are not thrown", Continue);
  3046             QCOMPARE(ret.property("lineNumber").toInt32(), i+2);
  3050             QCOMPARE(ret.property("lineNumber").toInt32(), i+2);
  3047         }
  3051         }
  3048     }
  3052     }
  3049 }
  3053 }
  3050 
  3054 
  3058 
  3062 
  3059 void tst_QScriptEngine::argumentsProperty()
  3063 void tst_QScriptEngine::argumentsProperty()
  3060 {
  3064 {
  3061     {
  3065     {
  3062         QScriptEngine eng;
  3066         QScriptEngine eng;
  3063         QEXPECT_FAIL("", "", Continue);
  3067         {
  3064         QVERIFY(eng.evaluate("arguments").isUndefined());
  3068             QScriptValue ret = eng.evaluate("arguments");
       
  3069             QVERIFY(ret.isError());
       
  3070             QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: arguments"));
       
  3071         }
  3065         eng.evaluate("arguments = 10");
  3072         eng.evaluate("arguments = 10");
  3066         QScriptValue ret = eng.evaluate("arguments");
  3073         {
  3067         QVERIFY(ret.isNumber());
  3074             QScriptValue ret = eng.evaluate("arguments");
  3068         QCOMPARE(ret.toInt32(), 10);
  3075             QVERIFY(ret.isNumber());
  3069         QEXPECT_FAIL("", "", Continue);
  3076             QCOMPARE(ret.toInt32(), 10);
  3070         QVERIFY(!eng.evaluate("delete arguments").toBoolean());
  3077         }
       
  3078         QVERIFY(eng.evaluate("delete arguments").toBoolean());
       
  3079         QVERIFY(!eng.globalObject().property("arguments").isValid());
  3071     }
  3080     }
  3072     {
  3081     {
  3073         QScriptEngine eng;
  3082         QScriptEngine eng;
  3074         eng.evaluate("o = { arguments: 123 }");
  3083         eng.evaluate("o = { arguments: 123 }");
  3075         QScriptValue ret = eng.evaluate("with (o) { arguments; }");
  3084         QScriptValue ret = eng.evaluate("with (o) { arguments; }");
  3076         QVERIFY(ret.isNumber());
  3085         QVERIFY(ret.isNumber());
  3077         QCOMPARE(ret.toInt32(), 123);
  3086         QCOMPARE(ret.toInt32(), 123);
  3078     }
  3087     }
  3079     {
  3088     {
  3080         QScriptEngine eng;
  3089         QScriptEngine eng;
       
  3090         QVERIFY(!eng.globalObject().property("arguments").isValid());
  3081         QScriptValue ret = eng.evaluate("(function() { arguments = 456; return arguments; })()");
  3091         QScriptValue ret = eng.evaluate("(function() { arguments = 456; return arguments; })()");
  3082         QVERIFY(ret.isNumber());
  3092         QVERIFY(ret.isNumber());
  3083         QCOMPARE(ret.toInt32(), 456);
  3093         QCOMPARE(ret.toInt32(), 456);
  3084         QEXPECT_FAIL("", "", Continue);
  3094         QVERIFY(!eng.globalObject().property("arguments").isValid());
  3085         QVERIFY(eng.evaluate("arguments").isUndefined());
       
  3086     }
  3095     }
  3087 
  3096 
  3088     {
  3097     {
  3089         QScriptEngine eng;
  3098         QScriptEngine eng;
  3090         QScriptValue fun = eng.newFunction(argumentsProperty_fun);
  3099         QScriptValue fun = eng.newFunction(argumentsProperty_fun);
  4287         QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
  4296         QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
  4288         QVERIFY(!eng.hasUncaughtException());
  4297         QVERIFY(!eng.hasUncaughtException());
  4289     }
  4298     }
  4290 }
  4299 }
  4291 
  4300 
       
  4301 static QScriptValue createProgram(QScriptContext *ctx, QScriptEngine *eng)
       
  4302 {
       
  4303     QString code = ctx->argument(0).toString();
       
  4304     QScriptProgram result(code);
       
  4305     return qScriptValueFromValue(eng, result);
       
  4306 }
       
  4307 
       
  4308 void tst_QScriptEngine::evaluateProgram()
       
  4309 {
       
  4310     QScriptEngine eng;
       
  4311 
       
  4312     {
       
  4313         QString code("1 + 2");
       
  4314         QString fileName("hello.js");
       
  4315         int lineNumber(123);
       
  4316         QScriptProgram program(code, fileName, lineNumber);
       
  4317         QVERIFY(!program.isNull());
       
  4318         QCOMPARE(program.sourceCode(), code);
       
  4319         QCOMPARE(program.fileName(), fileName);
       
  4320         QCOMPARE(program.firstLineNumber(), lineNumber);
       
  4321 
       
  4322         QScriptValue expected = eng.evaluate(code);
       
  4323         for (int x = 0; x < 10; ++x) {
       
  4324             QScriptValue ret = eng.evaluate(program);
       
  4325             QVERIFY(ret.equals(expected));
       
  4326         }
       
  4327 
       
  4328         // operator=
       
  4329         QScriptProgram sameProgram = program;
       
  4330         QVERIFY(sameProgram == program);
       
  4331         QVERIFY(eng.evaluate(sameProgram).equals(expected));
       
  4332 
       
  4333         // copy constructor
       
  4334         QScriptProgram sameProgram2(program);
       
  4335         QVERIFY(sameProgram2 == program);
       
  4336         QVERIFY(eng.evaluate(sameProgram2).equals(expected));
       
  4337 
       
  4338         QScriptProgram differentProgram("2 + 3");
       
  4339         QVERIFY(differentProgram != program);
       
  4340         QVERIFY(!eng.evaluate(differentProgram).equals(expected));
       
  4341     }
       
  4342 
       
  4343     // Program that accesses variable in the scope
       
  4344     {
       
  4345         QScriptProgram program("a");
       
  4346         QVERIFY(!program.isNull());
       
  4347         {
       
  4348             QScriptValue ret = eng.evaluate(program);
       
  4349             QVERIFY(ret.isError());
       
  4350             QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: a"));
       
  4351         }
       
  4352 
       
  4353         QScriptValue obj = eng.newObject();
       
  4354         obj.setProperty("a", 123);
       
  4355         QScriptContext *ctx = eng.currentContext();
       
  4356         ctx->pushScope(obj);
       
  4357         {
       
  4358             QScriptValue ret = eng.evaluate(program);
       
  4359             QVERIFY(!ret.isError());
       
  4360             QVERIFY(ret.equals(obj.property("a")));
       
  4361         }
       
  4362 
       
  4363         obj.setProperty("a", QScriptValue());
       
  4364         {
       
  4365             QScriptValue ret = eng.evaluate(program);
       
  4366             QVERIFY(ret.isError());
       
  4367         }
       
  4368 
       
  4369         QScriptValue obj2 = eng.newObject();
       
  4370         obj2.setProperty("a", 456);
       
  4371         ctx->pushScope(obj2);
       
  4372         {
       
  4373             QScriptValue ret = eng.evaluate(program);
       
  4374             QVERIFY(!ret.isError());
       
  4375             QVERIFY(ret.equals(obj2.property("a")));
       
  4376         }
       
  4377 
       
  4378         ctx->popScope();
       
  4379     }
       
  4380 
       
  4381     // Program that creates closure
       
  4382     {
       
  4383         QScriptProgram program("(function() { var count = 0; return function() { return count++; }; })");
       
  4384         QVERIFY(!program.isNull());
       
  4385         QScriptValue createCounter = eng.evaluate(program);
       
  4386         QVERIFY(createCounter.isFunction());
       
  4387         QScriptValue counter = createCounter.call();
       
  4388         QVERIFY(counter.isFunction());
       
  4389         {
       
  4390             QScriptValue ret = counter.call();
       
  4391             QVERIFY(ret.isNumber());
       
  4392         }
       
  4393         QScriptValue counter2 = createCounter.call();
       
  4394         QVERIFY(counter2.isFunction());
       
  4395         QVERIFY(!counter2.equals(counter));
       
  4396         {
       
  4397             QScriptValue ret = counter2.call();
       
  4398             QVERIFY(ret.isNumber());
       
  4399         }
       
  4400     }
       
  4401 
       
  4402     // Program created in a function call, then executed later
       
  4403     {
       
  4404         QScriptValue fun = eng.newFunction(createProgram);
       
  4405         QScriptProgram program = qscriptvalue_cast<QScriptProgram>(
       
  4406             fun.call(QScriptValue(), QScriptValueList() << "a + 1"));
       
  4407         QVERIFY(!program.isNull());
       
  4408         eng.globalObject().setProperty("a", QScriptValue());
       
  4409         {
       
  4410             QScriptValue ret = eng.evaluate(program);
       
  4411             QVERIFY(ret.isError());
       
  4412             QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: a"));
       
  4413         }
       
  4414         eng.globalObject().setProperty("a", 122);
       
  4415         {
       
  4416             QScriptValue ret = eng.evaluate(program);
       
  4417             QVERIFY(!ret.isError());
       
  4418             QVERIFY(ret.isNumber());
       
  4419             QCOMPARE(ret.toInt32(), 123);
       
  4420         }
       
  4421     }
       
  4422 
       
  4423     // Same program run in different engines
       
  4424     {
       
  4425         QString code("1 + 2");
       
  4426         QScriptProgram program(code);
       
  4427         QVERIFY(!program.isNull());
       
  4428         double expected = eng.evaluate(program).toNumber();
       
  4429         for (int x = 0; x < 2; ++x) {
       
  4430             QScriptEngine eng2;
       
  4431             for (int y = 0; y < 2; ++y) {
       
  4432                 double ret = eng2.evaluate(program).toNumber();
       
  4433                 QCOMPARE(ret, expected);
       
  4434             }
       
  4435         }
       
  4436     }
       
  4437 
       
  4438     // No program
       
  4439     {
       
  4440         QScriptProgram program;
       
  4441         QVERIFY(program.isNull());
       
  4442         QScriptValue ret = eng.evaluate(program);
       
  4443         QVERIFY(!ret.isValid());
       
  4444     }
       
  4445 }
       
  4446 
       
  4447 void tst_QScriptEngine::collectGarbageAfterConnect()
       
  4448 {
       
  4449     // QTBUG-6366
       
  4450     QScriptEngine engine;
       
  4451     QPointer<QWidget> widget = new QWidget;
       
  4452     engine.globalObject().setProperty(
       
  4453         "widget", engine.newQObject(widget, QScriptEngine::ScriptOwnership));
       
  4454     QVERIFY(engine.evaluate("widget.customContextMenuRequested.connect(\n"
       
  4455                             "  function() { print('hello'); }\n"
       
  4456                             ");")
       
  4457             .isUndefined());
       
  4458     QVERIFY(widget != 0);
       
  4459     engine.evaluate("widget = null;");
       
  4460     collectGarbage_helper(engine);
       
  4461     QVERIFY(widget == 0);
       
  4462 }
       
  4463 
  4292 static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; }
  4464 static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; }
  4293 
  4465 
  4294 void tst_QScriptEngine::qRegExpInport_data()
  4466 void tst_QScriptEngine::qRegExpInport_data()
  4295 {
  4467 {
  4296     QTest::addColumn<QRegExp>("rx");
  4468     QTest::addColumn<QRegExp>("rx");
  4334 
  4506 
  4335     QScriptValue func = eng.evaluate("(function(string, regexp) { return string.match(regexp); })");
  4507     QScriptValue func = eng.evaluate("(function(string, regexp) { return string.match(regexp); })");
  4336     QScriptValue result = func.call(QScriptValue(),  QScriptValueList() << string << rexp);
  4508     QScriptValue result = func.call(QScriptValue(),  QScriptValueList() << string << rexp);
  4337 
  4509 
  4338     rx.indexIn(string);
  4510     rx.indexIn(string);
  4339     for (int i = 0; i <= rx.numCaptures(); i++)  {
  4511     for (int i = 0; i <= rx.captureCount(); i++)  {
  4340         QCOMPARE(result.property(i).toString(), rx.cap(i));
  4512         QCOMPARE(result.property(i).toString(), rx.cap(i));
  4341     }
  4513     }
  4342 }
  4514 }
  4343 
  4515 
  4344 QTEST_MAIN(tst_QScriptEngine)
  4516 QTEST_MAIN(tst_QScriptEngine)