From 560557c5d7d6b48dada2c9966577c718eab7d19d Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 5 Sep 2017 09:41:16 +0200 Subject: tst_qquickmultipointtoucharea nonOverlapping: add visual feedback It's difficult to troubleshoot autotests like this without being able to either see what's happening while it runs or test it manually. Task-number: QTBUG-59960 Change-Id: Iba7b03036f2f631c9b6d34d563ebae2de77acf1f Reviewed-by: Shawn Rutledge --- .../data/nonOverlapping.qml | 40 +++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'tests/auto') 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 + } } } -- cgit v1.2.3 From 131243b3c8d71febe5294f0035844cea8a9e3049 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 6 Sep 2017 10:30:03 +0200 Subject: Stabilize the threadSignal() test We've seen the case in the CI where we delete the worker thread object before it has had a chance (resulting in a crash). This patch attempts to stabilize this by waiting for the thread to terminate properly. In addition QSignalSpy's connection to the done(QString) signal is forced to be direct, which means the spy's internal list is accessed from the gui thread (via QCOMPARE) at the same time as the thread may be emitting the signal and calling the signalspy's slot (metacall), which helgrind complains about (rightly so). I don't see any purpose in connecting to the signal, so let's remove that code. The test continues to cover the threading code in QQmlData::signalEmitted, once as the thread is triggered via C++ and once via QML (doIt invocation). Change-Id: I5e8a4ae65e2d0890a26491d25c73de1ba33a6668 Reviewed-by: Ulf Hermann --- tests/auto/qml/qqmlecmascript/testtypes.cpp | 9 ++++++++- tests/auto/qml/qqmlecmascript/testtypes.h | 5 +++++ .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 22 +++++++++------------- 3 files changed, 22 insertions(+), 14 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index 63c2918325..13bb0435cd 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 7b9a43dc38..14c2aa18bf 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -7440,21 +7440,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 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 object(c.create()); + QVERIFY(!object.isNull()); + QMetaObject::invokeMethod(object.data(), "doIt"); + QTRY_VERIFY(object->property("passed").toBool()); } } -- cgit v1.2.3 From e22b624d9ab1f36021adb9cdbfa9b37054282bb8 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 14 Aug 2017 16:29:46 +0200 Subject: Fix crashes with closures created in QML components When closures created inside QML components are called after the surrounding component (and consequently QML context) has been destroyed, we are in a somewhat limited environment. Initially we would just crash as the calling QML context is not valid anymore. We can alleviate that by introducing reference counting on the context and letting the QML context wrapper keep a strong reference. This avoids the crashes and also ensures that at least imports continue to be accessible within these contexts (as the singleton test case demonstrates). Task-number: QTBUG-61781 Change-Id: I893f171842d01b0863d95a02ea738adc2620e236 Reviewed-by: Lars Knoll --- tests/auto/qml/qqmlcontext/data/Singleton.qml | 5 ++++ .../data/contextViaClosureAfterDestruction.qml | 14 +++++++++++ tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 28 ++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 tests/auto/qml/qqmlcontext/data/Singleton.qml create mode 100644 tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml (limited to 'tests/auto') 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 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 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" -- cgit v1.2.3 From a32cf1a22d096b33340cddbe91328c6c088e221d Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 6 Sep 2017 16:26:27 +0200 Subject: Disable deferring when referenced as a grouped property This allows us to fix QTBUG-50992 - the issue with most votes in QQC2. Task-number: QTBUG-63036 Change-Id: I996cd1128582b80e0c8480ae143d682c1e8eb8fe Reviewed-by: Simon Hausmann Reviewed-by: Qt CI Bot --- .../qqmllanguage/data/MyLazyDeferredSubObject.qml | 6 ++++++ .../qml/qqmllanguage/data/lazyDeferredSubObject.qml | 5 +++++ tests/auto/qml/qqmllanguage/testtypes.cpp | 2 ++ tests/auto/qml/qqmllanguage/testtypes.h | 20 ++++++++++++++++++++ tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 16 ++++++++++++++++ 5 files changed, 49 insertions(+) create mode 100644 tests/auto/qml/qqmllanguage/data/MyLazyDeferredSubObject.qml create mode 100644 tests/auto/qml/qqmllanguage/data/lazyDeferredSubObject.qml (limited to 'tests/auto') 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("Test", 1, 0, "MyTypeObjectSingleton", myTypeObjectSingleton); qmlRegisterType("Test", 1, 0, "MyArrayBufferTestClass"); + + qmlRegisterType("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 7d7a8ac6d3..b0e677feb8 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1331,6 +1331,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(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 39f5082c70..8b84ee878f 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -247,6 +247,7 @@ private slots: void propertyCacheInSync(); void rootObjectInCreationNotForSubObjects(); + void lazyDeferredSubObject(); void noChildEvents(); @@ -4242,6 +4243,21 @@ void tst_qqmllanguage::rootObjectInCreationNotForSubObjects() QVERIFY(!ddata->rootObjectInCreation); } +// QTBUG-63036 +void tst_qqmllanguage::lazyDeferredSubObject() +{ + QQmlComponent component(&engine, testFile("lazyDeferredSubObject.qml")); + VERIFY_ERRORS(0); + QScopedPointer object(component.create()); + QVERIFY(!object.isNull()); + + QObject *subObject = qvariant_cast(object->property("subObject")); + QVERIFY(subObject); + + QCOMPARE(object->objectName(), QStringLiteral("custom")); + QCOMPARE(subObject->objectName(), QStringLiteral("custom")); +} + void tst_qqmllanguage::noChildEvents() { QQmlComponent component(&engine); -- cgit v1.2.3 From ebda8170a6b00b830fba59a230506ab3ca52e6c5 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 8 Sep 2017 10:03:48 +0200 Subject: Get rid of the root object index variable This is a follow-up to the parent commit to remove the variable that is really a constant (zero). Change-Id: I8fc20027c5c7b871269b814cb8b93636e94be267 Reviewed-by: Lars Knoll --- tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 2 +- tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 8b84ee878f..30c34426af 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -2136,7 +2136,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) { diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp index 1fc803a395..dd4edeb97d 100644 --- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp +++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp @@ -85,7 +85,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); @@ -140,7 +140,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); -- cgit v1.2.3 From c1fed764a2495373a9e4563bc3ac0d578b2f9409 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 8 Aug 2017 12:39:54 +0200 Subject: Fix reuse of regexp objects by regexp literals Accoding to the standard the regexp objects created by literals should be separate objects as if calling new. We were violating that by caching the same object for every instance of a literal. This also fixes a problem with leaking values of lastIndex between separate instances of the same global regexp literal. Task-number: QTBUG-62175 Change-Id: Ib22e9ee68de1d1209fbd4212e72f576bc059d245 Reviewed-by: Simon Hausmann --- tests/auto/qml/qjsengine/tst_qjsengine.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'tests/auto') diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 2642d10545..8b815f7a06 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(); @@ -3296,6 +3297,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; -- cgit v1.2.3 From 0b73daa4f6858aa8d52e6b958d8f0b3209858b80 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 31 Aug 2017 16:53:21 -0500 Subject: Fix issue with programmatic flicking at bounds Ensure that the same flick consistently produces the same results, by making sure we don't use old timestamps from previous flicks. Task-number: QTBUG-62939 Change-Id: Ie738076abba66d38ff505292925e9441c38a3c95 Reviewed-by: Shawn Rutledge --- .../data/programmaticFlickAtBounds3.qml | 19 ++++++++++++++ .../quick/qquicklistview/tst_qquicklistview.cpp | 30 ++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml (limited to 'tests/auto') 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 window(createView()); + window->setSource(testFileUrl("programmaticFlickAtBounds3.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast(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; -- cgit v1.2.3 From a763d6a88be732de4beb3c28dbe2cde7a063c83a Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Thu, 7 Sep 2017 22:20:14 -0700 Subject: Add missing math.h include for math functions On some platforms, math functions in the std namespace don't work even if cmath is included. Change-Id: Ia71d22b07f508e0584de5320f376fbf4b3a2887b Reviewed-by: Thiago Macieira --- tests/auto/quick/qquickgridview/tst_qquickgridview.cpp | 2 ++ tests/auto/quick/qquickpathview/tst_qquickpathview.cpp | 2 ++ 2 files changed, 4 insertions(+) (limited to 'tests/auto') 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 #include "qplatformdefs.h" +#include + Q_DECLARE_METATYPE(QQuickGridView::Flow) Q_DECLARE_METATYPE(Qt::LayoutDirection) Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection) 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 + using namespace QQuickViewTestUtil; using namespace QQuickVisualTestUtil; -- cgit v1.2.3 From 98358715930739ca8de172d88c5ce6941c275ff3 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 12 Sep 2017 15:13:33 +0200 Subject: Fix qml cache invalidation when changing dependent C++ registered QML singletons When a qml file uses a qml singleton, we need to reliably detect when the singleton changes and re-generate the cache of the qml file using it. This is a scenario covered and fixed by commit 5b94de09cc738837d1539e28b3c0dccd17c18d29, with the exception that currently QML singletons registered via qmlRegisterSingleton were not added to the list of dependent singletons for a qml file. We can fix this by extending findCompositeSingletons() to also cover the singletons that do not originate from a qmldir file. [ChangeLog][Qt][Qml] Fixed bug where sometimes changes to a qml singleton would not propagate to the users or cause crashes. Task-number: QTBUG-62243 Change-Id: I16c3d9ba65fd82e898a29b946c341907751135a9 Reviewed-by: Lars Knoll --- tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp | 61 ++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'tests/auto') 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 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 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 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" -- cgit v1.2.3 From fa00f0a0206f87b43cd1ee5448efe20cb6ff8e44 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 12 Sep 2017 17:20:47 +0200 Subject: Error out when compiling signal handlers with arguments in qml files Ahead of time we cannot tell whether the use of "arguments" in a signal hander refers to the JS arguments object or a potential arguments signal parameter. Resolving that requires access to information we currently don't have. The QML engine has it at run-time (in SignalHandlerConverter) and that's why it works there accordingly. However when generating caches ahead of time, let's rather produce an error message with a hint how to work around it instead of producing differing behavior at run-time. Task-number: QTBUG-60011 Change-Id: I9e460bd467dbb5998f12a44c439223ea44e7bbad Reviewed-by: Lars Knoll --- tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp | 35 ++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index b7e616a050..b69071dd59 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -43,6 +43,7 @@ private slots: void loadGeneratedFile(); void translationExpressionSupport(); + void errorOnArgumentsInSignalHandler(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -67,15 +68,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; @@ -158,6 +164,31 @@ void tst_qmlcachegen::translationExpressionSupport() QCOMPARE(obj->property("text").toString(), QString("All Ok")); } +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" -- cgit v1.2.3 From bb02a577f0fbf3bd2a273129e6cb57cfc9a338c8 Mon Sep 17 00:00:00 2001 From: Pal Toth Date: Tue, 12 Sep 2017 12:49:40 +0300 Subject: Add NOTIFY signal for QQuickAnimatedImage::frameCount Task-number: QTBUG-62913 Change-Id: Ib561e0ab6582c1df41ae1c75ba304377c00d63f0 Reviewed-by: Shawn Rutledge --- .../auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tests/auto') 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; } -- cgit v1.2.3 From 3604cae410f29597c97ba73df6d31a9b54e6d30d Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Tue, 12 Sep 2017 17:12:18 +0200 Subject: QQuickTextEdit: call implicitWidth() even if requireImplicitWidth is true Before once requireImplicitWidth was set to true by requesting the implicit width, the implicit (and width) was never updated again, even if the text was updated/changed. Adding also a test Task-number: QTBUG-63153 Change-Id: Ie3bac4baeb14c2e69acc43d11a351ac91d5400da Reviewed-by: Shawn Rutledge Reviewed-by: J-P Nurmi Reviewed-by: Alessandro Portale Reviewed-by: Thomas Hartmann --- tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'tests/auto') 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(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 }"; -- cgit v1.2.3 From bfab1db38167d31f0487f96d2d4b02d9243bc777 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 15 Sep 2017 13:56:36 +0200 Subject: Fall back to the ObjectWrapper for model advanceIterator When falling back to the QObjectWrapper it will add in the extra parts added when the roles were added to the object created by the model to hold the data being returned. This was causing the last entry to be duplicated and causing extra work too. Task-number: QTBUG-54285 Task-number: QTBUG-62156 Change-Id: I2907477277df8d16db4491a4999f004433e4205c Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index 555ca5713e..f5c0e5ddf7 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 scene(component.create()); + QQmlListModel *model = scene->findChild("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" -- cgit v1.2.3 From 71a18fd64c93afa00f4d89de2ba47663f41eba2c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 18 Sep 2017 16:26:17 +0200 Subject: Fix qmlClearTypeRegistrations() not dropping all registrations In commit 48c09a85ce397979c7e706e3694c879ffe456e09 we added the undeletableTypes container to hold a reference on C++ registered types to keep the indices returned by the public qmlRegisterType() API stable. Since qmlClearTypeRegistrations() is API that also resets those indices, we must also clear the undeletableTypes container to avoid leaking memory. Change-Id: I2038c00913f894d58aca3714d64d497493585326 Reviewed-by: Lars Knoll --- .../qml/qqmlenginecleanup/qqmlenginecleanup.pro | 2 +- .../qqmlenginecleanup/tst_qqmlenginecleanup.cpp | 59 +++++++++++++++++++--- 2 files changed, 52 insertions(+), 9 deletions(-) (limited to 'tests/auto') 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 #include #include +#include +#include //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("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("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) -- cgit v1.2.3