diff options
Diffstat (limited to 'tests/auto')
48 files changed, 1248 insertions, 315 deletions
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index 4d4d8e3db7..f304a99705 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -25,4 +25,5 @@ add_test(qtquickcompiler ${CMAKE_CTEST_COMMAND} --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-project qqc_test --build-options "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" ${BUILD_OPTIONS_LIST} + --test-command qqc_test ) diff --git a/tests/auto/cmake/qtquickcompiler/CMakeLists.txt b/tests/auto/cmake/qtquickcompiler/CMakeLists.txt index 6dee1e25dc..4e46544767 100644 --- a/tests/auto/cmake/qtquickcompiler/CMakeLists.txt +++ b/tests/auto/cmake/qtquickcompiler/CMakeLists.txt @@ -4,11 +4,14 @@ project(qqc_test) find_package(Qt5Qml 5.0.0 REQUIRED) find_package(Qt5Gui 5.0.0 REQUIRED) +find_package(Qt5Test 5.0.0 REQUIRED) find_package(Qt5QuickCompiler) set(CMAKE_CXXFLAGS "${CMAKE_CXXFLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") -qtquick_compiler_add_resources(RESOURCES qqc_test.qrc) +qtquick_compiler_add_resources(RESOURCES "resources with space/qqc_test.qrc") + +set(CMAKE_AUTOMOC ON) add_executable(qqc_test "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" ${RESOURCES}) -target_link_libraries(qqc_test Qt5::Gui Qt5::Qml) +target_link_libraries(qqc_test Qt5::Gui Qt5::Qml Qt5::Test) diff --git a/tests/auto/cmake/qtquickcompiler/main.cpp b/tests/auto/cmake/qtquickcompiler/main.cpp index 47fc709c0a..c357ef60e6 100644 --- a/tests/auto/cmake/qtquickcompiler/main.cpp +++ b/tests/auto/cmake/qtquickcompiler/main.cpp @@ -1,9 +1,30 @@ -#include <QtGui> +#include <QtCore> #include <QtQml> +#include <QtTest> -int main(int argc, char **argv) +class tst_QQC : public QObject { - QGuiApplication app(argc, argv); - return app.exec(); + Q_OBJECT +private slots: + void packaging(); +}; + +void tst_QQC::packaging() +{ + QVERIFY(QFile::exists(":/main.qml")); + QCOMPARE(QFileInfo(":/main.qml").size(), 0); + QVERIFY(QFile::exists(":/main.cpp")); + QVERIFY(QFileInfo(":/main.cpp").size() > 0); + + + QQmlEngine engine; + QQmlComponent component(&engine, QUrl("qrc:/main.qml")); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("success").toInt(), 42); } + +QTEST_MAIN(tst_QQC) + +#include "main.moc" diff --git a/tests/auto/cmake/qtquickcompiler/main.qml b/tests/auto/cmake/qtquickcompiler/resources with space/main.qml index 1f146d89c3..0836808dc2 100644 --- a/tests/auto/cmake/qtquickcompiler/main.qml +++ b/tests/auto/cmake/qtquickcompiler/resources with space/main.qml @@ -1,4 +1,4 @@ import QtQml 2.0 QtObject { - property bool success: 42 + property int success: 42 } diff --git a/tests/auto/cmake/qtquickcompiler/qqc_test.qrc b/tests/auto/cmake/qtquickcompiler/resources with space/qqc_test.qrc index f128b7004b..63d8d1f37e 100644 --- a/tests/auto/cmake/qtquickcompiler/qqc_test.qrc +++ b/tests/auto/cmake/qtquickcompiler/resources with space/qqc_test.qrc @@ -1,6 +1,6 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>./main.qml</file> -<file>./main.cpp</file> +<file alias="main.cpp">../main.cpp</file> </qresource> </RCC> diff --git a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp index a76740a3f9..52e7f85e52 100644 --- a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp +++ b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp @@ -126,8 +126,10 @@ void tst_QQmlDebuggingEnabler::qmlscene() } QCOMPARE(m_process->state(), QLatin1String("running")); - if (!blockMode) - QTRY_VERIFY(m_process->output().contains(QLatin1String("qml: Component.onCompleted"))); + if (!blockMode) { + QTRY_VERIFY_WITH_TIMEOUT(m_process->output().contains( + QLatin1String("Component.onCompleted")), 15000); + } } void tst_QQmlDebuggingEnabler::custom_data() @@ -171,8 +173,10 @@ void tst_QQmlDebuggingEnabler::custom() } QCOMPARE(m_process->state(), QLatin1String("running")); - if (!blockMode) - QTRY_VERIFY(m_process->output().contains(QLatin1String("QQmlEngine created"))); + if (!blockMode) { + QTRY_VERIFY_WITH_TIMEOUT(m_process->output().contains(QLatin1String("QQmlEngine created")), + 15000); + } } QTEST_MAIN(tst_QQmlDebuggingEnabler) diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp index d01d9a6791..89217e7556 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp @@ -141,6 +141,7 @@ private slots: void queryObjectWithNonStreamableTypes(); void asynchronousCreate(); void invalidContexts(); + void createObjectOnDestruction(); }; QmlDebugObjectReference tst_QQmlEngineDebugService::findRootObject( @@ -1345,6 +1346,29 @@ void tst_QQmlEngineDebugService::invalidContexts() QCOMPARE(m_dbg->rootContext().contexts.count(), 0); } +void tst_QQmlEngineDebugService::createObjectOnDestruction() +{ + QSignalSpy spy(m_dbg, SIGNAL(newObject(int))); + { + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData( + "import QtQml 2.0;" + "QtObject {" + "property Component x:" + "Qt.createQmlObject('import QtQml 2.0; Component { QtObject { } }'," + "this, 'x.qml');" + "Component.onDestruction: x.createObject(this, {});" + "}", QUrl::fromLocalFile("x.qml")); + QVERIFY(component.isReady()); + QVERIFY(component.create()); + QTRY_COMPARE(spy.count(), 2); + } + // Doesn't crash and doesn't give us another signal for the object created on destruction. + QTest::qWait(500); + QCOMPARE(spy.count(), 2); +} + int main(int argc, char *argv[]) { int _argc = argc + 1; diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index cd8e4216f3..562804bc45 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -221,6 +221,7 @@ private slots: void flushInterval(); void translationBinding(); void memory(); + void compile(); private: bool m_recordFromStart = true; @@ -525,6 +526,8 @@ void tst_QQmlProfilerService::connect() if (!traceEnabled) m_client->client->setRecording(true); + + QTRY_VERIFY(m_client->numLoadedEventTypes() > 0); m_client->client->setRecording(false); checkTraceReceived(); checkJsHeap(); @@ -643,6 +646,7 @@ void tst_QQmlProfilerService::controlFromJS() { QCOMPARE(connect(true, "controlFromJS.qml", false), ConnectSuccess); + QTRY_VERIFY(m_client->numLoadedEventTypes() > 0); m_client->client->setRecording(false); checkTraceReceived(); checkJsHeap(); @@ -749,6 +753,54 @@ void tst_QQmlProfilerService::memory() QVERIFY(smallItems > 5); } +static bool hasCompileEvents(const QVector<QQmlProfilerEventType> &types) +{ + for (const QQmlProfilerEventType &type : types) { + if (type.message() == QQmlProfilerDefinitions::MaximumMessage + && type.rangeType() == QQmlProfilerDefinitions::Compiling) + return true; + } + return false; +} + +void tst_QQmlProfilerService::compile() +{ + // Flush interval so that we actually get the events before we stop recording. + connect(true, "test.qml", true, 100); + + // We need to check specifically for compile events as we can otherwise stop recording after the + // StartTrace has arrived, but before it compiles anything. + QTRY_VERIFY(hasCompileEvents(m_client->types)); + m_client->client->setRecording(false); + + checkTraceReceived(); + checkJsHeap(); + + QQmlProfilerDefinitions::Message rangeStage = QQmlProfilerDefinitions::MaximumMessage; + for (auto message : m_client->qmlMessages) { + const QQmlProfilerEventType &type = m_client->types[message.typeIndex()]; + if (type.rangeType() == QQmlProfilerDefinitions::Compiling) { + switch (rangeStage) { + case QQmlProfilerDefinitions::MaximumMessage: + QCOMPARE(message.rangeStage(), QQmlProfilerDefinitions::RangeStart); + break; + case QQmlProfilerDefinitions::RangeStart: + QCOMPARE(message.rangeStage(), QQmlProfilerDefinitions::RangeEnd); + break; + default: + QFAIL("Wrong range stage"); + } + rangeStage = message.rangeStage(); + QCOMPARE(type.message(), QQmlProfilerDefinitions::MaximumMessage); + QCOMPARE(type.location().filename(), testFileUrl("test.qml").toString()); + QCOMPARE(type.location().line(), 0); + QCOMPARE(type.location().column(), 0); + } + } + + QCOMPARE(rangeStage, QQmlProfilerDefinitions::RangeEnd); +} + QTEST_MAIN(tst_QQmlProfilerService) #include "tst_qqmlprofilerservice.moc" diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index 5dd62da15a..4ce0f9fd89 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -316,6 +316,8 @@ private slots: void lastLineOfConditional_data(); void lastLineOfConditional(); + + void readThis(); private: QV4Debugger *debugger() const { @@ -865,6 +867,36 @@ void tst_qv4debugger::lastLineOfConditional() QCOMPARE(secondState.lineNumber, lastLine); } +void tst_qv4debugger::readThis() +{ + m_debuggerAgent->m_captureContextInfo = true; + QString script = + "var x = function() {\n" + " return this.a;\n" + "}.apply({a : 5}, []);\n"; + + TestAgent::ExpressionRequest request; + request.expression = "this"; + request.frameNr = 0; + request.context = -1; // no extra context + m_debuggerAgent->m_expressionRequests << request; + + debugger()->addBreakPoint("applyThis", 2); + evaluateJavaScript(script, "applyThis"); + QVERIFY(m_debuggerAgent->m_wasPaused); + + QCOMPARE(m_debuggerAgent->m_expressionResults.count(), 1); + QJsonObject result0 = m_debuggerAgent->m_expressionResults[0]; + QCOMPARE(result0.value("type").toString(), QStringLiteral("object")); + QCOMPARE(result0.value("value").toInt(), 1); + QJsonArray properties = result0.value("properties").toArray(); + QCOMPARE(properties.size(), 1); + QJsonObject a = properties.first().toObject(); + QCOMPARE(a.value("name").toString(), QStringLiteral("a")); + QCOMPARE(a.value("type").toString(), QStringLiteral("number")); + QCOMPARE(a.value("value").toInt(), 5); +} + void tst_qv4debugger::redundancy_data() { QTest::addColumn<bool>("redundantRefs"); diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262 -Subproject d60c4ed97e69639bc5bc1db43a98828debf80c8 +Subproject 40b4f28e98c416a092e26aa17489bf94ccb8bf4 diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 8f3011001b..f862cdb048 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -128,6 +128,8 @@ private slots: void JSONparse(); void arraySort(); void lookupOnDisappearingProperty(); + void arrayConcat(); + void recursiveBoundFunctions(); void qRegExpInport_data(); void qRegExpInport(); @@ -2995,7 +2997,7 @@ void tst_QJSEngine::arraySort() void tst_QJSEngine::lookupOnDisappearingProperty() { QJSEngine eng; - QJSValue func = eng.evaluate("(function(){\"use strict\"; return eval(\"function(obj) { return obj.someProperty; }\")})()"); + QJSValue func = eng.evaluate("(function(){\"use strict\"; return eval(\"(function(obj) { return obj.someProperty; })\")})()"); QVERIFY(func.isCallable()); QJSValue o = eng.newObject(); @@ -3008,6 +3010,31 @@ void tst_QJSEngine::lookupOnDisappearingProperty() QVERIFY(func.call(QJSValueList()<< o).isUndefined()); } +void tst_QJSEngine::arrayConcat() +{ + QJSEngine eng; + QJSValue v = eng.evaluate("var x = [1, 2, 3, 4, 5, 6];" + "var y = [];" + "for (var i = 0; i < 5; ++i)" + " x.shift();" + "for (var i = 10; i < 13; ++i)" + " x.push(i);" + "x.toString();"); + QCOMPARE(v.toString(), QString::fromLatin1("6,10,11,12")); +} + +void tst_QJSEngine::recursiveBoundFunctions() +{ + + QJSEngine eng; + QJSValue v = eng.evaluate("function foo(x, y, z)" + "{ return this + x + y + z; }" + "var bar = foo.bind(-1, 10);" + "var baz = bar.bind(-2, 20);" + "baz(30)"); + QCOMPARE(v.toInt(), 59); +} + static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; } void tst_QJSEngine::qRegExpInport_data() @@ -3327,7 +3354,7 @@ void tst_QJSEngine::prototypeChainGc() QJSValue getProto = engine.evaluate("Object.getPrototypeOf"); - QJSValue factory = engine.evaluate("function() { return Object.create(Object.create({})); }"); + QJSValue factory = engine.evaluate("(function() { return Object.create(Object.create({})); })"); QVERIFY(factory.isCallable()); QJSValue obj = factory.call(); engine.collectGarbage(); diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index 9557393a2e..3433b56864 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -69,6 +69,7 @@ PRIVATETESTS += \ qqmltranslation \ qqmlimport \ qqmlobjectmodel \ + qv4assembler \ qv4mm \ ecmascripttests \ bindingdependencyapi diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro index a8b72224ba..a2f963e8c3 100644 --- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro +++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro @@ -8,4 +8,8 @@ workerscripts_test.files = worker.js worker.qml workerscripts_test.prefix = /workerscripts RESOURCES += workerscripts_test +RESOURCES += versionchecks.qml + +RESOURCES += trickypaths.qrc + QT += core-private qml-private testlib diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qml b/tests/auto/qml/qmlcachegen/trickypaths.qml new file mode 100644 index 0000000000..0836808dc2 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/trickypaths.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property int success: 42 +} diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qrc b/tests/auto/qml/qmlcachegen/trickypaths.qrc new file mode 100644 index 0000000000..271cf6571e --- /dev/null +++ b/tests/auto/qml/qmlcachegen/trickypaths.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/directory with spaces"> +<file alias="file name with spaces.qml">trickypaths.qml</file> +</qresource> +</RCC> diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index 2f5ff0022e..5c1692f086 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -33,6 +33,7 @@ #include <QProcess> #include <QLibraryInfo> #include <QSysInfo> +#include <QLoggingCategory> #include <private/qqmlcomponent_p.h> class tst_qmlcachegen: public QObject @@ -47,8 +48,12 @@ private slots: void signalHandlerParameters(); void errorOnArgumentsInSignalHandler(); void aheadOfTimeCompilation(); + void functionExpressions(); + void versionChecksForAheadOfTimeUnits(); void workerScripts(); + + void trickyPaths(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -279,6 +284,50 @@ void tst_qmlcachegen::aheadOfTimeCompilation() QCOMPARE(result.toInt(), 42); } +static QQmlPrivate::CachedQmlUnit *temporaryModifiedCachedUnit = nullptr; + +void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() +{ + QVERIFY(QFile::exists(":/versionchecks.qml")); + QCOMPARE(QFileInfo(":/versionchecks.qml").size(), 0); + + Q_ASSERT(!temporaryModifiedCachedUnit); + QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; + const QV4::CompiledData::Unit *originalUnit = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error); + QVERIFY(originalUnit); + QV4::CompiledData::Unit *tweakedUnit = (QV4::CompiledData::Unit *)malloc(originalUnit->unitSize); + memcpy(reinterpret_cast<void *>(tweakedUnit), reinterpret_cast<const void *>(originalUnit), originalUnit->unitSize); + tweakedUnit->version = QV4_DATA_STRUCTURE_VERSION - 1; + temporaryModifiedCachedUnit = new QQmlPrivate::CachedQmlUnit{tweakedUnit, nullptr, nullptr}; + + auto testHandler = [](const QUrl &url) -> const QQmlPrivate::CachedQmlUnit * { + if (url == QUrl("qrc:/versionchecks.qml")) + return temporaryModifiedCachedUnit; + return nullptr; + }; + QQmlMetaType::prependCachedUnitLookupFunction(testHandler); + + { + QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; + QVERIFY(!QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error)); + QCOMPARE(error, QQmlMetaType::CachedUnitLookupError::VersionMismatch); + } + + { + QQmlEngine engine; + QQmlComponent component(&engine, QUrl("qrc:/versionchecks.qml")); + QCOMPARE(component.status(), QQmlComponent::Error); + QCOMPARE(component.errorString(), QString("qrc:/versionchecks.qml:-1 File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile\n")); + } + + Q_ASSERT(temporaryModifiedCachedUnit); + free(const_cast<QV4::CompiledData::Unit *>(temporaryModifiedCachedUnit->qmlData)); + delete temporaryModifiedCachedUnit; + temporaryModifiedCachedUnit = nullptr; + + QQmlMetaType::removeCachedUnitLookupFunction(testHandler); +} + void tst_qmlcachegen::workerScripts() { QVERIFY(QFile::exists(":/workerscripts/worker.js")); @@ -292,6 +341,81 @@ void tst_qmlcachegen::workerScripts() QTRY_VERIFY(obj->property("success").toBool()); } +void tst_qmlcachegen::functionExpressions() +{ + QTemporaryDir tempDir; + QVERIFY(tempDir.isValid()); + + const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) { + QFile f(tempDir.path() + '/' + fileName); + const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); + Q_ASSERT(ok); + f.write(contents); + return f.fileName(); + }; + + const QString testFilePath = writeTempFile( + "test.qml", + "import QtQuick 2.0\n" + "Item {\n" + " id: di\n" + " \n" + " property var f\n" + " property bool f_called: false\n" + " f : function() { f_called = true }\n" + " \n" + " signal g\n" + " property bool g_handler_called: false\n" + " onG: function() { g_handler_called = true }\n" + " \n" + " signal h(int i)\n" + " property bool h_connections_handler_called: false\n" + " Connections {\n" + " target: di\n" + " onH: function(magic) { h_connections_handler_called = (magic == 42)\n }\n" + " }\n" + " \n" + " function runTest() { \n" + " f()\n" + " g()\n" + " h(42)\n" + " }\n" + "}"); + + QVERIFY(generateCache(testFilePath)); + + const QString cacheFilePath = testFilePath + QLatin1Char('c'); + QVERIFY(QFile::exists(cacheFilePath)); + QVERIFY(QFile::remove(testFilePath)); + + QQmlEngine engine; + CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath)); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + + QCOMPARE(obj->property("f_called").toBool(), false); + QCOMPARE(obj->property("g_handler_called").toBool(), false); + QCOMPARE(obj->property("h_connections_handler_called").toBool(), false); + + QMetaObject::invokeMethod(obj.data(), "runTest"); + + QCOMPARE(obj->property("f_called").toBool(), true); + QCOMPARE(obj->property("g_handler_called").toBool(), true); + QCOMPARE(obj->property("h_connections_handler_called").toBool(), true); +} + +void tst_qmlcachegen::trickyPaths() +{ + QString pathWithSpaces(QStringLiteral(":/directory with spaces/file name with spaces.qml")); + QVERIFY2(QFile::exists(pathWithSpaces), qPrintable(pathWithSpaces)); + QCOMPARE(QFileInfo(pathWithSpaces).size(), 0); + QQmlEngine engine; + QQmlComponent component(&engine, QUrl("qrc" + pathWithSpaces)); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("success").toInt(), 42); +} + QTEST_GUILESS_MAIN(tst_qmlcachegen) #include "tst_qmlcachegen.moc" diff --git a/tests/auto/qml/qmlcachegen/versionchecks.qml b/tests/auto/qml/qmlcachegen/versionchecks.qml new file mode 100644 index 0000000000..77d67e7da4 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/versionchecks.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property bool ok: true +} diff --git a/tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml b/tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml new file mode 100644 index 0000000000..8dbd2fd3d9 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/bindingBoundFunctions.qml @@ -0,0 +1,34 @@ +import QtQuick 2.6 + +QtObject { + property bool success: false + property var num: 100 + property var simple: 0 + property var complex: 0 + + + Component.onCompleted: { + function s(x) { + return x + } + function c(x) { + return x + num + } + + var bound = s.bind(undefined, 100) + simple = Qt.binding(bound) + if (simple != 100) + return; + var bound = c.bind(undefined, 100) + complex = Qt.binding(bound); + + if (complex != 200) + return; + num = 0; + if (complex != 100) + return; + + print("success!!!"); + success = true; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/include_callback.js b/tests/auto/qml/qqmlecmascript/data/include_callback.js index ea19eba300..7f3195bb1f 100644 --- a/tests/auto/qml/qqmlecmascript/data/include_callback.js +++ b/tests/auto/qml/qqmlecmascript/data/include_callback.js @@ -1,6 +1,6 @@ function go() { var a = Qt.include("missing.js", function(o) { test2 = o.status == o.NETWORK_ERROR }); - test1 = a.status == a.NETWORK_ERROR + test1 = (a.status == a.NETWORK_ERROR) && (a.statusText.indexOf("Error opening source file") != -1); var b = Qt.include("blank.js", function(o) { test4 = o.status == o.OK }); test3 = b.status == b.OK diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml index 5103168fd3..99c49ebf62 100644 --- a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml +++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml @@ -10,6 +10,11 @@ Item { objectName: "msco" } + Component { + id: mscoComponent + MySequenceConversionObject { } + } + property bool success: false property variant intList @@ -252,4 +257,13 @@ Item { if (testSequence.valueOf() == prevValueOf) referenceDeletion = false; if (testSequence.length == prevLength) referenceDeletion = false; } + + function jsonConversion() { + success = true + var msco = mscoComponent.createObject() + if (JSON.stringify(msco.intListProperty) != "[1,2,3,4]") success = false; + if (JSON.stringify(msco.qrealListProperty) != "[1.1,2.2,3.3,4.4]") success = false; + if (JSON.stringify(msco.boolListProperty) != "[true,false,true,false]") success = false; + if (JSON.stringify(msco.stringListProperty) != "[\"first\",\"second\",\"third\",\"fourth\"]") success = false; + } } diff --git a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml index cd68fb9b82..14326bb9e6 100644 --- a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml +++ b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml @@ -102,4 +102,17 @@ QtObject { }) return testSuccess } + + property QtObject subObject: QtObject { + id: subObject + property int value + property bool ok: false + onValueChanged: this.ok = true + } + + function testThisInSignalHandler() { + subObject.ok = false + subObject.value = subObject.value + 1 + return subObject.ok + } } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 5ff959515e..f40a9758f7 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -289,6 +289,7 @@ private slots: void withStatement(); void tryStatement(); void replaceBinding(); + void bindingBoundFunctions(); void deleteRootObjectInCreation(); void onDestruction(); void onDestructionViaGC(); @@ -351,6 +352,7 @@ private slots: void shadowedFunctionName(); void anotherNaN(); void callPropertyOnUndefined(); + void jumpStrictNotEqualUndefined(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -5561,17 +5563,18 @@ void tst_qqmlecmascript::sequenceConversionArray() // ensure that in JS the returned sequences act just like normal JS Arrays. QUrl qmlFile = testFileUrl("sequenceConversion.array.qml"); QQmlComponent component(&engine, qmlFile); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QMetaObject::invokeMethod(object, "indexedAccess"); + QMetaObject::invokeMethod(object.data(), "indexedAccess"); QVERIFY(object->property("success").toBool()); - QMetaObject::invokeMethod(object, "arrayOperations"); + QMetaObject::invokeMethod(object.data(), "arrayOperations"); QVERIFY(object->property("success").toBool()); - QMetaObject::invokeMethod(object, "testEqualitySemantics"); + QMetaObject::invokeMethod(object.data(), "testEqualitySemantics"); QVERIFY(object->property("success").toBool()); - QMetaObject::invokeMethod(object, "testReferenceDeletion"); + QMetaObject::invokeMethod(object.data(), "testReferenceDeletion"); QCOMPARE(object->property("referenceDeletion").toBool(), true); - delete object; + QMetaObject::invokeMethod(object.data(), "jsonConversion"); + QVERIFY(object->property("success").toBool()); } @@ -6278,41 +6281,40 @@ void tst_qqmlecmascript::includeRemoteSuccess() void tst_qqmlecmascript::signalHandlers() { QQmlComponent component(&engine, testFileUrl("signalHandlers.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - QCOMPARE(o->property("count").toInt(), 0); - QMetaObject::invokeMethod(o, "testSignalCall"); + QMetaObject::invokeMethod(o.data(), "testSignalCall"); QCOMPARE(o->property("count").toInt(), 1); - QMetaObject::invokeMethod(o, "testSignalHandlerCall"); + QMetaObject::invokeMethod(o.data(), "testSignalHandlerCall"); QCOMPARE(o->property("count").toInt(), 1); QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function")); QCOMPARE(o->property("funcCount").toInt(), 0); - QMetaObject::invokeMethod(o, "testSignalConnection"); + QMetaObject::invokeMethod(o.data(), "testSignalConnection"); QCOMPARE(o->property("funcCount").toInt(), 1); - QMetaObject::invokeMethod(o, "testSignalHandlerConnection"); + QMetaObject::invokeMethod(o.data(), "testSignalHandlerConnection"); QCOMPARE(o->property("funcCount").toInt(), 2); - QMetaObject::invokeMethod(o, "testSignalDefined"); + QMetaObject::invokeMethod(o.data(), "testSignalDefined"); QCOMPARE(o->property("definedResult").toBool(), true); - QMetaObject::invokeMethod(o, "testSignalHandlerDefined"); + QMetaObject::invokeMethod(o.data(), "testSignalHandlerDefined"); QCOMPARE(o->property("definedHandlerResult").toBool(), true); QVariant result; - QMetaObject::invokeMethod(o, "testConnectionOnAlias", Q_RETURN_ARG(QVariant, result)); + QMetaObject::invokeMethod(o.data(), "testConnectionOnAlias", Q_RETURN_ARG(QVariant, result)); QCOMPARE(result.toBool(), true); - QMetaObject::invokeMethod(o, "testAliasSignalHandler", Q_RETURN_ARG(QVariant, result)); + QMetaObject::invokeMethod(o.data(), "testAliasSignalHandler", Q_RETURN_ARG(QVariant, result)); QCOMPARE(result.toBool(), true); - QMetaObject::invokeMethod(o, "testSignalWithClosureArgument", Q_RETURN_ARG(QVariant, result)); + QMetaObject::invokeMethod(o.data(), "testSignalWithClosureArgument", Q_RETURN_ARG(QVariant, result)); + QCOMPARE(result.toBool(), true); + QMetaObject::invokeMethod(o.data(), "testThisInSignalHandler", Q_RETURN_ARG(QVariant, result)); QCOMPARE(result.toBool(), true); - - delete o; } void tst_qqmlecmascript::qtbug_37351() @@ -7246,6 +7248,17 @@ void tst_qqmlecmascript::replaceBinding() delete obj; } +void tst_qqmlecmascript::bindingBoundFunctions() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("bindingBoundFunctions.qml")); + QObject *obj = c.create(); + QVERIFY(obj != nullptr); + + QVERIFY(obj->property("success").toBool()); + delete obj; +} + void tst_qqmlecmascript::deleteRootObjectInCreation() { { @@ -8480,6 +8493,26 @@ void tst_qqmlecmascript::callPropertyOnUndefined() QVERIFY(!v.isError()); // well, more importantly: this shouldn't fail on an assert. } +void tst_qqmlecmascript::jumpStrictNotEqualUndefined() +{ + QJSEngine engine; + QJSValue v = engine.evaluate(QString::fromLatin1( + "var ok = 0\n" + "var foo = 0\n" + "if (foo !== void 1)\n" + " ++ok;\n" + "else\n" + " --ok;\n" + "if (foo === void 1)\n" + " --ok;\n" + "else\n" + " ++ok;\n" + "ok\n" + )); + QVERIFY(!v.isError()); + QCOMPARE(v.toInt(), 2); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp index e1ad1e8c5f..1decc04ad2 100644 --- a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp +++ b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp @@ -101,8 +101,12 @@ void tst_qqmlexpression::syntaxError() { QQmlEngine engine; QQmlExpression expression(engine.rootContext(), nullptr, "asd asd"); - QVariant v = expression.evaluate(); + bool isUndefined = false; + QVariant v = expression.evaluate(&isUndefined); QCOMPARE(v, QVariant()); + QVERIFY(expression.hasError()); + QCOMPARE(expression.error().description(), "SyntaxError: Expected token `;'"); + QVERIFY(isUndefined); } void tst_qqmlexpression::exception() diff --git a/tests/auto/qml/qqmllanguage/data/alias.16.qml b/tests/auto/qml/qqmllanguage/data/alias.16.qml new file mode 100644 index 0000000000..4637aec58f --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.16.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 + +Window { + visible: true + + property alias list: repeater.model + + list: ["A", "B", "C"] + + Repeater { + id: repeater + } +} + diff --git a/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml b/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml index fce248a381..69b0096a5e 100644 --- a/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml +++ b/tests/auto/qml/qqmllanguage/data/assignLiteralToJSValue.qml @@ -30,6 +30,7 @@ QtObject { MyQmlObject { id: testObj22; objectName: "test22"; qjsvalue: null }, MyQmlObject { id: testObj1Bound; objectName: "test1Bound"; qjsvalue: testObj1.qjsvalue + 4 }, // 1 + 4 + 4 = 9 MyQmlObject { id: testObj20Bound; objectName: "test20Bound"; qjsvalue: testObj20.qjsvalue(testObj1Bound.qjsvalue) }, // 9 * 3 = 27 + MyQmlObject { id: testObj23; objectName: "test23"; qjsvalue: QtObject { objectName: "blah" } }, QtObject { id: varProperties objectName: "varProperties" diff --git a/tests/auto/qml/qqmllanguage/data/empty.errors.txt b/tests/auto/qml/qqmllanguage/data/empty.errors.txt index 620db2bbba..ba685d78ae 100644 --- a/tests/auto/qml/qqmllanguage/data/empty.errors.txt +++ b/tests/auto/qml/qqmllanguage/data/empty.errors.txt @@ -1,2 +1 @@ -1:1:Expected token `numeric literal' -1:1:Expected a qualified name id +-1:-1:File is empty diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml index 7763c783f1..2913ceca08 100644 --- a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml +++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml @@ -2,4 +2,7 @@ import QtQuick 2.0 pragma Singleton Item { + enum EnumInSingleton { + EnumValue = 42 + } } diff --git a/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml new file mode 100644 index 0000000000..ff2f0f5a2c --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml @@ -0,0 +1,9 @@ +import QtQml 2.0 + +QtObject { + property int secondVar: { + stats.increaseEvaluationCounter() + return 1 + } + property int firstVar: secondVar + 1 +} diff --git a/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml new file mode 100644 index 0000000000..0eb5e03642 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml @@ -0,0 +1,9 @@ +import QtQml 2.0 + +QtObject { + property int firstVar: secondVar + 1 + property int secondVar: { + stats.increaseEvaluationCounter() + return 1 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml b/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml index 2509fc0df1..43e54bbf1d 100644 --- a/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml +++ b/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml @@ -1,8 +1,10 @@ import QtQuick 2.0 +import org.qtproject.MixedModule 1.0 QtObject { property int enumValue: TypeWithEnum.EnumValue2 property int enumValue2: -1 property int scopedEnumValue: TypeWithEnum.MyEnum.EnumValue3 + property int enumValueFromSingleton: { var x = SingletonType.EnumValue; return x; } Component.onCompleted: enumValue2 = TypeWithEnum.EnumValue1 } diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 5bb2b69565..8913528d79 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -125,6 +125,8 @@ private slots: void dynamicObjectProperties(); void dynamicSignalsAndSlots(); void simpleBindings(); + void noDoubleEvaluationForFlushedBindings_data(); + void noDoubleEvaluationForFlushedBindings(); void autoComponentCreation(); void autoComponentCreationInGroupProperty(); void propertyValueSource(); @@ -372,9 +374,11 @@ void tst_qqmllanguage::insertedSemicolon() QQmlComponent component(&engine, testFileUrl(file)); + QScopedPointer<QObject> object; + if(create) { - QObject *object = component.create(); - QVERIFY(!object); + object.reset(component.create()); + QVERIFY(object.isNull()); } VERIFY_ERRORS(errorFile.toLatin1().constData()); @@ -606,9 +610,11 @@ void tst_qqmllanguage::errors() QQmlComponent component(&engine, testFileUrl(file)); + QScopedPointer<QObject> object; + if (create) { - QObject *object = component.create(); - QVERIFY(!object); + object.reset(component.create()); + QVERIFY(object.isNull()); } VERIFY_ERRORS(errorFile.toLatin1().constData()); @@ -618,7 +624,7 @@ void tst_qqmllanguage::simpleObject() { QQmlComponent component(&engine, testFileUrl("simpleObject.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -626,7 +632,7 @@ void tst_qqmllanguage::simpleContainer() { QQmlComponent component(&engine, testFileUrl("simpleContainer.qml")); VERIFY_ERRORS(0); - MyContainer *container= qobject_cast<MyContainer*>(component.create()); + QScopedPointer<MyContainer> container(qobject_cast<MyContainer*>(component.create())); QVERIFY(container != nullptr); QCOMPARE(container->getChildren()->count(),2); } @@ -635,7 +641,7 @@ void tst_qqmllanguage::interfaceProperty() { QQmlComponent component(&engine, testFileUrl("interfaceProperty.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->interface()); QCOMPARE(object->interface()->id, 913); @@ -645,7 +651,7 @@ void tst_qqmllanguage::interfaceQList() { QQmlComponent component(&engine, testFileUrl("interfaceQList.qml")); VERIFY_ERRORS(0); - MyContainer *container= qobject_cast<MyContainer*>(component.create()); + QScopedPointer<MyContainer> container(qobject_cast<MyContainer*>(component.create())); QVERIFY(container != nullptr); QCOMPARE(container->getQListInterfaces()->count(), 2); for(int ii = 0; ii < 2; ++ii) @@ -656,7 +662,7 @@ void tst_qqmllanguage::assignObjectToSignal() { QQmlComponent component(&engine, testFileUrl("assignObjectToSignal.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot"); emit object->basicSignal(); @@ -666,7 +672,7 @@ void tst_qqmllanguage::assignObjectToVariant() { QQmlComponent component(&engine, testFileUrl("assignObjectToVariant.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVariant v = object->property("a"); QVERIFY(v.userType() == qMetaTypeId<QObject *>()); @@ -676,7 +682,7 @@ void tst_qqmllanguage::assignLiteralSignalProperty() { QQmlComponent component(&engine, testFileUrl("assignLiteralSignalProperty.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->onLiteralSignal(), 10); } @@ -686,7 +692,7 @@ void tst_qqmllanguage::assignQmlComponent() { QQmlComponent component(&engine, testFileUrl("assignQmlComponent.qml")); VERIFY_ERRORS(0); - MyContainer *object = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->getChildren()->count(), 1); QObject *child = object->getChildren()->at(0); @@ -699,7 +705,7 @@ void tst_qqmllanguage::assignBasicTypes() { QQmlComponent component(&engine, testFileUrl("assignBasicTypes.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3); QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2); @@ -744,7 +750,7 @@ void tst_qqmllanguage::assignTypeExtremes() { QQmlComponent component(&engine, testFileUrl("assignTypeExtremes.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->uintProperty(), 0xEE6B2800); QCOMPARE(object->intProperty(), -0x77359400); @@ -755,7 +761,7 @@ void tst_qqmllanguage::assignCompositeToType() { QQmlComponent component(&engine, testFileUrl("assignCompositeToType.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -764,7 +770,7 @@ void tst_qqmllanguage::assignLiteralToVariant() { QQmlComponent component(&engine, testFileUrl("assignLiteralToVariant.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(isJSNumberType(object->property("test1").userType())); @@ -792,8 +798,6 @@ void tst_qqmllanguage::assignLiteralToVariant() QCOMPARE(object->property("test10"), QVariant(bool(true))); QCOMPARE(object->property("test11"), QVariant(bool(false))); QVERIFY(object->property("test12") == QVariant(QVector4D(100, 100, 100, 100))); - - delete object; } // Test that literals are stored correctly in "var" properties @@ -803,7 +807,7 @@ void tst_qqmllanguage::assignLiteralToVar() { QQmlComponent component(&engine, testFileUrl("assignLiteralToVar.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(isJSNumberType(object->property("test1").userType())); @@ -843,15 +847,13 @@ void tst_qqmllanguage::assignLiteralToVar() QCOMPARE(object->property("test16"), QVariant(QVector3D(100, 100, 100))); QCOMPARE(object->property("variantTest1Bound"), QVariant(9)); QCOMPARE(object->property("test1Bound"), QVariant(11)); - - delete object; } void tst_qqmllanguage::assignLiteralToJSValue() { QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); { @@ -932,6 +934,11 @@ void tst_qqmllanguage::assignLiteralToJSValue() QJSValue value = object->qjsvalue(); QVERIFY(value.isNumber()); QCOMPARE(value.toNumber(), qreal(27)); + } { + MyQmlObject *object = root->findChild<MyQmlObject *>("test23"); + QJSValue value = object->qjsvalue(); + QVERIFY(value.isQObject()); + QCOMPARE(value.toQObject()->objectName(), "blah"); } } @@ -939,11 +946,11 @@ void tst_qqmllanguage::assignNullStrings() { QQmlComponent component(&engine, testFileUrl("assignNullStrings.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->stringProperty().isNull()); QVERIFY(object->byteArrayProperty().isNull()); - QMetaObject::invokeMethod(object, "assignNullStringsFromJs", Qt::DirectConnection); + QMetaObject::invokeMethod(object.data(), "assignNullStringsFromJs", Qt::DirectConnection); QVERIFY(object->stringProperty().isNull()); QVERIFY(object->byteArrayProperty().isNull()); } @@ -953,7 +960,7 @@ void tst_qqmllanguage::bindJSValueToVar() QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); QObject *object = root->findChild<QObject *>("varProperties"); @@ -1002,7 +1009,7 @@ void tst_qqmllanguage::bindJSValueToVariant() QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); QObject *object = root->findChild<QObject *>("variantProperties"); @@ -1051,7 +1058,7 @@ void tst_qqmllanguage::bindJSValueToType() QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); { @@ -1086,7 +1093,7 @@ void tst_qqmllanguage::bindTypeToJSValue() QQmlComponent component(&engine, testFileUrl("bindTypeToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); { @@ -1225,7 +1232,7 @@ void tst_qqmllanguage::customParserTypes() { QQmlComponent component(&engine, testFileUrl("customParserTypes.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("count"), QVariant(2)); } @@ -1235,7 +1242,7 @@ void tst_qqmllanguage::rootAsQmlComponent() { QQmlComponent component(&engine, testFileUrl("rootAsQmlComponent.qml")); VERIFY_ERRORS(0); - MyContainer *object = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->property("x"), QVariant(11)); QCOMPARE(object->getChildren()->count(), 2); @@ -1259,12 +1266,12 @@ void tst_qqmllanguage::inlineQmlComponents() { QQmlComponent component(&engine, testFileUrl("inlineQmlComponents.qml")); VERIFY_ERRORS(0); - MyContainer *object = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->getChildren()->count(), 1); QQmlComponent *comp = qobject_cast<QQmlComponent *>(object->getChildren()->at(0)); QVERIFY(comp != nullptr); - MyQmlObject *compObject = qobject_cast<MyQmlObject *>(comp->create()); + QScopedPointer<MyQmlObject> compObject(qobject_cast<MyQmlObject *>(comp->create())); QVERIFY(compObject != nullptr); QCOMPARE(compObject->value(), 11); } @@ -1275,7 +1282,7 @@ void tst_qqmllanguage::idProperty() { QQmlComponent component(&engine, testFileUrl("idProperty.qml")); VERIFY_ERRORS(0); - MyContainer *object = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->getChildren()->count(), 2); MyTypeObject *child = @@ -1306,14 +1313,14 @@ void tst_qqmllanguage::autoNotifyConnection() { QQmlComponent component(&engine, testFileUrl("autoNotifyConnection.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QMetaProperty prop = object->metaObject()->property(object->metaObject()->indexOfProperty("receivedNotify")); QVERIFY(prop.isValid()); - QCOMPARE(prop.read(object), QVariant::fromValue(false)); + QCOMPARE(prop.read(object.data()), QVariant::fromValue(false)); object->setPropertyWithNotify(1); - QCOMPARE(prop.read(object), QVariant::fromValue(true)); + QCOMPARE(prop.read(object.data()), QVariant::fromValue(true)); } // Tests that signals can be assigned to @@ -1321,7 +1328,7 @@ void tst_qqmllanguage::assignSignal() { QQmlComponent component(&engine, testFileUrl("assignSignal.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot"); emit object->basicSignal(); @@ -1333,7 +1340,7 @@ void tst_qqmllanguage::assignSignalFunctionExpression() { QQmlComponent component(&engine, testFileUrl("assignSignalFunctionExpression.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot"); emit object->basicSignal(); @@ -1362,10 +1369,9 @@ void tst_qqmllanguage::overrideSignal() QQmlComponent component(&engine, testFileUrl(file)); if (errorFile.isEmpty()) { VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(object->property("success").toBool()); - delete object; } else { VERIFY_ERRORS(errorFile.toLatin1().constData()); } @@ -1376,8 +1382,7 @@ void tst_qqmllanguage::dynamicProperties() { QQmlComponent component(&engine, testFileUrl("dynamicProperties.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); - QVERIFY(object != nullptr); + QScopedPointer<QObject> object(component.create()); QCOMPARE(object->property("intProperty"), QVariant(10)); QCOMPARE(object->property("boolProperty"), QVariant(false)); QCOMPARE(object->property("doubleProperty"), QVariant(-10.1)); @@ -1394,15 +1399,13 @@ void tst_qqmllanguage::dynamicPropertiesNested() { QQmlComponent component(&engine, testFileUrl("dynamicPropertiesNested.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("super_a").toInt(), 11); // Overridden QCOMPARE(object->property("super_c").toInt(), 14); // Inherited QCOMPARE(object->property("a").toInt(), 13); // New QCOMPARE(object->property("b").toInt(), 12); // New - - delete object; } // Tests the creation and assignment to dynamic list properties @@ -1410,7 +1413,7 @@ void tst_qqmllanguage::listProperties() { QQmlComponent component(&engine, testFileUrl("listProperties.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("test").toInt(), 2); @@ -1430,7 +1433,7 @@ void tst_qqmllanguage::dynamicObjectProperties() { QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("objectProperty"), qVariantFromValue((QObject*)nullptr)); @@ -1439,7 +1442,7 @@ void tst_qqmllanguage::dynamicObjectProperties() { QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.2.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(object->property("objectProperty") != qVariantFromValue((QObject*)nullptr)); @@ -1453,7 +1456,7 @@ void tst_qqmllanguage::dynamicSignalsAndSlots() QQmlComponent component(&engine, testFileUrl("dynamicSignalsAndSlots.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(object->metaObject()->indexOfMethod("signal1()") != -1); QVERIFY(object->metaObject()->indexOfMethod("signal2()") != -1); @@ -1461,7 +1464,7 @@ void tst_qqmllanguage::dynamicSignalsAndSlots() QVERIFY(object->metaObject()->indexOfMethod("slot2()") != -1); QCOMPARE(object->property("test").toInt(), 0); - QMetaObject::invokeMethod(object, "slot3", Qt::DirectConnection, Q_ARG(QVariant, QVariant(10))); + QMetaObject::invokeMethod(object.data(), "slot3", Qt::DirectConnection, Q_ARG(QVariant, QVariant(10))); QCOMPARE(object->property("test").toInt(), 10); } @@ -1469,13 +1472,44 @@ void tst_qqmllanguage::simpleBindings() { QQmlComponent component(&engine, testFileUrl("simpleBindings.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("value1"), QVariant(10)); QCOMPARE(object->property("value2"), QVariant(10)); QCOMPARE(object->property("value3"), QVariant(21)); QCOMPARE(object->property("value4"), QVariant(10)); - QCOMPARE(object->property("objectProperty"), QVariant::fromValue(object)); + QCOMPARE(object->property("objectProperty"), QVariant::fromValue(object.data())); +} + +class EvaluationCounter : public QObject +{ + Q_OBJECT +public: + int counter = 0; + Q_INVOKABLE void increaseEvaluationCounter() { ++counter; } +}; + +void tst_qqmllanguage::noDoubleEvaluationForFlushedBindings_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::newRow("order1") << QString("noDoubleEvaluationForFlushedBindings.qml"); + QTest::newRow("order2") << QString("noDoubleEvaluationForFlushedBindings.2.qml"); +} + +void tst_qqmllanguage::noDoubleEvaluationForFlushedBindings() +{ + QFETCH(QString, fileName); + QQmlEngine engine; + + EvaluationCounter stats; + engine.rootContext()->setContextProperty("stats", &stats); + + QQmlComponent component(&engine, testFileUrl(fileName)); + VERIFY_ERRORS(0); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + + QCOMPARE(stats.counter, 1); } void tst_qqmllanguage::autoComponentCreation() @@ -1483,20 +1517,20 @@ void tst_qqmllanguage::autoComponentCreation() { QQmlComponent component(&engine, testFileUrl("autoComponentCreation.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->componentProperty() != nullptr); - MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create()); + QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create())); QVERIFY(child != nullptr); QCOMPARE(child->realProperty(), qreal(9)); } { QQmlComponent component(&engine, testFileUrl("autoComponentCreation.2.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->componentProperty() != nullptr); - MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create()); + QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create())); QVERIFY(child != nullptr); QCOMPARE(child->realProperty(), qreal(9)); } @@ -1506,10 +1540,10 @@ void tst_qqmllanguage::autoComponentCreationInGroupProperty() { QQmlComponent component(&engine, testFileUrl("autoComponentCreationInGroupProperties.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->componentProperty() != nullptr); - MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create()); + QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create())); QVERIFY(child != nullptr); QCOMPARE(child->realProperty(), qreal(9)); } @@ -1519,7 +1553,7 @@ void tst_qqmllanguage::propertyValueSource() { QQmlComponent component(&engine, testFileUrl("propertyValueSource.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QList<QObject *> valueSources; @@ -1533,14 +1567,14 @@ void tst_qqmllanguage::propertyValueSource() MyPropertyValueSource *valueSource = qobject_cast<MyPropertyValueSource *>(valueSources.at(0)); QVERIFY(valueSource != nullptr); - QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object)); + QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object.data())); QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty"))); } { QQmlComponent component(&engine, testFileUrl("propertyValueSource.2.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QList<QObject *> valueSources; @@ -1554,7 +1588,7 @@ void tst_qqmllanguage::propertyValueSource() MyPropertyValueSource *valueSource = qobject_cast<MyPropertyValueSource *>(valueSources.at(0)); QVERIFY(valueSource != nullptr); - QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object)); + QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object.data())); QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty"))); } } @@ -1563,9 +1597,9 @@ void tst_qqmllanguage::attachedProperties() { QQmlComponent component(&engine, testFileUrl("attachedProperties.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QObject *attached = qmlAttachedPropertiesObject<MyQmlObject>(object); + QObject *attached = qmlAttachedPropertiesObject<MyQmlObject>(object.data()); QVERIFY(attached != nullptr); QCOMPARE(attached->property("value"), QVariant(10)); QCOMPARE(attached->property("value2"), QVariant(13)); @@ -1576,7 +1610,7 @@ void tst_qqmllanguage::dynamicObjects() { QQmlComponent component(&engine, testFileUrl("dynamicObject.1.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -1585,7 +1619,7 @@ void tst_qqmllanguage::customVariantTypes() { QQmlComponent component(&engine, testFileUrl("customVariantTypes.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->customType().a, 10); } @@ -1599,7 +1633,7 @@ void tst_qqmllanguage::valueTypes() QTest::ignoreMessage(QtWarningMsg, qPrintable(message)); QTest::ignoreMessage(QtWarningMsg, qPrintable(message)); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); @@ -1630,20 +1664,17 @@ void tst_qqmllanguage::cppnamespace() { QQmlComponent component(&engine, testFileUrl("cppnamespace.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("intProperty").toInt(), (int)MyNamespace::MyOtherNSEnum::OtherKey2); - - delete object; } { QQmlComponent component(&engine, testFileUrl("cppnamespace.2.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - delete object; } } @@ -1653,7 +1684,7 @@ void tst_qqmllanguage::aliasProperties() { QQmlComponent component(&engine, testFileUrl("alias.1.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); // Read through alias @@ -1665,15 +1696,13 @@ void tst_qqmllanguage::aliasProperties() object->setProperty("valueAlias", QVariant(19)); QCOMPARE(object->property("valueAlias").toInt(), 19); QCOMPARE(object->property("value").toInt(), 19); - - delete object; } // Complex object alias { QQmlComponent component(&engine, testFileUrl("alias.2.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); // Read through alias @@ -1684,21 +1713,19 @@ void tst_qqmllanguage::aliasProperties() // Write through alias MyQmlObject *v2 = new MyQmlObject(); - v2->setParent(object); + v2->setParent(object.data()); object->setProperty("aliasObject", qVariantFromValue(v2)); MyQmlObject *v3 = qvariant_cast<MyQmlObject *>(object->property("aliasObject")); QVERIFY(v3 != nullptr); QCOMPARE(v3, v2); - - delete object; } // Nested aliases { QQmlComponent component(&engine, testFileUrl("alias.3.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("value").toInt(), 1892); @@ -1711,27 +1738,23 @@ void tst_qqmllanguage::aliasProperties() object->setProperty("value2", QVariant(8080)); QCOMPARE(object->property("value").toInt(), 8080); QCOMPARE(object->property("value2").toInt(), 8080); - - delete object; } // Enum aliases { QQmlComponent component(&engine, testFileUrl("alias.4.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("enumAlias").toInt(), 1); - - delete object; } // Id aliases { QQmlComponent component(&engine, testFileUrl("alias.5.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVariant v = object->property("otherAlias"); @@ -1745,15 +1768,13 @@ void tst_qqmllanguage::aliasProperties() QCOMPARE(v.userType(), qMetaTypeId<MyQmlObject*>()); o = qvariant_cast<MyQmlObject*>(v); QVERIFY(!o); - - delete object; } // Nested aliases - this used to cause a crash { QQmlComponent component(&engine, testFileUrl("alias.6.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("a").toInt(), 1923); @@ -1765,7 +1786,7 @@ void tst_qqmllanguage::aliasProperties() QQmlComponent component(&engine, testFileUrl("alias.7.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QObject *object1 = qvariant_cast<QObject *>(object->property("object")); @@ -1778,10 +1799,10 @@ void tst_qqmllanguage::aliasProperties() delete object1; - QObject *alias2 = object; // "Random" start value + QObject *alias2 = object.data(); // "Random" start value int status = -1; void *a[] = { &alias2, nullptr, &status }; - QMetaObject::metacall(object, QMetaObject::ReadProperty, + QMetaObject::metacall(object.data(), QMetaObject::ReadProperty, object->metaObject()->indexOfProperty("aliasedObject"), a); QVERIFY(!alias2); } @@ -1790,24 +1811,20 @@ void tst_qqmllanguage::aliasProperties() { QQmlComponent component(&engine, testFileUrl("alias.8.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("value").toInt(), 10); - - delete object; } // Complex composite type { QQmlComponent component(&engine, testFileUrl("alias.9.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("value").toInt(), 10); - - delete object; } // Valuetype alias @@ -1815,7 +1832,7 @@ void tst_qqmllanguage::aliasProperties() { QQmlComponent component(&engine, testFileUrl("alias.10.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); // Read through alias @@ -1827,15 +1844,13 @@ void tst_qqmllanguage::aliasProperties() object->setProperty("valueAlias", QVariant(QRect(3, 3, 4, 9))); QCOMPARE(object->property("valueAlias").toRect(), QRect(3, 3, 4, 9)); QCOMPARE(object->property("rectProperty").toRect(), QRect(3, 3, 4, 9)); - - delete object; } // Valuetype sub-alias { QQmlComponent component(&engine, testFileUrl("alias.11.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); // Read through alias @@ -1847,8 +1862,6 @@ void tst_qqmllanguage::aliasProperties() object->setProperty("aliasProperty", QVariant(4)); QCOMPARE(object->property("aliasProperty").toInt(), 4); QCOMPARE(object->property("rectProperty").toRect(), QRect(4, 8, 102, 111)); - - delete object; } // Nested aliases with a qml file @@ -1906,6 +1919,16 @@ void tst_qqmllanguage::aliasProperties() QCOMPARE(subItem->property("y").toInt(), 1); } + + // Alias to sub-object with binding (QTBUG-57041) + { + // This is shold *not* crash. + QQmlComponent component(&engine, testFileUrl("alias.16.qml")); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + } } // QTBUG-13374 Test that alias properties and signals can coexist @@ -1913,10 +1936,9 @@ void tst_qqmllanguage::aliasPropertiesAndSignals() { QQmlComponent component(&engine, testFileUrl("aliasPropertiesAndSignals.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o); QCOMPARE(o->property("test").toBool(), true); - delete o; } // Test that the root element in a composite type can be a Component @@ -1924,7 +1946,7 @@ void tst_qqmllanguage::componentCompositeType() { QQmlComponent component(&engine, testFileUrl("componentCompositeType.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -1958,11 +1980,9 @@ void tst_qqmllanguage::i18n() QFETCH(QString, stringProperty); QQmlComponent component(&engine, testFileUrl(file)); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->stringProperty(), stringProperty); - - delete object; } // Check that the Component::onCompleted attached property works @@ -1973,7 +1993,7 @@ void tst_qqmllanguage::onCompleted() QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); QTest::ignoreMessage(QtDebugMsg, "Completed 10 11"); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -1982,12 +2002,11 @@ void tst_qqmllanguage::onDestruction() { QQmlComponent component(&engine, testFileUrl("onDestruction.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10"); QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10"); QTest::ignoreMessage(QtDebugMsg, "Destruction 10 11"); - delete object; } // Check that assignments to QQmlScriptString properties work @@ -1997,7 +2016,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QVERIFY(!object->scriptProperty().isEmpty()); QCOMPARE(object->scriptProperty().stringLiteral(), QString()); @@ -2008,21 +2027,21 @@ void tst_qqmllanguage::scriptString() const QQmlScriptStringPrivate *scriptPrivate = QQmlScriptStringPrivate::get(object->scriptProperty()); QVERIFY(scriptPrivate != nullptr); QCOMPARE(scriptPrivate->script, QString("foo + bar")); - QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object)); - QCOMPARE(scriptPrivate->context, qmlContext(object)); + QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object.data())); + QCOMPARE(scriptPrivate->context, qmlContext(object.data())); QVERIFY(object->grouped() != nullptr); const QQmlScriptStringPrivate *groupedPrivate = QQmlScriptStringPrivate::get(object->grouped()->script()); QCOMPARE(groupedPrivate->script, QString("console.log(1921)")); - QCOMPARE(groupedPrivate->scope, qobject_cast<QObject*>(object)); - QCOMPARE(groupedPrivate->context, qmlContext(object)); + QCOMPARE(groupedPrivate->scope, qobject_cast<QObject*>(object.data())); + QCOMPARE(groupedPrivate->context, qmlContext(object.data())); } { QQmlComponent component(&engine, testFileUrl("scriptString2.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->scriptProperty().stringLiteral(), QString("hello\\n\\\"world\\\"")); } @@ -2031,7 +2050,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString3.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); bool ok; QCOMPARE(object->scriptProperty().numberLiteral(&ok), qreal(12.345)); @@ -2043,7 +2062,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString4.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); bool ok; QCOMPARE(object->scriptProperty().booleanLiteral(&ok), true); @@ -2054,7 +2073,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString5.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->scriptProperty().isNullLiteral(), true); } @@ -2063,7 +2082,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString6.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->scriptProperty().isUndefinedLiteral(), true); } @@ -2071,12 +2090,12 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString7.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QQmlScriptString ss = object->scriptProperty(); { - QQmlExpression expr(ss, /*context*/nullptr, object); + QQmlExpression expr(ss, /*context*/nullptr, object.data()); QCOMPARE(expr.evaluate().toInt(), int(100)); } @@ -2097,9 +2116,9 @@ void tst_qqmllanguage::scriptStringJs() QQmlComponent component(&engine, testFileUrl("scriptStringJs.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); - QQmlContext *context = QQmlEngine::contextForObject(object); + QQmlContext *context = QQmlEngine::contextForObject(object.data()); QVERIFY(context != nullptr); bool ok; @@ -2111,8 +2130,8 @@ void tst_qqmllanguage::scriptStringJs() QVERIFY(object->scriptProperty().numberLiteral(&ok) == 0.0 && !ok); QVERIFY(!object->scriptProperty().booleanLiteral(&ok) && !ok); - QJSValue inst = engine.newQObject(object); - QJSValue func = engine.evaluate("function(value) { this.scriptProperty = value }"); + QJSValue inst = engine.newQObject(object.data()); + QJSValue func = engine.evaluate("(function(value) { this.scriptProperty = value })"); func.callWithInstance(inst, QJSValueList() << "test a \"string "); QCOMPARE(QQmlScriptStringPrivate::get(object->scriptProperty())->script, QString("\"test a \\\"string \"")); @@ -2201,7 +2220,7 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode() QQmlComponent component(&engine, url); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QQmlScriptString ss = object->scriptProperty(); QVERIFY(!ss.isEmpty()); @@ -2213,11 +2232,11 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode() const QQmlScriptStringPrivate *scriptPrivate = QQmlScriptStringPrivate::get(ss); QVERIFY(scriptPrivate != nullptr); QVERIFY(scriptPrivate->script.isEmpty()); - QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object)); - QCOMPARE(scriptPrivate->context, qmlContext(object)); + QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object.data())); + QCOMPARE(scriptPrivate->context, qmlContext(object.data())); { - QQmlExpression expr(ss, /*context*/nullptr, object); + QQmlExpression expr(ss, /*context*/nullptr, object.data()); QCOMPARE(expr.evaluate().toInt(), int(100)); } } @@ -2228,23 +2247,23 @@ void tst_qqmllanguage::scriptStringComparison() { QQmlComponent component1(&engine, testFileUrl("scriptString.qml")); QVERIFY(!component1.isError() && component1.errors().isEmpty()); - MyTypeObject *object1 = qobject_cast<MyTypeObject*>(component1.create()); + QScopedPointer<MyTypeObject> object1(qobject_cast<MyTypeObject*>(component1.create())); QVERIFY(object1 != nullptr); QQmlComponent component2(&engine, testFileUrl("scriptString2.qml")); QVERIFY(!component2.isError() && component2.errors().isEmpty()); - MyTypeObject *object2 = qobject_cast<MyTypeObject*>(component2.create()); + QScopedPointer<MyTypeObject> object2(qobject_cast<MyTypeObject*>(component2.create())); QVERIFY(object2 != nullptr); QQmlComponent component3(&engine, testFileUrl("scriptString3.qml")); QVERIFY(!component3.isError() && component3.errors().isEmpty()); - MyTypeObject *object3 = qobject_cast<MyTypeObject*>(component3.create()); + QScopedPointer<MyTypeObject> object3(qobject_cast<MyTypeObject*>(component3.create())); QVERIFY(object3 != nullptr); //QJSValue inst1 = engine.newQObject(object1); - QJSValue inst2 = engine.newQObject(object2); - QJSValue inst3 = engine.newQObject(object3); - QJSValue func = engine.evaluate("function(value) { this.scriptProperty = value }"); + QJSValue inst2 = engine.newQObject(object2.data()); + QJSValue inst3 = engine.newQObject(object3.data()); + QJSValue func = engine.evaluate("(function(value) { this.scriptProperty = value })"); const QString s = "hello\\n\\\"world\\\""; const qreal n = 12.345; @@ -2298,7 +2317,7 @@ void tst_qqmllanguage::scriptStringComparison() // While this are two instances of the same object they are still considered different // because the (none literal) script string may access variables which have different // values in both instances and hence evaluated to different results. - MyTypeObject *object1_2 = qobject_cast<MyTypeObject*>(component1.create()); + QScopedPointer<MyTypeObject> object1_2(qobject_cast<MyTypeObject*>(component1.create())); QVERIFY(object1_2 != nullptr); QVERIFY(object1->scriptProperty() != object1_2->scriptProperty()); } @@ -2310,7 +2329,7 @@ void tst_qqmllanguage::defaultPropertyListOrder() QQmlComponent component(&engine, testFileUrl("defaultPropertyListOrder.qml")); VERIFY_ERRORS(0); - MyContainer *container = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> container(qobject_cast<MyContainer *>(component.create())); QVERIFY(container != nullptr); QCOMPARE(container->getChildren()->count(), 6); @@ -2331,15 +2350,13 @@ void tst_qqmllanguage::declaredPropertyValues() void tst_qqmllanguage::dontDoubleCallClassBegin() { QQmlComponent component(&engine, testFileUrl("dontDoubleCallClassBegin.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o); MyParserStatus *o2 = qobject_cast<MyParserStatus *>(qvariant_cast<QObject *>(o->property("object"))); QVERIFY(o2); QCOMPARE(o2->classBeginCount(), 1); QCOMPARE(o2->componentCompleteCount(), 1); - - delete o; } void tst_qqmllanguage::reservedWords_data() @@ -2439,10 +2456,9 @@ void tst_qqmllanguage::testType(const QString& qml, const QString& type, const Q QCOMPARE(actualerror.left(partialMatch ? expectederror.length(): -1),expectederror); } else { VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(QString(object->metaObject()->className()), type); - delete object; } engine.setImportPathList(defaultImportPathList); @@ -2453,10 +2469,9 @@ void tst_qqmllanguage::inlineAssignmentsOverrideBindings() { QQmlComponent component(&engine, testFileUrl("inlineAssignmentsOverrideBindings.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toInt(), 11); - delete o; } // QTBUG-19354 @@ -2887,10 +2902,9 @@ void tst_qqmllanguage::importsPath() QTRY_VERIFY(component.isReady()); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("test").toString(), value); - delete object; engine.setImportPathList(defaultImportPathList); } @@ -3098,10 +3112,9 @@ void tst_qqmllanguage::importJs() } if (performTest) { - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("test").toBool(),true); - delete object; } engine.setImportPathList(defaultImportPathList); @@ -3150,21 +3163,21 @@ void tst_qqmllanguage::qmlAttachedPropertiesObjectMethod() { QQmlComponent component(&engine, testFileUrl("qmlAttachedPropertiesObjectMethod.1.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(object, false), (QObject *)nullptr); - QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, true) != nullptr); + QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), false), (QObject *)nullptr); + QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), true) != nullptr); } { QQmlComponent component(&engine, testFileUrl("qmlAttachedPropertiesObjectMethod.2.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, false) != nullptr); - QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, true) != nullptr); + QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), false) != nullptr); + QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), true) != nullptr); } } @@ -3185,12 +3198,10 @@ void tst_qqmllanguage::customOnProperty() QQmlComponent component(&engine, testFileUrl("customOnProperty.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("on").toInt(), 10); - - delete object; } // QTBUG-12601 @@ -3199,12 +3210,10 @@ void tst_qqmllanguage::variantNotify() QQmlComponent component(&engine, testFileUrl("variantNotify.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("notifyCount").toInt(), 1); - - delete object; } void tst_qqmllanguage::revisions() @@ -3213,38 +3222,32 @@ void tst_qqmllanguage::revisions() QQmlComponent component(&engine, testFileUrl("revisions11.qml")); VERIFY_ERRORS(0); - MyRevisionedClass *object = qobject_cast<MyRevisionedClass*>(component.create()); + QScopedPointer<MyRevisionedClass> object(qobject_cast<MyRevisionedClass*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->prop2(), 10.0); - - delete object; } { QQmlEngine myEngine; QQmlComponent component(&myEngine, testFileUrl("revisionssub11.qml")); VERIFY_ERRORS(0); - MyRevisionedSubclass *object = qobject_cast<MyRevisionedSubclass*>(component.create()); + QScopedPointer<MyRevisionedSubclass> object(qobject_cast<MyRevisionedSubclass*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->prop1(), 10.0); QCOMPARE(object->prop2(), 10.0); QCOMPARE(object->prop3(), 10.0); QCOMPARE(object->prop4(), 10.0); - - delete object; } { QQmlComponent component(&engine, testFileUrl("versionedbase.qml")); VERIFY_ERRORS(0); - MySubclass *object = qobject_cast<MySubclass*>(component.create()); + QScopedPointer<MySubclass> object(qobject_cast<MySubclass*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->prop1(), 10.0); QCOMPARE(object->prop2(), 10.0); - - delete object; } } @@ -3290,8 +3293,8 @@ void tst_qqmllanguage::subclassedUncreateableRevision() QQmlComponent c(&engine); QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath())); - QObject *obj = c.create(); - QCOMPARE(obj, static_cast<QObject*>(nullptr)); + QScopedPointer<QObject> obj(c.create()); + QCOMPARE(obj.data(), static_cast<QObject*>(nullptr)); QCOMPARE(c.errors().count(), 1); QCOMPARE(c.errors().first().description(), QString("Cannot create MyUncreateableBaseClass")); } @@ -3302,17 +3305,16 @@ void tst_qqmllanguage::subclassedUncreateableRevision() if (!shouldWork) QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath())); - QObject *obj = c.create(); + QScopedPointer<QObject> obj(c.create()); if (!shouldWork) { - QCOMPARE(obj, static_cast<QObject*>(nullptr)); + QCOMPARE(obj.data(), static_cast<QObject*>(nullptr)); return; } QVERIFY(obj); - MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj); + MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj.data()); QVERIFY(base); QCOMPARE(base->property(prop.toLatin1()).toBool(), true); - delete obj; } void tst_qqmllanguage::subclassedExtendedUncreateableRevision_data() @@ -3346,8 +3348,8 @@ void tst_qqmllanguage::subclassedExtendedUncreateableRevision() QQmlComponent c(&engine); QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath())); - QObject *obj = c.create(); - QCOMPARE(obj, static_cast<QObject*>(nullptr)); + QScopedPointer<QObject> obj(c.create()); + QCOMPARE(obj.data(), static_cast<QObject*>(nullptr)); QCOMPARE(c.errors().count(), 1); QCOMPARE(c.errors().first().description(), QString("Cannot create MyExtendedUncreateableBaseClass")); } @@ -3358,17 +3360,16 @@ void tst_qqmllanguage::subclassedExtendedUncreateableRevision() if (!shouldWork) QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath())); - QObject *obj = c.create(); + QScopedPointer<QObject> obj(c.create()); if (!shouldWork) { - QCOMPARE(obj, static_cast<QObject*>(nullptr)); + QCOMPARE(obj.data(), static_cast<QObject*>(nullptr)); return; } QVERIFY(obj); - MyExtendedUncreateableBaseClass *base = qobject_cast<MyExtendedUncreateableBaseClass*>(obj); + MyExtendedUncreateableBaseClass *base = qobject_cast<MyExtendedUncreateableBaseClass*>(obj.data()); QVERIFY(base); QCOMPARE(base->property(prop.toLatin1()).toBool(), true); - delete obj; } void tst_qqmllanguage::uncreatableTypesAsProperties() @@ -3429,12 +3430,10 @@ void tst_qqmllanguage::aliasPropertyChangeSignals() QQmlComponent component(&engine, testFileUrl("aliasPropertyChangeSignals.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toBool(), true); - - delete o; } // QTCREATORBUG-2769 @@ -3442,12 +3441,10 @@ void tst_qqmllanguage::aliasPropertyChangeSignals() QQmlComponent component(&engine, testFileUrl("aliasPropertyChangeSignals.2.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toBool(), true); - - delete o; } } @@ -3458,24 +3455,20 @@ void tst_qqmllanguage::propertyInit() QQmlComponent component(&engine, testFileUrl("propertyInit.1.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toInt(), 1); - - delete o; } { QQmlComponent component(&engine, testFileUrl("propertyInit.2.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toInt(), 123); - - delete o; } } @@ -3485,17 +3478,16 @@ void tst_qqmllanguage::registrationOrder() { QQmlComponent component(&engine, testFileUrl("registrationOrder.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->metaObject(), &MyVersion2Class::staticMetaObject); - delete o; } void tst_qqmllanguage::readonly() { QQmlComponent component(&engine, testFileUrl("readonly.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test1").toInt(), 10); @@ -3521,8 +3513,6 @@ void tst_qqmllanguage::readonly() QCOMPARE(o->property("test1").toInt(), 10); QCOMPARE(o->property("test2").toInt(), 22); QCOMPARE(o->property("test3").toInt(), 2); - - delete o; } void tst_qqmllanguage::readonlyObjectProperties() @@ -3547,7 +3537,7 @@ void tst_qqmllanguage::receivers() { QQmlComponent component(&engine, testFileUrl("receivers.qml")); - MyReceiversTestObject *o = qobject_cast<MyReceiversTestObject*>(component.create()); + QScopedPointer<MyReceiversTestObject> o(qobject_cast<MyReceiversTestObject*>(component.create())); QVERIFY(o != nullptr); QCOMPARE(o->mySignalCount(), 1); QCOMPARE(o->propChangedCount(), 2); @@ -3556,8 +3546,6 @@ void tst_qqmllanguage::receivers() QVERIFY(o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::mySignal))); QVERIFY(o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::propChanged))); QVERIFY(!o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::myUnconnectedSignal))); - - delete o; } void tst_qqmllanguage::registeredCompositeType() @@ -3565,10 +3553,8 @@ void tst_qqmllanguage::registeredCompositeType() QQmlComponent component(&engine, testFileUrl("registeredCompositeType.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - - delete o; } // QTBUG-43582 @@ -3577,14 +3563,12 @@ void tst_qqmllanguage::registeredCompositeTypeWithEnum() QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeWithEnum.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("enumValue0").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue0)); QCOMPARE(o->property("enumValue42").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue42)); QCOMPARE(o->property("enumValue15").toInt(), static_cast<int>(MyCompositeBaseType::ScopedCompositeEnum::EnumValue15)); - - delete o; } // QTBUG-43581 @@ -3593,12 +3577,10 @@ void tst_qqmllanguage::registeredCompositeTypeWithAttachedProperty() QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeWithAttachedProperty.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("attachedProperty").toString(), QStringLiteral("test")); - - delete o; } // QTBUG-18268 @@ -3611,15 +3593,14 @@ void tst_qqmllanguage::remoteLoadCrash() while (component.isLoading()) QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents, 50); - QObject *o = component.create(); - delete o; + QScopedPointer<QObject> o(component.create()); } void tst_qqmllanguage::signalWithDefaultArg() { QQmlComponent component(&engine, testFileUrl("signalWithDefaultArg.qml")); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->property("signalCount").toInt(), 0); @@ -3634,15 +3615,13 @@ void tst_qqmllanguage::signalWithDefaultArg() QCOMPARE(object->property("signalArg").toInt(), 15); - QMetaObject::invokeMethod(object, "emitNoArgSignal"); + QMetaObject::invokeMethod(object.data(), "emitNoArgSignal"); QCOMPARE(object->property("signalCount").toInt(), 3); QCOMPARE(object->property("signalArg").toInt(), 5); - QMetaObject::invokeMethod(object, "emitArgSignal"); + QMetaObject::invokeMethod(object.data(), "emitArgSignal"); QCOMPARE(object->property("signalCount").toInt(), 4); QCOMPARE(object->property("signalArg").toInt(), 22); - - delete object; } void tst_qqmllanguage::signalParameterTypes() @@ -3650,19 +3629,17 @@ void tst_qqmllanguage::signalParameterTypes() // bound signal handlers { QQmlComponent component(&engine, testFileUrl("signalParameterTypes.1.qml")); - QObject *obj = component.create(); + QScopedPointer<QObject> obj(component.create()); QVERIFY(obj != nullptr); QVERIFY(obj->property("success").toBool()); - delete obj; } // dynamic signal connections { QQmlComponent component(&engine, testFileUrl("signalParameterTypes.2.qml")); - QObject *obj = component.create(); + QScopedPointer<QObject> obj(component.create()); QVERIFY(obj != nullptr); QVERIFY(obj->property("success").toBool()); - delete obj; } } @@ -3675,7 +3652,7 @@ void tst_qqmllanguage::globalEnums() QQmlComponent component(&engine, testFileUrl("globalEnums.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); MyEnum1Class *enum1Class = o->findChild<MyEnum1Class *>(QString::fromLatin1("enum1Class")); @@ -3701,7 +3678,7 @@ void tst_qqmllanguage::globalEnums() QSignalSpy signalA(enum2Class, SIGNAL(valueAChanged(MyEnum1Class::EnumA))); QSignalSpy signalB(enum2Class, SIGNAL(valueBChanged(MyEnum2Class::EnumB))); - QMetaObject::invokeMethod(o, "setEnumValues"); + QMetaObject::invokeMethod(o.data(), "setEnumValues"); QVERIFY(enum1Class->getValue() == MyEnum1Class::A_13); QVERIFY(enum2Class->getValueA() == MyEnum1Class::A_11); @@ -3720,8 +3697,6 @@ void tst_qqmllanguage::globalEnums() QVERIFY(enum2Class->property("dValue") == 2); QVERIFY(enum2Class->property("eValue") == 14); QVERIFY(enum2Class->property("e2Value") == 76); - - delete o; } void tst_qqmllanguage::lowercaseEnumRuntime_data() @@ -3767,7 +3742,7 @@ void tst_qqmllanguage::scopedEnum() { QQmlComponent component(&engine, testFileUrl("scopedEnum.qml")); - MyTypeObject *o = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> o(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(o != nullptr); QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal1); @@ -3775,16 +3750,19 @@ void tst_qqmllanguage::scopedEnum() QCOMPARE(o->property("listValue").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal3); QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal1); - QMetaObject::invokeMethod(o, "assignNewValue"); + QMetaObject::invokeMethod(o.data(), "assignNewValue"); QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal2); QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal2); } void tst_qqmllanguage::qmlEnums() { + QQmlEngine engine; + engine.setImportPathList(QStringList(defaultImportPathList) << testFile("lib")); + { QQmlComponent component(&engine, testFileUrl("TypeWithEnum.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o); QCOMPARE(o->property("enumValue").toInt(), 1); QCOMPARE(o->property("enumValue2").toInt(), 2); @@ -3799,11 +3777,12 @@ void tst_qqmllanguage::qmlEnums() { QQmlComponent component(&engine, testFileUrl("usingTypeWithEnum.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o); QCOMPARE(o->property("enumValue").toInt(), 1); QCOMPARE(o->property("enumValue2").toInt(), 0); QCOMPARE(o->property("scopedEnumValue").toInt(), 2); + QCOMPARE(o->property("enumValueFromSingleton").toInt(), 42); } } @@ -3844,10 +3823,9 @@ void tst_qqmllanguage::literals() QQmlComponent component(&engine, testFile("literals.qml")); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property(property.toLatin1()), value); - delete object; } void tst_qqmllanguage::objectDeletionNotify_data() @@ -3866,19 +3844,17 @@ void tst_qqmllanguage::objectDeletionNotify() QQmlComponent component(&engine, testFile(file)); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("success").toBool(), true); - QMetaObject::invokeMethod(object, "destroyObject"); + QMetaObject::invokeMethod(object.data(), "destroyObject"); // Process the deletion event QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QCoreApplication::processEvents(); QCOMPARE(object->property("success").toBool(), true); - - delete object; } void tst_qqmllanguage::scopedProperties() @@ -3912,7 +3888,7 @@ void tst_qqmllanguage::implicitImportsLast() QQmlComponent component(&engine, testFile("localOrderTest.qml")); VERIFY_ERRORS(0); - QObject *object = qobject_cast<QObject *>(component.create()); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(QString(object->metaObject()->className()).startsWith(QLatin1String("QQuickMouseArea"))); QObject* object2 = object->property("item").value<QObject*>(); @@ -3932,10 +3908,10 @@ void tst_qqmllanguage::getSingletonInstance(QQmlEngine& engine, const char* file QQmlComponent component(&engine, testFile(fileName)); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - getSingletonInstance(object, propertyName, result); + getSingletonInstance(object.data(), propertyName, result); } void tst_qqmllanguage::getSingletonInstance(QObject* o, const char* propertyName, QObject** result /* out */) @@ -3972,10 +3948,10 @@ void tst_qqmllanguage::compositeSingletonProperties() { QQmlComponent component(&engine, testFile("singletonTest1.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55); } // Checks that the addresses of the composite singletons used in the same @@ -4026,15 +4002,15 @@ void tst_qqmllanguage::compositeSingletonQualifiedNamespace() { QQmlComponent component(&engine, testFile("singletonTest5.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55); // lets verify that the singleton instance we are using is the same // when loaded through another file (without namespace!) QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); QObject* s2 = nullptr; @@ -4051,16 +4027,16 @@ void tst_qqmllanguage::compositeSingletonModule() QQmlComponent component(&engine, testFile("singletonTest6.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55); - verifyCompositeSingletonPropertyValues(o, "value3", 125, "value4", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value3", 125, "value4", -55); // lets verify that the singleton instance we are using is the same // when loaded through another file QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); QObject* s2 = nullptr; @@ -4077,16 +4053,16 @@ void tst_qqmllanguage::compositeSingletonModuleVersioned() QQmlComponent component(&engine, testFile("singletonTest7.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55); - verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 225, "value2", 55); + verifyCompositeSingletonPropertyValues(o.data(), "value3", 225, "value4", 55); // lets verify that the singleton instance we are using is the same // when loaded through another file QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); QObject* s2 = nullptr; @@ -4103,16 +4079,16 @@ void tst_qqmllanguage::compositeSingletonModuleQualified() QQmlComponent component(&engine, testFile("singletonTest8.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55); - verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 225, "value2", 55); + verifyCompositeSingletonPropertyValues(o.data(), "value3", 225, "value4", 55); // lets verify that the singleton instance we are using is the same // when loaded through another file QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); QObject* s2 = nullptr; @@ -4142,10 +4118,10 @@ void tst_qqmllanguage::compositeSingletonDynamicSignal() { QQmlComponent component(&engine, testFile("singletonTest11.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", -55); } // Use qmlRegisterType to register a qml composite type with pragma Singleton defined in it. @@ -4191,10 +4167,10 @@ void tst_qqmllanguage::compositeSingletonRemote() QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents, 50); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 525, "value2", 355); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 525, "value2", 355); } // Load a composite singleton type and a javascript file that has .pragma library @@ -4204,14 +4180,14 @@ void tst_qqmllanguage::compositeSingletonJavaScriptPragma() { QQmlComponent component(&engine, testFile("singletonTest16.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); // The value1 that is read from the SingletonType was changed from 125 to 99 // in compositeSingletonDynamicSignal() above. As the type is a singleton and // the engine has not been destroyed, we just retrieve the old instance and // the value is still 99. - verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", 333); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", 333); } // Reads values from a Singleton accessed through selectors. @@ -4222,10 +4198,10 @@ void tst_qqmllanguage::compositeSingletonSelectors() qmlSelector.setExtraSelectors(QStringList() << "basicSelector"); QQmlComponent component(&e2, testFile("singletonTest1.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 625, "value2", 455); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 625, "value2", 455); } // Reads values from a Singleton that was registered through the C++ API: @@ -4234,10 +4210,10 @@ void tst_qqmllanguage::compositeSingletonRegistered() { QQmlComponent component(&engine, testFile("singletonTest17.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 925, "value2", 755); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 925, "value2", 755); } void tst_qqmllanguage::compositeSingletonCircular() @@ -4247,7 +4223,7 @@ void tst_qqmllanguage::compositeSingletonCircular() QQmlTestMessageHandler messageHandler; - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); // ensure we aren't hitting the recursion warning @@ -4602,7 +4578,7 @@ 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()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->childAddedEventCount(), 0); } @@ -4622,10 +4598,10 @@ void tst_qqmllanguage::deleteSingletons() QQmlEngine tmpEngine; QQmlComponent component(&tmpEngine, testFile("singletonTest5.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); singleton = s1; QVERIFY(singleton.data() != nullptr); @@ -4649,7 +4625,7 @@ void tst_qqmllanguage::arrayBuffer() QFETCH(QString, file); QQmlComponent component(&engine, testFile(file)); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("ok").toBool(), true); } diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index 4618ea4071..9fdc54f067 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -125,6 +125,7 @@ private slots: void bindingsOnGetResult(); void stringifyModelEntry(); void qobjectTrackerForDynamicModelObjects(); + void crash_append_empty_array(); }; bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object) @@ -1534,6 +1535,27 @@ void tst_qqmllistmodel::qobjectTrackerForDynamicModelObjects() QVERIFY(!ddata->jsWrapper.isNullOrUndefined()); } +void tst_qqmllistmodel::crash_append_empty_array() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + " ListModel {\n" + " id: testModel\n" + " objectName: \"testModel\"" + " }\n" + "}\n", QUrl()); + QScopedPointer<QObject> scene(component.create()); + QQmlListModel *model = scene->findChild<QQmlListModel*>("testModel"); + QSignalSpy spy(model, &QQmlListModel::rowsAboutToBeInserted); + QQmlExpression expr(engine.rootContext(), model, "append(new Array())"); + expr.evaluate(); + QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString())); + QCOMPARE(spy.count(), 0); +} + QTEST_MAIN(tst_qqmllistmodel) #include "tst_qqmllistmodel.moc" diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index c252bba001..a456facd2f 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -89,6 +89,7 @@ private slots: void customValueType(); void customValueTypeInQml(); void gadgetInheritance(); + void gadgetTemplateInheritance(); void toStringConversion(); void enumerableProperties(); void enumProperties(); @@ -1613,6 +1614,19 @@ public: Q_INVOKABLE void functionInDerivedGadget(int value) { m_derivedProperty = value; } }; +// QTBUG-66744: we want a Q_GADGET giving us generic type safety in C++ and property access in Qml +template <typename T> +struct DerivedTypedGadget : public BaseGadget +{ + // cannot use Q_GADGET here +public: + DerivedTypedGadget() {} +}; + +class DerivedTypedGadgetDummyType {}; + +Q_DECLARE_METATYPE(DerivedTypedGadget<DerivedTypedGadgetDummyType>) + class TypeWithCustomValueType : public QObject { Q_OBJECT @@ -1657,6 +1671,21 @@ void tst_qqmlvaluetypes::gadgetInheritance() QCOMPARE(value.property("baseProperty").toInt(), 42); } +void tst_qqmlvaluetypes::gadgetTemplateInheritance() +{ + QJSEngine engine; + + QJSValue value = engine.toScriptValue(DerivedTypedGadget<DerivedTypedGadgetDummyType>()); + + QCOMPARE(value.property("baseProperty").toInt(), 0); + value.setProperty("baseProperty", 10); + QCOMPARE(value.property("baseProperty").toInt(), 10); + + QJSValue method = value.property("functionInBaseGadget"); + method.call(QJSValueList() << QJSValue(42)); + QCOMPARE(value.property("baseProperty").toInt(), 42); +} + struct StringLessGadget { Q_GADGET }; diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js b/tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js new file mode 100644 index 0000000000..adb7269310 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/noqmlcontext.js @@ -0,0 +1,11 @@ +(function(url, resultCollector) { + var x = new XMLHttpRequest; + x.open("GET", url); + x.setRequestHeader("Accept-Language","en-US"); + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + resultCollector.responseText = x.responseText + } + } + x.send() +}) diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp index 59716acc0d..ecce6515ed 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp +++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp @@ -108,6 +108,8 @@ private slots: void text(); void cdata(); + void noQmlContext(); + // Crashes // void outstanding_request_at_shutdown(); @@ -1243,6 +1245,30 @@ void tst_qqmlxmlhttprequest::cdata() QCOMPARE(object->property("status").toInt(), 200); } +void tst_qqmlxmlhttprequest::noQmlContext() +{ + TestHTTPServer server; + QVERIFY2(server.listen(), qPrintable(server.errorString())); + QVERIFY(server.wait(testFileUrl("open_network.expect"), + testFileUrl("open_network.reply"), + testFileUrl("testdocument.html"))); + QUrl url = server.urlString(QStringLiteral("/testdocument.html")); + + QQmlEngine engine; + + QFile f(testFile("noqmlcontext.js")); + QVERIFY(f.open(QIODevice::ReadOnly)); + QString script = QString::fromUtf8(f.readAll()); + QJSValue testFunction = engine.evaluate(script); + QVERIFY(testFunction.isCallable()); + + QJSValue resultCollector = engine.newObject(); + + testFunction.call(QJSValueList() << url.toString() << resultCollector); + + QTRY_COMPARE(resultCollector.property("responseText").toString(), "QML Rocks!\n"); + } + void tst_qqmlxmlhttprequest::stateChangeCallingContext() { #ifdef Q_OS_WIN diff --git a/tests/auto/qml/qv4assembler/qv4assembler.pro b/tests/auto/qml/qv4assembler/qv4assembler.pro new file mode 100644 index 0000000000..afd7586ac7 --- /dev/null +++ b/tests/auto/qml/qv4assembler/qv4assembler.pro @@ -0,0 +1,7 @@ +CONFIG += testcase +TARGET = tst_qv4assembler +macos:CONFIG -= app_bundle + +SOURCES += tst_qv4assembler.cpp + +QT += qml-private testlib diff --git a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp new file mode 100644 index 0000000000..9bd1afa256 --- /dev/null +++ b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qprocess.h> +#include <QtCore/qtemporaryfile.h> + +class tst_QV4Assembler : public QObject +{ + Q_OBJECT + +private slots: + void perfMapFile(); +}; + +void tst_QV4Assembler::perfMapFile() +{ +#if !defined(Q_OS_LINUX) + QSKIP("perf map files are only generated on linux"); +#else + const QString qmljs = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs"; + QProcess process; + + QTemporaryFile infile; + QVERIFY(infile.open()); + infile.write("'use strict'; function foo() { return 42 }; foo();"); + infile.close(); + + QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); + environment.insert("QV4_PROFILE_WRITE_PERF_MAP", "1"); + environment.insert("QV4_JIT_CALL_THRESHOLD", "0"); + + process.setProcessEnvironment(environment); + process.start(qmljs, QStringList({infile.fileName()})); + QVERIFY(process.waitForStarted()); + const qint64 pid = process.processId(); + QVERIFY(pid != 0); + QVERIFY(process.waitForFinished()); + QCOMPARE(process.exitCode(), 0); + + QFile file(QString::fromLatin1("/tmp/perf-%1.map").arg(pid)); + QVERIFY(file.exists()); + QVERIFY(file.open(QIODevice::ReadOnly)); + QList<QByteArray> functions; + while (!file.atEnd()) { + const QByteArray contents = file.readLine(); + QVERIFY(contents.endsWith('\n')); + QList<QByteArray> fields = contents.split(' '); + QCOMPARE(fields.length(), 3); + bool ok = false; + const qulonglong address = fields[0].toULongLong(&ok, 16); + QVERIFY(ok); + QVERIFY(address > 0); + const ulong size = fields[1].toULong(&ok, 16); + QVERIFY(ok); + QVERIFY(size > 0); + functions.append(fields[2]); + } + QVERIFY(functions.contains("foo\n")); +#endif +} + +QTEST_MAIN(tst_QV4Assembler) + +#include "tst_qv4assembler.moc" + diff --git a/tests/auto/qmltest/statemachine/tst_triggeredArguments2.qml b/tests/auto/qmltest/statemachine/tst_triggeredArguments2.qml index 73bc653404..f23cc14152 100644 --- a/tests/auto/qmltest/statemachine/tst_triggeredArguments2.qml +++ b/tests/auto/qmltest/statemachine/tst_triggeredArguments2.qml @@ -67,7 +67,6 @@ TestCase { // Emit the signalTrans.signal testCase.mysignal("test1", true, 2) - expectFail("", "QTBUG-50328") compare(testCase.mystr, "test1") compare(testCase.mybool, true) compare(testCase.myint, 2) diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp index 716651ec0c..eee8dfcf26 100644 --- a/tests/auto/quick/examples/tst_examples.cpp +++ b/tests/auto/quick/examples/tst_examples.cpp @@ -86,6 +86,7 @@ tst_examples::tst_examples() excludedDirs << "snippets/qml/visualdatamodel_rootindex"; excludedDirs << "snippets/qml/qtbinding"; excludedDirs << "snippets/qml/imports"; + excludedFiles << "snippets/qml/image-ext.qml"; excludedFiles << "examples/quick/shapes/content/main.qml"; // relies on resources excludedFiles << "examples/quick/shapes/content/interactive.qml"; // relies on resources diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index 3613ba6d87..d1f46a3912 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -445,6 +445,12 @@ void tst_qquickimage::svg() // Due to aspect ratio calculations we can't get a precise // check for all setups, so we allow a small margin of error QVERIFY(qAbs(obj->height() - 141) < 1); + + // Setting it to a size bigger than the actual file, SVG formats + // can scale up although other image formats cannot + obj->setSourceSize(QSize(800,0)); + QCOMPARE(obj->width(), 800.0); + QVERIFY(qAbs(obj->height() - 1131) < 1); delete obj; } diff --git a/tests/auto/quick/qquickitem/BLACKLIST b/tests/auto/quick/qquickitem/BLACKLIST index f00b061356..d94a3ef102 100644 --- a/tests/auto/quick/qquickitem/BLACKLIST +++ b/tests/auto/quick/qquickitem/BLACKLIST @@ -1,4 +1,2 @@ [contains:hollow square: testing points inside] xcb -[ignoreButtonPressNotInAcceptedMouseButtons] -* diff --git a/tests/auto/quick/qquickloader/data/rootContext.qml b/tests/auto/quick/qquickloader/data/rootContext.qml new file mode 100644 index 0000000000..277db43d57 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/rootContext.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + width: 360 + height: 360 + + property alias loader: loader + + Loader { + id: loader + } + + property Component component: Item { + property bool trigger: false + onTriggerChanged: { + objectInRootContext.doIt() // make sure we can resolve objectInRootContext + loader.active = false + objectInRootContext.doIt() // make sure we can STILL resolve objectInRootContext + anotherProperty = true // see if we can trigger subsequent signal handlers (we shouldn't) + } + property bool anotherProperty: false + onAnotherPropertyChanged: { + // this should never be executed + objectInRootContext.doIt() + } + } +} diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index 30fc52f95a..7a176661e8 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -29,6 +29,7 @@ #include <QSignalSpy> +#include <QtQml/QQmlContext> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> #include <QtQml/qqmlincubator.h> @@ -123,6 +124,8 @@ private slots: void bindings(); void parentErrors(); + + void rootContext(); }; Q_DECLARE_METATYPE(QList<QQmlError>) @@ -1327,6 +1330,64 @@ void tst_QQuickLoader::parentErrors() QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage)); } +class ObjectInRootContext: public QObject +{ + Q_OBJECT + +public: + int didIt = 0; + +public slots: + void doIt() { + didIt += 1; + } +}; + +void tst_QQuickLoader::rootContext() +{ + QQmlEngine engine; + ObjectInRootContext objectInRootContext; + engine.rootContext()->setContextProperty("objectInRootContext", &objectInRootContext); + + QQmlComponent component(&engine, testFileUrl("rootContext.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QQuickLoader *loader = object->property("loader").value<QQuickLoader*>(); + QVERIFY(loader); + + QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>))); + + // Give the loader a component + loader->setSourceComponent(object->property("component").value<QQmlComponent*>()); + QTRY_VERIFY(loader->active()); + QTRY_VERIFY(loader->item()); + + QString failureMessage; + if (!warningsSpy.isEmpty()) { + QDebug stream(&failureMessage); + stream << warningsSpy.first().first().value<QList<QQmlError>>(); + } + QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage)); + QCOMPARE(objectInRootContext.didIt, 0); + + // Deactivate the loader, which deletes the item. + // Check that a) there are no errors, and b) the objectInRootContext can still be resolved even + // after deactivating the loader. If it cannot, a ReferenceError for objectInRootContext is + // generated (and the 'doIt' counter in objectInRootContext will be 1 for the call before + // the deactivation). + loader->item()->setProperty("trigger", true); + QTRY_VERIFY(!loader->active()); + QTRY_VERIFY(!loader->item()); + + if (!warningsSpy.isEmpty()) { + QDebug stream(&failureMessage); + stream << warningsSpy.first().first().value<QList<QQmlError>>(); + } + QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage)); + QCOMPARE(objectInRootContext.didIt, 2); +} + QTEST_MAIN(tst_QQuickLoader) #include "tst_qquickloader.moc" diff --git a/tests/auto/quick/qquicktext/data/elideParentChanged.qml b/tests/auto/quick/qquicktext/data/elideParentChanged.qml new file mode 100644 index 0000000000..f605cf58f1 --- /dev/null +++ b/tests/auto/quick/qquicktext/data/elideParentChanged.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Item { + width: 100 + height: 30 + + Text { + width: parent ? parent.width : 0 + height: parent ? parent.height : 0 + elide: Text.ElideRight + text: "wot" + } +} diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index 609a84ce82..89d2590c03 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -38,6 +38,7 @@ #include <QFontMetrics> #include <qmath.h> #include <QtQuick/QQuickView> +#include <QtQuick/qquickitemgrabresult.h> #include <private/qguiapplication_p.h> #include <limits.h> #include <QtGui/QMouseEvent> @@ -64,6 +65,7 @@ private slots: void width(); void wrap(); void elide(); + void elideParentChanged(); void multilineElide_data(); void multilineElide(); void implicitElide_data(); @@ -554,6 +556,45 @@ void tst_qquicktext::elide() } } +// QTBUG-60328 +// Tests that text with elide set is rendered after +// having its parent cleared and then set again. +void tst_qquicktext::elideParentChanged() +{ + QQuickView window; + window.setSource(testFileUrl("elideParentChanged.qml")); + QTRY_COMPARE(window.status(), QQuickView::Ready); + + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + QQuickItem *root = window.rootObject(); + QVERIFY(root); + QCOMPARE(root->childItems().size(), 1); + + // Store a snapshot of the scene so that we can compare it later. + QSharedPointer<QQuickItemGrabResult> grabResult = root->grabToImage(); + QTRY_VERIFY(!grabResult->image().isNull()); + const QImage expectedItemImageGrab(grabResult->image()); + + // Clear the text's parent. It shouldn't render anything. + QQuickItem *text = root->childItems().first(); + text->setParentItem(nullptr); + QCOMPARE(text->width(), 0.0); + QCOMPARE(text->height(), 0.0); + + // Set the parent back to what it was. The text should + // be rendered identically to how it was before. + text->setParentItem(root); + QCOMPARE(text->width(), 100.0); + QCOMPARE(text->height(), 30.0); + + grabResult = root->grabToImage(); + QTRY_VERIFY(!grabResult->image().isNull()); + const QImage actualItemImageGrab(grabResult->image()); + QCOMPARE(actualItemImageGrab, expectedItemImageGrab); +} + void tst_qquicktext::multilineElide_data() { QTest::addColumn<QQuickText::TextFormat>("format"); diff --git a/tests/auto/quickwidgets/qquickwidget/data/activeFocusOnTab.qml b/tests/auto/quickwidgets/qquickwidget/data/activeFocusOnTab.qml new file mode 100644 index 0000000000..9ad1cafed9 --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/data/activeFocusOnTab.qml @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 + +Item { + Rectangle { + objectName: "topRect" + x: 0 + width: 50 + height: 50 + activeFocusOnTab: true + focus: true + color: activeFocus ? "green" : "red" + } + Rectangle { + objectName: "middleRect" + x: 50 + width: 50 + height: 50 + focus: true + activeFocusOnTab: true + color: activeFocus ? "green" : "red" + } + Rectangle { + objectName: "bottomRect" + x: 100 + width: 50 + height: 50 + focus: true + activeFocusOnTab: true + color: activeFocus ? "green" : "red" + } +} + diff --git a/tests/auto/quickwidgets/qquickwidget/data/noActiveFocusOnTab.qml b/tests/auto/quickwidgets/qquickwidget/data/noActiveFocusOnTab.qml new file mode 100644 index 0000000000..6d86ce45bb --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/data/noActiveFocusOnTab.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 + +Item { + Rectangle { + objectName: "topRect2" + x: 0 + width: 50 + height: 50 + focus: true + color: activeFocus ? "green" : "red" + } + Rectangle { + objectName: "middleRect2" + x: 50 + width: 50 + height: 50 + focus: true + color: activeFocus ? "green" : "red" + } + Rectangle { + objectName: "bottomRect3" + x: 100 + width: 50 + height: 50 + focus: true + color: activeFocus ? "green" : "red" + } +} + diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp index a97e3c0538..af358925fe 100644 --- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp +++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp @@ -40,7 +40,7 @@ #include <QtQml/qqmlengine.h> #include <QtCore/QLoggingCategory> - +#include <QtGui/qstylehints.h> #include <QtWidgets/QBoxLayout> #include <QtWidgets/QLabel> @@ -140,6 +140,7 @@ private slots: void mouseEventWindowPos(); void synthMouseFromTouch_data(); void synthMouseFromTouch(); + void tabKey(); private: QTouchDevice *device = QTest::createTouchDevice(); @@ -620,6 +621,43 @@ void tst_qquickwidget::synthMouseFromTouch() QCOMPARE(ev.source(), Qt::MouseEventSynthesizedByQt); } +void tst_qquickwidget::tabKey() +{ + if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls) + QSKIP("This function doesn't support NOT iterating all."); + QWidget window1; + QQuickWidget *qqw = new QQuickWidget(&window1); + qqw->setSource(testFileUrl("activeFocusOnTab.qml")); + QQuickWidget *qqw2 = new QQuickWidget(&window1); + qqw2->setSource(testFileUrl("noActiveFocusOnTab.qml")); + qqw2->move(100, 0); + window1.show(); + qqw->setFocus(); + QVERIFY(QTest::qWaitForWindowExposed(&window1, 5000)); + QVERIFY(qqw->hasFocus()); + QQuickItem *item = qobject_cast<QQuickItem *>(qqw->rootObject()); + QQuickItem *topItem = item->findChild<QQuickItem *>("topRect"); + QQuickItem *middleItem = item->findChild<QQuickItem *>("middleRect"); + QQuickItem *bottomItem = item->findChild<QQuickItem *>("bottomRect"); + topItem->forceActiveFocus(); + QVERIFY(topItem->property("activeFocus").toBool()); + QTest::keyClick(qqw, Qt::Key_Tab); + QTRY_VERIFY(middleItem->property("activeFocus").toBool()); + QTest::keyClick(qqw, Qt::Key_Tab); + QTRY_VERIFY(bottomItem->property("activeFocus").toBool()); + QTest::keyClick(qqw, Qt::Key_Backtab); + QTRY_VERIFY(middleItem->property("activeFocus").toBool()); + + qqw2->setFocus(); + QQuickItem *item2 = qobject_cast<QQuickItem *>(qqw2->rootObject()); + QQuickItem *topItem2 = item2->findChild<QQuickItem *>("topRect2"); + QTRY_VERIFY(qqw2->hasFocus()); + QVERIFY(topItem2->property("activeFocus").toBool()); + QTest::keyClick(qqw2, Qt::Key_Tab); + QTRY_VERIFY(qqw->hasFocus()); + QVERIFY(middleItem->property("activeFocus").toBool()); +} + QTEST_MAIN(tst_qquickwidget) #include "tst_qquickwidget.moc" |