tests/auto/qscriptengine/tst_qscriptengine.cpp
branchRCL_3
changeset 14 c0432d11811c
parent 8 3f74d0d4af4c
equal deleted inserted replaced
13:cc75c76972ee 14:c0432d11811c
   102     void newQMetaObject();
   102     void newQMetaObject();
   103     void newActivationObject();
   103     void newActivationObject();
   104     void getSetGlobalObject();
   104     void getSetGlobalObject();
   105     void globalObjectProperties();
   105     void globalObjectProperties();
   106     void globalObjectGetterSetterProperty();
   106     void globalObjectGetterSetterProperty();
       
   107     void customGlobalObjectWithPrototype();
       
   108     void globalObjectWithCustomPrototype();
   107     void builtinFunctionNames_data();
   109     void builtinFunctionNames_data();
   108     void builtinFunctionNames();
   110     void builtinFunctionNames();
   109     void checkSyntax_data();
   111     void checkSyntax_data();
   110     void checkSyntax();
   112     void checkSyntax();
   111     void canEvaluate_data();
   113     void canEvaluate_data();
   150     void getSetAgent();
   152     void getSetAgent();
   151     void reentrancy();
   153     void reentrancy();
   152     void incDecNonObjectProperty();
   154     void incDecNonObjectProperty();
   153     void installTranslatorFunctions_data();
   155     void installTranslatorFunctions_data();
   154     void installTranslatorFunctions();
   156     void installTranslatorFunctions();
       
   157     void translateScript();
       
   158     void translateWithInvalidArgs_data();
       
   159     void translateWithInvalidArgs();
       
   160     void translationContext_data();
       
   161     void translationContext();
   155     void functionScopes();
   162     void functionScopes();
   156     void nativeFunctionScopes();
   163     void nativeFunctionScopes();
   157     void evaluateProgram();
   164     void evaluateProgram();
   158     void collectGarbageAfterConnect();
   165     void collectGarbageAfterConnect();
   159 
   166 
   791     }
   798     }
   792     obj.setProperty("isCalledAsConstructor", QScriptValue(eng, ctx->isCalledAsConstructor()));
   799     obj.setProperty("isCalledAsConstructor", QScriptValue(eng, ctx->isCalledAsConstructor()));
   793     return obj;
   800     return obj;
   794 }
   801 }
   795 
   802 
       
   803 static QScriptValue instanceofJS(const QScriptValue &inst, const QScriptValue &ctor)
       
   804 {
       
   805     return inst.engine()->evaluate("(function(inst, ctor) { return inst instanceof ctor; })")
       
   806         .call(QScriptValue(), QScriptValueList() << inst << ctor);
       
   807 }
       
   808 
   796 void tst_QScriptEngine::newQMetaObject()
   809 void tst_QScriptEngine::newQMetaObject()
   797 {
   810 {
   798     QScriptEngine eng;
   811     QScriptEngine eng;
   799 #if 0
   812 #if 0
   800     QScriptValue qclass = eng.newQMetaObject<QObject>();
   813     QScriptValue qclass = eng.newQMetaObject<QObject>();
   821 
   834 
   822     QScriptValue instance = qclass.construct();
   835     QScriptValue instance = qclass.construct();
   823     QCOMPARE(instance.isQObject(), true);
   836     QCOMPARE(instance.isQObject(), true);
   824     QCOMPARE(instance.toQObject()->metaObject(), qclass.toQMetaObject());
   837     QCOMPARE(instance.toQObject()->metaObject(), qclass.toQMetaObject());
   825     QVERIFY(instance.instanceOf(qclass));
   838     QVERIFY(instance.instanceOf(qclass));
       
   839     QVERIFY(instanceofJS(instance, qclass).strictlyEquals(true));
   826 
   840 
   827     QScriptValue instance2 = qclass2.construct();
   841     QScriptValue instance2 = qclass2.construct();
   828     QCOMPARE(instance2.isQObject(), true);
   842     QCOMPARE(instance2.isQObject(), true);
   829     QCOMPARE(instance2.toQObject()->metaObject(), qclass2.toQMetaObject());
   843     QCOMPARE(instance2.toQObject()->metaObject(), qclass2.toQMetaObject());
   830     QVERIFY(instance2.instanceOf(qclass2));
   844     QVERIFY(instance2.instanceOf(qclass2));
       
   845     QVERIFY(instanceofJS(instance2, qclass2).strictlyEquals(true));
       
   846     QVERIFY(!instance2.instanceOf(qclass));
       
   847     QVERIFY(instanceofJS(instance2, qclass).strictlyEquals(false));
   831 
   848 
   832     QScriptValueList args;
   849     QScriptValueList args;
   833     args << instance;
   850     args << instance;
   834     QScriptValue instance3 = qclass.construct(args);
   851     QScriptValue instance3 = qclass.construct(args);
   835     QCOMPARE(instance3.isQObject(), true);
   852     QCOMPARE(instance3.isQObject(), true);
   836     QCOMPARE(instance3.toQObject()->parent(), instance.toQObject());
   853     QCOMPARE(instance3.toQObject()->parent(), instance.toQObject());
   837     QVERIFY(instance3.instanceOf(qclass));
   854     QVERIFY(instance3.instanceOf(qclass));
       
   855     QVERIFY(instanceofJS(instance3, qclass).strictlyEquals(true));
       
   856     QVERIFY(!instance3.instanceOf(qclass2));
       
   857     QVERIFY(instanceofJS(instance3, qclass2).strictlyEquals(false));
   838     args.clear();
   858     args.clear();
   839 
   859 
   840     QPointer<QObject> qpointer1 = instance.toQObject();
   860     QPointer<QObject> qpointer1 = instance.toQObject();
   841     QPointer<QObject> qpointer2 = instance2.toQObject();
   861     QPointer<QObject> qpointer2 = instance2.toQObject();
   842     QPointer<QObject> qpointer3 = instance3.toQObject();
   862     QPointer<QObject> qpointer3 = instance3.toQObject();
   868         QScriptValue ret = qclass3.call();
   888         QScriptValue ret = qclass3.call();
   869         QVERIFY(ret.isObject());
   889         QVERIFY(ret.isObject());
   870         QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
   890         QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
   871         QVERIFY(!ret.property("isCalledAsConstructor").toBoolean());
   891         QVERIFY(!ret.property("isCalledAsConstructor").toBoolean());
   872         QVERIFY(ret.instanceOf(qclass3));
   892         QVERIFY(ret.instanceOf(qclass3));
       
   893         QVERIFY(instanceofJS(ret, qclass3).strictlyEquals(true));
       
   894         QVERIFY(!ret.instanceOf(qclass));
       
   895         QVERIFY(instanceofJS(ret, qclass).strictlyEquals(false));
   873     }
   896     }
   874     {
   897     {
   875         QScriptValue ret = qclass3.construct();
   898         QScriptValue ret = qclass3.construct();
   876         QVERIFY(ret.isObject());
   899         QVERIFY(ret.isObject());
   877         QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
   900         QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
   878         QVERIFY(ret.property("isCalledAsConstructor").toBoolean());
   901         QVERIFY(ret.property("isCalledAsConstructor").toBoolean());
   879         QVERIFY(ret.instanceOf(qclass3));
   902         QVERIFY(ret.instanceOf(qclass3));
       
   903         QVERIFY(instanceofJS(ret, qclass3).strictlyEquals(true));
       
   904         QVERIFY(!ret.instanceOf(qclass2));
       
   905         QVERIFY(instanceofJS(ret, qclass2).strictlyEquals(false));
   880     }
   906     }
   881 
   907 
   882     // subclassing
   908     // subclassing
   883     qclass2.setProperty("prototype", qclass.construct());
   909     qclass2.setProperty("prototype", qclass.construct());
   884     QVERIFY(qclass2.construct().instanceOf(qclass));
   910     QVERIFY(qclass2.construct().instanceOf(qclass));
       
   911     QVERIFY(instanceofJS(qclass2.construct(), qclass).strictlyEquals(true));
   885 
   912 
   886     // with meta-constructor
   913     // with meta-constructor
   887     QScriptValue qclass4 = eng.newQMetaObject(&QObject::staticMetaObject);
   914     QScriptValue qclass4 = eng.newQMetaObject(&QObject::staticMetaObject);
   888     {
   915     {
   889         QScriptValue inst = qclass4.construct();
   916         QScriptValue inst = qclass4.construct();
   890         QVERIFY(inst.isQObject());
   917         QVERIFY(inst.isQObject());
   891         QVERIFY(inst.toQObject() != 0);
   918         QVERIFY(inst.toQObject() != 0);
   892         QCOMPARE(inst.toQObject()->parent(), (QObject*)0);
   919         QCOMPARE(inst.toQObject()->parent(), (QObject*)0);
   893         QVERIFY(inst.instanceOf(qclass4));
   920         QVERIFY(inst.instanceOf(qclass4));
       
   921         QVERIFY(instanceofJS(inst, qclass4).strictlyEquals(true));
       
   922         QVERIFY(!inst.instanceOf(qclass3));
       
   923         QVERIFY(instanceofJS(inst, qclass3).strictlyEquals(false));
   894     }
   924     }
   895     {
   925     {
   896         QScriptValue inst = qclass4.construct(QScriptValueList() << eng.newQObject(this));
   926         QScriptValue inst = qclass4.construct(QScriptValueList() << eng.newQObject(this));
   897         QVERIFY(inst.isQObject());
   927         QVERIFY(inst.isQObject());
   898         QVERIFY(inst.toQObject() != 0);
   928         QVERIFY(inst.toQObject() != 0);
   899         QCOMPARE(inst.toQObject()->parent(), (QObject*)this);
   929         QCOMPARE(inst.toQObject()->parent(), (QObject*)this);
   900         QVERIFY(inst.instanceOf(qclass4));
   930         QVERIFY(inst.instanceOf(qclass4));
       
   931         QVERIFY(instanceofJS(inst, qclass4).strictlyEquals(true));
       
   932         QVERIFY(!inst.instanceOf(qclass2));
       
   933         QVERIFY(instanceofJS(inst, qclass2).strictlyEquals(false));
   901     }
   934     }
   902 }
   935 }
   903 
   936 
   904 void tst_QScriptEngine::newActivationObject()
   937 void tst_QScriptEngine::newActivationObject()
   905 {
   938 {
  1170     QVERIFY(global.property("bar").equals(global.property("foo")));
  1203     QVERIFY(global.property("bar").equals(global.property("foo")));
  1171 
  1204 
  1172     engine.evaluate("__defineGetter__('baz', function() { return 789; })");
  1205     engine.evaluate("__defineGetter__('baz', function() { return 789; })");
  1173     QVERIFY(engine.evaluate("baz").equals(789));
  1206     QVERIFY(engine.evaluate("baz").equals(789));
  1174     QVERIFY(global.property("baz").equals(789));
  1207     QVERIFY(global.property("baz").equals(789));
       
  1208 }
       
  1209 
       
  1210 void tst_QScriptEngine::customGlobalObjectWithPrototype()
       
  1211 {
       
  1212     for (int x = 0; x < 2; ++x) {
       
  1213         QScriptEngine engine;
       
  1214         QScriptValue wrap = engine.newObject();
       
  1215         QScriptValue global = engine.globalObject();
       
  1216         QScriptValue originalGlobalProto = global.prototype();
       
  1217         if (!x) {
       
  1218             // Set prototype before setting global object
       
  1219             wrap.setPrototype(global);
       
  1220             QVERIFY(wrap.prototype().strictlyEquals(global));
       
  1221             engine.setGlobalObject(wrap);
       
  1222         } else {
       
  1223             // Set prototype after setting global object
       
  1224             engine.setGlobalObject(wrap);
       
  1225             wrap.setPrototype(global);
       
  1226             QVERIFY(wrap.prototype().strictlyEquals(global));
       
  1227         }
       
  1228         {
       
  1229             QScriptValue ret = engine.evaluate("print");
       
  1230             QVERIFY(ret.isFunction());
       
  1231             QVERIFY(ret.strictlyEquals(wrap.property("print")));
       
  1232         }
       
  1233         {
       
  1234             QScriptValue ret = engine.evaluate("this.print");
       
  1235             QVERIFY(ret.isFunction());
       
  1236             QVERIFY(ret.strictlyEquals(wrap.property("print")));
       
  1237         }
       
  1238         {
       
  1239             QScriptValue ret = engine.evaluate("hasOwnProperty('print')");
       
  1240             QVERIFY(ret.isBool());
       
  1241             QVERIFY(!ret.toBool());
       
  1242         }
       
  1243         {
       
  1244             QScriptValue ret = engine.evaluate("this.hasOwnProperty('print')");
       
  1245             QVERIFY(ret.isBool());
       
  1246             QVERIFY(!ret.toBool());
       
  1247         }
       
  1248 
       
  1249         QScriptValue anotherProto = engine.newObject();
       
  1250         anotherProto.setProperty("anotherProtoProperty", 123);
       
  1251         global.setPrototype(anotherProto);
       
  1252         {
       
  1253             QScriptValue ret = engine.evaluate("print");
       
  1254             QVERIFY(ret.isFunction());
       
  1255             QVERIFY(ret.strictlyEquals(wrap.property("print")));
       
  1256         }
       
  1257         {
       
  1258             QScriptValue ret = engine.evaluate("anotherProtoProperty");
       
  1259             QVERIFY(ret.isNumber());
       
  1260             QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty")));
       
  1261         }
       
  1262         {
       
  1263             QScriptValue ret = engine.evaluate("this.anotherProtoProperty");
       
  1264             QVERIFY(ret.isNumber());
       
  1265             QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty")));
       
  1266         }
       
  1267 
       
  1268         wrap.setPrototype(anotherProto);
       
  1269         {
       
  1270             QScriptValue ret = engine.evaluate("print");
       
  1271             QVERIFY(ret.isError());
       
  1272             QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: print"));
       
  1273         }
       
  1274         {
       
  1275             QScriptValue ret = engine.evaluate("anotherProtoProperty");
       
  1276             QVERIFY(ret.isNumber());
       
  1277             QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty")));
       
  1278         }
       
  1279         QVERIFY(global.prototype().strictlyEquals(anotherProto));
       
  1280 
       
  1281         global.setPrototype(originalGlobalProto);
       
  1282         engine.setGlobalObject(global);
       
  1283         {
       
  1284             QScriptValue ret = engine.evaluate("anotherProtoProperty");
       
  1285             QVERIFY(ret.isError());
       
  1286             QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: anotherProtoProperty"));
       
  1287         }
       
  1288         {
       
  1289             QScriptValue ret = engine.evaluate("print");
       
  1290             QVERIFY(ret.isFunction());
       
  1291             QVERIFY(ret.strictlyEquals(global.property("print")));
       
  1292         }
       
  1293         QVERIFY(!anotherProto.property("print").isValid());
       
  1294     }
       
  1295 }
       
  1296 
       
  1297 void tst_QScriptEngine::globalObjectWithCustomPrototype()
       
  1298 {
       
  1299     QScriptEngine engine;
       
  1300     QScriptValue proto = engine.newObject();
       
  1301     proto.setProperty("protoProperty", 123);
       
  1302     QScriptValue global = engine.globalObject();
       
  1303     QScriptValue originalProto = global.prototype();
       
  1304     global.setPrototype(proto);
       
  1305     {
       
  1306         QScriptValue ret = engine.evaluate("protoProperty");
       
  1307         QVERIFY(ret.isNumber());
       
  1308         QVERIFY(ret.strictlyEquals(global.property("protoProperty")));
       
  1309     }
       
  1310     {
       
  1311         QScriptValue ret = engine.evaluate("this.protoProperty");
       
  1312         QVERIFY(ret.isNumber());
       
  1313         QVERIFY(ret.strictlyEquals(global.property("protoProperty")));
       
  1314     }
       
  1315     {
       
  1316         QScriptValue ret = engine.evaluate("hasOwnProperty('protoProperty')");
       
  1317         QVERIFY(ret.isBool());
       
  1318         QVERIFY(!ret.toBool());
       
  1319     }
       
  1320     {
       
  1321         QScriptValue ret = engine.evaluate("this.hasOwnProperty('protoProperty')");
       
  1322         QVERIFY(ret.isBool());
       
  1323         QVERIFY(!ret.toBool());
       
  1324     }
       
  1325 
       
  1326     // Custom prototype set from JS
       
  1327     {
       
  1328         QScriptValue ret = engine.evaluate("this.__proto__ = { 'a': 123 }; a");
       
  1329         QVERIFY(ret.isNumber());
       
  1330         QEXPECT_FAIL("", "QTBUG-9737", Continue);
       
  1331         QVERIFY(ret.strictlyEquals(global.property("a")));
       
  1332     }
  1175 }
  1333 }
  1176 
  1334 
  1177 void tst_QScriptEngine::builtinFunctionNames_data()
  1335 void tst_QScriptEngine::builtinFunctionNames_data()
  1178 {
  1336 {
  1179     QTest::addColumn<QString>("expression");
  1337     QTest::addColumn<QString>("expression");
  3701     {
  3859     {
  3702         QScriptValue tmp = eng.toObject(falskt);
  3860         QScriptValue tmp = eng.toObject(falskt);
  3703         QVERIFY(tmp.isObject());
  3861         QVERIFY(tmp.isObject());
  3704         QCOMPARE(tmp.toNumber(), falskt.toNumber());
  3862         QCOMPARE(tmp.toNumber(), falskt.toNumber());
  3705     }
  3863     }
       
  3864     QVERIFY(falskt.isBool());
  3706 
  3865 
  3707     QScriptValue sant(true);
  3866     QScriptValue sant(true);
  3708     {
  3867     {
  3709         QScriptValue tmp = eng.toObject(sant);
  3868         QScriptValue tmp = eng.toObject(sant);
  3710         QVERIFY(tmp.isObject());
  3869         QVERIFY(tmp.isObject());
  3711         QCOMPARE(tmp.toNumber(), sant.toNumber());
  3870         QCOMPARE(tmp.toNumber(), sant.toNumber());
  3712     }
  3871     }
       
  3872     QVERIFY(sant.isBool());
  3713 
  3873 
  3714     QScriptValue number(123.0);
  3874     QScriptValue number(123.0);
  3715     {
  3875     {
  3716         QScriptValue tmp = eng.toObject(number);
  3876         QScriptValue tmp = eng.toObject(number);
  3717         QVERIFY(tmp.isObject());
  3877         QVERIFY(tmp.isObject());
  3718         QCOMPARE(tmp.toNumber(), number.toNumber());
  3878         QCOMPARE(tmp.toNumber(), number.toNumber());
  3719     }
  3879     }
       
  3880     QVERIFY(number.isNumber());
  3720 
  3881 
  3721     QScriptValue str = QScriptValue(&eng, QString("ciao"));
  3882     QScriptValue str = QScriptValue(&eng, QString("ciao"));
  3722     {
  3883     {
  3723         QScriptValue tmp = eng.toObject(str);
  3884         QScriptValue tmp = eng.toObject(str);
  3724         QVERIFY(tmp.isObject());
  3885         QVERIFY(tmp.isObject());
  3725         QCOMPARE(tmp.toString(), str.toString());
  3886         QCOMPARE(tmp.toString(), str.toString());
  3726     }
  3887     }
       
  3888     QVERIFY(str.isString());
  3727 
  3889 
  3728     QScriptValue object = eng.newObject();
  3890     QScriptValue object = eng.newObject();
  3729     {
  3891     {
  3730         QScriptValue tmp = eng.toObject(object);
  3892         QScriptValue tmp = eng.toObject(object);
  3731         QVERIFY(tmp.isObject());
  3893         QVERIFY(tmp.isObject());
  3734 
  3896 
  3735     QScriptValue qobject = eng.newQObject(this);
  3897     QScriptValue qobject = eng.newQObject(this);
  3736     QVERIFY(eng.toObject(qobject).strictlyEquals(qobject));
  3898     QVERIFY(eng.toObject(qobject).strictlyEquals(qobject));
  3737 
  3899 
  3738     QVERIFY(!eng.toObject(QScriptValue()).isValid());
  3900     QVERIFY(!eng.toObject(QScriptValue()).isValid());
       
  3901 
       
  3902     // v1 constructors
       
  3903 
       
  3904     QScriptValue boolValue(&eng, true);
       
  3905     {
       
  3906         QScriptValue ret = eng.toObject(boolValue);
       
  3907         QVERIFY(ret.isObject());
       
  3908         QCOMPARE(ret.toBool(), boolValue.toBool());
       
  3909     }
       
  3910     QVERIFY(boolValue.isBool());
       
  3911 
       
  3912     QScriptValue numberValue(&eng, 123.0);
       
  3913     {
       
  3914         QScriptValue ret = eng.toObject(numberValue);
       
  3915         QVERIFY(ret.isObject());
       
  3916         QCOMPARE(ret.toNumber(), numberValue.toNumber());
       
  3917     }
       
  3918     QVERIFY(numberValue.isNumber());
       
  3919 
       
  3920     QScriptValue stringValue(&eng, QString::fromLatin1("foo"));
       
  3921     {
       
  3922         QScriptValue ret = eng.toObject(stringValue);
       
  3923         QVERIFY(ret.isObject());
       
  3924         QCOMPARE(ret.toString(), stringValue.toString());
       
  3925     }
       
  3926     QVERIFY(stringValue.isString());
  3739 }
  3927 }
  3740 
  3928 
  3741 void tst_QScriptEngine::reservedWords_data()
  3929 void tst_QScriptEngine::reservedWords_data()
  3742 {
  3930 {
  3743     QTest::addColumn<QString>("word");
  3931     QTest::addColumn<QString>("word");
  4185         QVERIFY(ret.isString());
  4373         QVERIFY(ret.isString());
  4186         QCOMPARE(ret.toString(), QString::fromLatin1("foobar"));
  4374         QCOMPARE(ret.toString(), QString::fromLatin1("foobar"));
  4187     }
  4375     }
  4188 }
  4376 }
  4189 
  4377 
       
  4378 static QScriptValue callQsTr(QScriptContext *ctx, QScriptEngine *eng)
       
  4379 {
       
  4380     return eng->globalObject().property("qsTr").call(ctx->thisObject(), ctx->argumentsObject());
       
  4381 }
       
  4382 
       
  4383 void tst_QScriptEngine::translateScript()
       
  4384 {
       
  4385     QScriptEngine engine;
       
  4386 
       
  4387     QTranslator translator;
       
  4388     translator.load(":/translations/translatable_la");
       
  4389     QCoreApplication::instance()->installTranslator(&translator);
       
  4390     engine.installTranslatorFunctions();
       
  4391 
       
  4392     QString fileName = QString::fromLatin1("translatable.js");
       
  4393     // Top-level
       
  4394     QCOMPARE(engine.evaluate("qsTr('One')", fileName).toString(), QString::fromLatin1("En"));
       
  4395     QCOMPARE(engine.evaluate("qsTr('Hello')", fileName).toString(), QString::fromLatin1("Hallo"));
       
  4396     // From function
       
  4397     QCOMPARE(engine.evaluate("(function() { return qsTr('One'); })()", fileName).toString(), QString::fromLatin1("En"));
       
  4398     QCOMPARE(engine.evaluate("(function() { return qsTr('Hello'); })()", fileName).toString(), QString::fromLatin1("Hallo"));
       
  4399     // From eval
       
  4400     QCOMPARE(engine.evaluate("eval('qsTr(\\'One\\')')", fileName).toString(), QString::fromLatin1("En"));
       
  4401     QCOMPARE(engine.evaluate("eval('qsTr(\\'Hello\\')')", fileName).toString(), QString::fromLatin1("Hallo"));
       
  4402 
       
  4403     QCOMPARE(engine.evaluate("qsTranslate('FooContext', 'Two')", fileName).toString(), QString::fromLatin1("To"));
       
  4404     QCOMPARE(engine.evaluate("qsTranslate('FooContext', 'Goodbye')", fileName).toString(), QString::fromLatin1("Farvel"));
       
  4405     // From eval
       
  4406     QCOMPARE(engine.evaluate("eval('qsTranslate(\\'FooContext\\', \\'Two\\')')", fileName).toString(), QString::fromLatin1("To"));
       
  4407     QCOMPARE(engine.evaluate("eval('qsTranslate(\\'FooContext\\', \\'Goodbye\\')')", fileName).toString(), QString::fromLatin1("Farvel"));
       
  4408 
       
  4409     QCOMPARE(engine.evaluate("qsTranslate('FooContext', 'Goodbye', '', 'UnicodeUTF8')", fileName).toString(), QString::fromLatin1("Farvel"));
       
  4410 
       
  4411     QCOMPARE(engine.evaluate("qsTr('One', 'not the same one')", fileName).toString(), QString::fromLatin1("Enda en"));
       
  4412 
       
  4413     QVERIFY(engine.evaluate("QT_TR_NOOP()").isUndefined());
       
  4414     QCOMPARE(engine.evaluate("QT_TR_NOOP('One')").toString(), QString::fromLatin1("One"));
       
  4415 
       
  4416     QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP()").isUndefined());
       
  4417     QVERIFY(engine.evaluate("QT_TRANSLATE_NOOP('FooContext')").isUndefined());
       
  4418     QCOMPARE(engine.evaluate("QT_TRANSLATE_NOOP('FooContext', 'Two')").toString(), QString::fromLatin1("Two"));
       
  4419 
       
  4420     // Don't exist in translation
       
  4421     QCOMPARE(engine.evaluate("qsTr('Three')", fileName).toString(), QString::fromLatin1("Three"));
       
  4422     QCOMPARE(engine.evaluate("qsTranslate('FooContext', 'So long')", fileName).toString(), QString::fromLatin1("So long"));
       
  4423     QCOMPARE(engine.evaluate("qsTranslate('BarContext', 'Goodbye')", fileName).toString(), QString::fromLatin1("Goodbye"));
       
  4424 
       
  4425     // From C++
       
  4426     // There is no context, but it shouldn't crash
       
  4427     QCOMPARE(engine.globalObject().property("qsTr").call(
       
  4428                  QScriptValue(), QScriptValueList() << "One").toString(), QString::fromLatin1("One"));
       
  4429 
       
  4430     // Translate strings from the second script (translatable2.js)
       
  4431 
       
  4432     QString fileName2 = QString::fromLatin1("translatable2.js");
       
  4433 
       
  4434     QCOMPARE(engine.evaluate("qsTr('Three')", fileName2).toString(), QString::fromLatin1("Tre"));
       
  4435     QCOMPARE(engine.evaluate("qsTr('Happy birthday!')", fileName2).toString(), QString::fromLatin1("Gratulerer med dagen!"));
       
  4436 
       
  4437     // Not translated because translation is only in translatable.js
       
  4438     QCOMPARE(engine.evaluate("qsTr('One')", fileName2).toString(), QString::fromLatin1("One"));
       
  4439     QCOMPARE(engine.evaluate("(function() { return qsTr('One'); })()", fileName2).toString(), QString::fromLatin1("One"));
       
  4440 
       
  4441     // For qsTranslate() the filename shouldn't matter
       
  4442     QCOMPARE(engine.evaluate("qsTranslate('FooContext', 'Two')", fileName2).toString(), QString::fromLatin1("To"));
       
  4443     QCOMPARE(engine.evaluate("qsTranslate('BarContext', 'Congratulations!')", fileName).toString(), QString::fromLatin1("Gratulerer!"));
       
  4444 
       
  4445     // qsTr() should use the innermost filename as context
       
  4446     engine.evaluate("function foo(s) { return bar(s); }", fileName);
       
  4447     engine.evaluate("function bar(s) { return qsTr(s); }", fileName2);
       
  4448     QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Tre"));
       
  4449     QCOMPARE(engine.evaluate("bar('Three')", fileName).toString(), QString::fromLatin1("Tre"));
       
  4450     QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("One"));
       
  4451 
       
  4452     engine.evaluate("function foo(s) { return bar(s); }", fileName2);
       
  4453     engine.evaluate("function bar(s) { return qsTr(s); }", fileName);
       
  4454     QCOMPARE(engine.evaluate("bar('Three')", fileName2).toString(), QString::fromLatin1("Three"));
       
  4455     QCOMPARE(engine.evaluate("bar('One')", fileName).toString(), QString::fromLatin1("En"));
       
  4456     QCOMPARE(engine.evaluate("bar('One')", fileName2).toString(), QString::fromLatin1("En"));
       
  4457 
       
  4458     // Calling qsTr() from a native function
       
  4459     engine.globalObject().setProperty("qsTrProxy", engine.newFunction(callQsTr));
       
  4460     QCOMPARE(engine.evaluate("qsTrProxy('One')", fileName).toString(), QString::fromLatin1("En"));
       
  4461     QCOMPARE(engine.evaluate("qsTrProxy('One')", fileName2).toString(), QString::fromLatin1("One"));
       
  4462     QCOMPARE(engine.evaluate("qsTrProxy('Three')", fileName).toString(), QString::fromLatin1("Three"));
       
  4463     QCOMPARE(engine.evaluate("qsTrProxy('Three')", fileName2).toString(), QString::fromLatin1("Tre"));
       
  4464 
       
  4465     QCoreApplication::instance()->removeTranslator(&translator);
       
  4466 }
       
  4467 
       
  4468 void tst_QScriptEngine::translateWithInvalidArgs_data()
       
  4469 {
       
  4470     QTest::addColumn<QString>("expression");
       
  4471     QTest::addColumn<QString>("expectedError");
       
  4472 
       
  4473     QTest::newRow("qsTr()")  << "qsTr()" << "Error: qsTr() requires at least one argument";
       
  4474     QTest::newRow("qsTr(123)")  << "qsTr(123)" << "Error: qsTr(): first argument (text) must be a string";
       
  4475     QTest::newRow("qsTr('foo', 123)")  << "qsTr('foo', 123)" << "Error: qsTr(): second argument (comment) must be a string";
       
  4476     QTest::newRow("qsTr('foo', 'bar', 'baz')")  << "qsTr('foo', 'bar', 'baz')" << "Error: qsTr(): third argument (n) must be a number";
       
  4477     QTest::newRow("qsTr('foo', 'bar', true)")  << "qsTr('foo', 'bar', true)" << "Error: qsTr(): third argument (n) must be a number";
       
  4478 
       
  4479     QTest::newRow("qsTranslate()")  << "qsTranslate()" << "Error: qsTranslate() requires at least two arguments";
       
  4480     QTest::newRow("qsTranslate('foo')")  << "qsTranslate('foo')" << "Error: qsTranslate() requires at least two arguments";
       
  4481     QTest::newRow("qsTranslate('foo', 123)")  << "qsTranslate('foo', 123)" << "Error: qsTranslate(): second argument (text) must be a string";
       
  4482     QTest::newRow("qsTranslate('foo', 'bar', 123)")  << "qsTranslate('foo', 'bar', 123)" << "Error: qsTranslate(): third argument (comment) must be a string";
       
  4483     QTest::newRow("qsTranslate('foo', 'bar', 'baz', 123)")  << "qsTranslate('foo', 'bar', 'baz', 123)" << "Error: qsTranslate(): fourth argument (encoding) must be a string";
       
  4484     QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')")  << "qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')" << "Error: qsTranslate(): fifth argument (n) must be a number";
       
  4485     QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 123)")  << "qsTranslate('foo', 'bar', 'baz', 'zab', 123)" << "Error: qsTranslate(): invalid encoding 'zab'";
       
  4486 }
       
  4487 
       
  4488 void tst_QScriptEngine::translateWithInvalidArgs()
       
  4489 {
       
  4490     QFETCH(QString, expression);
       
  4491     QFETCH(QString, expectedError);
       
  4492     QScriptEngine engine;
       
  4493     engine.installTranslatorFunctions();
       
  4494     QScriptValue result = engine.evaluate(expression);
       
  4495     QVERIFY(result.isError());
       
  4496     QCOMPARE(result.toString(), expectedError);
       
  4497 }
       
  4498 
       
  4499 void tst_QScriptEngine::translationContext_data()
       
  4500 {
       
  4501     QTest::addColumn<QString>("path");
       
  4502     QTest::addColumn<QString>("text");
       
  4503     QTest::addColumn<QString>("expectedTranslation");
       
  4504 
       
  4505     QTest::newRow("translatable.js")  << "translatable.js" << "One" << "En";
       
  4506     QTest::newRow("/translatable.js")  << "/translatable.js" << "One" << "En";
       
  4507     QTest::newRow("/foo/translatable.js")  << "/foo/translatable.js" << "One" << "En";
       
  4508     QTest::newRow("/foo/bar/translatable.js")  << "/foo/bar/translatable.js" << "One" << "En";
       
  4509     QTest::newRow("./translatable.js")  << "./translatable.js" << "One" << "En";
       
  4510     QTest::newRow("../translatable.js")  << "../translatable.js" << "One" << "En";
       
  4511     QTest::newRow("foo/translatable.js")  << "foo/translatable.js" << "One" << "En";
       
  4512     QTest::newRow("file:///home/qt/translatable.js")  << "file:///home/qt/translatable.js" << "One" << "En";
       
  4513     QTest::newRow(":/resources/translatable.js")  << ":/resources/translatable.js" << "One" << "En";
       
  4514     QTest::newRow("/translatable.js.foo")  << "/translatable.js.foo" << "One" << "En";
       
  4515     QTest::newRow("/translatable.txt")  << "/translatable.txt" << "One" << "En";
       
  4516     QTest::newRow("translatable")  << "translatable" << "One" << "En";
       
  4517     QTest::newRow("foo/translatable")  << "foo/translatable" << "One" << "En";
       
  4518 
       
  4519     QTest::newRow("native separators")
       
  4520         << (QDir::toNativeSeparators(QDir::currentPath()) + QDir::separator() + "translatable.js")
       
  4521         << "One" << "En";
       
  4522 
       
  4523     QTest::newRow("translatable.js/")  << "translatable.js/" << "One" << "One";
       
  4524     QTest::newRow("nosuchscript.js")  << "" << "One" << "One";
       
  4525     QTest::newRow("(empty)")  << "" << "One" << "One";
       
  4526 }
       
  4527 
       
  4528 void tst_QScriptEngine::translationContext()
       
  4529 {
       
  4530     QTranslator translator;
       
  4531     translator.load(":/translations/translatable_la");
       
  4532     QCoreApplication::instance()->installTranslator(&translator);
       
  4533 
       
  4534     QScriptEngine engine;
       
  4535     engine.installTranslatorFunctions();
       
  4536 
       
  4537     QFETCH(QString, path);
       
  4538     QFETCH(QString, text);
       
  4539     QFETCH(QString, expectedTranslation);
       
  4540     QScriptValue ret = engine.evaluate(QString::fromLatin1("qsTr('%0')").arg(text), path);
       
  4541     QVERIFY(ret.isString());
       
  4542     QCOMPARE(ret.toString(), expectedTranslation);
       
  4543 
       
  4544     QCoreApplication::instance()->removeTranslator(&translator);
       
  4545 }
       
  4546 
  4190 void tst_QScriptEngine::functionScopes()
  4547 void tst_QScriptEngine::functionScopes()
  4191 {
  4548 {
  4192     QScriptEngine eng;
  4549     QScriptEngine eng;
  4193     {
  4550     {
  4194         // top-level functions have only the global object in their scope
  4551         // top-level functions have only the global object in their scope