aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp23
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp35
-rw-r--r--tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp61
-rw-r--r--tests/auto/qml/qqmlcontext/data/Singleton.qml5
-rw-r--r--tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml14
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp28
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.cpp9
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h5
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp22
-rw-r--r--tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro2
-rw-r--r--tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp59
-rw-r--r--tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp2
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h20
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp18
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp23
-rw-r--r--tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp4
-rw-r--r--tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp10
-rw-r--r--tests/auto/quick/qquickgridview/tst_qquickgridview.cpp2
-rw-r--r--tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml19
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp30
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml40
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp2
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp13
25 files changed, 424 insertions, 33 deletions
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index a3a2efd565..446f9b04a7 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -145,6 +145,7 @@ private slots:
void array_join_QTBUG_53672();
void regexpLastMatch();
+ void regexpLastIndex();
void indexedAccesses();
void prototypeChainGc();
@@ -3289,6 +3290,28 @@ void tst_QJSEngine::regexpLastMatch()
}
+void tst_QJSEngine::regexpLastIndex()
+{
+ QJSEngine eng;
+ QJSValue result;
+ result = eng.evaluate("function test(text, rx) {"
+ " var res;"
+ " while (res = rx.exec(text)) { "
+ " return true;"
+ " }"
+ " return false;"
+ " }"
+ "function tester(text) {"
+ " return test(text, /,\\s*/g);"
+ "}");
+ QVERIFY(!result.isError());
+
+ result = eng.evaluate("tester(\", \\n\");");
+ QVERIFY(result.toBool());
+ result = eng.evaluate("tester(\", \\n\");");
+ QVERIFY(result.toBool());
+}
+
void tst_QJSEngine::indexedAccesses()
{
QJSEngine engine;
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index 1f80ff46d0..7e81df93b9 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -44,6 +44,7 @@ private slots:
void loadGeneratedFile();
void translationExpressionSupport();
void signalHandlerParameters();
+ void errorOnArgumentsInSignalHandler();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -68,15 +69,20 @@ public:
}
};
-static bool generateCache(const QString &qmlFileName)
+static bool generateCache(const QString &qmlFileName, QByteArray *capturedStderr = nullptr)
{
QProcess proc;
- proc.setProcessChannelMode(QProcess::ForwardedChannels);
+ if (capturedStderr == nullptr)
+ proc.setProcessChannelMode(QProcess::ForwardedChannels);
proc.setProgram(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator() + QLatin1String("qmlcachegen"));
proc.setArguments(QStringList() << (QLatin1String("--target-architecture=") + QSysInfo::buildCpuArchitecture()) << (QLatin1String("--target-abi=") + QSysInfo::buildAbi()) << qmlFileName);
proc.start();
if (!proc.waitForFinished())
return false;
+
+ if (capturedStderr)
+ *capturedStderr = proc.readAllStandardError();
+
if (proc.exitStatus() != QProcess::NormalExit)
return false;
return proc.exitCode() == 0;
@@ -194,6 +200,31 @@ void tst_qmlcachegen::signalHandlerParameters()
QCOMPARE(obj->property("result").toInt(), 42);
}
+void tst_qmlcachegen::errorOnArgumentsInSignalHandler()
+{
+ 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 QtQml 2.2\n"
+ "QtObject {\n"
+ " signal mySignal(var arguments);\n"
+ " onMySignal: console.log(arguments);\n"
+ "}");
+
+
+ QByteArray errorOutput;
+ QVERIFY(!generateCache(testFilePath, &errorOutput));
+ QVERIFY2(errorOutput.contains("error: The use of the arguments object in signal handlers is"), errorOutput);
+}
+
QTEST_GUILESS_MAIN(tst_qmlcachegen)
#include "tst_qmlcachegen.moc"
diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
index 6ab84774f2..e75e51ed29 100644
--- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
+++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp
@@ -59,6 +59,7 @@ private slots:
void cacheResources();
void stableOrderOfDependentCompositeTypes();
void singletonDependency();
+ void cppRegisteredSingletonDependency();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -790,6 +791,66 @@ void tst_qmldiskcache::singletonDependency()
}
}
+void tst_qmldiskcache::cppRegisteredSingletonDependency()
+{
+ qmlClearTypeRegistrations();
+ QScopedPointer<QQmlEngine> engine(new QQmlEngine);
+
+ 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();
+ };
+
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 42 }");
+
+ qmlRegisterSingletonType(QUrl::fromLocalFile(tempDir.path() + QLatin1String("/MySingleton.qml")), "CppRegisteredSingletonDependency", 1, 0, "Singly");
+
+ const QString testFilePath = writeTempFile("main.qml", "import QtQml 2.0\nimport CppRegisteredSingletonDependency 1.0\nQtObject {\n"
+ " function getValue() { return Singly.value; }\n"
+ "}");
+
+ {
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QVariant value;
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "getValue", Q_RETURN_ARG(QVariant, value)));
+ QCOMPARE(value.toInt(), 42);
+ }
+
+ const QString testFileCachePath = testFilePath + QLatin1Char('c');
+ QVERIFY(QFile::exists(testFileCachePath));
+ QDateTime initialCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
+
+ engine.reset(new QQmlEngine);
+ waitForFileSystem();
+
+ writeTempFile("MySingleton.qml", "import QtQml 2.0\npragma Singleton\nQtObject { property int value: 100 }");
+ waitForFileSystem();
+
+ {
+ CleanlyLoadingComponent component(engine.data(), QUrl::fromLocalFile(testFilePath));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ {
+ QVERIFY(QFile::exists(testFileCachePath));
+ QDateTime newCacheTimeStamp = QFileInfo(testFileCachePath).lastModified();
+ QVERIFY2(newCacheTimeStamp > initialCacheTimeStamp, qPrintable(newCacheTimeStamp.toString()));
+ }
+
+ QVariant value;
+ QVERIFY(QMetaObject::invokeMethod(obj.data(), "getValue", Q_RETURN_ARG(QVariant, value)));
+ QCOMPARE(value.toInt(), 100);
+ }
+}
+
QTEST_MAIN(tst_qmldiskcache)
#include "tst_qmldiskcache.moc"
diff --git a/tests/auto/qml/qqmlcontext/data/Singleton.qml b/tests/auto/qml/qqmlcontext/data/Singleton.qml
new file mode 100644
index 0000000000..68ef5850e3
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/Singleton.qml
@@ -0,0 +1,5 @@
+pragma Singleton
+import QtQml 2.0
+QtObject {
+ readonly property string song: "Highway to Hell"
+}
diff --git a/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml b/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml
new file mode 100644
index 0000000000..2e0e6f20e2
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml
@@ -0,0 +1,14 @@
+import QtQml 2.0
+
+import constants 1.0
+
+QtObject {
+ function createClosure() {
+ return function() { return Sing.song; }
+ }
+ function createComponentFactory() {
+ return function(parentObj) {
+ return Qt.createQmlObject('import QtQml 2.0; QtObject { property string test: "ok"; }', parentObj);
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index f49fd391ac..5f57b9ebb0 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -62,6 +62,7 @@ private slots:
void evalAfterInvalidate();
void qobjectDerived();
void qtbug_49232();
+ void contextViaClosureAfterDestruction();
private:
QQmlEngine engine;
@@ -723,6 +724,33 @@ void tst_qqmlcontext::qtbug_49232()
QCOMPARE(obj->property("valueTwo"), QVariant(97));
}
+void tst_qqmlcontext::contextViaClosureAfterDestruction()
+{
+ qmlRegisterSingletonType(testFileUrl("Singleton.qml"), "constants", 1, 0, "Sing");
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("contextViaClosureAfterDestruction.qml"));
+ QJSValue valueClosure;
+ QJSValue componentFactoryClosure;
+ {
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ // meta-calls don't support QJSValue return types, so do the call "by hand"
+ valueClosure = engine.newQObject(obj.data()).property(QStringLiteral("createClosure")).call();
+ QVERIFY(valueClosure.isCallable());
+ componentFactoryClosure = engine.newQObject(obj.data()).property(QStringLiteral("createComponentFactory")).call();
+ QVERIFY(componentFactoryClosure.isCallable());
+ }
+ QCOMPARE(valueClosure.call().toString(), QLatin1String("Highway to Hell"));
+
+ QScopedPointer<QObject> parent(new QObject);
+ QJSValue parentWrapper = engine.newQObject(parent.data());
+ QQmlEngine::setObjectOwnership(parent.data(), QQmlEngine::CppOwnership);
+
+ QJSValue subObject = componentFactoryClosure.callWithInstance(componentFactoryClosure, QJSValueList() << parentWrapper);
+ QVERIFY(subObject.isError());
+ QCOMPARE(subObject.toString(), QLatin1String("Error: Qt.createQmlObject(): Cannot create a component in an invalid context"));
+}
+
QTEST_MAIN(tst_qqmlcontext)
#include "tst_qqmlcontext.moc"
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp
index c4692fdf31..80da5d7e52 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.cpp
+++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp
@@ -245,9 +245,16 @@ public:
MyWorkerObject *o;
};
+MyWorkerObject::~MyWorkerObject()
+{
+ if (m_thread)
+ m_thread->wait();
+}
+
void MyWorkerObject::doIt()
{
- new MyWorkerObjectThread(this);
+ Q_ASSERT(!m_thread);
+ m_thread = new MyWorkerObjectThread(this);
}
class MyDateClass : public QObject
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
index eedeb66647..e15a05a00c 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.h
+++ b/tests/auto/qml/qqmlecmascript/testtypes.h
@@ -1532,12 +1532,17 @@ private:
class MyWorkerObject : public QObject
{
Q_OBJECT
+public:
+ ~MyWorkerObject();
public Q_SLOTS:
void doIt();
Q_SIGNALS:
void done(const QString &result);
+
+private:
+ QThread *m_thread = 0;
};
class MyUnregisteredEnumTypeObject : public QObject
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 45f312e934..35f1534478 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -7444,21 +7444,17 @@ void tst_qqmlecmascript::signalEmitted()
void tst_qqmlecmascript::threadSignal()
{
{
- QQmlComponent c(&engine, testFileUrl("threadSignal.qml"));
- QObject *object = c.create();
- QVERIFY(object != 0);
- QTRY_VERIFY(object->property("passed").toBool());
- delete object;
+ QQmlComponent c(&engine, testFileUrl("threadSignal.qml"));
+ QScopedPointer<QObject> object(c.create());
+ QVERIFY(!object.isNull());
+ QTRY_VERIFY(object->property("passed").toBool());
}
{
- QQmlComponent c(&engine, testFileUrl("threadSignal.2.qml"));
- QObject *object = c.create();
- QVERIFY(object != 0);
- QSignalSpy doneSpy(object, SIGNAL(done(QString)));
- QMetaObject::invokeMethod(object, "doIt");
- QTRY_VERIFY(object->property("passed").toBool());
- QCOMPARE(doneSpy.count(), 1);
- delete object;
+ QQmlComponent c(&engine, testFileUrl("threadSignal.2.qml"));
+ QScopedPointer<QObject> object(c.create());
+ QVERIFY(!object.isNull());
+ QMetaObject::invokeMethod(object.data(), "doIt");
+ QTRY_VERIFY(object->property("passed").toBool());
}
}
diff --git a/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro b/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro
index 5bcec9f5b4..90508609a8 100644
--- a/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro
+++ b/tests/auto/qml/qqmlenginecleanup/qqmlenginecleanup.pro
@@ -6,4 +6,4 @@ include (../../shared/util.pri)
SOURCES += tst_qqmlenginecleanup.cpp
-QT += testlib qml
+QT += testlib qml qml-private
diff --git a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
index d0a8b6401f..7e9a1524b0 100644
--- a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
+++ b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
@@ -31,6 +31,8 @@
#include <QtQml/qqml.h>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlComponent>
+#include <private/qhashedstring_p.h>
+#include <private/qqmlmetatype_p.h>
//Separate test, because if engine cleanup attempts fail they can easily break unrelated tests
class tst_qqmlenginecleanup : public QQmlDataTest
@@ -44,41 +46,82 @@ private slots:
void test_valueTypeProviderModule(); // QTBUG-43004
};
+// A wrapper around QQmlComponent to ensure the temporary reference counts
+// on the type data as a result of the main thread <> loader thread communication
+// are dropped. Regular Synchronous loading will leave us with an event posted
+// to the gui thread and an extra refcount that will only be dropped after the
+// event delivery. A plain sendPostedEvents() however is insufficient because
+// we can't be sure that the event is posted after the constructor finished.
+class CleanlyLoadingComponent : public QQmlComponent
+{
+public:
+ CleanlyLoadingComponent(QQmlEngine *engine, const QUrl &url)
+ : QQmlComponent(engine, url, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+ CleanlyLoadingComponent(QQmlEngine *engine, const QString &fileName)
+ : QQmlComponent(engine, fileName, QQmlComponent::Asynchronous)
+ { waitForLoad(); }
+
+ void waitForLoad()
+ {
+ QTRY_VERIFY(status() == QQmlComponent::Ready || status() == QQmlComponent::Error);
+ }
+};
+
void tst_qqmlenginecleanup::test_qmlClearTypeRegistrations()
{
//Test for preventing memory leaks is in tests/manual/qmltypememory
QQmlEngine* engine;
- QQmlComponent* component;
+ CleanlyLoadingComponent* component;
QUrl testFile = testFileUrl("types.qml");
+ const auto qmlTypeForTestType = []() {
+ return QQmlMetaType::qmlType(QStringLiteral("TestTypeCpp"), QStringLiteral("Test"), 2, 0);
+ };
+
+ QVERIFY(!qmlTypeForTestType().isValid());
qmlRegisterType<QObject>("Test", 2, 0, "TestTypeCpp");
+ QVERIFY(qmlTypeForTestType().isValid());
+
engine = new QQmlEngine;
- component = new QQmlComponent(engine, testFile);
+ component = new CleanlyLoadingComponent(engine, testFile);
QVERIFY(component->isReady());
- delete engine;
delete component;
- qmlClearTypeRegistrations();
+ delete engine;
+
+ {
+ auto cppType = qmlTypeForTestType();
+
+ qmlClearTypeRegistrations();
+ QVERIFY(!qmlTypeForTestType().isValid());
+
+ // cppType should hold the last ref, qmlClearTypeRegistration should have wiped
+ // all internal references.
+ QCOMPARE(QQmlType::refCount(cppType.priv()), 1);
+ }
//2nd run verifies that types can reload after a qmlClearTypeRegistrations
qmlRegisterType<QObject>("Test", 2, 0, "TestTypeCpp");
+ QVERIFY(qmlTypeForTestType().isValid());
engine = new QQmlEngine;
- component = new QQmlComponent(engine, testFile);
+ component = new CleanlyLoadingComponent(engine, testFile);
QVERIFY(component->isReady());
- delete engine;
delete component;
+ delete engine;
qmlClearTypeRegistrations();
+ QVERIFY(!qmlTypeForTestType().isValid());
//3nd run verifies that TestTypeCpp is no longer registered
engine = new QQmlEngine;
- component = new QQmlComponent(engine, testFile);
+ component = new CleanlyLoadingComponent(engine, testFile);
QVERIFY(component->isError());
QCOMPARE(component->errorString(),
testFile.toString() +":33 module \"Test\" is not installed\n");
- delete engine;
delete component;
+ delete engine;
}
static void cleanState(QQmlEngine **e)
diff --git a/tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml b/tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml
new file mode 100644
index 0000000000..f311f6b602
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml
@@ -0,0 +1,6 @@
+import QtQml 2.0
+import Test 1.0
+LazyDeferredSubObject {
+ subObject: QtObject { objectName: 'default' }
+ objectName: subObject.objectName
+}
diff --git a/tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml b/tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml
new file mode 100644
index 0000000000..2465a18320
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+import Test 1.0
+MyLazyDeferredSubObject {
+ subObject.objectName: 'custom'
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index bdcdaa8137..72e06d26aa 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -103,6 +103,8 @@ void registerTypes()
qmlRegisterSingletonType<MyTypeObjectSingleton>("Test", 1, 0, "MyTypeObjectSingleton", myTypeObjectSingleton);
qmlRegisterType<MyArrayBufferTestClass>("Test", 1, 0, "MyArrayBufferTestClass");
+
+ qmlRegisterType<LazyDeferredSubObject>("Test", 1, 0, "LazyDeferredSubObject");
}
QVariant myCustomVariantTypeConverter(const QString &data)
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index e4a76b4324..09c6992a51 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -1349,6 +1349,26 @@ private:
QObject *obj;
};
+class LazyDeferredSubObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *subObject READ subObject WRITE setSubObject NOTIFY subObjectChanged FINAL)
+ Q_CLASSINFO("DeferredPropertyNames", "subObject");
+public:
+ LazyDeferredSubObject()
+ : obj(0)
+ {}
+
+ QObject *subObject() const { if (!obj) qmlExecuteDeferred(const_cast<LazyDeferredSubObject *>(this)); return obj; }
+ void setSubObject(QObject *o) { if (obj == o) return; obj = o; emit subObjectChanged(); }
+
+signals:
+ void subObjectChanged();
+
+private:
+ QObject *obj;
+};
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index f09c130e38..e5366b5c48 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -250,6 +250,7 @@ private slots:
void propertyCacheInSync();
void rootObjectInCreationNotForSubObjects();
+ void lazyDeferredSubObject();
void noChildEvents();
@@ -2152,7 +2153,7 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
td->compilationUnit()->data = qmlUnit;
- const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
+ const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(/*root object*/0);
QCOMPARE(qmlUnit->stringAt(rootObject->inheritedTypeNameIndex), QString("MyTypeObject"));
quint32 i;
for (i = 0; i < rootObject->nBindings; ++i) {
@@ -4314,6 +4315,21 @@ void tst_qqmllanguage::rootObjectInCreationNotForSubObjects()
QVERIFY(!ddata->rootObjectInCreation);
}
+// QTBUG-63036
+void tst_qqmllanguage::lazyDeferredSubObject()
+{
+ QQmlComponent component(&engine, testFile("lazyDeferredSubObject.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QObject *subObject = qvariant_cast<QObject *>(object->property("subObject"));
+ QVERIFY(subObject);
+
+ QCOMPARE(object->objectName(), QStringLiteral("custom"));
+ QCOMPARE(subObject->objectName(), QStringLiteral("custom"));
+}
+
void tst_qqmllanguage::noChildEvents()
{
QQmlComponent component(&engine);
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index e442dd1421..4089673d68 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -123,6 +123,7 @@ private slots:
void about_to_be_signals();
void modify_through_delegate();
void bindingsOnGetResult();
+ void stringifyModelEntry();
};
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@@ -1482,6 +1483,28 @@ void tst_qqmllistmodel::bindingsOnGetResult()
QVERIFY(obj->property("success").toBool());
}
+void tst_qqmllistmodel::stringifyModelEntry()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(
+ "import QtQuick 2.0\n"
+ "Item {\n"
+ " ListModel {\n"
+ " id: testModel\n"
+ " objectName: \"testModel\"\n"
+ " ListElement { name: \"Joe\"; age: 22 }\n"
+ " }\n"
+ "}\n", QUrl());
+ QScopedPointer<QObject> scene(component.create());
+ QQmlListModel *model = scene->findChild<QQmlListModel*>("testModel");
+ QQmlExpression expr(engine.rootContext(), model, "JSON.stringify(get(0));");
+ QVariant v = expr.evaluate();
+ QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString()));
+ const QString expectedString = QStringLiteral("{\"age\":22,\"name\":\"Joe\"}");
+ QCOMPARE(v.toString(), expectedString);
+}
+
QTEST_MAIN(tst_qqmllistmodel)
#include "tst_qqmllistmodel.moc"
diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
index 1c9523fc38..80c54bdf8e 100644
--- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
+++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
@@ -86,7 +86,7 @@ void tst_qqmltranslation::translation()
<< QStringLiteral("singular") << QStringLiteral("plural");
const QV4::CompiledData::Unit *unit = compilationUnit->data;
- const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject);
+ const QV4::CompiledData::Object *rootObject = unit->objectAt(/*root object*/0);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
const QString propertyName = unit->stringAt(binding->propertyNameIndex);
@@ -141,7 +141,7 @@ void tst_qqmltranslation::idTranslation()
QVERIFY(compilationUnit);
const QV4::CompiledData::Unit *unit = compilationUnit->data;
- const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject);
+ const QV4::CompiledData::Object *rootObject = unit->objectAt(/*root object*/0);
const QV4::CompiledData::Binding *binding = rootObject->bindingTable();
for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) {
const QString propertyName = unit->stringAt(binding->propertyNameIndex);
diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
index 34b9fb6b07..e303495944 100644
--- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
+++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
@@ -132,6 +132,16 @@ void tst_qquickanimatedimage::frameCount()
QVERIFY(anim->isPlaying());
QCOMPARE(anim->frameCount(), 3);
+ QSignalSpy frameCountChangedSpy(anim, &QQuickAnimatedImage::frameCountChanged);
+
+ const QUrl origSource = anim->source();
+ anim->setSource(QUrl());
+ QCOMPARE(anim->frameCount(), 0);
+ QCOMPARE(frameCountChangedSpy.count(), 1);
+ anim->setSource(origSource);
+ QCOMPARE(anim->frameCount(), 3);
+ QCOMPARE(frameCountChangedSpy.count(), 2);
+
delete anim;
}
diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
index b2d6584701..2b14842658 100644
--- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
+++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
@@ -46,6 +46,8 @@
#include <QtGui/qguiapplication.h>
#include "qplatformdefs.h"
+#include <math.h>
+
Q_DECLARE_METATYPE(QQuickGridView::Flow)
Q_DECLARE_METATYPE(Qt::LayoutDirection)
Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection)
diff --git a/tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml b/tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml
new file mode 100644
index 0000000000..bd913b2ce1
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.9
+
+ListView {
+ id: view
+ width: 200; height: 400
+
+ property real minOvershoot
+ onVerticalOvershootChanged: if (verticalOvershoot < minOvershoot) minOvershoot = verticalOvershoot
+
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ preferredHighlightBegin: 0
+ preferredHighlightEnd: 0
+
+ model: 10
+ delegate: Rectangle {
+ width: 200; height: 50
+ color: index % 2 ? "red" : "green"
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 2eb87b9431..0d0f234d33 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -236,6 +236,7 @@ private slots:
void QTBUG_38209();
void programmaticFlickAtBounds();
void programmaticFlickAtBounds2();
+ void programmaticFlickAtBounds3();
void layoutChange();
@@ -8069,6 +8070,35 @@ void tst_QQuickListView::programmaticFlickAtBounds2()
QTRY_COMPARE(listview->contentY(), qreal(100.0));
}
+void tst_QQuickListView::programmaticFlickAtBounds3()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("programmaticFlickAtBounds3.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = qobject_cast<QQuickListView *>(window->rootObject());
+ QVERIFY(listview);
+
+ // flick down
+ listview->flick(0, 2000);
+
+ // verify scope of the movement
+ QTRY_VERIFY(listview->property("minOvershoot").toReal() < qreal(-50.0));
+
+ // reset, and test a second time
+ listview->cancelFlick();
+ listview->returnToBounds();
+ QTRY_COMPARE(listview->contentY(), qreal(0.0));
+ listview->setProperty("minOvershoot", qreal(0.0));
+
+ // flick down
+ listview->flick(0, 2000);
+
+ // verify scope of the movement is the same
+ QTRY_VERIFY(listview->property("minOvershoot").toReal() < qreal(-50.0));
+}
+
void tst_QQuickListView::layoutChange()
{
RandomSortModel *model = new RandomSortModel;
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml
index 039607e26c..027f90c7f4 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml
@@ -11,9 +11,21 @@ Rectangle {
maximumTouchPoints: 2
onGestureStarted: gesture.grab()
touchPoints: [
- TouchPoint { objectName: "point11" },
- TouchPoint { objectName: "point12" }
+ TouchPoint { id: point11; objectName: "point11" },
+ TouchPoint { id: point12; objectName: "point12" }
]
+ Rectangle {
+ color: "red"
+ width: 10; height: 10; radius: 5
+ x: point11.x - radius; y: point11.y - radius
+ visible: point11.pressed
+ }
+ Rectangle {
+ color: "tomato"
+ width: 10; height: 10; radius: 5
+ x: point12.x - radius; y: point12.y - radius
+ visible: point12.pressed
+ }
}
MultiPointTouchArea {
@@ -24,9 +36,27 @@ Rectangle {
maximumTouchPoints: 3
onGestureStarted: gesture.grab()
touchPoints: [
- TouchPoint { objectName: "point21" },
- TouchPoint { objectName: "point22" },
- TouchPoint { objectName: "point23" }
+ TouchPoint { id: point21; objectName: "point21" },
+ TouchPoint { id: point22; objectName: "point22" },
+ TouchPoint { id: point23; objectName: "point23" }
]
+ Rectangle {
+ color: "lightgreen"
+ width: 10; height: 10; radius: 5
+ x: point21.x - radius; y: point21.y - radius
+ visible: point21.pressed
+ }
+ Rectangle {
+ color: "green"
+ width: 10; height: 10; radius: 5
+ x: point22.x - radius; y: point22.y - radius
+ visible: point22.pressed
+ }
+ Rectangle {
+ color: "darkgreen"
+ width: 10; height: 10; radius: 5
+ x: point23.x - radius; y: point23.y - radius
+ visible: point23.pressed
+ }
}
}
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index b01d0c3cec..cbef0fcc8d 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -48,6 +48,8 @@
#include "../shared/viewtestutil.h"
#include "../shared/visualtestutil.h"
+#include <math.h>
+
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index ac57a05176..d58fc6c389 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -158,6 +158,7 @@ private slots:
#endif
void implicitSize_data();
void implicitSize();
+ void implicitSize_QTBUG_63153();
void contentSize();
void boundingRect();
void clipRect();
@@ -3388,6 +3389,18 @@ void tst_qquicktextedit::implicitSize()
QCOMPARE(textObject->height(), textObject->implicitHeight());
}
+void tst_qquicktextedit::implicitSize_QTBUG_63153()
+{
+ QString componentStr = "import QtQuick 2.0\nTextEdit { }";
+ QQmlComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
+ textObject->setText("short");
+ qreal shortImplicitWidth = textObject->implicitWidth();
+ textObject->setText("in contrast to short this is long");
+ QVERIFY2(shortImplicitWidth < textObject->implicitWidth(), qPrintable(QString("%1 < %2").arg(textObject->implicitWidth()).arg(shortImplicitWidth)));
+}
+
void tst_qquicktextedit::contentSize()
{
QString componentStr = "import QtQuick 2.0\nTextEdit { width: 75; height: 16; font.pixelSize: 10 }";