diff options
Diffstat (limited to 'tests/auto/qml')
33 files changed, 718 insertions, 109 deletions
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 6dbdc83b08..a918e23a05 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -208,7 +208,9 @@ void QQmlProfilerClient::messageReceived(const QByteArray &message) switch (data.detailType) { case QQmlProfilerClient::AnimationFrame: { - stream >> data.framerate >> data.animationcount; + int threadId; + stream >> data.framerate >> data.animationcount >> threadId; + QVERIFY(threadId >= 0); QVERIFY(data.framerate != -1); QVERIFY(data.animationcount != -1); break; @@ -396,6 +398,7 @@ void tst_QQmlProfilerService::nonBlockingConnect() m_client->setTraceState(true); m_client->setTraceState(false); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); + QVERIFY(m_client->traceMessages.count()); // must start with "StartTrace" QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); @@ -422,7 +425,8 @@ void tst_QQmlProfilerService::pixmapCacheData() m_client->setTraceState(false); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); - QVERIFY(m_client->traceMessages.count() >= 20); + QVERIFY2(m_client->traceMessages.count() >= 20, + QString::number(m_client->traceMessages.count()).toUtf8().constData()); // must start with "StartTrace" QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); @@ -495,7 +499,8 @@ void tst_QQmlProfilerService::profileOnExit() m_client->setTraceState(true); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); - QVERIFY(m_client->traceMessages.count() >= 2); + QVERIFY2(m_client->traceMessages.count() >= 2, + QString::number(m_client->traceMessages.count()).toUtf8().constData()); // must start with "StartTrace" QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); @@ -514,7 +519,8 @@ void tst_QQmlProfilerService::controlFromJS() m_client->setTraceState(false); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); - QVERIFY(m_client->traceMessages.count() >= 2); + QVERIFY2(m_client->traceMessages.count() >= 2, + QString::number(m_client->traceMessages.count()).toUtf8().constData()); // must start with "StartTrace" QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); @@ -537,22 +543,26 @@ void tst_QQmlProfilerService::signalSourceLocation() m_client->setTraceState(false); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); - QVERIFY(m_client->traceMessages.count() >= 20); + QVERIFY2(m_client->traceMessages.count() >= 20, + QString::number(m_client->traceMessages.count()).toUtf8().constData()); + // must start with "StartTrace" QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace); - QVERIFY(m_client->traceMessages[14].messageType == QQmlProfilerClient::RangeLocation); - QVERIFY(m_client->traceMessages[14].detailType == QQmlProfilerClient::HandlingSignal); - QVERIFY(m_client->traceMessages[14].detailData.endsWith("signalSourceLocation.qml")); - QVERIFY(m_client->traceMessages[14].line == 8); - QVERIFY(m_client->traceMessages[14].column == 28); + QCOMPARE(m_client->traceMessages[14].messageType, (int)QQmlProfilerClient::RangeLocation); + QCOMPARE(m_client->traceMessages[14].detailType, (int)QQmlProfilerClient::HandlingSignal); + QVERIFY2(m_client->traceMessages[14].detailData.endsWith("signalSourceLocation.qml"), + m_client->traceMessages[14].detailData.toUtf8().constData()); + QCOMPARE(m_client->traceMessages[14].line, 8); + QCOMPARE(m_client->traceMessages[14].column, 28); - QVERIFY(m_client->traceMessages[19].messageType == QQmlProfilerClient::RangeLocation); - QVERIFY(m_client->traceMessages[19].detailType == QQmlProfilerClient::HandlingSignal); - QVERIFY(m_client->traceMessages[19].detailData.endsWith("signalSourceLocation.qml")); - QVERIFY(m_client->traceMessages[19].line == 7); - QVERIFY(m_client->traceMessages[19].column == 21); + QCOMPARE(m_client->traceMessages[19].messageType, (int)QQmlProfilerClient::RangeLocation); + QCOMPARE(m_client->traceMessages[19].detailType, (int)QQmlProfilerClient::HandlingSignal); + QVERIFY2(m_client->traceMessages[19].detailData.endsWith("signalSourceLocation.qml"), + m_client->traceMessages[19].detailData.toUtf8().constData()); + QCOMPARE(m_client->traceMessages[19].line, 7); + QCOMPARE(m_client->traceMessages[19].column, 21); // must end with "EndTrace" QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event); @@ -571,26 +581,29 @@ void tst_QQmlProfilerService::javascript() m_client->setTraceState(false); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); - QVERIFY(m_client->traceMessages.count() >= 36); + QVERIFY2(m_client->traceMessages.count() >= 36, + QString::number(m_client->traceMessages.count()).toUtf8().constData()); // must start with "StartTrace" QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace); - QVERIFY(m_client->traceMessages[32].messageType == QQmlProfilerClient::RangeStart); - QVERIFY(m_client->traceMessages[32].detailType == QQmlProfilerClient::Javascript); + QCOMPARE(m_client->traceMessages[32].messageType, (int)QQmlProfilerClient::RangeStart); + QCOMPARE(m_client->traceMessages[32].detailType, (int)QQmlProfilerClient::Javascript); - QVERIFY(m_client->traceMessages[33].messageType == QQmlProfilerClient::RangeLocation); - QVERIFY(m_client->traceMessages[33].detailType == QQmlProfilerClient::Javascript); - QVERIFY(m_client->traceMessages[33].detailData.endsWith("javascript.qml")); - QVERIFY(m_client->traceMessages[33].line == 4); - QVERIFY(m_client->traceMessages[33].column == 5); + QCOMPARE(m_client->traceMessages[33].messageType, (int)QQmlProfilerClient::RangeLocation); + QCOMPARE(m_client->traceMessages[33].detailType, (int)QQmlProfilerClient::Javascript); + QVERIFY2(m_client->traceMessages[33].detailData.endsWith("javascript.qml"), + m_client->traceMessages[33].detailData.toUtf8().constData()); + QCOMPARE(m_client->traceMessages[33].line, 4); + QCOMPARE(m_client->traceMessages[33].column, 5); - QVERIFY(m_client->traceMessages[34].messageType == QQmlProfilerClient::RangeData); - QVERIFY(m_client->traceMessages[34].detailType == QQmlProfilerClient::Javascript); - QVERIFY(m_client->traceMessages[34].detailData == "something"); + QCOMPARE(m_client->traceMessages[34].messageType, (int)QQmlProfilerClient::RangeData); + QCOMPARE(m_client->traceMessages[34].detailType, (int)QQmlProfilerClient::Javascript); + QVERIFY2(m_client->traceMessages[34].detailData == "something", + m_client->traceMessages[34].detailData.toUtf8().constData()); - QVERIFY(m_client->traceMessages[35].messageType == QQmlProfilerClient::RangeEnd); - QVERIFY(m_client->traceMessages[35].detailType == QQmlProfilerClient::Javascript); + QCOMPARE(m_client->traceMessages[35].messageType, (int)QQmlProfilerClient::RangeEnd); + QCOMPARE(m_client->traceMessages[35].detailType, (int)QQmlProfilerClient::Javascript); // must end with "EndTrace" QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event); diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 53e86268a6..b2723b02fd 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -48,6 +48,7 @@ #include <qstandarditemmodel.h> #include <QtCore/qnumeric.h> #include <qqmlengine.h> +#include <qqmlcomponent.h> #include <stdlib.h> #include <private/qv4alloca_p.h> @@ -115,7 +116,8 @@ private slots: void jsForInStatement_prototypeProperties(); void jsForInStatement_mutateWhileIterating(); void jsForInStatement_arrays(); - void jsForInStatement_nullAndUndefined(); + void jsForInStatement_constant(); + void with_constant(); void stringObjects(); void jsStringPrototypeReplaceBugs(); void getterSetterThisObject_global(); @@ -150,6 +152,11 @@ private slots: void regexpLastMatch(); void indexedAccesses(); + void prototypeChainGc(); + void prototypeChainGc_QTBUG38299(); + + void dynamicProperties(); + signals: void testSignal(); }; @@ -162,6 +169,9 @@ tst_QJSEngine::~tst_QJSEngine() { } +Q_DECLARE_METATYPE(Qt::KeyboardModifier) +Q_DECLARE_METATYPE(Qt::KeyboardModifiers) + class OverloadedSlots : public QObject { Q_OBJECT @@ -174,6 +184,7 @@ signals: void slotWithoutArgCalled(); void slotWithSingleArgCalled(const QString &arg); void slotWithArgumentsCalled(const QString &arg1, const QString &arg2, const QString &arg3); + void slotWithOverloadedArgumentsCalled(const QString &arg, Qt::KeyboardModifier modifier, Qt::KeyboardModifiers moreModifiers); public slots: void slotToCall() { emit slotWithoutArgCalled(); } @@ -182,6 +193,10 @@ public slots: { slotWithArgumentsCalled(arg, arg2, arg3); } + void slotToCall(const QString &arg, Qt::KeyboardModifier modifier, Qt::KeyboardModifiers blah = Qt::ShiftModifier) + { + emit slotWithOverloadedArgumentsCalled(arg, modifier, blah); + } }; void tst_QJSEngine::callQObjectSlot() @@ -227,6 +242,18 @@ void tst_QJSEngine::callQObjectSlot() QCOMPARE(arguments.at(1).toString(), QString("arg2")); QCOMPARE(arguments.at(2).toString(), QString("arg3")); } + + { + QSignalSpy spy(&dummy, SIGNAL(slotWithOverloadedArgumentsCalled(QString, Qt::KeyboardModifier, Qt::KeyboardModifiers))); + eng.evaluate(QStringLiteral("dummy.slotToCall('arg', %1);").arg(QString::number(Qt::ControlModifier))); + QCOMPARE(spy.count(), 1); + + const QList<QVariant> arguments = spy.first(); + QCOMPARE(arguments.at(0).toString(), QString("arg")); + QCOMPARE(arguments.at(1).toInt(), int(Qt::ControlModifier)); + QCOMPARE(int(qvariant_cast<Qt::KeyboardModifiers>(arguments.at(2))), int(Qt::ShiftModifier)); + + } } void tst_QJSEngine::constructWithParent() @@ -1011,6 +1038,8 @@ void tst_QJSEngine::evaluate_data() QTest::newRow("/a/g") << QString("/a/g") << -1 << false << -1; QTest::newRow("/a/gim") << QString("/a/gim") << -1 << false << -1; QTest::newRow("/a/gimp") << QString("/a/gimp") << 1 << true << 1; + QTest::newRow("empty-array-concat") << QString("var a = []; var b = [1]; var c = a.concat(b); ") << 1 << false << -1; + QTest::newRow("object-literal") << QString("var a = {\"0\":\"#\",\"2\":\"#\",\"5\":\"#\",\"8\":\"#\",\"6\":\"#\",\"12\":\"#\",\"13\":\"#\",\"16\":\"#\",\"18\":\"#\",\"39\":\"#\",\"40\":\"#\"}") << 1 << false << -1; } void tst_QJSEngine::evaluate() @@ -1207,6 +1236,14 @@ void tst_QJSEngine::valueConversion_QVariant() QCOMPARE(qjsvalue_cast<QVariant>(QJSValue(123)), QVariant(123)); QVERIFY(eng.toScriptValue(QVariant(QMetaType::VoidStar, 0)).isNull()); + + { + QVariantMap map; + map.insert("42", "the answer to life the universe and everything"); + QJSValue val = eng.toScriptValue(map); + QVERIFY(val.isObject()); + QCOMPARE(val.property(42).toString(), map.value(QStringLiteral("42")).toString()); + } } void tst_QJSEngine::valueConversion_basic2() @@ -1982,7 +2019,7 @@ void tst_QJSEngine::jsForInStatement_arrays() } } -void tst_QJSEngine::jsForInStatement_nullAndUndefined() +void tst_QJSEngine::jsForInStatement_constant() { QJSEngine eng; { @@ -1995,6 +2032,34 @@ void tst_QJSEngine::jsForInStatement_nullAndUndefined() QVERIFY(ret.isBool()); QVERIFY(ret.toBool()); } + { + QJSValue ret = eng.evaluate("r = false; for (var p in 1) r = true; r"); + QVERIFY(ret.isBool()); + QVERIFY(!ret.toBool()); + } + { + QJSValue ret = eng.evaluate("r = false; for (var p in 'abc') r = true; r"); + QVERIFY(ret.isBool()); + QVERIFY(ret.toBool()); + } +} + +void tst_QJSEngine::with_constant() +{ + QJSEngine eng; + { + QJSValue ret = eng.evaluate("r = false; with(null) { r= true; } r"); + QVERIFY(ret.isError()); + } + { + QJSValue ret = eng.evaluate("r = false; with(undefined) { r= true; } r"); + QVERIFY(ret.isError()); + } + { + QJSValue ret = eng.evaluate("r = false; with(1) { r= true; } r"); + QVERIFY(ret.isBool()); + QVERIFY(ret.toBool()); + } } void tst_QJSEngine::stringObjects() @@ -2883,6 +2948,69 @@ void tst_QJSEngine::indexedAccesses() QVERIFY(v.isUndefined()); } +void tst_QJSEngine::prototypeChainGc() +{ + QJSEngine engine; + + QJSValue getProto = engine.evaluate("Object.getPrototypeOf"); + + QJSValue factory = engine.evaluate("function() { return Object.create(Object.create({})); }"); + QVERIFY(factory.isCallable()); + QJSValue obj = factory.call(); + engine.collectGarbage(); + + QJSValue proto = getProto.call(QJSValueList() << obj); + proto = getProto.call(QJSValueList() << proto); + QVERIFY(proto.isObject()); +} + +void tst_QJSEngine::prototypeChainGc_QTBUG38299() +{ + QJSEngine engine; + engine.evaluate("var mapping = {" + "'prop1': \"val1\",\n" + "'prop2': \"val2\"\n" + "}\n" + "\n" + "delete mapping.prop2\n" + "delete mapping.prop1\n" + "\n"); + // Don't hang! + engine.collectGarbage(); +} + +void tst_QJSEngine::dynamicProperties() +{ + { + QJSEngine engine; + QObject *obj = new QObject; + QJSValue wrapper = engine.newQObject(obj); + wrapper.setProperty("someRandomProperty", 42); + QCOMPARE(wrapper.property("someRandomProperty").toInt(), 42); + QVERIFY(!qmlContext(obj)); + } + { + QQmlEngine qmlEngine; + QQmlComponent component(&qmlEngine); + component.setData("import QtQml 2.0; QtObject { property QtObject subObject: QtObject {} }", QUrl()); + QObject *root = component.create(0); + QVERIFY(root); + QVERIFY(qmlContext(root)); + + QJSValue wrapper = qmlEngine.newQObject(root); + wrapper.setProperty("someRandomProperty", 42); + QVERIFY(!wrapper.hasProperty("someRandomProperty")); + + QObject *subObject = qvariant_cast<QObject*>(root->property("subObject")); + QVERIFY(subObject); + QVERIFY(qmlContext(subObject)); + + wrapper = qmlEngine.newQObject(subObject); + wrapper.setProperty("someRandomProperty", 42); + QVERIFY(!wrapper.hasProperty("someRandomProperty")); + } +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index 74369685f5..c909a2d35a 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -68,7 +68,7 @@ qtHaveModule(widgets) { SUBDIRS += $$PUBLICTESTS SUBDIRS += $$METATYPETESTS -SUBDIRS += debugger +!winrt: SUBDIRS += debugger # no QProcess on winrt contains(QT_CONFIG, private_tests) { SUBDIRS += $$PRIVATETESTS diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp index dbf48779d6..1cd1583f22 100644 --- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp +++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp @@ -251,10 +251,9 @@ void tst_qqmlconnections::rewriteErrors() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("rewriteError-unnamed.qml")); + QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal uses unnamed parameter followed by named parameter.").toLatin1()); TestObject *obj = qobject_cast<TestObject*>(c.create()); QVERIFY(obj != 0); - - QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal uses unnamed parameter followed by named parameter.").toLatin1()); obj->unnamedArgumentSignal(1, .5, "hello"); QCOMPARE(obj->ran(), false); @@ -264,10 +263,10 @@ void tst_qqmlconnections::rewriteErrors() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("rewriteError-global.qml")); + QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal parameter \"parseInt\" hides global variable.").toLatin1()); TestObject *obj = qobject_cast<TestObject*>(c.create()); QVERIFY(obj != 0); - QTest::ignoreMessage(QtWarningMsg, (c.url().toString() + ":5:35: QML Connections: Signal parameter \"parseInt\" hides global variable.").toLatin1()); obj->signalWithGlobalName(10); QCOMPARE(obj->ran(), false); diff --git a/tests/auto/qml/qqmlecmascript/data/SubObject.qml b/tests/auto/qml/qqmlecmascript/data/SubObject.qml new file mode 100644 index 0000000000..4658edd1db --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/SubObject.qml @@ -0,0 +1,8 @@ +import QtQml 2.0 +QtObject { + property int testValue: -1 + property int subValue; + onSubValueChanged: { + testValue = this.someExpression + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/Types.js b/tests/auto/qml/qqmlecmascript/data/Types.js new file mode 100644 index 0000000000..8da80a9565 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/Types.js @@ -0,0 +1,3 @@ +.pragma library + +var Foo = 0; diff --git a/tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml b/tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml new file mode 100644 index 0000000000..33b21c74a8 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/contextObjectOnLazyBindings.qml @@ -0,0 +1,10 @@ +import QtQml 2.0 +QtObject { + property SubObject subObject: SubObject { + subValue: 20; + property int someExpression: { + return someValue; + } + } + property int someValue: 42 +} diff --git a/tests/auto/qml/qqmlecmascript/data/importedScriptsAccessOnObjectWithInvalidContext.qml b/tests/auto/qml/qqmlecmascript/data/importedScriptsAccessOnObjectWithInvalidContext.qml new file mode 100644 index 0000000000..74310c6d6b --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/importedScriptsAccessOnObjectWithInvalidContext.qml @@ -0,0 +1,42 @@ +import QtQuick 2.0 + +import "Types.js" as Types + +Rectangle { + id: root + property bool success: false + + color: "white" + height: 100 + width: 100 + + signal modelChanged + + Timer { + id: timer + interval: 100 + onTriggered: { + root.modelChanged(); + root.success = true; + } + } + + Loader{ + id: weekPage + sourceComponent: Component { + Item{ + function createAllDayEvents() { + if (3 == Types.Foo) { + console.log("Hello") + } + } + } + } + onLoaded: root.modelChanged.connect(item.createAllDayEvents); + } + + Component.onCompleted: { + weekPage.sourceComponent = null + timer.running = true + } +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 2809124028..770d6b8197 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -320,6 +320,8 @@ private slots: void singletonWithEnum(); void lazyBindingEvaluation(); void varPropertyAccessOnObjectWithInvalidContext(); + void importedScriptsAccessOnObjectWithInvalidContext(); + void contextObjectOnLazyBindings(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -2316,7 +2318,7 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::ValueRef o, ctx->catchException(); return false; } - return Runtime::strictEqual(value, result); + return QV4::Runtime::strictEqual(value, result); } static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::ValueRef o, @@ -7579,6 +7581,28 @@ void tst_qqmlecmascript::varPropertyAccessOnObjectWithInvalidContext() QVERIFY(obj->property("success") == true); } +void tst_qqmlecmascript::importedScriptsAccessOnObjectWithInvalidContext() +{ + QQmlComponent component(&engine, testFileUrl("importedScriptsAccessOnObjectWithInvalidContext.qml")); + QScopedPointer<QObject> obj(component.create()); + if (obj.isNull()) + qDebug() << component.errors().first().toString(); + QVERIFY(!obj.isNull()); + QTRY_VERIFY(obj->property("success") == true); +} + +void tst_qqmlecmascript::contextObjectOnLazyBindings() +{ + QQmlComponent component(&engine, testFileUrl("contextObjectOnLazyBindings.qml")); + QScopedPointer<QObject> obj(component.create()); + if (obj.isNull()) + qDebug() << component.errors().first().toString(); + QVERIFY(!obj.isNull()); + QObject *subObject = qvariant_cast<QObject*>(obj->property("subObject")); + QVERIFY(subObject); + QCOMPARE(subObject->property("testValue").toInt(), int(42)); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlincubator/data/objectDeleted.qml b/tests/auto/qml/qqmlincubator/data/objectDeleted.qml index f00f975923..c9f6f8b564 100644 --- a/tests/auto/qml/qqmlincubator/data/objectDeleted.qml +++ b/tests/auto/qml/qqmlincubator/data/objectDeleted.qml @@ -2,7 +2,9 @@ import QtQuick 2.0 import Qt.test 1.0 Item { - SelfRegistering { - value: 11 + SelfRegisteringOuter { + value: SelfRegistering { + value: 11 + } } } diff --git a/tests/auto/qml/qqmlincubator/testtypes.cpp b/tests/auto/qml/qqmlincubator/testtypes.cpp index d926b6ae9b..b35636dd86 100644 --- a/tests/auto/qml/qqmlincubator/testtypes.cpp +++ b/tests/auto/qml/qqmlincubator/testtypes.cpp @@ -58,6 +58,25 @@ void SelfRegisteringType::clearMe() m_me = 0; } +SelfRegisteringOuterType *SelfRegisteringOuterType::m_me = 0; +bool SelfRegisteringOuterType::beenDeleted = false; +SelfRegisteringOuterType::SelfRegisteringOuterType() +: m_v(0) +{ + m_me = this; + beenDeleted = false; +} + +SelfRegisteringOuterType::~SelfRegisteringOuterType() +{ + beenDeleted = true; +} + +SelfRegisteringOuterType *SelfRegisteringOuterType::me() +{ + return m_me; +} + CompletionRegisteringType *CompletionRegisteringType::m_me = 0; CompletionRegisteringType::CompletionRegisteringType() { @@ -131,6 +150,7 @@ void CompletionCallbackType::registerCallback(callback c, void *d) void registerTypes() { qmlRegisterType<SelfRegisteringType>("Qt.test", 1,0, "SelfRegistering"); + qmlRegisterType<SelfRegisteringOuterType>("Qt.test", 1,0, "SelfRegisteringOuter"); qmlRegisterType<CompletionRegisteringType>("Qt.test", 1,0, "CompletionRegistering"); qmlRegisterType<CallbackRegisteringType>("Qt.test", 1,0, "CallbackRegistering"); qmlRegisterType<CompletionCallbackType>("Qt.test", 1,0, "CompletionCallback"); diff --git a/tests/auto/qml/qqmlincubator/testtypes.h b/tests/auto/qml/qqmlincubator/testtypes.h index fedff61510..8202cdd9dc 100644 --- a/tests/auto/qml/qqmlincubator/testtypes.h +++ b/tests/auto/qml/qqmlincubator/testtypes.h @@ -63,6 +63,27 @@ private: int m_v; }; +class SelfRegisteringOuterType : public QObject +{ +Q_OBJECT +Q_PROPERTY(QObject* value READ value WRITE setValue); +public: + SelfRegisteringOuterType(); + ~SelfRegisteringOuterType(); + + static bool beenDeleted; + + QObject *value() const { return m_v; } + void setValue(QObject *v) { m_v = v; } + + static SelfRegisteringOuterType *me(); + +private: + static SelfRegisteringOuterType *m_me; + + QObject *m_v; +}; + class CallbackRegisteringType : public QObject { Q_OBJECT diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp index d6d0b0402a..0b9872f94c 100644 --- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp +++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp @@ -52,6 +52,8 @@ #include <QQmlComponent> #include <QQmlIncubator> #include "../../shared/util.h" +#include <private/qqmlincubator_p.h> +#include <private/qqmlobjectcreator_p.h> class tst_qqmlincubator : public QQmlDataTest { @@ -141,35 +143,50 @@ void tst_qqmlincubator::incubationMode() void tst_qqmlincubator::objectDeleted() { - SelfRegisteringType::clearMe(); + { + QQmlEngine engine; + QQmlIncubationController controller; + engine.setIncubationController(&controller); + SelfRegisteringType::clearMe(); - QQmlComponent component(&engine, testFileUrl("objectDeleted.qml")); - QVERIFY(component.isReady()); + QQmlComponent component(&engine, testFileUrl("objectDeleted.qml")); + QVERIFY(component.isReady()); - QQmlIncubator incubator; - component.create(incubator); + QQmlIncubator incubator; + component.create(incubator); - QCOMPARE(incubator.status(), QQmlIncubator::Loading); - QVERIFY(SelfRegisteringType::me() == 0); + QCOMPARE(incubator.status(), QQmlIncubator::Loading); + QVERIFY(SelfRegisteringType::me() == 0); - while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { - bool b = false; - controller.incubateWhile(&b); - } + while (SelfRegisteringOuterType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } - QVERIFY(SelfRegisteringType::me() != 0); - QVERIFY(incubator.isLoading()); + QVERIFY(SelfRegisteringOuterType::me() != 0); + QVERIFY(incubator.isLoading()); - delete SelfRegisteringType::me(); + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } - { - bool b = true; - controller.incubateWhile(&b); - } + // We have to cheat and manually remove it from the creator->allCreatedObjects + // otherwise we will do a double delete + QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(&incubator); + incubatorPriv->creator->allCreatedObjects().pop(); + delete SelfRegisteringType::me(); - QVERIFY(incubator.isError()); - VERIFY_ERRORS(incubator, "objectDeleted.errors.txt"); - QVERIFY(incubator.object() == 0); + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isError()); + VERIFY_ERRORS(incubator, "objectDeleted.errors.txt"); + QVERIFY(incubator.object() == 0); + } + QVERIFY(SelfRegisteringOuterType::beenDeleted); } void tst_qqmlincubator::clear() @@ -1111,6 +1128,10 @@ void tst_qqmlincubator::selfDelete() QVERIFY(SelfRegisteringType::me() != 0); QVERIFY(incubator->isLoading()); + // We have to cheat and manually remove it from the creator->allCreatedObjects + // otherwise we will do a double delete + QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubator); + incubatorPriv->creator->allCreatedObjects().pop(); delete SelfRegisteringType::me(); { diff --git a/tests/auto/qml/qqmllanguage/data/SubType.qml b/tests/auto/qml/qqmllanguage/data/SubType.qml new file mode 100644 index 0000000000..0698ae2349 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/SubType.qml @@ -0,0 +1,3 @@ +import QtQml 2.0 +QtObject { +} diff --git a/tests/auto/qml/qqmllanguage/data/assignNullStrings.qml b/tests/auto/qml/qqmllanguage/data/assignNullStrings.qml new file mode 100644 index 0000000000..5e1c3a9b03 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/assignNullStrings.qml @@ -0,0 +1,9 @@ +import Test 1.0 +MyTypeObject { + stringProperty: "" + byteArrayProperty: "" + function assignNullStringsFromJs() { + stringProperty = "" + byteArrayProperty = "" + } +} diff --git a/tests/auto/qml/qqmllanguage/data/customParserProperties.qml b/tests/auto/qml/qqmllanguage/data/customParserProperties.qml new file mode 100644 index 0000000000..5d72edb8e5 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/customParserProperties.qml @@ -0,0 +1,7 @@ +import Test 1.0 +import QtQml 2.0 +SimpleObjectWithCustomParser { + intProperty: 42 + property string qmlString: "Hello" + property var someObject: QtObject {} +} diff --git a/tests/auto/qml/qqmllanguage/data/idProperty.qml b/tests/auto/qml/qqmllanguage/data/idProperty.qml index bf048ea60a..dbb242804a 100644 --- a/tests/auto/qml/qqmllanguage/data/idProperty.qml +++ b/tests/auto/qml/qqmllanguage/data/idProperty.qml @@ -5,4 +5,8 @@ MyContainer { MyTypeObject { id: "myObjectId" } + + MyTypeObject { + selfGroupProperty.id: "name.with.dots" + } } diff --git a/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.errors.txt b/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.errors.txt new file mode 100644 index 0000000000..d62dbd703d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.errors.txt @@ -0,0 +1 @@ +3:5:Cannot assign to non-existent property "nonExistantGrouped" diff --git a/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.qml b/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.qml new file mode 100644 index 0000000000..3b66a5f6c7 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/nonexistantProperty.7.qml @@ -0,0 +1,4 @@ +import Test 1.0 +MyQmlObject { + nonExistantGrouped.blah: MyQmlObject {} +} diff --git a/tests/auto/qml/qqmllanguage/data/rootObjectInCreationNotForSubObjects.qml b/tests/auto/qml/qqmllanguage/data/rootObjectInCreationNotForSubObjects.qml new file mode 100644 index 0000000000..afba278ade --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/rootObjectInCreationNotForSubObjects.qml @@ -0,0 +1,7 @@ +import QtQml 2.0 +import Test 1.0 +RootObjectInCreationTester { + subObject: SubType { + property int testValue: 42; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/scriptString7.qml b/tests/auto/qml/qqmllanguage/data/scriptString7.qml new file mode 100644 index 0000000000..a9d5b47e2b --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/scriptString7.qml @@ -0,0 +1,6 @@ +import Test 1.0 + +MyTypeObject { + intProperty: 100; + scriptProperty: intProperty; +} diff --git a/tests/auto/qml/qqmllanguage/data/{subdir}/Test.qml b/tests/auto/qml/qqmllanguage/data/{subdir}/Test.qml new file mode 100644 index 0000000000..f789a905f2 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/{subdir}/Test.qml @@ -0,0 +1,2 @@ +import QtQuick 2.0 +Rectangle { } diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index fad5c1e65d..8ffa327cf2 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -92,6 +92,9 @@ void registerTypes() qmlRegisterType<MyCreateableDerivedClass,1>("Test", 1, 1, "MyCreateableDerivedClass"); qmlRegisterCustomType<CustomBinding>("Test", 1, 0, "CustomBinding", new CustomBindingParser); + qmlRegisterCustomType<SimpleObjectWithCustomParser>("Test", 1, 0, "SimpleObjectWithCustomParser", new SimpleObjectCustomParser); + + qmlRegisterType<RootObjectInCreationTester>("Test", 1, 0, "RootObjectInCreationTester"); } QVariant myCustomVariantTypeConverter(const QString &data) @@ -102,9 +105,8 @@ QVariant myCustomVariantTypeConverter(const QString &data) } -QByteArray CustomBindingParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings) +QByteArray CustomBindingParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { - Q_UNUSED(objectIndex) QByteArray result; QDataStream ds(&result, QIODevice::WriteOnly); @@ -123,7 +125,7 @@ QByteArray CustomBindingParser::compile(const QV4::CompiledData::QmlUnit *qmlUni return result; } -void CustomBindingParser::setCustomData(QObject *object, const QByteArray &data) +void CustomBindingParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*) { CustomBinding *customBinding = qobject_cast<CustomBinding*>(object); Q_ASSERT(customBinding); @@ -155,10 +157,9 @@ void CustomBinding::componentComplete() } } -QByteArray EnumSupportingCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings) +QByteArray EnumSupportingCustomParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { Q_UNUSED(qmlUnit) - Q_UNUSED(objectIndex) if (bindings.count() != 1) { error(bindings.first(), QStringLiteral("Custom parser invoked incorrectly for unit test")); @@ -189,3 +190,35 @@ QByteArray EnumSupportingCustomParser::compile(const QV4::CompiledData::QmlUnit return QByteArray(); } + + +QByteArray SimpleObjectCustomParser::compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings) +{ + return QByteArray::number(bindings.count()); +} + +void SimpleObjectCustomParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData*) +{ + SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object); + Q_ASSERT(o); + bool ok = false; + o->setCustomBindingsCount(data.toInt(&ok)); + Q_ASSERT(ok); +} + + +MyQmlObject::MyQmlObject() + : m_value(-1) + , m_interface(0) + , m_qmlobject(0) + , m_childAddedEventCount(0) +{ + qRegisterMetaType<MyCustomVariantType>("MyCustomVariantType"); +} + +bool MyQmlObject::event(QEvent *event) +{ + if (event->type() == QEvent::ChildAdded) + m_childAddedEventCount++; + return QObject::event(event); +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index a1e2b76bd1..1c13a2e21c 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -119,7 +119,7 @@ class MyQmlObject : public QObject, public MyInterface Q_INTERFACES(MyInterface) public: - MyQmlObject() : m_value(-1), m_interface(0), m_qmlobject(0) { qRegisterMetaType<MyCustomVariantType>("MyCustomVariantType"); } + MyQmlObject(); int value() const { return m_value; } void setValue(int v) { m_value = v; } @@ -161,6 +161,8 @@ public: QJSValue qjsvalue() const { return m_qjsvalue; } void setQJSValue(const QJSValue &value) { m_qjsvalue = value; emit qjsvalueChanged(); } + int childAddedEventCount() const { return m_childAddedEventCount; } + public slots: void basicSlot() { qWarning("MyQmlObject::basicSlot"); } void basicSlotWithArgs(int v) { qWarning("MyQmlObject::basicSlotWithArgs(%d)", v); } @@ -173,6 +175,9 @@ signals: void signalWithDefaultArg(int parameter = 5); void qjsvalueChanged(); +protected: + virtual bool event(QEvent *event); + private: friend class tst_qqmllanguage; int m_value; @@ -181,6 +186,7 @@ private: MyCustomVariantType m_custom; int m_propertyWithNotify; QJSValue m_qjsvalue; + int m_childAddedEventCount; }; QML_DECLARE_TYPE(MyQmlObject) QML_DECLARE_TYPEINFO(MyQmlObject, QML_HAS_ATTACHED_PROPERTIES) @@ -230,6 +236,7 @@ class MyTypeObject : public QObject Q_PROPERTY(MyMirroredEnum mirroredEnumProperty READ mirroredEnumProperty WRITE setMirroredEnumProperty NOTIFY mirroredEnumPropertyChanged) Q_PROPERTY(MyEnumContainer::RelatedEnum relatedEnumProperty READ relatedEnumProperty WRITE setRelatedEnumProperty) Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringPropertyChanged) + Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty NOTIFY byteArrayPropertyChanged) Q_PROPERTY(uint uintProperty READ uintProperty WRITE setUintProperty NOTIFY uintPropertyChanged) Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intPropertyChanged) Q_PROPERTY(qreal realProperty READ realProperty WRITE setRealProperty NOTIFY realPropertyChanged) @@ -351,6 +358,15 @@ public: emit stringPropertyChanged(); } + QByteArray byteArrayPropertyValue; + QByteArray byteArrayProperty() const { + return byteArrayPropertyValue; + } + void setByteArrayProperty(const QByteArray &v) { + byteArrayPropertyValue = v; + emit byteArrayPropertyChanged(); + } + uint uintPropertyValue; uint uintProperty() const { return uintPropertyValue; @@ -564,6 +580,7 @@ signals: void qtEnumPropertyChanged(); void mirroredEnumPropertyChanged(); void stringPropertyChanged(); + void byteArrayPropertyChanged(); void uintPropertyChanged(); void intPropertyChanged(); void realPropertyChanged(); @@ -722,15 +739,15 @@ class MyCustomParserType : public QObject class MyCustomParserTypeParser : public QQmlCustomParser { public: - QByteArray compile(const QV4::CompiledData::QmlUnit *, int, const QList<const QV4::CompiledData::Binding *> &) { return QByteArray(); } - void setCustomData(QObject *, const QByteArray &) {} + QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) { return QByteArray(); } + void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {} }; class EnumSupportingCustomParser : public QQmlCustomParser { public: - QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings); - void setCustomData(QObject *, const QByteArray &) {} + QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); + void setCustomData(QObject *, const QByteArray &, QQmlCompiledData*) {} }; class MyParserStatus : public QObject, public QQmlParserStatus @@ -1100,8 +1117,52 @@ public: class CustomBindingParser : public QQmlCustomParser { - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, int objectIndex, const QList<const QV4::CompiledData::Binding *> &bindings); - virtual void setCustomData(QObject *object, const QByteArray &data); + virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); + virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *); +}; + +class SimpleObjectWithCustomParser : public QObject +{ + Q_OBJECT + Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty) +public: + SimpleObjectWithCustomParser() + : m_intProperty(0) + , m_customBindingsCount(0) + {} + + int intProperty() const { return m_intProperty; } + void setIntProperty(int value) { m_intProperty = value; } + + void setCustomBindingsCount(int count) { m_customBindingsCount = count; } + int customBindingsCount() const { return m_customBindingsCount; } + +private: + int m_intProperty; + int m_customBindingsCount; +}; + +class SimpleObjectCustomParser : public QQmlCustomParser +{ + virtual QByteArray compile(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &bindings); + virtual void setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *); +}; + +class RootObjectInCreationTester : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject *subObject READ subObject WRITE setSubObject FINAL) + Q_CLASSINFO("DeferredPropertyNames", "subObject"); +public: + RootObjectInCreationTester() + : obj(0) + {} + + QObject *subObject() const { return obj; } + void setSubObject(QObject *o) { obj = o; } + +private: + QObject *obj; }; void registerTypes(); diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index cf43352c40..be417df325 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -65,6 +65,17 @@ DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES) +static inline bool isCaseSensitiveFileSystem(const QString &path) { + Q_UNUSED(path) +#if defined(Q_OS_MAC) + return pathconf(path.toLatin1().constData(), _PC_CASE_SENSITIVE); +#elif defined(Q_OS_WIN) + return false; +#else + return true; +#endif +} + /* This test case covers QML language issues. This covers everything that does not involve evaluating ECMAScript expressions and bindings. @@ -99,6 +110,7 @@ private slots: void assignLiteralToVariant(); void assignLiteralToVar(); void assignLiteralToJSValue(); + void assignNullStrings(); void bindJSValueToVar(); void bindJSValueToVariant(); void bindJSValueToType(); @@ -218,10 +230,15 @@ private slots: void customParserBindingScopes(); void customParserEvaluateEnum(); + void customParserProperties(); void preservePropertyCacheOnGroupObjects(); void propertyCacheInSync(); + void rootObjectInCreationNotForSubObjects(); + + void noChildEvents(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -328,6 +345,7 @@ void tst_qqmllanguage::errors_data() QTest::newRow("nonexistantProperty.4") << "nonexistantProperty.4.qml" << "nonexistantProperty.4.errors.txt" << false; QTest::newRow("nonexistantProperty.5") << "nonexistantProperty.5.qml" << "nonexistantProperty.5.errors.txt" << false; QTest::newRow("nonexistantProperty.6") << "nonexistantProperty.6.qml" << "nonexistantProperty.6.errors.txt" << false; + QTest::newRow("nonexistantProperty.7") << "nonexistantProperty.7.qml" << "nonexistantProperty.7.errors.txt" << false; QTest::newRow("wrongType (string for int)") << "wrongType.1.qml" << "wrongType.1.errors.txt" << false; QTest::newRow("wrongType (int for bool)") << "wrongType.2.qml" << "wrongType.2.errors.txt" << false; @@ -493,13 +511,11 @@ void tst_qqmllanguage::errors_data() QTest::newRow("notAvailable") << "notAvailable.qml" << "notAvailable.errors.txt" << false; QTest::newRow("singularProperty") << "singularProperty.qml" << "singularProperty.errors.txt" << false; QTest::newRow("singularProperty.2") << "singularProperty.2.qml" << "singularProperty.2.errors.txt" << false; - QTest::newRow("incorrectCase") << "incorrectCase.qml" -#if defined(Q_OS_MAC) || defined(Q_OS_WIN32) - << "incorrectCase.errors.insensitive.txt" -#else - << "incorrectCase.errors.sensitive.txt" -#endif - << false; + + const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ? + QStringLiteral("incorrectCase.errors.sensitive.txt") : + QStringLiteral("incorrectCase.errors.insensitive.txt"); + QTest::newRow("incorrectCase") << "incorrectCase.qml" << expectedError << false; QTest::newRow("metaobjectRevision.1") << "metaobjectRevision.1.qml" << "metaobjectRevision.1.errors.txt" << false; QTest::newRow("metaobjectRevision.2") << "metaobjectRevision.2.qml" << "metaobjectRevision.2.errors.txt" << false; @@ -859,6 +875,19 @@ void tst_qqmllanguage::assignLiteralToJSValue() } } +void tst_qqmllanguage::assignNullStrings() +{ + QQmlComponent component(&engine, testFileUrl("assignNullStrings.qml")); + VERIFY_ERRORS(0); + MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QVERIFY(object != 0); + QVERIFY(object->stringProperty().isNull()); + QVERIFY(object->byteArrayProperty().isNull()); + QMetaObject::invokeMethod(object, "assignNullStringsFromJs", Qt::DirectConnection); + QVERIFY(object->stringProperty().isNull()); + QVERIFY(object->byteArrayProperty().isNull()); +} + void tst_qqmllanguage::bindJSValueToVar() { QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml")); @@ -1175,12 +1204,17 @@ void tst_qqmllanguage::idProperty() VERIFY_ERRORS(0); MyContainer *object = qobject_cast<MyContainer *>(component.create()); QVERIFY(object != 0); - QCOMPARE(object->getChildren()->count(), 1); + QCOMPARE(object->getChildren()->count(), 2); MyTypeObject *child = qobject_cast<MyTypeObject *>(object->getChildren()->at(0)); QVERIFY(child != 0); QCOMPARE(child->id(), QString("myObjectId")); QCOMPARE(object->property("object"), QVariant::fromValue((QObject *)child)); + + child = + qobject_cast<MyTypeObject *>(object->getChildren()->at(1)); + QVERIFY(child != 0); + QCOMPARE(child->id(), QString("name.with.dots")); } // Tests automatic connection to notify signals if "onBlahChanged" syntax is used @@ -1874,6 +1908,28 @@ void tst_qqmllanguage::scriptString() QVERIFY(object != 0); QCOMPARE(object->scriptProperty().isUndefinedLiteral(), true); } + { + QQmlComponent component(&engine, testFileUrl("scriptString7.qml")); + VERIFY_ERRORS(0); + + MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QVERIFY(object != 0); + QQmlScriptString ss = object->scriptProperty(); + + { + QQmlExpression expr(ss, /*context*/0, object); + QCOMPARE(expr.evaluate().toInt(), int(100)); + } + + { + SimpleObjectWithCustomParser testScope; + QVERIFY(testScope.metaObject()->indexOfProperty("intProperty") != object->metaObject()->indexOfProperty("intProperty")); + + testScope.setIntProperty(42); + QQmlExpression expr(ss, /*context*/0, &testScope); + QCOMPARE(expr.evaluate().toInt(), int(42)); + } + } } // Check that default property assignments are correctly spliced into explicit @@ -2208,6 +2264,11 @@ void tst_qqmllanguage::importsLocal_data() "Test {}" << (!qmlCheckTypes()?"TestType":"") << (!qmlCheckTypes()?"":"Test is ambiguous. Found in org/qtproject/Test/ and in subdir/"); + QTest::newRow("file URL survives percent-encoding") + << "import \"" + QUrl::fromLocalFile(QDir::currentPath() + "/{subdir}").toString() + "\"\n" + "Test {}" + << "QQuickRectangle" + << ""; } void tst_qqmllanguage::importsLocal() @@ -2574,12 +2635,9 @@ void tst_qqmllanguage::importIncorrectCase() QList<QQmlError> errors = component.errors(); QCOMPARE(errors.count(), 1); -#if defined(Q_OS_MAC) || defined(Q_OS_WIN) - QString expectedError = QLatin1String("File name case mismatch"); -#else - QString expectedError = QLatin1String("File not found"); -#endif - + const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ? + QStringLiteral("File not found") : + QStringLiteral("File name case mismatch"); QCOMPARE(errors.at(0).description(), expectedError); engine.setImportPathList(defaultImportPathList); @@ -3591,6 +3649,20 @@ void tst_qqmllanguage::customParserEvaluateEnum() QVERIFY(!o.isNull()); } +void tst_qqmllanguage::customParserProperties() +{ + QQmlComponent component(&engine, testFile("customParserProperties.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); + SimpleObjectWithCustomParser *testObject = qobject_cast<SimpleObjectWithCustomParser*>(o.data()); + QVERIFY(testObject); + QCOMPARE(testObject->customBindingsCount(), 0); + QCOMPARE(testObject->intProperty(), 42); + QCOMPARE(testObject->property("qmlString").toString(), QStringLiteral("Hello")); + QVERIFY(!testObject->property("someObject").isNull()); +} + void tst_qqmllanguage::preservePropertyCacheOnGroupObjects() { QQmlComponent component(&engine, testFile("preservePropertyCacheOnGroupObjects.qml")); @@ -3630,6 +3702,41 @@ void tst_qqmllanguage::propertyCacheInSync() QCOMPARE(anchors->property("margins").toInt(), 50); } +void tst_qqmllanguage::rootObjectInCreationNotForSubObjects() +{ + QQmlComponent component(&engine, testFile("rootObjectInCreationNotForSubObjects.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); + + // QQmlComponent should have set this back to false anyway + QQmlData *ddata = QQmlData::get(o.data()); + QVERIFY(!ddata->rootObjectInCreation); + + QObject *subObject = qvariant_cast<QObject*>(o->property("subObject")); + QVERIFY(!subObject); + + qmlExecuteDeferred(o.data()); + + subObject = qvariant_cast<QObject*>(o->property("subObject")); + QVERIFY(subObject); + + ddata = QQmlData::get(subObject); + // This should never have been set in the first place as there is no + // QQmlComponent to set it back to false. + QVERIFY(!ddata->rootObjectInCreation); +} + +void tst_qqmllanguage::noChildEvents() +{ + QQmlComponent component(&engine); + component.setData("import QtQml 2.0; import Test 1.0; MyQmlObject { property QtObject child: QtObject {} }", QUrl()); + VERIFY_ERRORS(0); + MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->childAddedEventCount(), 0); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index bdc0646b8e..9b57eeffa9 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -101,6 +101,8 @@ private slots: void static_types_data(); void static_i18n(); void static_i18n_data(); + void dynamic_i18n(); + void dynamic_i18n_data(); void static_nestedElements(); void static_nestedElements_data(); void dynamic_data(); @@ -296,17 +298,17 @@ void tst_qqmllistmodel::static_i18n_data() QTest::newRow("QT_TR_NOOP extra param") << QString::fromUtf8("ListElement { foo: QT_TR_NOOP(\"hello\",\"world\") }") << QVariant(QString()) - << QString("ListElement: improperly specified QT_TR_NOOP"); + << QString("ListElement: cannot use script for property value"); QTest::newRow("QT_TRANSLATE_NOOP missing params") << "ListElement { foo: QT_TRANSLATE_NOOP() }" << QVariant(QString()) - << QString("ListElement: improperly specified QT_TRANSLATE_NOOP"); + << QString("ListElement: cannot use script for property value"); QTest::newRow("QT_TRID_NOOP missing param") << QString::fromUtf8("ListElement { foo: QT_TRID_NOOP() }") << QVariant(QString()) - << QString("ListElement: improperly specified QT_TRID_NOOP"); + << QString("ListElement: cannot use script for property value"); } void tst_qqmllistmodel::static_i18n() @@ -341,6 +343,54 @@ void tst_qqmllistmodel::static_i18n() delete obj; } +void tst_qqmllistmodel::dynamic_i18n_data() +{ + QTest::addColumn<QString>("qml"); + QTest::addColumn<QVariant>("value"); + QTest::addColumn<QString>("error"); + + QTest::newRow("qsTr") + << QString::fromUtf8("ListElement { foo: qsTr(\"test\") }") + << QVariant(QString::fromUtf8("test")) + << QString("ListElement: cannot use script for property value"); + + QTest::newRow("qsTrId") + << "ListElement { foo: qsTrId(\"qtn_test\") }" + << QVariant(QString("qtn_test")) + << QString("ListElement: cannot use script for property value"); +} + +void tst_qqmllistmodel::dynamic_i18n() +{ + QFETCH(QString, qml); + QFETCH(QVariant, value); + QFETCH(QString, error); + + qml = "import QtQuick 2.0\nItem { property variant test: model.get(0).foo; ListModel { id: model; " + qml + " } }"; + + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(qml.toUtf8(), + QUrl::fromLocalFile(QString("dummy.qml"))); + + if (!error.isEmpty()) { + QVERIFY(component.isError()); + QCOMPARE(component.errors().at(0).description(), error); + return; + } + + QVERIFY(!component.isError()); + + QObject *obj = component.create(); + QVERIFY(obj != 0); + + QVariant actual = obj->property("test"); + + QCOMPARE(actual, value); + QCOMPARE(actual.toString(), value.toString()); + + delete obj; +} void tst_qqmllistmodel::static_nestedElements() { QFETCH(int, elementCount); @@ -528,6 +578,8 @@ void tst_qqmllistmodel::dynamic_data() QTest::newRow("nested-count") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]}); get(0).bars.count}" << 3 << "" << dr; QTest::newRow("nested-clear") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]}); get(0).bars.clear(); get(0).bars.count}" << 0 << "" << dr; } + + QTest::newRow("jsarray") << "{append({'foo':['1', '2', '3']});get(0).foo.get(0)}" << 0 << "" << false; } void tst_qqmllistmodel::dynamic() diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp index 0eb38d92e6..9653cac988 100644 --- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp +++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp @@ -932,7 +932,6 @@ void tst_qqmllocale::dateFromLocaleString_data() void tst_qqmllocale::dateFromLocaleString() { - QSKIP("Needs fixes in our date time parser"); QFETCH(QString, locale); QFETCH(QString, format); @@ -977,7 +976,6 @@ void tst_qqmllocale::dateFromLocaleDateString_data() void tst_qqmllocale::dateFromLocaleDateString() { - QSKIP("Needs fixes in our date time parser"); QFETCH(QString, locale); QFETCH(QString, format); @@ -1022,7 +1020,6 @@ void tst_qqmllocale::dateFromLocaleTimeString_data() void tst_qqmllocale::dateFromLocaleTimeString() { - QSKIP("Needs fixes in our date time parser"); QFETCH(QString, locale); QFETCH(QString, format); diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml b/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml index f44f4f926c..b35c31d513 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml +++ b/tests/auto/qml/qqmlxmlhttprequest/data/stateChangeCallingContext.qml @@ -8,7 +8,7 @@ Item { SequentialAnimation { id: anim - PauseAnimation { duration: 525 } // delay mode is 500 msec. + PauseAnimation { duration: 1000 } // delay mode is 500 msec. ScriptAction { script: loadcomponent(0) } PauseAnimation { duration: 525 } // delay mode is 500 msec. ScriptAction { script: loadcomponent(1) } diff --git a/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro b/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro index f1fbfde0ec..fcfdf23d33 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro +++ b/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro @@ -2,8 +2,6 @@ CONFIG += testcase TARGET = tst_qqmlxmlhttprequest macx:CONFIG -= app_bundle -CONFIG+=insignificant_test # QTQAINFRA-573 - INCLUDEPATH += ../../shared/ HEADERS += ../../shared/testhttpserver.h diff --git a/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test1.html b/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test1.html new file mode 100644 index 0000000000..4da4639310 --- /dev/null +++ b/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test1.html @@ -0,0 +1 @@ +<P>This file contains some HTML.</P> diff --git a/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test2.html b/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test2.html new file mode 100644 index 0000000000..4da4639310 --- /dev/null +++ b/tests/auto/qml/qquickfolderlistmodel/data/resetfiltering/test2.html @@ -0,0 +1 @@ +<P>This file contains some HTML.</P> diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp index a6e6345223..4296ae4f09 100644 --- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp +++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp @@ -73,6 +73,7 @@ private slots: void basicProperties(); void showFiles(); void resetFiltering(); + void nameFilters(); void refresh(); void cdUp(); #ifdef Q_OS_WIN32 @@ -169,26 +170,50 @@ void tst_qquickfolderlistmodel::resetFiltering() QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create()); QVERIFY(flm != 0); + flm->setProperty("folder", testFileUrl("resetfiltering")); + // _q_directoryUpdated may be triggered if model was empty before, but there won't be a rowsRemoved signal + QTRY_COMPARE(flm->property("count").toInt(),3); // all files visible + + flm->setProperty("folder", testFileUrl("resetfiltering/innerdir")); + // _q_directoryChanged is triggered so it's a total model refresh + QTRY_COMPARE(flm->property("count").toInt(),1); // should just be "test2.txt" visible + + flm->setProperty("folder", testFileUrl("resetfiltering")); + // _q_directoryChanged is triggered so it's a total model refresh + QTRY_COMPARE(flm->property("count").toInt(),3); // all files visible +} + +void tst_qquickfolderlistmodel::nameFilters() +{ + // see QTBUG-36576 + QQmlComponent component(&engine, testFileUrl("resetFiltering.qml")); + checkNoErrors(component); + + QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create()); + QVERIFY(flm != 0); + connect(flm, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(removed(QModelIndex,int,int))); + QTRY_VERIFY(flm->rowCount() > 0); flm->setProperty("folder", testFileUrl("resetfiltering")); - QTRY_COMPARE(flm->property("count").toInt(),1); // should just be "test.txt" visible + QTRY_COMPARE(flm->property("count").toInt(),3); // all files visible + int count = flm->rowCount(); + flm->setProperty("nameFilters", QStringList() << "*.txt"); + // _q_directoryUpdated triggered with range 0:1 + QTRY_COMPARE(flm->property("count").toInt(),1); + QCOMPARE(flm->data(flm->index(0),FileNameRole), QVariant("test.txt")); QCOMPARE(removeStart, 0); QCOMPARE(removeEnd, count-1); - flm->setProperty("folder", testFileUrl("resetfiltering/innerdir")); - QTRY_COMPARE(flm->property("count").toInt(),1); // should just be "test2.txt" visible - count = flm->rowCount(); - QCOMPARE(removeStart, 0); - QCOMPARE(removeEnd, count-1); + flm->setProperty("nameFilters", QStringList() << "*.html"); + QTRY_COMPARE(flm->property("count").toInt(),2); + QCOMPARE(flm->data(flm->index(0),FileNameRole), QVariant("test1.html")); + QCOMPARE(flm->data(flm->index(1),FileNameRole), QVariant("test2.html")); - flm->setProperty("folder", testFileUrl("resetfiltering")); - QTRY_COMPARE(flm->property("count").toInt(),1); // should just be "test.txt" visible - count = flm->rowCount(); - QCOMPARE(removeStart, 0); - QCOMPARE(removeEnd, count-1); + flm->setProperty("nameFilters", QStringList()); + QTRY_COMPARE(flm->property("count").toInt(),3); // all files visible } void tst_qquickfolderlistmodel::refresh() diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp index 15a6acc272..b7e5cf48e0 100644 --- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp @@ -48,6 +48,9 @@ using namespace QV4; using namespace QV4::Debugging; +typedef QV4::ReturnedValue (*InjectedFunction)(QV4::CallContext*); +Q_DECLARE_METATYPE(InjectedFunction) + static bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000) { QEventLoop loop; @@ -80,9 +83,7 @@ public: QV4::ExecutionEngine *v4Engine() { return QV8Engine::getV4(this); } - typedef QV4::ReturnedValue (*InjectedFunction)(QV4::CallContext*); - - Q_INVOKABLE void injectFunction(const QString &functionName, TestEngine::InjectedFunction injectedFunction) + Q_INVOKABLE void injectFunction(const QString &functionName, InjectedFunction injectedFunction) { QV4::ExecutionEngine *v4 = v4Engine(); QV4::Scope scope(v4); @@ -96,7 +97,6 @@ signals: void evaluateFinished(); }; -Q_DECLARE_METATYPE(TestEngine::InjectedFunction) namespace { class TestCollector: public QV4::Debugging::Debugger::Collector @@ -404,7 +404,7 @@ void tst_qv4debugger::removeBreakPointForNextInstruction() "var i = 42;"; QMetaObject::invokeMethod(m_engine, "injectFunction", Qt::BlockingQueuedConnection, - Q_ARG(QString, "someCall"), Q_ARG(TestEngine::InjectedFunction, someCall)); + Q_ARG(QString, "someCall"), Q_ARG(InjectedFunction, someCall)); m_debuggerAgent->addBreakPoint("removeBreakPointForNextInstruction", 2); |