aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp')
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp278
1 files changed, 234 insertions, 44 deletions
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index e764ae783c..6b19c13109 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -304,9 +304,21 @@ private slots:
void propertyOverride();
void concatenatedStringPropertyAccess();
void jsOwnedObjectsDeletedOnEngineDestroy();
+ void updateCall();
void numberParsing();
void stringParsing();
+ void push_and_shift();
void qtbug_32801();
+ void thisObject();
+ void qtbug_33754();
+ void qtbug_34493();
+ void singletonFromQMLToCpp();
+ void singletonFromQMLAndBackAndCompare();
+ void setPropertyOnInvalid();
+ void miscTypeTest();
+ void stackLimits();
+ void idsAsLValues();
+ void qtbug_34792();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -1304,6 +1316,7 @@ void tst_qqmlecmascript::scope()
QVERIFY(object != 0);
QCOMPARE(object->property("test1").toBool(), true);
+ QEXPECT_FAIL("", "Properties resolvable at compile time come before the global object, which is not 100% compatible with older QML versions", Continue);
QCOMPARE(object->property("test2").toBool(), true);
QCOMPARE(object->property("test3").toBool(), true);
@@ -2257,15 +2270,16 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::ValueRef o, cons
QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->current;
QV4::Scope scope(ctx);
- try {
- QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
- if (!function)
- return false;
- QV4::ScopedCallData d(scope, 1);
- d->args[0] = o;
- d->thisObject = engine->global();
- function->call(d);
- } catch (...) {
+ QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
+ if (scope.engine->hasException) {
+ ctx->catchException();
+ return true;
+ }
+ QV4::ScopedCallData d(scope, 1);
+ d->args[0] = o;
+ d->thisObject = engine->global();
+ function->call(d);
+ if (scope.engine->hasException) {
ctx->catchException();
return true;
}
@@ -2284,21 +2298,24 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::ValueRef o,
QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->current;
QV4::Scope scope(ctx);
- try {
- QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
- if (!function)
- return false;
-
- QV4::ScopedValue value(scope);
- QV4::ScopedCallData d(scope, 1);
- d->args[0] = o;
- d->thisObject = engine->global();
- value = function->call(d);
- return __qmljs_strict_equal(value, result);
- } catch (...) {
+ QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
+ if (scope.engine->hasException) {
ctx->catchException();
+ return false;
}
- return false;
+ if (!function)
+ return false;
+
+ QV4::ScopedValue value(scope);
+ QV4::ScopedCallData d(scope, 1);
+ d->args[0] = o;
+ d->thisObject = engine->global();
+ value = function->call(d);
+ if (scope.engine->hasException) {
+ ctx->catchException();
+ return false;
+ }
+ return __qmljs_strict_equal(value, result);
}
static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::ValueRef o,
@@ -2312,18 +2329,23 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::ValueRef
QV4::Script program(QV8Engine::getV4(engine)->rootContext, functionSource);
program.inheritContext = true;
- try {
- QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
- if (!function)
- return QV4::Encode::undefined();
- QV4::ScopedCallData d(scope, 1);
- d->args[0] = o;
- d->thisObject = engine->global();
- return function->call(d);
- } catch (...) {
+
+ QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
+ if (scope.engine->hasException) {
+ ctx->catchException();
+ return QV4::Encode::undefined();
+ }
+ if (!function)
+ return QV4::Encode::undefined();
+ QV4::ScopedCallData d(scope, 1);
+ d->args[0] = o;
+ d->thisObject = engine->global();
+ QV4::ScopedValue result(scope, function->call(d));
+ if (scope.engine->hasException) {
ctx->catchException();
+ return QV4::Encode::undefined();
}
- return QV4::Encode::undefined();
+ return result.asReturnedValue();
}
#define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
@@ -3479,9 +3501,9 @@ void tst_qqmlecmascript::compiled()
QCOMPARE(object->property("test15").toBool(), false);
QCOMPARE(object->property("test16").toBool(), true);
- QCOMPARE(object->property("test17").toInt(), 5);
+ QCOMPARE(object->property("test17").toInt(), 4);
QCOMPARE(object->property("test18").toReal(), qreal(176));
- QCOMPARE(object->property("test19").toInt(), 7);
+ QCOMPARE(object->property("test19").toInt(), 6);
QCOMPARE(object->property("test20").toReal(), qreal(6.7));
QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
@@ -3506,7 +3528,7 @@ void tst_qqmlecmascript::numberAssignment()
QCOMPARE(object->property("test3"), QVariant((qreal)6));
QCOMPARE(object->property("test4"), QVariant((qreal)6));
- QCOMPARE(object->property("test5"), QVariant((int)7));
+ QCOMPARE(object->property("test5"), QVariant((int)6));
QCOMPARE(object->property("test6"), QVariant((int)7));
QCOMPARE(object->property("test7"), QVariant((int)6));
QCOMPARE(object->property("test8"), QVariant((int)6));
@@ -3880,15 +3902,15 @@ void tst_qqmlecmascript::singletonTypeResolution()
void tst_qqmlecmascript::verifyContextLifetime(QQmlContextData *ctxt) {
QQmlContextData *childCtxt = ctxt->childContexts;
- if (!ctxt->importedScripts.isEmpty()) {
+ if (!ctxt->importedScripts.isNullOrUndefined()) {
QV8Engine *engine = QV8Engine::get(ctxt->engine);
- foreach (const QV4::PersistentValue& qmlglobal, ctxt->importedScripts) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Scope scope(v4);
+ QV4::ScopedArrayObject scripts(scope, ctxt->importedScripts);
+ QV4::ScopedValue qml(scope);
+ for (quint32 i = 0; i < scripts->arrayLength(); ++i) {
QQmlContextData *scriptContext, *newContext;
-
- if (qmlglobal.isUndefined())
- continue;
- QV4::Scope scope(QV8Engine::getV4((engine)));
- QV4::ScopedValue qml(scope, qmlglobal.value());
+ qml = scripts->getIndexed(i);
scriptContext = QV4::QmlContextWrapper::getContext(qml);
qml = QV4::Encode::undefined();
@@ -3900,7 +3922,7 @@ void tst_qqmlecmascript::verifyContextLifetime(QQmlContextData *ctxt) {
}
engine->gc();
- qml = qmlglobal.value();
+ qml = scripts->getIndexed(i);
newContext = QV4::QmlContextWrapper::getContext(qml);
QVERIFY(scriptContext == newContext);
}
@@ -5411,6 +5433,8 @@ void tst_qqmlecmascript::sequenceConversionIndexes()
QTest::ignoreMessage(QtWarningMsg, qPrintable(w3));
QMetaObject::invokeMethod(object, "indexedAccess");
QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "indexOf");
+ QVERIFY(object->property("success").toBool());
delete object;
}
@@ -6435,7 +6459,7 @@ void tst_qqmlecmascript::realToInt()
QMetaObject::invokeMethod(object, "test1");
QCOMPARE(object->value(), int(4));
QMetaObject::invokeMethod(object, "test2");
- QCOMPARE(object->value(), int(8));
+ QCOMPARE(object->value(), int(7));
}
void tst_qqmlecmascript::urlProperty()
@@ -7261,6 +7285,17 @@ void tst_qqmlecmascript::jsOwnedObjectsDeletedOnEngineDestroy()
delete object;
}
+void tst_qqmlecmascript::updateCall()
+{
+ // update is a slot on QQuickItem. Even though it's not
+ // documented it can be called from within QML. Make sure
+ // we don't crash when calling it.
+ QString file("updateCall.qml");
+ QQmlComponent component(&engine, testFileUrl(file));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+}
+
void tst_qqmlecmascript::numberParsing()
{
for (int i = 1; i < 8; ++i) {
@@ -7289,6 +7324,18 @@ void tst_qqmlecmascript::stringParsing()
}
}
+void tst_qqmlecmascript::push_and_shift()
+{
+ QJSEngine e;
+ const QString program =
+ "var array = []; "
+ "for (var i = 0; i < 10000; i++) {"
+ " array.push(5); array.unshift(5); array.push(5);"
+ "}"
+ "array.length;";
+ QVERIFY(e.evaluate(program).toNumber() == 30000);
+}
+
void tst_qqmlecmascript::qtbug_32801()
{
QQmlComponent component(&engine, testFileUrl("qtbug_32801.qml"));
@@ -7301,6 +7348,149 @@ void tst_qqmlecmascript::qtbug_32801()
QVERIFY(QMetaObject::invokeMethod(obj.data(), "emitTestSignal"));
}
+void tst_qqmlecmascript::thisObject()
+{
+ QQmlComponent component(&engine, testFileUrl("thisObject.qml"));
+ QObject *object = component.create();
+ QVERIFY(object);
+ QCOMPARE(qvariant_cast<QObject*>(object->property("subObject"))->property("test").toInt(), 2);
+ delete object;
+}
+
+void tst_qqmlecmascript::qtbug_33754()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_33754.qml"));
+
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(obj != 0);
+}
+
+void tst_qqmlecmascript::qtbug_34493()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug_34493.qml"));
+
+ QScopedPointer<QObject> obj(component.create());
+ if (component.errors().size())
+ qDebug() << component.errors();
+ QVERIFY(component.errors().isEmpty());
+ QVERIFY(obj != 0);
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "doIt"));
+ QTRY_VERIFY(obj->property("prop").toString() == QLatin1String("Hello World!"));
+}
+
+// Check that a Singleton can be passed from QML to C++
+// as its type*, it's parent type* and as QObject*
+void tst_qqmlecmascript::singletonFromQMLToCpp()
+{
+ QQmlComponent component(&engine, testFile("singletonTest.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ if (component.errors().size())
+ qDebug() << component.errors();
+ QVERIFY(component.errors().isEmpty());
+ QVERIFY(obj != 0);
+
+ QCOMPARE(obj->property("qobjectTest"), QVariant(true));
+ QCOMPARE(obj->property("myQmlObjectTest"), QVariant(true));
+ QCOMPARE(obj->property("myInheritedQmlObjectTest"), QVariant(true));
+}
+
+// Check that a Singleton can be passed from QML to C++
+// as its type*, it's parent type* and as QObject*
+// and correctly compares to itself
+void tst_qqmlecmascript::singletonFromQMLAndBackAndCompare()
+{
+ QQmlComponent component(&engine, testFile("singletonTest2.qml"));
+ QScopedPointer<QObject> o(component.create());
+ if (component.errors().size())
+ qDebug() << component.errors();
+ QVERIFY(component.errors().isEmpty());
+ QVERIFY(o != 0);
+
+ QCOMPARE(o->property("myInheritedQmlObjectTest1"), QVariant(true));
+ QCOMPARE(o->property("myInheritedQmlObjectTest2"), QVariant(true));
+ QCOMPARE(o->property("myInheritedQmlObjectTest3"), QVariant(true));
+
+ QCOMPARE(o->property("myQmlObjectTest1"), QVariant(true));
+ QCOMPARE(o->property("myQmlObjectTest2"), QVariant(true));
+ QCOMPARE(o->property("myQmlObjectTest3"), QVariant(true));
+
+ QCOMPARE(o->property("qobjectTest1"), QVariant(true));
+ QCOMPARE(o->property("qobjectTest2"), QVariant(true));
+ QCOMPARE(o->property("qobjectTest3"), QVariant(true));
+
+ QCOMPARE(o->property("singletonEqualToItself"), QVariant(true));
+}
+
+void tst_qqmlecmascript::setPropertyOnInvalid()
+{
+ {
+ QQmlComponent component(&engine, testFileUrl("setPropertyOnNull.qml"));
+ QString warning = component.url().toString() + ":4: TypeError: Type error";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+ QObject *object = component.create();
+ QVERIFY(object);
+ delete object;
+ }
+
+ {
+ QQmlComponent component(&engine, testFileUrl("setPropertyOnUndefined.qml"));
+ QString warning = component.url().toString() + ":4: TypeError: Type error";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+ QObject *object = component.create();
+ QVERIFY(object);
+ delete object;
+ }
+}
+
+void tst_qqmlecmascript::miscTypeTest()
+{
+ QQmlComponent component(&engine, testFileUrl("misctypetest.qml"));
+
+ QObject *object = component.create();
+ if (object == 0)
+ qDebug() << component.errorString();
+ QVERIFY(object != 0);
+
+ QVariant q;
+ QMetaObject::invokeMethod(object, "test_invalid_url_equal", Q_RETURN_ARG(QVariant, q));
+ QVERIFY(q.toBool() == true);
+ QMetaObject::invokeMethod(object, "test_invalid_url_strictequal", Q_RETURN_ARG(QVariant, q));
+ QVERIFY(q.toBool() == true);
+ QMetaObject::invokeMethod(object, "test_valid_url_equal", Q_RETURN_ARG(QVariant, q));
+ QVERIFY(q.toBool() == true);
+ QMetaObject::invokeMethod(object, "test_valid_url_strictequal", Q_RETURN_ARG(QVariant, q));
+ QVERIFY(q.toBool() == true);
+
+ delete object;
+}
+
+void tst_qqmlecmascript::stackLimits()
+{
+ QJSEngine engine;
+ engine.evaluate(QStringLiteral("function foo() {foo();} try {foo()} catch(e) { }"));
+}
+
+void tst_qqmlecmascript::idsAsLValues()
+{
+ QString err = QString(QLatin1String("%1:5 left-hand side of assignment operator is not an lvalue\n")).arg(testFileUrl("idAsLValue.qml").toString());
+ QQmlComponent component(&engine, testFileUrl("idAsLValue.qml"));
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(!object);
+ QCOMPARE(component.errorString(), err);
+}
+
+void tst_qqmlecmascript::qtbug_34792()
+{
+ QQmlComponent component(&engine, testFileUrl("qtbug34792.qml"));
+
+ QObject *object = component.create();
+ if (object == 0)
+ qDebug() << component.errorString();
+ QVERIFY(object != 0);
+ delete object;
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"